Int8量化算子在移动端CPU的性能优化

2757a9f044c6fc26cd2d8be31dec079f.gif

本文介绍了Depthwise Convolution 的Int8算子在移动端CPU上的性能优化方案。ARM架构的升级和相应指令集的更新不断提高移动端各算子的性能上限,结合数据重排和Sdot指令能给DepthwiseConv量化算子的性能带来较大提升。

58f1dd0a776e994a8b31670fc50dd0f3.png

背景

MNN对ConvolutionDepthwise Int8量化算子在ARM V8(64位)和ARM V8.2上的性能做了较大的优化,主要优化方法包括改变数据的排列方式以及使用Sdot指令。为了方便叙述,后文统一用DepthwiseConvInt8来表示ConvolutionDepthwiseInt8量化算子。在优化前在安卓手机上测得该量化算子的耗时比使用FP16推理多三倍,严重影响量化模型在端侧的性能。本文从ARM汇编算子的角度出发讲解DepthwiseConvInt8算子的优化方案。

e4d886e47febc1358e81a66d43c5ac90.png

性能瓶颈定位及优化方案

▐  ARM V8 优化数据排列方式
  • 方案介绍

MNN中DepthwiseConvInt8的输入数据格式是e12158cbca3e8f19493877bf12b6a7f4.png,后文简称这种数据排列数据方式为C4),即每4个Channel的数据排列在一起。同理,我们用C16表示每16个Channel的数据连续排列的数据排布方式。下图直观地描述了C4的数据排列方式,假设b9a3da19a62bd3319cb2490cde131abc.jpeg,图中每一个小正方形代表一个数据,四种颜色分别代表feature map上四个坐标点,正方形内的数字编号d39e03b6c6d4ddc63b09cd56c15e1614.png表示它们在内存中的排列次序。

1b0faf502bd434895f744c2a7ee60a0b.jpeg

一般地,我们会对da28bb200badf81d09d73fc2a5b23f04.png采取多线程计算,对8ddd783c4e21837f86e8f501fddd20bb.png采取ARM汇编并行计算。本文关注单线程时对c40f95a237b1bda0e40fe761e8ba5a20.png维度做性能优化。在ARM汇编中通常会同时计算输出的特征图上多个点的结果,这要求我们尽量能够同时读取输入特征图上的点数据。例如当Depthwise层的Stride参数等于1时,同时计算输出特征图中4个点坐标的数据(一共4(坐标点)*4(channel)=16个数据),我们需要读取上图中编号为ded67a97eecd1549f3374a0a867af552.png的正方形数据。当每个数据占4个字节(32位)时,4个输入数据正好填满一个向量寄存器。但是在Int8量化算子中,每个输入数据占8位(1个字节),如果仍然采取C4的数据排列,则4个数据填不满一个向量寄存器。特别地,当Depthwise层的Stride参数不是1时,采用C4的数据排列方式会导致feature map上多个数据时不能连续读取,进而导致性能损失。所以对于Int8类型的输入数据,在ARM平台上我们首先考虑将C4的数据排列方式改为C16的排列,这样保证可以连续地读取16个Int8类型数据来填满一个向量寄存器。我们用汇编代码来表示这两种数据读取方式的差异。

/* x0: source address, 读取feature map上的4个点 */
/* pack=4, stridex = 2, sizeof(inputData)=1 */
ld1 {v0.s}[0], [x0], #8
ld1 {v1.s}[0], [x0], #8
ld1 {v2.s}[0], [x0], #8
ld1 {v3.s}[0], [x0], #8
/* pack=16, stridex = 2, sizeof(inputData)=1 */
ld1 {v0.4s}, [x0], #32
ld1 {v1.4s}, [x0], #32
ld1 {v2.4s}, [x0], #32
ld1 {v3.4s}, [x0], #32

从代码中可以看到同样是使用4条指令读取数据,C16比C4多读取3倍的数据。所以对于ARM V8平台,我们将pack=4更改为pack=16,虽然该方案额外增加了推理时数据排布的转换时间,但是在ARM汇编内部更好地并行化带来的收益更大。

  • ARM V8 性能提升结果

