深度学习算法优化系列

2023-11-03

1. 前言
这是Google在CVPR 2018上发表的一篇int8量化的论文,题目为《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》。也是入门量化最经典的论文之一。论文介绍了一种只使用整数运算的量化方式,相比于浮点数运算效率更高。一起先来看看这篇论文吧。论文的axriv地址可以在附录中找到。

2. 背景
模型量化仍然属于模型压缩的范畴,而模型压缩的目的是降低模型占用的内存大小,加快模型推理速度。在这之前,主要有两方面的研究用于减少模型的大小和前向推理的时间。一是在网络结构上的改进,诸如MobileNet,SqueezeNet,ShuffleNet和DenseNet等等。二是量化权重和激活函数,将32位的浮点数用更低位的数来表示,如half-float,int,bit等等。然而这些方法并没有在一个合理的BaseLine基础上进行评估。这些网络的BaseLine几乎都是选在AlexNet,VGG16,GoogleNet这种大型网络,而这些大型网络在设计时为了达到高准确率存在很多冗余,所以在压缩这些网络时都有不小的效果体现。其二在于量化方法没有在真正的硬件上进行有效性证明。有的方法只在权重上进行量化,仅仅关心设备的存储,而不关心计算效率。有的方法如2-bit/3-bit权重网络和bit-shifit网络,它们把权重限制为0或者2n2^n2 
n
 ,即把乘法操作用二进制移位来实现。但在某些硬件上,二进制移位实现并不比乘法,加法好。并且,只有当Bit大的时候,乘法操作才显得比较"昂贵"。从上面的介绍引出这篇论文的目的,即是要将乘法的输入:权重和激活值都量化成比较小的位宽,即int8量化。

同时,量化一般可以分为两种模式,即训练后量化(post-training-quantizated)以及训练时量化(quantization-aware-training)。训练后量化比较容易理解,即将训练后的模型中的权重从float32量化到int8,并以int8的形式保存,但在实际推理时,还需要反量化为浮点数类型进行计算。这种量化方式在大模型上的效果很好,因为大模型的抗噪能力很强,但在小模型上表现就比较差了。而训练中量化意思是在训练的过程中引入伪量化操作,即在前向传播的时候,采用量化后的权重和激活值,但在反向传播的时候仍然对float类型的权重进行梯度下降,前向推理时全部使用int8的方式进行计算。

3. 方法
这篇论文提出了一种将float32量化为int8的方法,并给出了一个训练和推理框架,推理框架使得模型可以在能执行整型运算的计算设备上高效运行,训练框架和推理框架相辅相成,可以显著降低量化过程中的精度损失。

3.1 量化推理
3.1.1 量化方案
首先,定义qqq代表量化后的值,rrr代表原始的float32值,这篇论文抛弃了之前使用查表的方式将浮点数映射为整数的方法,而是直接引入了一个映射关系来表示,如公式(1)所示:


其中SSS代表缩放系数,ZZZ代表zero−pointzero-pointzero−point,即真实浮点数000映射到整数时所对应的值,和qqq的数据类型一致。对于int8量化,qqq就是8-bit整数,对于B-bit量化,q就是B-bit的实数,对于有bias的情况,就固定量化为·32-bit的实数。其中SSS的计算方式为:

S=arraymax−arraymin2bitwidth−1S=\frac{array_{max}-array_{min}}{2^{bit_width}-1}S= 

bit 
w
​    
 idth
 −1
array 
max
​    
 −array 
min
​    
 
​    
 

然后ZZZ可以表示为:
Z=round(−arrayminS)Z = round(-\frac{array_{min}}{S})Z=round(− 
S
array 
min
​    
 
​    
 )

