派大星 · 2021年01月18日

TNN行业首发Arm 32位 FP16指令加速,理论性能翻倍

首发:NeuralTalk
作者:腾讯优图

这次TNN又迎来重大更新,下面一起看看吧!


TNN由腾讯优图实验室打造,移动端高性能、轻量级推理框架,同时拥有跨平台、高性能、模型压缩、代码裁剪等众多突出优势。TNN框架在原有Rapidnet、ncnn框架的基础上进一步加强了移动端设备的支持以及性能优化,同时也借鉴了业界主流开源框架高性能和良好拓展性的优点。目前TNN已经在手Q、微视、P图等应用中落地,欢迎大家参与协同共建,促进TNN推理框架进一步完善。

01

Why-FP16指令加速背景

1.1 什么是FP16数据?FP16指令有什么好处?

image.png

FP16是半精度浮点格式,相比常用的FP32单精度浮点,数据宽度降低了一半。2016年Arm更新了Armv8.2-A Extension扩展指令集,其中包含FP16半精度浮点运算。Arm NEON向量指令长度为128位,一条FP32向量可完成4个单精度浮点数运算,一条FP16向量可完成8个半精度浮点数运算,使理论峰值性能翻倍。如果该指令用于加速网络推理,相比于FP32预期能达到2倍加速。

 

1.2 为什么要支持Arm32位FP16指令加速?

智能手机分为Arm32和Arm64位两种架构,其中Arm64占绝大比例,苹果从2013年9月发布iPhone5s后,所有机型全都是Arm64架构。在Arm64架构手机上,App编译为64位可以获得最大的性能,但Arm64架构也支持按照32位编译的APP运行,而Arm32架构无法支持按照64位编译的APP运行。因此出于机型覆盖率以及软件包大小的考虑,当前众多App只会发布32位编译的版本。

经调研,行业开源推理框架如ncnn、MNN等仅支持Arm64位FP16指令加速,这样32位App无法享受FP16指令加速效果。针对这个行业缺失,TNN在架构兼容、模型兼容、代码结构设计等方面率先进行探索,对Arm64位和Arm32架构均实现了FP16指令优化,让64位和32位App都能发挥硬件FP16向量加速的能力。

02

How-如何支持FP16指令加速

 

2.1 架构兼容性设计

由于深度学习网络的算子种类繁多,并且随着新模型不断被开发,算子类型也会随之增加,因此,难以一次性为所有层提供FP16加速。我们采用TNN中广泛使用的注册机制,以实现FP16加速的增量开发。实现如下:

①在ArmDevice下维护一个全局的layer\_precision\_map,将算子类型映射到其支持的数据类型;

②每实现一个FP16加速算子,使用REGISTER\_ARM\_PRECISION\_FP16+LayerType,更新layer\_precision\_map;

③在运行模型的初始化过程,TNN根据layer\_precision\_map的信息,为模型中的每一层分发计算精度。仅当算子已支持FP16加速,并且运行平台具备FP16加速硬件时,该层才会使用FP16精度计算。当用户设置的网络精度为PRECISION\_HIGH时,可以强制禁用FP16加速。

 

2.2 模型兼容性设计

部署时模型的算子各种各种,为了获得最大的性能,TNN支持模型按照FP32和FP16混合运行加速。对模型中已实现FP16加速的算子,TNN默认自动按照FP16加速,而对模型中未实现FP16加速的算子,TNN在静态图中自动插入Reformat层转为FP32加速。如下图所示:

image.png

在TNN的图优化过程中,当发现Pad层不支持FP16加速时(如图a所示),会在其输入和输出分别插入Reformat层。Reformat层负责将FP16和FP32数据格式以及数据排布做相互转换,以支持Pad层单独采用FP32计算,其余层仍采用FP16计算。

如果模型中存在多个相连的层不支持FP16(如图b所示),TNN的图优化机制会避免在这些层之间插入成对的Reformat层,以提高运行效率。

 

2.3 代码结构设计

为了在32位和64位库中都支持FP16,整体代码结构如下图所示。其主要分为五个部分,通过CMake中不同的配置项,可编译出不同的target。各个部分的主要区别体现在针对不同Arm指令集实现了特定优化。

image.png

由上图可知,aarch32和aarch64 FP16指令代码独立于其他部分。因为编译FP16指令需要添加特定的编译选项,如果对TNN代码全局添加该选项,会导致编译器将选项应用到所有代码中,然后基于Armv8.2-A架构生成目标文件。