本文中所有的性能数据均来源于美颜模型在华为Mate40 Pro上的测试结果。美颜模型中一共含有23个Convolution Depthwise算子,所有算子都是3x3 kernel,其中19个算子的stride=1,4个算子的stride=2. 表格中记录的算子耗时是美颜模型中所有23个convolution depthwise算子在一次推理中的耗时总和,单位:ms.

华为 Mate40 Pro ARM V8

优化前 C4数据排列

优化后 C16数据排列

Convolution Depthwise Int8 量化算子

4.46 ms

2.78 ms

改变数据排列方式的方案性能加速比是1.6.

▐  ARM V8.2 使用sdot指令提高性能
  • 为什么sdot指令能提高算子性能?

虽然在ARM V8平台上DepthwiseConvInt8算子的性能加速已经有明显效果,但ARM V8.2指令集为ARM平台上CPU算子的性能加速提供了更大的空间。与此同时,随着ARM V8.2指令集在旗舰型手机上的普及,浮点模型使用fp16推理极大地提高了移动端性能,量化模型想要保持竞争力也需要进一步优化。在DepthwiseConvInt8算子含有大量乘加计算,以3x3kernel为例,先进行9次乘法再进行1次加法,此时需要9条指令才能得到一个输出数据。ARM V8.2平台提供的sdot指令能实现3条指令即可得到1个输入数据。汇编代码能够直观展示两者差异:

// 3x3kernel 不使用sdot指令,进行9次循环
Loop_Kernel_H3:Loop_Kernel_W3:smlal v0.4s, v1.4h, v2.4s // 累加结果存储在v0中// 3x3kernel 使用sdot指令
sdot v0.4s, v1.16b, v3.16b
sdot v0.4s, v2.16b, v4.16b
smlal v0.4s, v5.4h, v6.4h
  • 使用sdot指令会带来额外开销吗?

我们先关注sdot指令是如何加速若干个元素乘加操作的,下面的代码展示了sdot指令计算原理。

// v0.16b : [0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15]
// v1.16b : [0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15]// v2.s[0]=v0.b[0]*v1.b[0]+v0.b[1]*v1.b[1]
//         +v0.b[2]*v1.b[2]+v0.b[3]*v1.b[3]
sdot v2.4s, v0.16b, v1.16b // v2.4s: [14,126,366,734]

由代码示例得知,进行累加的4个元素在内存中是连续排列的。上文中已经介绍了算子的输入数据排列是C4,同一个Kernel中的所有元素在内存中肯定不能连续读取。

sdot指令的使用之前需要重排数据才能得到正确的结果,注意此时的数据重排和ARM V8优化中的数据重排完全不同。上文中我们提到的ARM V8上的数据重排仅仅是在Channel维度将C4修改为C16,而ARM V8.2上sdot 指令之前的数据重排需要将一个kernel中的9个元素每4个连续排列在一起。我们用一张图来解释重排规则。不妨假设kernel size是3x3,后文中均采取此假设。

78aab95968d23433e6bd60ca10cfe240.jpeg

显然数据重排的时间会极大影响算子性能,高效地进行数据重排是ARM V8.2 DepthwiseConvInt8性能优化的关键步骤。

  • ARM V8.2 如何进行数据重排

思考重排问题时我们将问题简化,不需要写代码就能得到最高效的解决方案(前提是足够熟悉ARM汇编指令,因为指令集了解地越多,解决方法就越多)。我们把问题抽象为如何高效重排一个向量寄存器中的16个int8_t数据。重排前后的数据排列对比图如下:

830155cebddbddd7e60b2c3a1da7bd08.jpeg

从抽象问题回到对3x3 kernel中的数据进行重排,我们最终需要9个元素相乘再累加,所以我们对kernel中的每4个元素进行重排,剩下的1个再使用smlal指令累加结果即可。当然我们推理前就可以对权值矩阵进行对应元素的重排,不占用推理时间。跟ARM V8上的优化不同的是,ARM V8.2的重排是基于C4进行的而不是C16. 无论是C8还是C16都会给数据重排带来更多的开销,具体来说就是需要的重排指令条数更多,这里就不详细讲解C8和C16场景下的最优重排方案了。

因为数据重排这一步是必不可少的,所以在该算子中使用sdot指令的前提是kernel size是已知的。当前MNN对于DepthwiseConvInt8 在ARM V8.2平台上的优化仅支持3x3 kernel.

  • ARM V8.2 性能提升结果

华为 Mate40 Pro ARM V8

