TensorFlow 8 bit模型量化
本文基本参考自这篇文章:8-Bit Quantization and TensorFlow Lite: Speeding up mobile inference with low precision
首先来一段keras dalao Francois Chollet的鸡汤:
- make it possible
- make it work
- make it efficient
- make it dependable and invisible
- move on to next layer and think about it again
这段鸡汤已经把8-bit量化的需求和阶段已经说得很清楚了:提升算法效率
What is 8 bit
目前DL中大部分都是用32bit float类型进行计算的,bit位数的多少直接限制了数据类型能够表达的数据范围,比如float 32的数据是由1bit表示符号,8bit表示整数部,23位表示分数部组成。
num bits | Min value | Max value |
---|---|---|
8 bit | -128 (-2^7) | 128 (x^7) |
16 bit | -32768 (-2^15) | 32768(2^15) |
32 bit | –2147483648 (-2^31) | –2147483648 (2^31) |
用更低位的数值类型意味着更小的数据表示范围和更稀疏的数值,量化的时候就会造成数值精度损失。比如要把float数值量化到int类型,那么首先小数部分会损失,而那些超过int类型能够表达的范围的值也会被压缩到int能够表达的最大或最小值。
Why 8 bit?
那么既然会有精度损失那为啥现在int8运算越来越流行,主要原因就是快跟省了。
快:低bit位的数值计算一般会比高bit的要快。虽然现代计算芯片上浮点型的计算已经并不比int类型慢,但是这主要是设计了专用的float计算核,而现在很流行的ai芯片和一些嵌入式芯片上一般并不会设计很多的float计算核,因此对float数值的计算算力很低算力。
下图就是Nvidia RTX2080ti的芯片架构(ref)
- 省:从32bit压缩到8bit,最直接的就是内存能够减少1/4。同时,从RAM中读取数据的时间也会缩短;也能降低运算能好。
这也就说明了为什么现在越来越多的ai芯片专门针对int8计算进行优化并提供很大的int8算力,比如RK3399 pro搭载的NPU提供3T int8算力。
Why 8 bit works?
那么为什么int8在DL模型中能够应用呢?不是有数值精度损失么?主要原因有两个:
- 训练好的DNN网络时出了名的对噪声和扰动鲁棒性强。
- 大部分训练好的权重都落在一个很小的区间内。
一般正常操作的话,8 bit量化只会造成很低的精度损失,而且这个损失是可以通过微调重训练进行弥补的。比如在Han等人在这篇文章里对AlexNet其中一层的权重进行分析:
<imge="https://cdn-images-1.medium.com/max/1600/0*UkgbJuMdr6eOBjux.png" style="zoom:50%"/>
左图是实际权重,大部分分布在-0.1到0.1的范围内,而右图是进行了4bit量化后的权重数值分布,4bit能够最大表示16个数值,因此大部分权重都有塌缩,能够保持原来的值的只有16个值。那么如果进行8bit的量化,最大能够保持256个值,对原始权重的保留会更加完整,量化造成的数值损失会很小。
虽然目前已经有文章开始研究直接用低精度的数值进行训练,比如这个,但是需要替换乘法操作,训练非常复杂,而且效果也暂时不够好,还是处于实验阶段。这主要是目前的SGD等算法需要不断积累小非常小的梯度值进行权重更新。
How 8 bit works?
那么如何用int类型来表示float类型呢?最简单的方式就是乘一个系数把float类型的小数部分转换成整数部分,然后用这个转换出来的整数进行计算,计算结果在还原成float。类似的,量化具体需要以下几点:
- 量化的变换必须是线性的,这样才能确保计算结果能够映射会原始值
- 量化必须能够保持0.f的精度,这是因为0在DNN中作用很大,如果原始的0映射到量化后的值变成了其他值并出现了精度损失,那个在计算过程中就会引入偏差。
因此对于实际值和量化值的映射关系,一般可以用以下公式表示:
\(r= (r_{max}-r_{min})/(2^B-1)-0*(q-z)\)
其中,r表示实际值;q表示量化的比特数,比如int8量化就是8;z表示量化后的0点值。
具体的映射关系如下:
从公式中可以看到,量化的重要一点就是要确定合适的\(r_{max}\)和\(r_{min}\).对于训练好的模型就行post-training 量化来说,这点比较容易,只需要统计冻存的所有权重参数即可。
Post training quantization
一般来说,冻好的模型中典型的conv层包含以下参数:
- weights tensor
- input tensor
- forward pass operator
- output tensor
对输出来说,大部分层输出的值都只会落在一个很窄的区间内,因此对output进行量化就需要利用在在训练的时候统计大部分输入得到的输出来进行统计确定合适的最大和最小值。
但是对于operation来说,直接利用之前的量化方式需要注意一点:由于计算包括乘法,因此有可能会有计算结果的值溢出量化值(比如int8)所能表达的范围(overflow)。因此这里常用的方法是首先将结果用较大数值空间的量化值(比如int32)进行存储,然后再量化到8 bit。采用int32至少可以完全覆盖原始float类型运算的结果而不担心溢出。
此外,对于一些操作,其逻辑需要改变。比如ReLU,量化后需要比较的值是quantize(0)而不是原来的0.f。
如上图所示,权重,输入首先进行量化,其中输入的量化范围是需要训练数据作为参考;而输出进行两步量化,来兼容计算过程可能出现的溢出。
Fake Quantization in TFLite
在TensorFlow中,量化是通过fake quantization node来进行的。对于大模型来说,冗余参数比较多,直接量化的影响比较小;但是对于小模型来说,冗余参数就比较少了,直接量化导致的 精度损失可能会比较大。在fake quantizaiton中,训练过重就就会模拟评估量化带来的round effect在inference的时候的影响,因此在训练过程中量化值还是会议float类型保存,并可以通过反向传播进行调整。具体quantization aware training可以查看这里.
此外,就如之前所说的fake quantizaiton node会记录计算和输出值的范围用于量化。
Result
下表记录了量化造成的精度损失,总体来看还是非常小的。
What's next
到这位置,只是介绍了8bit量化在TF上的实现原理和方式。而现在学术界对于量化有很多新的研究包括:quantized training, non-linear quantization, binary quantization, networks without multipliers等等,在不久的将来希望能够出现无损且高效的量化手段,这将极大收益训练和推测。
TensorFlow 8 bit模型量化的更多相关文章
- tensorflow模型量化
tensorflow模型量化/DATA/share/DeepLearning/code/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/t ...
- tensorflow模型量化实例
1,概述 模型量化应该是现在最容易实现的模型压缩技术,而且也基本上是在移动端部署的模型的毕竟之路.模型量化基本可以分为两种:post training quantizated和quantization ...
- 模型量化原理及tflite示例
模型量化 什么是量化 模型的weights数据一般是float32的,量化即将他们转换为int8的.当然其实量化有很多种,主流是int8/fp16量化,其他的还有比如 二进制神经网络:在运行时具有二进 ...
- FaceRank-人脸打分基于 TensorFlow 的 CNN 模型
FaceRank-人脸打分基于 TensorFlow 的 CNN 模型 隐私 因为隐私问题,训练图片集并不提供,稍微可能会放一些卡通图片. 数据集 130张 128*128 张网络图片,图片名: 1- ...
- Tensorflow滑动平均模型tf.train.ExponentialMovingAverage解析
觉得有用的话,欢迎一起讨论相互学习~Follow Me 移动平均法相关知识 移动平均法又称滑动平均法.滑动平均模型法(Moving average,MA) 什么是移动平均法 移动平均法是用一组最近的实 ...
- tensorflow初次接触记录,我用python写的tensorflow第一个模型
tensorflow初次接触记录,我用python写的tensorflow第一个模型 刚用python写的tensorflow机器学习代码,训练60000张手写文字图片,多层神经网络学习拟合17000 ...
- tensorflow笔记:模型的保存与训练过程可视化
tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代码分析 ...
- 139、TensorFlow Serving 实现模型的部署(二) TextCnn文本分类模型
昨晚终于实现了Tensorflow模型的部署 使用TensorFlow Serving 1.使用Docker 获取Tensorflow Serving的镜像,Docker在国内的需要将镜像的Repos ...
- TensorFlow 训练好模型参数的保存和恢复代码
TensorFlow 训练好模型参数的保存和恢复代码,之前就在想模型不应该每次要个结果都要重新训练一遍吧,应该训练一次就可以一直使用吧. TensorFlow 提供了 Saver 类,可以进行保存和恢 ...
随机推荐
- 命令行的方式启动和关闭Mysql
命令行的方式启动和关闭Mysql mysql -h 主机名 -P 端口号 -u 用户名 -p 密码 例如:mysql -h localhost -P 3306 -u root -p11111(p和密码 ...
- UiAutomatorViewer无法获取手机截图进行元素定位的解决办法
问题描述 本来想使用UIAutomatorView定位app页面元素的,最开始我使用的是夜神模拟器,打开UIAutomatorView连接模拟器没有问题,但是后来我使用真机时发现无法连接到真机获取真机 ...
- Angular pagination分页模块 只提供分页参数处理 不处理分页记录数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- excel双击下拉制作(以及双击下拉字符超限处理)
最近,在项目的开发过程中,遇到了一个问题,自己要修改代码中的excel模板,有些列要处理成双击下拉的形式. excel制作双击下拉: 当然,我想,这对于大家来说是不难的,好实现,但是,我在制作的过程中 ...
- 在Maven项目中,jsp不解析el表达式
我的这个项目是用Maven-archetype-webapp项目创建的,如下图所示: 有这种方式创建有一个坑,就是它使用的servlet版本是2.3,而servlet2.4以下的版本是不会自动解析el ...
- Docker网络配置、Docker部署分布式项目
目标 1.Docker网络配置 2.Docker部署SpringCloud项目 Docker网络配置 Docker网络模式介绍 Docker在创建容器时有四种网络模式:bridge/host/cont ...
- vue项目开发期间,配置webpack解决后台接口在不同服务器上的问题 之 二 ( node搭建服务 )
由于今天上午 后端人员把接口都整合都一个服务器了,所以就没有硬关注 上一篇文章的问题, 晚上回来,用node搭了一个简单服务器,测试了下,是没有问题的.代码如下: 一. 自己初始化项目, 1.pack ...
- python函数 | 三元运算
三元运算符就是在赋值变量的时候,可以直接加判断,然后赋值 格式: [on_true] if [expression] else [on_false] 三元运算只适用于简单的if else判断,再多一层 ...
- TCP三次握手的过程,accept发生在三次握手的哪一个阶段?
答案是:accept过程发生在三次握手之后,三次握手完成后,客户端和服务器就建立了tcp连接并可以进行数据交互了.这时可以调用accept函数获得此连接. TCP Accept总结 TCP Accep ...
- 洛谷 P1621 集合
目录 题目 思路 \(Code\) 题目 P1621 集合 思路 并查集+埃氏筛,一开始连通块的个数是\(b-a+1\)个,在筛素数的过程中只要当前素数大于\(p\)就对该素数筛出来的数进行判断,如果 ...