模型量化原理及tflite示例

模型量化

什么是量化

模型的weights数据通常是float32的,量化即将他们转换为int8的。固然其实量化有不少种,主流是int8/fp16量化,其余的还有好比git

  • 二进制神经网络:在运行时具备二进制权重和激活的神经网络,以及在训练时计算参数的梯度。
  • 三元权重网络:权重约束为+1,0和-1的神经网络
  • XNOR网络:过滤器和卷积层的输入是二进制的。 XNOR 网络主要使用二进制运算来近似卷积。
    如今不少框架或者工具好比nvidia的TensorRT,xilinx的DNNDK,TensorFlow,PyTorch,MxNet 等等都有量化的功能.

量化的优缺点

量化的优势很明显了,int8占用内存更少,运算更快,量化后的模型能够更好地跑在低功耗嵌入式设备上。以应用到手机端,自动驾驶等等。
缺点天然也很明显,量化后的模型损失了精度。形成模型准确率降低.github

量化的原理

先来看一下计算机如何存储浮点数与定点数:


其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^128. 能够看到float的值域分布是极其广的。api

说回量化的本质是:找到一个映射关系,使得float32与int8可以一一对应. 。那问题来了,float32可以表达值域是很是广的,而int8只能表达[0,255].
怎么可以用255个数表明无限多(其实也不是无限多,不少,可是也仍是有限个)的浮点数?网络

幸运地是,实践证实,神经网络的weights每每是集中在一个很是狭窄的范围,以下:

因此这个问题解决了,即咱们并不须要对值域-2^128 ~ +2^128的全部值都作映射。但即使是一个很小的范围,好比[-1,1]可以表达的浮点数也是很是多的,因此势必
会有多个浮点数被映射成同一个int8整数.从而形成精度的丢失.框架

这时候,第二个问题来了,为何量化是有效的,为何weights变为int8后,并不会让模型的精度降低太多?
在搜索了大量的资料之后,我发现目前并无一个很严谨的理论解释这个事情.工具

您可能会问为何量化是有效的(具备足够好的预测准确度),尤为是将 FP32 转换为 INT8 时已经丢失了信息?严格来讲,目前还没有出现相关的严谨的理论。一个直觉解释是,神经网络被过分参数化,进而包含足够的冗余信息,裁剪这些冗余信息不会致使明显的准确度降低。相关证据是,对于给定的量化方法,FP32 网络和 INT8 网络之间的准确度差距对于大型网络来讲较小,由于大型网络过分参数化的程度更高学习

和深度学习模型同样,不少时候,咱们没法解释为何有的参数就是能work,量化也是同样,实践证实,量化损失的精度不会太多,do not know why it works,it just works.spa

如何作量化

由如下公式完成float和int8之间的相互映射.
\(x_{float} = x_{scale} \times (x_{quantized} - x_{zero\_point})\)
其中参数由如下公式肯定:

举个例子,假设原始fp32模型的weights分布在[-1.0,1.0],要映射到[0,255],则\(x_{scale}=2/255\),\(x_{zero\_point}=255-1/(2/255)=127\)code

量化后的乘法和加法:
依旧以上述例子为例:
咱们能够获得0.0:127,1.0:255的映射关系.
那么原先的0.0 X 1.0 = 0.0 注意:并不是用127x255再用公式转回为float,这样算获得的float=(2/255)x(127x255-127)=253


咱们假设全部layer的数据分布都是一致的.则根据上述公式可得\(z_{quantized}=127\),再将其转换回float32,即0.0.blog

同理加法:


tflite_convert

平常吐槽:tensorflow sucks. tensorflow要不是大公司开发的,绝对不可能这么流行. 文档混乱,又多又杂,api难理解难使用.

tensorflow中使用tflite_convert作模型量化.用法:

tflite_convert \
  --output_file=/tmp/foo.cc \
  --graph_def_file=/tmp/mobilenet_v1_0.50_128/frozen_graph.pb \
  --inference_type=QUANTIZED_UINT8 \
  --input_arrays=input \
  --output_arrays=MobilenetV1/Predictions/Reshape_1 \
  --default_ranges_min=0 \
  --default_ranges_max=6 \
  --mean_values=128 \
  --std_dev_values=127

官方指导:https://www.tensorflow.org/lite/convert/cmdline_examples
关于各参数的说明参见:
https://www.tensorflow.org/lite/convert/cmdline_reference

关于参数mean_values,std_dev_values比较让人困惑.tf的文档里,对这个参数的描述有3种形式.

  • (mean, std_dev)
  • (zero_point, scale)
  • (min,max)
    转换关系以下:
std_dev = 1.0 / scale
mean = zero_point

mean = 255.0*min / (min - max)
std_dev = 255.0 / (max - min)

结论:
训练时模型的输入tensor的值在不一样范围时,对应的mean_values,std_dev_values分别以下:

  • range (0,255) then mean = 0, std_dev = 1
  • range (-1,1) then mean = 127.5, std_dev = 127.5
  • range (0,1) then mean = 0, std_dev = 255

参考:
https://heartbeat.fritz.ai/8-bit-quantization-and-tensorflow-lite-speeding-up-mobile-inference-with-low-precision-a882dfcafbbd
https://stackoverflow.com/questions/54830869/understanding-tf-contrib-lite-tfliteconverter-quantization-parameters/58096430#58096430
https://arleyzhang.github.io/articles/923e2c40/
https://zhuanlan.zhihu.com/p/79744430
https://zhuanlan.zhihu.com/p/58182172

相关文章
相关标签/搜索