优化前 C4数据排列

ARM V8使用C16优化后

ARM V8 使用sdot指令优化后

Convolution Depthwise Int8 量化算子

4.46 ms

2.78 ms

1.75 ms

通过使用sdot 指令,算子性能加速比达到了2.55.

▐  ARM V8.2和ARM V8的优化方案差异总结

在ARM V8.2 上优化DepthwiseConvInt8算子性能的核心是重排输入数据以方便使用sdot指令进行累加。因为Depthwise算子的计算复杂度比Convolution低,所以数据重排的耗时对算子性能影响更大。经过稿纸推演和实际测试,我们确定了耗时最低的数据重排方案,即在输入数据是NC4HW4时,用tbl指令将与3x3kernel中9个数据分成3组,第一组和第二组分别有4个数据连续排列,最后一个数据单独排列。在ARM V8上的优化受限于指令种类数量,目前仅从减少数据读取时间角度优化算子性能。

▐  总结

ARM架构的升级和相应指令集的更新不断提高移动端各算子的性能上限,目前在ARM V8.2上对于Convolution depthwise Int8量化算子的性能已经接近最优,但受限于数据重排带来的额外负载,Int8量化算子的性能仍然无法超越半浮点精度推理性能。

e49ab99313a80c37ef3503114e7a2fb4.png

团队介绍

大淘宝技术Meta Team,负责面向消费场景的3D/XR基础技术建设和创新应用探索,通过技术和应用创新找到以手机及XR 新设备为载体的消费购物3D/XR新体验。团队在端智能、商品三维重建、3D引擎、XR引擎等方面有深厚的技术积累。先后发布端侧推理引擎MNN,端侧实时视觉算法库PixelAI,商品三维重建工具Object Drawer等技术。团队在OSDI、MLSys、CVPR、ICCV、NeurIPS、TPAMI等顶级学术会议和期刊上发表多篇论文。

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/170983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Shell脚本:Linux Shell脚本学习指南(第三部分Shell高级)二

七、Shell Here String&#xff08;内嵌字符串&#xff0c;嵌入式字符串&#xff09; Here String 是《六、Shell Here Document&#xff08;内嵌文档/立即文档&#xff09;》的一个变种&#xff0c;它的用法如下&#xff1a; command <<< string command 是 Shell 命…

网络攻击的常见手段

网络攻击的常见手段&#xff1a;IP欺骗、洪水攻击与TCP重置反击 随着互联网的普及和信息技术的快速发展&#xff0c;网络攻击手段日益复杂和多样化。在众多网络攻击手段中&#xff0c;IP欺骗、洪水攻击和TCP重置反击是三种较为常见且具有代表性的攻击方法。本文将详细介绍这三种…

JavaScript如何实现钟表效果,时分秒针指向当前时间,并显示当前年月日,及2024春节倒计时,源码奉上

本篇有运用jQuery&#xff0c;记得引入jQuery库&#xff0c;否则不会执行的喔~ <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> <meta name"chenc" content"Runoob"> <met…

element-ui表格无法横向拖动问题

是不是用到了fixed // 因为我只有在小屏显示不下的时候才会出现这个问题所以我在这里做了适配(建议把样式放在全局) media screen and (max-width: 1800px) {// 由于使用了fixed导致横向条无法拖动出现bug.Table-page .el-table__fixed {height: auto !important;bottom: 2px …

计算机编程基础教程,中文编程工具下载,编程构件组合按钮

计算机编程基础教程&#xff0c;中文编程工具下载&#xff0c;编程构件组合按钮 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c…

开卷翻到毒蘑菇?浅谈大模型检索增强(RAG)的鲁棒性

©PaperWeekly 原创 作者 | 陈思硕 单位 | 北京大学 研究方向 | 自然语言处理 很久没有写论文 notes 了&#xff0c;近期因为参与对检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;范式鲁棒性的研究&#xff0c;注意到了近两个月来社区中涌现了…

打包运行报no main manifest attribute

文章目录 场景解决 场景 打包运行报错&#xff1a;打包运行报no main manifest attribute, 包的大小也只有几十kb 解决 spring-boot-maven-plugin添加repackage配置,这会把引入jar <plugin><groupId>org.springframework.boot</groupId><artifactId>sp…

Java核心知识点整理大全15-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