其中roundroundround算子表示:
round(x)=⎧⎩⎨0,⌊x⌉,2n−1x<00<⌊x⌉<2n−1x>2n−1round(x)= \left\{\begin{aligned}0 ,& &x<0\\⌊x⌉ ,& & 0<⌊x⌉ <2^n-1\\2^n-1& & x>2^n-1\end{aligned}\right.
round(x)= 





​    
  
0,
⌊x⌉,

n
 −1
​    
  
​    
  
x<0
0<⌊x⌉<2 
n
 −1
x>2 
n
 −1
​    
 

再从公式(1)推导得到反量化公式,这是训练的时候反向传播要用到的:
q=round(Z+rS)q=round(Z+\frac{r}{S})q=round(Z+ 
S
r
​    
 )

如果我们用C++里面的结构体来表示这个数据结构,那么就可以写成下面的形式:

可以将卷积层的量化过程总结如下,这部分借鉴了一篇CSDN博主的流程,链接放在附录的参考博客1了。卷积层的量化过程表示为:

1、输入 量化的特征图lhs_quantized_val, uint8类型, 偏移量 lhs_zero_point, int32类型。

2、输入 量化的卷积核rhs_quantized_val, uint8类型, 偏移量 rhs_zero_point, int32类型。

3、转换uint8到int32类型。

4、每一块卷积求和,注意int32_accumulator求和有溢出的风险,可以换成固定点小数乘法。这部分公式表示为:
int32_accumulator += (lhs_quantized_val(i, j) - lhs_zero_point) * (rhs_quantized_val(j, k) - rhs_zero_point)。

5、输入量化的乘子quantized_multiplier, int32类型和右移次数记录right_shift, int类型。将int32_accumulator右移right_shift位。

6、计算乘法,得到int32结果,仍有溢出风险,可以换为固定点小数乘法。这部分公式表示为:quantized_multiplier * int32_accumulator。

7、加上结果的偏移量 result_zero_point。

8、左移right_shift位还原,得到int32的结果。

9、将int32类型结果 限幅到[0, 255], 再强制转换到 uint8类型。

10、之后再反量化到浮点数,更新统计输出值分布信息max和min。

11、再量化回uint8。

12、之后量化激活层。

13、最后反量化到浮点数,即卷积层的输出。

14、进入下一层,循环执行1-13步骤。

值得注意的一点事,如果有连续的层需要进行量化操作时,就没有必要反量化了,如上面的10->11步骤,但这很有可能带来乘加累积导致的溢出,所以每层量化似乎似乎是比较稳妥的做法。

3.1.2 纯整数算术矩阵乘法
从公式(1)可以看到,每个arrayarrayarray中的实数rir_ir 
i
​    
 都表示带有一对参数SSS和ZZZ的实数qiq_iq 
i
​    
 。则对实数矩阵R1R_1R 
1
​    
 ,R2R_2R 
2
​    
 做乘法,其结果矩阵的每个实数可以用下面的公式表示:


这个公式可以重写为:


其中:


可以看到MMM是式子(3)中唯一不是整数的值,并且经验发现MMM的值总是在(0,1)(0,1)(0,1)中,所以可以将MMM表示为下面的式子:


其中nnn是非负整数,M0M_0M 
0
​    
 是一个整数。这样实数运算就变成了整数运算,同时2−n2^{-n}2 
−n
 可以用移位运算。这个nnn就是上面介绍的卷积层量化过程中的右移参数。

注意,这里还有一个关键点就是在预测阶段,权重矩阵的量化系数SSS可以通过已有的参数统计出来。而激活层的量化参数是大量训练数据指数移动均值计算出来的,所以这里才会有q3q_3q 
3
​    
 没出来,但先使用了S3S_3S 
3
​    
 。

3.1.3 零点的有效处理
在上面的公式(4)中因为两个矩阵都需要减去各自的零点Z值,减法运算后得到的值可能会突破int8范围,到时候就需要int16来存储,但整个运算为了控制在int8的类型下计算,论文做了下面的变换。


这样可以有效的避免计算过程中的值溢出int8范围。但可以发现,这个等效变换仍然没有改变整个计算的复杂度,都为O(2N3)O(2N^3)O(2N 
3
 )。

3.1.4 融合一个层
前面描述了权重的矩阵计算,但在神经网络中还有偏置bias和激活函数的映射,因为int8类型的运算完之后的值应该是在int32之内的,所以bias选择int32的类型,这样的选择一是因为bias在整个神经网络中只占据极少的一部分,此外bias的作用其实非常重要,高精度的bias可以降低模型的偏差。因此加上bias之后就变成了int32,我们需要再次转换成int8类型(反量化),之后再进入到激活中。具体如下图所示:


再用公式详细表达一下,定义bias的量化:
其中,SbiasS_{bias}S 
bias
​    
 用int32表示。将weights和input执行矩阵乘法后加上bias,公式表达为:
得到了int32之后的结果后需要再次转换成int8类型(反量化),之后再执行激活函数的操作。

4. 模拟量化训练
在介绍中提到,后处理量化过程适合大模型,而小模型会导致精度损失比较大。论文认为后处理量化主要存在两点问题:

同一层不同通道的权重分布尺度差很多(超过100x)
离散的权重会导致所有剩余权重的精度下降
因此,论文提出了一种在前向传播阶段模拟量化的方法,反向传播和平常一样,所有的权重和biases都用浮点数保存以微调小变化。具体的量化方法如下:
1、 weights再输入进行卷积之前就开始量化,如果有bn层,将bn层融入到weights中。
2、 激活在激活函数执行完之后再量化。

如下图所示:


量化的公式如下:

这和上面介绍的推理阶段的量化公式完全一致,我就不再赘述了。

4.1 学习量化范围
对于上面的量化范围(a, b),weight和activation是不一样的,对于weight来说很简单,就是该权重中最大最小值,但是对于activation是不太一样的, 对于activation采用了EMA(滑动平均)来对输入中的最大最小值计算得到的,但是在训练初期,因为输入的值变化较大,会影响到滑动平均的值,因此在初期不对activation做量化,而是在网络稳定之后再引入。

4.2 折叠BN
对于bn层,在训练时是一个单独的层存在,但是在前向推理时为了提升效率是融合到卷积或全连接层的权重和偏置中的,如下图:

所以,为了模拟推断过程,训练时需要把BN层考虑到权重中,公式如下:


考虑了fold bn之后,最终可以用下图来表示训练过程中的量化:

后记
今天解读了CVPR 2018 《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》,对int8量化了有了基本认识,这两天随缘更新一个实战篇吧。

附录
论文原文:https://arxiv.org/pdf/1712.05877.pdf

参考博客1:https://blog.csdn.net/qq_19784349/article/details/82883271

参考博客2:https://blog.csdn.net/holmosaint/article/details/82423610
————————————————
版权声明:本文为CSDN博主「just_sort」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/just_sort/article/details/103704975

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度学习算法优化系列 的相关文章

随机推荐

  • windows nignx 常用操作命令(启动、停止、重启服务)

    文章目录 1 查看nginx 版本号 2 根据名称查询 window 下的nginx 的启动进程 3 再根据端口号查询进程 4 启动nginx 命令 5 停止nginx 6 快速停止或关闭Nginx 7 正常停止或关闭Nginx 8 配置文
  • Open3D Ransac拟合分割多个球体

    目录 一 算法原理 二 代码实现 三 结果展示 四 测试数据 一 算法原理 算法的核心原理还是RANSAC拟合球面 具体理论可参考 Open3D RANSAC三维点云球面拟合 只是对代码稍加修改使其适用于分割点云数据中的多个球体 二 代码实
  • 回归平方和 ESS,残差平方和 RSS,总体平方和 TSS

    https zhidao baidu com question 565190261749684764 html 回归平方和 ESS 残差平方和 RSS 总体平方和 TSS 总变差 TSS 被解释变量Y的观测值与其平均值的离差平方和 总平方和
  • 5.12 数据结构——哈夫曼编码

    在远程通讯中 要将待传字符转换成二进制的字符串 假设要传输的字符为 ABACCDA 若编码为 A 00 B 01 C 10 D 11 那么要传输的字符的编码为 00010010101100 若将编码设计为长度不等的二进制编码 即让待传字符串
  • 基于深度学习的人脸表情识别(一)

    第一篇博客就不用Markdown 什么鬼 来写了 今天主要是被老板一通说 然后说两月看10篇paper 算了 还是丫丫自己先多码码论文吧 再加之这几天有开博的想法 就索性一起开了 顺道总结下最近看的一篇中文的 Facial Expressi
  • 【CPU】常见术语解释

    interrupt service routine ISR 中断服务程序 中断 指当CPU正在处理某件事情时 外部发生的某一事件 如一个电平的变化 一个脉冲沿的发生或 定时器计数溢出等 请求CPU迅速去处理 于是CPU暂时中止当前的工作 转
  • 【机器学习基础】Python机器学习入门指南(全)

    前言 机器学习 作为人工智能领域的核心组成 是计算机程序学习数据经验以优化自身算法 并产生相应的 智能化的 建议与决策的过程 一个经典的机器学习的定义是 A computer program is said to learn from ex
  • 计算机转换汉子英语,中英文切换(电脑怎么切换拼音打字)

    在打字时需要输入英文怎么切换 用搜狗等各类拼音法的话 不用切换就可自由地 中英 非常简单 没有人不知道吧 方法是 汉字状态时 按回车键就是英文字母 此时按空格键是汉字 谁能告诉我小键盘旁边 也就是全角和半角的旁边的中文和英文符号 切换的 c
  • vue-element-admin/template登录Request failed with status code 405

    问题 vue element admin vue admin template 登录不上 报错Request failed with status code 405 解决 main js的开发配置production修改为开发模式 deve
  • opencv 识别长方形_使用OpenCV检测图像中的矩形

    本文实例为大家分享了OpenCV检测图像中矩形的具体代码 供大家参考 具体内容如下 前言 1 OpenCV没有内置的矩形检测的函数 如果想检测矩形 要自己去实现 2 我这里使用的OpenCV版本是3 30 矩形检测 1 得到原始图像之后 代
  • shell基础语法

    1 变量 语法 变量名 变量值 PS 两边不能有空格 1 使用变量 变量名 ex Name wendy 声明变量 echo Name 或 echo Name 输出变量 ps 花括号可选 2 只读变量 readonly 变量 3 删除变量 u
  • maven明明本地仓库有依赖包,还会远程下载的问题

    我今天在无网的环境下 打算进行maven编译打包 可是明明有本地仓库 也配置了本地仓库 但是还是会从远程下载 然后再各大网友的帮助下 百度 谷歌 查询到主要的原因是在本地仓库的每个依赖包都存在 remote repositories文件 直
  • layui多文件上传与下载示例

    第一次写文件上传 不知道怎么下手 幸好有万能layui 方便了很多 HTML div class layui body header span class layui body header title 产品文件上传 span div di
  • 对话用友网络副总裁、用友大易创始合伙人石磊:新的人力资源红利时代已经到来

    数科星球原创 作者丨苑晶 编辑丨十里香 在这个日新月异的科技时代 无论是企业还是个人 拥抱先进的技术工具以及前沿的思维成为建立差异化优势 取得长期价值的不二法门 在真实的场景中 企业内部的管理状况更为复杂 2023年 在全行业跑步奔向增长之
  • 用python编写一个弹球游戏

    用python编写一个简单的弹球游戏 这是学习python时用来练习的一个项目 作为笔记 最终是实现一个简单的弹球游戏 效果图如下 源代码 无限命版的弹球游戏python代码 from tkinter import 来源于python的标准
  • “互联网+”定义及相关概念解析

    来源 中国互联网技术联盟 2015年5月 6月 7月 国家密集性的发布了三大重型文件 中国制造2025 大众创业万众创新政策措施意见 互联网 行动指导意见 随后 中国互联网技术联盟邀请专家委员会对此专门进行了闭门研讨和解读梳理 并将梳理成果
  • 有关res://ieframe.dll/dnserrordiagoff_webOC.htm# http://www.51hainuo.cn

    有关这个 res ieframe dll dnserrordiagoff webOC htm http www 51hainuo cn 大部分的人应该会觉得是dns错误或者dns解析本机不正常 然后就去找杀毒软件来杀毒 网上我搜索的到的很多
  • html水平导航和垂直导航,简单却实用的CSS水平和垂直导航栏【演示/源码】

    说到CSS导航栏 各种漂亮炫酷的样式都应有尽有 不过本文要介绍的是简单却又很实用的导航栏 分为水平导航栏和垂直导航栏两种样式 适合初学者学习使用 以及一些对设计要求不高的网页使用 简单却实用的CSS水平和垂直导航栏 概述 这个简单的教程将教
  • IOException parsing XML document from class path resource [applicationContent.xml]; nested exception

    Spring报错问题 IOException parsing XML document from class path resource applicationContent xml nested exception is java io
  • 深度学习算法优化系列

    1 前言 这是Google在CVPR 2018上发表的一篇int8量化的论文 题目为 Quantization and Training of Neural Networks for Efficient Integer Arithmetic