例如在Arm64 Target中,在编译Armv8指令代码时添加该选项,会生成一些Armv8.1或Armv8.2指令集中独有的指令。这些指令若在不支持v8.1和v8.2的Armv8 CPU上运行,会直接导致程序崩溃。因此,为了最大限度地提高兼容性,Armv8.2-A FP16指令代码被单独剥离,单独使用编译选项,避免影响其他部分。

综上所述,TNN库会同时包含两种架构的指令:

  • 64位库:包含Armv8指令和aarch64 Armv8.2-A FP16指令。
  • 32位库:包含Armv7指令和aarch32 Armv8.2-A FP16指令。

 

2.4 运行时兼容性设计

由上可知,TNN库中包含两种架构的指令。当运行64位或32位库时,若在不支持Armv8.2-A的CPU上执行Armv8.2-A指令,会直接导致程序崩溃,在运行时造成兼容性问题。
针对上述问题,在执行推理之前,TNN会判断当前运行的CPU是否在白名单中、是否支持Armv8.2-A。如果支持,则会运行FP16算子,否则仍然运行FP32算子,避免执行Armv8.2-A FP16指令。具体判断方式如下:
①在IOS和OSX下,通过系统调用sysctlbyname("hw.cpufamily"),获取CPU型号,然后与维护的白名单比较,判断CPU是否支持FP16加速。目前的白名单包括IOS的A11-A14,和OSX的M1。
②在Android和Linux下,通过系统调用getauxval(AT\_HWCAP),获取hwcap flag,然后与HWCAP\_FPHP和HWCAP\_ASIMDHP掩码比较,当FPHP位和ASIMDHP位都为1时,CPU可支持FP16加速。
由于Android的C库在API级别18及更高版本中才支持 getauxval,在低版本的32位Android系统中,该系统调用可能会失败。为了支持aarch32 FP16加速,采用直接解析/proc/cpuinfo的方式,判断CPU是否支持FP16加速。通过/proc/cpuinfo获取处理器的MIDR(Main ID Register),根据该标志可判断处理器厂商和型号,例如Arm的Cortex-A55,海思的Cortex-A76 (HiSilicon)等。然后与维护的白名单比较,最终判断硬件是否支持FP16加速。

03

What-FP16指令加速效果

TNN已对部分算子实现了FP16优化,在64位和32位库中均取得了不错的加速效果,相比于一些开源框架也具备一定的性能优势,如下图中的对比数据所示。

image.png

image.png

在A76大核上,TNN的FP32和FP16性能均能保持前列。在A55小核上,Bolt框架针对A55单独做了特殊优化,在性能测试时效果会更好。但实际应用中,由于进程可能会在小核和大核上动态调度,A55特殊优化版本在A76大核上运行的性能较差,所以实际应用的表现不一定会好。TNN采取的是相对折中的实现,在大核和小核上都能取得不错的性能表现。

04

Where-TNN如何启用FP16加速

TNN已经对大量的实现细节做了封装,只需要对少量参数进行配置,就可以轻松获得FP16的加速。

链接:https://github.com/Tencent/TNN

1)编译

TNN工程的根目录下提供了各个平台的编译脚本,只需要在这些脚本的基础上打开TNN\_ARM82\_ENABLE,就可以将Armv8.2的优化代码编译到TNN的lib中,当前默认是OFF。

image.png

2)运行

在初始化时,将precision参数设置成PRECISON\_AUTO,TNN内部就会根据CPU的型号以及layer的实现情况自动去调用FP16的代码,当前默认是PRECISION\_AUTO,所以不用做任何修改。

image.png

05

结束语

TNN当前正在与PCG光影团队合作,后续还会支持更多算子的Armv8.2-A FP16优化,同时也会尝试去实现Armv8.2-A的Dot扩展指令,优化在最新机型上的int8模型性能。

往期回顾


本作品采用知识共享署名-相同方式共享 4.0 通用许可协议进行许可。
欢迎关注公众号,关注模型压缩、低比特量化、移动端推理加速优化、部署。
嵌入式AI.jpg
更多嵌入式AI相关技术干货请关注嵌入式AI专栏。
推荐阅读
关注数
18801
内容数
1347
嵌入式端AI,包括AI算法在推理框架Tengine,MNN,NCNN,PaddlePaddle及相关芯片上的实现。欢迎加入微信交流群,微信号:aijishu20(备注:嵌入式)
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息