【Kotlin】类与接口

文章目录 类的定义创建类的实例构造函数主构造函数次构造函数init语句块 数据类的定义数据类定义了componentN方法 继承AnyAny&#xff1a;非空类型的根类型Any?&#xff1a;所有类型的根类型 覆盖方法覆盖属性覆盖 抽象类接口:使用interface关键字函数&#xff1a;funUnit:让…

基于SSM和微信小程序的场地预约网站

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SSM和微信小程序的场地预约网站,jav…

RocketMq 队列(MessageQueue)

RocketMq是阿里出品&#xff08;基于MetaQ&#xff09;的开源中间件&#xff0c;已捐赠给Apache基金会并成为Apache的顶级项目。基于java语言实现&#xff0c;十万级数据吞吐量&#xff0c;ms级处理速度&#xff0c;分布式架构&#xff0c;功能强大&#xff0c;扩展性强。 官方…

Kerberos 高可用配置和验证

参考 https://cloud.tencent.com/developer/article/1078314 https://mp.weixin.qq.com/s?__bizMzI4OTY3MTUyNg&mid2247485861&idx1&snbb930a497f63ac5e63ed20c64643eec5 机器准备 Kerberos主 ip-172-31-22-86.ap-southeast-1.compute.internal 7.common2.hado…

K8s Docker实践三

单主机创建多个node 在Mac桌面上部署多个Kubernetes节点可以使用Minikube工具。Minikube是一个轻量级的Kubernetes工具&#xff0c;它可以在单个主机上创建一个虚拟集群。以下是在Mac桌面上使用Minikube部署多个Kubernetes节点的步骤&#xff1a; 安装Minikube&#xff0c;运…

【华为数通HCIP | 网络工程师】821-IGP高频题、易错题之OSPF(7)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

C语言盐水的故事(ZZULIOJ1214:盐水的故事)

题目描述 挂盐水的时候&#xff0c;如果滴起来有规律&#xff0c;先是滴一滴&#xff0c;停一下&#xff1b;然后滴二滴&#xff0c;停一 下&#xff1b;再滴三滴&#xff0c;停一下...&#xff0c;现在有一个问题&#xff1a;这瓶盐水一共有VUL毫升&#xff0c;每一滴是D毫升&…

【brpc学习实践八】bvar及其应用

什么是bvar bvar是多线程环境下的计数器类库&#xff0c;支持单维度bvar和多维度mbvar&#xff0c;方便记录和查看用户程序中的各类数值&#xff0c;它利用了thread local存储减少了cache bouncing&#xff0c;相比UbMonitor(百度内的老计数器库)几乎不会给程序增加性能开销&a…

STM32 SCF文件

文章目录 1 SCF文件2 SCT分散加载文件3 SCF文件编写 1 SCF文件 keil编译器在链接的时候&#xff0c;是根据分散加载(.scf后缀的文件)来确定程序的加载域和运行域的。 加载域就是程序运行前在flash中具体分区情况执行域就是程序运行后&#xff0c;程序在flash和ram中的分区情况…

在Windows系统上安装git-Git的过程记录

01-上git的官网下载git的windows安装版本 下载页面链接&#xff1a; https://git-scm.com/downloads 选择Standalone Installer的版本进行下载&#xff1a; 这里给大家一全git-2.43.0的百度网盘下载链接&#xff1a; https://pan.baidu.com/s/11HwNTCZmtSWj0VG2x60HIA?pwdut…

Linux 基础-常用的命令和搭建 Java 部署环境

文章目录 目录相关查看目录中的内容查看目录当前的完整路径切换目录 文件相关创建文件查看文件内容写文件vim 基础 创建删除创建目录 移动和复制移动(剪切粘贴)复制(复制粘贴) 搭建 Java 部署环境1. 安装 jdk2. 安装 tomcat1). 我们在自己电脑上下好 tomcat2). 从官网下载的 .z…

Vue: Cannot find module @/xx/xx/xx.vue or its corresponding type declarations.

编辑器&#xff1a;Webstorm项目技术栈&#xff1a;vitevuets解决 1.vite.config.js设置别名resolve: {alias: {: path.resolve(__dirname, ./src),}, }, 2.src下创建globals.d.ts//通用声明 // Vue declare module *.vue {import { DefineComponent } from vue;const componen…