圈圈虫 · 2月28日

Int8量化-ncnn社区Int8重构之路

本文是对NCNN社区int8模块的重构开发,再也不用担心溢出问题了,速度也还行。
作者:圈圈虫
首发知乎

传送门



从去年8月初首次向社区提交armv7a版本的int8功能模块到现在过去半年了,中途经过N次迭代。原本以为提交后就可以去别处摸鱼打望,谁知已掉进不断自己挖坑填坑的过程。中间多次尝试放弃,社区维护比想象的困难大得多:速度上不去,精度掉得多,armv7-a位速度OK,arm64-v8a位负优化,x86模拟int8没问题,切换到arm平台精度就狂掉,各种trick不work,社区大佬们天天吹水。

有幸同nihui共进晚餐(哈哈,有些人羡慕得都流口水了……)本尊原话:“ncnn也是我摸鱼创造出来的,2017年开源到现在(2019年1月)也快两年了,你不做int8就没人做了,反正大家喜欢当伸手党,既然开源出来,就要做到第一梯队,推动业界发展,向大家提供一个新的思路也算成功!”得嘞,我被上纲上线了,摊手.gif,幸运的是,感谢圈内各路大神的鼓励和指点,最终还是熬过来了,完成了这次int8模块的重构开发,再也不用担心溢出问题了,速度也还行吧。

这里非常感谢公司以及合作伙伴@格灵深瞳DeepGlint对开源社区的大力支持。

起因

去年(2018年8月)首次向ncnn社区提交的int8功能的模块,源于公司内部项目的一小部分,当初只是为了实现人脸检测网络模型加速,所以只支持conv3x3/conv1x1的卷积成,而且还只支持armv7-a架构。后面考虑社区对arm64-v8a平台需求更大,现在能用的手机也几乎100%是64位arm架构的,所以去年国庆节又疯狂码代码7天,补全arm64-v8a架构的int8支持。美滋滋上班不到一周被社区打回原形了,arm平台存在相当严重的溢出问题(基本上就不能用)。当初方案背锅了,由于最初的代码采用s8 * s8 -> s16,s16累加8次 -> s32,那么问题就出现了

1.jpg
不听高叔叔的指点,打脸了吧……

打脸都打肿了。退而求其次,只能采用s8->s16,s16* s16->s32的方案了,牺牲速度,满足int8量化任务顺利完成,开启本次int8模块重构旅程。

目标

  • 解决卷积乘加累加导致的溢出问题
  • int8 conv3x3s1速度比fp32 conv3x3s1慢的问题
  • 含有dwconv layer的网络模型,量化后精度下降过多的问题
  • 其余常规尺寸卷积层的int8支持

实现过程

解决卷积乘加累加导致的溢出问题

方案很简单,就是用s16乘加替换原有s8乘加,初次在hisi3519(Cortex-A17,armv7a)平台上完成conv1x1s1 layer的新版实现,实测速度有惊喜,咦~速度比之前还快了一丢丢,我简直是天才(出来混迟早要还的,后续在arm64-v8a上无限制打脸)。真是服了arm当初的流水线设计,arm64-v8a上neon浮点比整型多一个发射单元,于是在arm64-v8a(例如Cortex-A72)上单精度浮点乘加指令与s16整型乘加指令的吞吐率是一样的。当初qnnpack也提及过,合理使用sadalp和smlal指令实现Dual-Issue ,提高IPC(instruction per cycle)。

int8 conv3x3s1速度比fp32 conv3x3s1慢的问题

这个问题很麻烦,conv3x3s1是有Winograd F(6,3)算法增益的,理论计算量缩小5.0625倍,wino43是4倍,wino23是2.25倍,当然实际工程还要考虑两次trans和访存开销,加速比并没那么高。 int8直接卷积计算的速度肯定是赶不上了。能否实现int8 winograd呢?

答案是可以的,毕竟2018年中旬的时候,商汤科技已经发了paper了,虽然是基于FPGA平台的,但也说明工程应用是完全可行。Intel的mkl-dnn模块也已经实现了int8 winograd F(2,3),winograd-cnn的作者(给大佬倒冰红茶.gif)也在其github中置顶issue进行了相关讨论。于是站在巨人的肩膀上实现了int8 winograd F(2,3),哈哈全面超越fp32了,一天后在arm64-v8a上被打脸,于是又实现了int8 winograd F(4,3)。下面是int8 winograd F(2,3)实现的部分细节(假设你们都懂winograd在cnn中的实现原理)

2.jpg
Int8 Winograd F(2,3)实现技巧

3.jpg
基于armv7a框架上的wino-fp32 F(6,3)与wino-int8 F(2,3)/F(4,3)速度对比

含有ConvolutonDepthwise layer的网络模型,量化后精度下降过多的问题

当初精度效果差,原因在于权重没有分通道量化,实现分通道量化后,精度美滋滋。
4.jpg

其余常规尺寸卷积层的int8支持

其余尺寸的实现为了赶进度,就偷懒使用常规的im2col+sgemm的方式了,目前只实现了sgemm_int8_4x4_kernel,先解决有没有,再说快不快吧~

结果

圈子太小,就不和别的框架对比了,ncnn-int8全面超越ncnn-fp32,成功!(下图貌似有模型打脸了,说明还有优化空间

5.jpg
荣耀V10 Kirin970(Cortex-A73@2.3GHz)

6.jpg
荣耀V10 Kirin970(Cortex-A53@1.8GHz)

7.jpg
RK3288(Cortex-A17@1.8GHz)

感想

今年将是深度学习-计算机视觉领域模型低比特量化产品落地的第一年,毕竟各路NPU厂家均采用int8量化压缩方案,安谋科技(我偏不说ARM……)推出了新的框架Cortex-A76/A55,Mali-G76全面支持int8 dot指令,高通的超强DSP int8 tensor虎视眈眈,Intel的AVX512默默吃瓜,NVIDIA黄老板身穿皮衣手持TensorRT说“我不是针对谁……”,三大炼丹炉(TensorFlow、PyTorch、MxNet)也开始发布自己的int8模型训练方案。希望年末int8模型能够满足当前所有的任务精度需求。

相关传送门


更多AI移动端优化相关技术干货请关注嵌入式AI专栏 及知乎账号圈圈虫
9 阅读 919
推荐阅读
5 条评论
关注数
12218
内容数
190
嵌入式端AI,包括AI算法在推理框架Tengine,MNN,NCNN,PaddlePaddle及相关芯片上的实现。欢迎加入微信交流群,微信号:gg15319381845(备注:嵌入式)
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
Arm中国学堂公众号
关注Arm中国学堂
实时获取免费 Arm 教学资源信息
Arm中国招聘公众号
关注Arm中国招聘
实时获取 Arm 中国职位信息