量化_深度学习


一、模型量化的背景需求
Resnet-152神经网络的提出证明了越宽越深越大的模型往往比越窄越浅越小的模型精度要高,但是越宽越深越大的模型对计算资源要求更高,而现在模型应用越来越倾向于从云端部署到边缘侧,受限于边缘侧设备的计算资源,我们不得不考虑设备存储空间(storage)、设备内存大小(memory)、设备运行功耗(power)及时延性(latency)等等问题,特别是在移动终端和嵌入式设备等资源受限的边缘侧应用场景中更加需要我们进行优化。因此,为了解决此类问题模型量化应运而生,本篇我们将探讨模型量化的概念原理、优缺点及tensorflow模型量化的实现方法。

二、什么是模型量化
模型量化的定义没有统一的说法,但个人理解为:

模型量化即以较低的推理精度损失将连续取值(或者大量可能的离散取值)的浮点型模型权重或流经模型的张量数据定点近似(通常为int8)为有限多个(或较少的)离散值的过程,它是以更少位数的数据类型用于近似表示32位有限范围浮点型数据的过程,而模型的输入输出依然是浮点型,从而达到减少模型尺寸大小、减少模型内存消耗及加快模型推理速度等目标。

在这里插入图片描述
三、模型量化有什么好处
减小模型尺寸,如8位整型量化可减少75%的模型大小
减少存储空间,在边缘侧存储空间不足时更具有意义
易于在线升级,模型更小意味着更加容易传输
减少内存耗用,更小的模型大小意味着不需要更多的内存
加快推理速度,访问一次32位浮点型可以访问四次int8整型,整型运算比浮点型运算更快
减少设备功耗,内存耗用少了推理速度快了自然减少了设备功耗
支持微处理器,有些微处理器属于8位的,低功耗运行浮点运算速度慢,需要进行8bit量化
总体来看,模型量化优势明显,但是其也有一些缺点:

模型量化增加了操作复杂度,在量化时需要做一些特殊的处理,否则精度损失更严重
模型量化会损失一定的精度,虽然在微调后可以减少精度损失,但推理精度确实下降
四、模型量化的原理
模型量化桥接了定点与浮点,建立了一种有效的数据映射关系,使得以较小的精度损失代价获得了较好的收益,要弄懂模型量化的原理就是要弄懂这种数据映射关系。

由浮点到定点的量化公式如下:
在这里插入图片描述
这里的S和Z均是量化参数,而Q和R均可由公式进行求值,不管是量化后的Q还是反推求得的浮点值R,如果它们超出各自可表示的最大范围,那么均需要进行截断处理。而浮点值0在神经网络里有着举足轻重的意义,比如padding就是用的0,因而必须有精确的整型值来对应浮点值0。根据查看的tensorflow相关文档,以往一般使用uint8进行定点量化,而目前有提供float16和int8等定点量化方法,而int8定点量化针对不同的数据有不同的范围定义:

在这里插入图片描述
我们重点关注的是如下两项:

每轴(或每通道)或每张量的权重用int8进行定点量化的可表示范围为[-127,127],且zero-point就是量化值0
每张量的激活值或输入值用int8进行定点量化的可表示范围为[-128,127],其zero-point在[-128,127]内依据公式求得
举例说明模型量化求值过程

模型训练后权重或激活值往往在一个有限的范围内分布,如激活值范围为[-2.0, 6.0],然后我们用int8进行模型量化,则定点量化值范围为[-128, 127],那么S和Z的求值过程如下:
在这里插入图片描述
五、tensorflow训练后量化(Post-training quantization)介绍及其实现方法
tensorflow训练后量化是针对已训练好的模型来说的,针对大部分我们已训练未做任何处理的模型来说均可用此方法进行模型量化,而tensorflow提供了一整套完整的模型量化工具,如TensorFlow Lite Optimizing COnverter(toco命令工具)以及TensorFlow Lite converter(API源码调用接口).

tensorflow训练后量化有几种选择,不同选择的对比如下:

在这里插入图片描述
图四 训练后量化的几种方式比较
选择何种方式,需要结合业务场景及所拥有的硬件资源,目的是以最小损失达到最大化模型量化效果,官方提供了一棵决策树用于选择不同的训练后量化方式,实作中可进行参考。
在这里插入图片描述
训练后量化方式的实现方法如下:

第一种,混合量化–仅量化权重

该方式将浮点型的权重量化为int8整型,可将模型大小直接减少75%、提升推理速度最大3倍。该方式在推理的过程中,需要将int8量化值反量化为浮点型后再进行计算,如果某些Ops不支持int8整型量化,那么其保存的权重依然是浮点型的,即部分支持int8量化的Ops其权重保存为int8整型且存在quantize和dequantize操作,否则依然是浮点型的,因而称该方式为混合量化。该方式可达到近乎全整型量化的效果,但存在quantize和dequantize操作其速度依然不够理想,支持该方式的操作如下:

在这里插入图片描述
图六 混合量化Ops
混合量化的实现方式比较简单,仅需调用tf.lite.TFLiteConverter的API转化即可:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
tflite_quant_model = converter.convert()

第二种,全整型量化–权重和激活值都进行量化

该方式则试图将权重、激活值及输入值均全部做int8量化,并且将所有模型运算操作置于int8下进行执行,以达到最好的量化效果。为了达到此目的,我们需要一个具有代表性的小数据集,用于统计激活值和输入值等的浮点型范围,以便进行精准量化,方法如下:

import tensorflow as tf

def representative_dataset_gen():
  for _ in range(num_calibration_steps):
    # Get sample input data as a numpy array in a method of your choosing.
    yield [input]

converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset_gen
tflite_quant_model = converter.convert()

全整型量化的输入输出依然是浮点型的,但如果某些Ops未实现该方法,则转化是没问题的且其依然会自动保存为浮点型,这就要求我们的硬件支持这样的操作,为了防止这样的问题出现,我们可以在代码里添加如下语句强制检查并在Ops不支持全整型量化时进行报错!

converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]

第三种,半精度float16量化–仅量化权重

该方式是将权重量化为半精度float16形式,其可以减少一半的模型大小、相比于int8更小的精度损失,如果硬件支持float16计算的话那么其效果更佳,这种方式是google近段时间提供的,其实现方式也比较简单,仅需在代码中调用如下接口即可:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.lite.constants.FLOAT16]
tflite_quant_model = converter.convert()

当在CPU运行时,半精度量化也需要像int8量化一样进行反量化到float32在进行计算,但在GPU则不需要,因为GPU可以支持float16运算,但官方说float16量化没有int8量化性价比高,因此,在实作中也需要仁者见仁智者见智了。

六、tensorflow量化感知训练(Quantization-aware training)介绍及其实现方法
tensorflow量化感知训练是一种伪量化的过程,它是在可识别的某些操作内嵌入伪量化节点(fake quantization nodes),用以统计训练时流经该节点数据的最大最小值,便于在使用TOCO转换tflite格式时量化使用并减少精度损失,其参与模型训练的前向推理过程令模型获得量化损失,但梯度更新需要在浮点下进行因而其并不参与反向传播过程。某些操作无法添加伪量化节点,这时候就需要人为的去统计某些操作的最大最小值,但如果统计不准那么将会带来较大的精度损失,因而需要较谨慎检查哪些操作无法添加伪量化节点。值得注意的是,伪量化节点的意义在于统计流经数据的最大最小值并参与前向传播提升精确度,但其在TOCO工具转换为量化模型后,其工作原理还是与训练后量化方式一致的!

量化感知训练工作过程举例说明如下图所示:

在这里插入图片描述
可识别的ReLU节点嵌入了对应的伪量化节点QuantizedRelu,统计了其流经数据的max和min值,但存在quantize和dequantize的过程,其输入输出依然是float浮点型。而当多个可识别的操作相邻时其嵌入伪量化节点的形式如图八左半部分所示,但多个quantize和dequantize连接时是可以相互抵消的,图八右半部分展示了精简的伪量化节点连接的过程。
在这里插入图片描述
tensorflow量化感知训练需要对训练和推理过程添加相应的代码,其方法如下:

第一步,在训练图结构内添加伪量化节点

# Build forward pass of model.
loss = tf.losses.get_total_loss()

# Call the training rewrite which rewrites the graph in-place with
# FakeQuantization nodes and folds batchnorm for training. It is
# often needed to fine tune a floating point model for quantization
# with this training tool. When training from scratch, quant_delay
# can be used to activate quantization after training to converge
# with the float graph, effectively fine-tuning the model.
g = tf.get_default_graph()
tf.contrib.quantize.create_training_graph(input_graph=g, quant_delay=2000000)

# Call backward pass optimizer as usual.
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
optimizer.minimize(loss)

般是在loss之后optimizer之前添加tf.contrib.quantize.create_training_graph关键函数,其将自动的帮我们在可识别的操作上嵌入伪量化节点,训练并保存模型后,模型图结构就会自动的存在伪量化节点及其统计的参数。tf.contrib.quantize.create_training_graph的参数input_graph表示训练的默认图层,quant_delay是指多少次迭代之后再进行量化,如果是已训练好进行微调量化的话,那么可以将quant_delay设为0。

第二步,重写推理图结构并保存为新的模型

# Build eval model
logits = tf.nn.softmax_cross_entropy_with_logits_v2(...)

# Call the eval rewrite which rewrites the graph in-place with
# FakeQuantization nodes and fold batchnorm for eval.
g = tf.get_default_graph()
tf.contrib.quantize.create_eval_graph(input_graph=g)

# Save the checkpoint and eval graph proto to disk for freezing
# and providing to TFLite.
with open(eval_graph_file, ‘w’) as f:
  f.write(str(g.as_graph_def()))
saver = tf.train.Saver()
saver.save(sess, checkpoint_name)

推理和训练的伪量化图结构是存在较大差异的,而该操作正是要消除量化操作对batch normalization的影响,这是该步骤的目的所在。

第三步,转换模型为全量化模型

首先,需要对第二步重写后的模型进行固化:

freeze_graph \
  --input_graph=eval_graph_def.pb \
  --input_checkpoint=checkpoint \
  --output_graph=frozen_eval_graph.pb --output_node_names=outputs

然后,使用TOCO转换得到真正的量化模型:

toco \
  --input_file=frozen_eval_graph.pb \
  --output_file=tflite_model.tflite \
  --input_format=TENSORFLOW_GRAPHDEF --output_format=TFLITE \
  --inference_type=QUANTIZED_UINT8 \
  --input_shape="1,224, 224,3" \
  --input_array=input \
  --output_array=outputs \
  --std_value=127.5 --mean_value=127.5

至此,我们将得到一个经过Tensorflow量化感知训练后的全量化模型,我们可以使用Tensorflow lite框架进行模型推理加速!

七、tensorflow两种量化方式的比较
tensorflow训练后量化和量化感知训练是两种不同的量化方式,前者是一种offline的方式,而后者则是一种online的方式,由于深度学习神经网络DNN对噪声和扰动比较鲁棒且训练出来的模型权重往往落入一个有限的区间范围内,因而这两者均可达到以较少精度损失达到模型量化的目的,各自的优缺点如下:

两者均可达到模型量化的作用
两者的推理工作原理是一样的
两者都可工作在Tensorflow lite推理框架下并进行相应加速
训练后量化工作量稍微简单些,而量化感知训练工作量更繁琐一些
量化感知训练比训练后量化损失的精度更少,官方推荐使用量化感知训练方式
以下是官方给出的一些模型经过训练后量化(post-training quantization) 和量化感知训练(quantization-aware training)后的延迟和准确性结果对比表格,该表中所有单帧推理时间都是在使用单个大内核的 Pixel 2 设备上测量的,从中可以看出量化感知训练是比训练后量化效果更优的!
在这里插入图片描述
图九 训练后量化与量化感知训练性能对比表

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值