ncnn是腾讯优图实验室第一次对外公开深度学习的研究成果。作为一个为手机端极致优化的高性能神经网络前向计算框架,ncnn于2017年7月正式开源,在设计之初便将手机端的特殊场景融入核心理念,成为业界首个为移动端优化的开源神经网络推断库。
1月19日,腾讯优图举办了优Tech线上沙龙,ncnn开源负责人、腾讯优图实验室高级研究员nihui围绕《ncnn的设计理念和软件工程》进行了直播分享,讲述了ncnn项目的设计动机、架构设计以及运作多年所依赖的软件工程方法。
据nihui介绍,ncnn在设计之初首先考虑的就是可用性(易用性),也就是不仅要让ncnn项目能使用,还要让开发者在使用的同时能学习,从而创造新项目。其次考虑的是移植性,基于此,ncnn项目采用了C 03标准,而非当前安卓和ios平台使用的C 11,这样就能保证老的嵌入式平台或其他平台也能同样适用。另外,ncnn项目使用了Vulkan的API,让一套代码可以在诸如安卓、IOS等任意平台上实现。
维护性也是ncnn项目的设计理念之一,为方便开发者阅读,降低阅读成本,ncnn中的优化代码都是可选的,这就相当于整个框架不依赖于优化代码,有利于分离。最后,ncnn作为底层推理框架要考虑兼容性,底层赋能后,开发者就算换代码,也能适用最新框架。
数据结构方面,ncnn的Mat只有W、H、C三个维度,没有其他框架常见的batch维度。其优势主要表现在两个方面:一是代码数量少,维护性更好;二是在实际应用场景中,像美颜、自拍等可以更快速应用出结果。
据了解,Mat中加了cstep属性,可以让每一个channel都做一个数据对齐,访问、储存等操作都可以在对齐内存上进行,效率更高。举例来说,如果不加cstep,像armV7就有很多对齐和不对齐的数据,访问速度会存在差异。
此外,ncnn的数据结构还做了Type-less,起初Mat只能放float数据类型,但int8需要放其他类型的数据,出于兼容性的考虑,Mat在尽量不改变数据结构的基础上,通过层实现的自我约定来实现数据类型解读,降低复杂性,按软件工程中的一句话说就是“约定优于配置”。
ncnn的模型中有两个文件,对此,开发者可能会有疑问:为什么成套使用的结构和权重还要放两个文件?
ncnn模型其中一个文件是Human editable(人类可编辑)。AI推理部署有一个很难的环节叫模型转换,有很多模型因为缺少某个算子或转换器没写好等问题无法转换,ncnn遇到这种情况,转出的模型也是不可用的,这时就需要用到Human editable。ncnn 主流操作方式是把param文件用编译器打开,找到不支持的算子,如Expand,删掉它或改为支持的算子,手工去优化模型结构的图。算子的参数表示是扩展性比较好的Key =Value。
另一个文件Bin,纯粹是放权重的文件,没有结构化信息,结构要放在Param中。可以把多个模型的Bin文件直接拼在一起,形成一个大的模型文件,更便于部署。
ncnn在动态推理的设计上比较前瞻,在2017年发布时就已具备三种dynamic。
一是尺寸,ncnn可以任意输入尺寸,一般其他推理加载模型时会需要指定最大尺寸,但ncnn不需要,开发者给它多少它就能算多少。
二是维度,动态shape分为两种:知道输入维度和不确定维度,ncnn的算子是直接支持不确定维度操作的,比如BinaryOp运行时接受两维数据,也接受一维和三维数据。
三是推理图,在ncnn中,可以在同一模型中实现任意节点到节点的推理路径,像条件判断和循环也可以通过不同子图,换来换去,在运行时判断和调度哪部分需要计算,哪部分不需要计算,这样的动态推理路径可以提升效率。
ncnn采用了一个纯粹的继承关系去做的架构设计,精心优化的架构代码,比如:x86、arm、vulkan等都是继承自cpu的一个最基础实践的,当遇到没有优化的参数组合时能方便的回退到cpu基础实现。ncnn中的算子kernel和op定义是不分离的,只需要一份代码,方便凝聚算子自身的模块性,减少算子之间的耦合。此外,kernel和op定义不分离也很好的践行了最初的设计理念,对于想要学习、自己做优化的开发者来说更加方便。
nihui 表示,ncnn已经做了一个比较完整的代码覆盖率,每次提交都会有代码覆盖率的检查,从而检查出许多corner case的bug,对于底层框架来说是非常好的健壮性保证。此外,ncnn项目还会用Swiftshader、QEMU去做GPU和各种架构的测试,进行一个更全面的代码健壮性检查。
作为腾讯下顶级人工智能实验室之一,腾讯优图一直聚焦计算机视觉,专注人脸识别、图像识别、OCR、机器学习、数据挖掘等领域开展技术研发和行业落地。未来腾讯优图将继续优化ncnn项目,让开发者能够更轻松将深度学习算法移植到手机端,输出高效的执行,进而产出人工智能APP,将AI技术带到用户指尖。