int8模型量化

1. 量化原理

模型量化是用8bit整数去表示32bit浮点型小数的过程,模型量在移动端是比不可少的步骤,量化化的好处主要在于减少模型的体积,加快模型的计算速度,但在一定程度上会损失模型的精度。

模型量化的原理:

这里的S和Z均是量化参数,而Q和R均可由公式进行求值,不管是量化后的Q还是反推求得的浮点值R,如果它们超出各自可表示的最大范围,那么均需要进行截断处理,

前向传播是将float32权重缩放到int8范围以内,缩放系数通过float32的max,min可以求解得到,float32 乘以缩放系数可能是个小数,不是int8数值,需要取整得到int8权重

反向传播时求得的梯度是模型权重量化之后权值的梯度,用这个梯度去更新量化前的权值

具体可参考:Tensorflow模型量化(Quantization)原理及其实现方法 - 知乎

Pytorch实现卷积神经网络训练量化(QAT) - 云+社区 - 腾讯云 (tencent.com)

神经网络量化入门--后训练量化 - 知乎 (zhihu.com)

量化参考:https://heartbeat.fritz.ai/8-bit-quantization-and-tensorflow-lite-speeding-up-mobile-inference-with-low-precision-a882dfcafbbd

2. 模型量化的步骤

         模型量化是一个复杂的过程,网上虽然有不少的教程,但不少都讲的不是太清楚明了,本文主要是将tensorflow模型量化,

pytorch模型量化请参考:(quantization aware training)(beta) Quantized Transfer Learning for Computer Vision Tutorial — PyTorch Tutorials 1.11.0+cu102 documentation

模型量化主要有两种:

   1. 训练量化(quantization-aware training)

       训练量化是指在训练时会生成fake quantize node(虚量化节点),fake quant其本质是quantization-aware training,是train的过程中模拟量化。这个虚量化节点会记录训练时的max和min值,只要你想fully quantize一个模型,那就必须手动插入fake quant node去训练

   2.训练后量化(Post-training quantization)

      训练后量化也就是模型训练好以后再进行量化,这种量化是一种不完全量化,在inference时,模型会把uint8的weights再转换回float32来做矩阵乘法。所以,这种方法其实依然相当于没做quantization。它的存在应当只是便于用户转换model,计算时依然是个非量化model

       所以,要实现真正的全量化模型,需要使用方式1,模型训练时插入fake quantize node(当然,可能有些操作插入不成功,如RNN,这时需要手动插入),实现训练量化需要进行以下步骤:

        a)训练模型时create_train_graph(), 模型参数可以保存为ckpt,官方提供了如何进行训练量化的demo:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/speech_commands/train.py

        b) freeze模型,在模型inference时创建create_eval_graph(), 进行参数restore,通过session获取graph(sess.graph_def),通过

               tf.graph_util.convert_variables_to_constants(sess,graph,output_names)生成pb,这时的pb记录了training的max和min,可通过Netron进行可视化,会发现每个node都多出了max和min两个参数,这时的模型仍然是float32,官方提供了如何进行create_eval_graph()的demo:

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/speech_commands/freeze.py

        c)然后对freeze的模型进行量化,通过下面代码可以将pb模型进行量化,量化后的模型才是int8,这种方式不需要通过toco工具就可以直接进行量化:

# 如果模型在训练时没有做归一化,模型的输入范围是(0,255),输入是numpy.uint8数据类型,converter的参数进行设置如下
converter = tf.lite.TFLiteConverter.from_frozen_graph(
  graph_def_file, input_arrays, output_arrays)
converter.inference_type = tf.lite.constants.QUANTIZED_UINT8
converter.quantized_input_stats = {"input_image" : (0., 1.)} //mean,std
converter.default_ranges_stats=(0, 255)  //如果op没有min和max,则用该参数自动补上
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)


# 如果模型在训练时做了归一化,模型的输入范围是(0,1),输入是float32类型,模型输出需要乘以255,converter的参数进行设置如下
converter = tf.lite.TFLiteConverter.from_frozen_graph(
  graph_def_file, input_arrays, output_arrays)
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)

        其中,graph_def_file是freeze生成的pb文件,input_arrays是模型输入数组,output_arrays是模型输出数组(多个输出节点用逗号隔开,如["clone/output1","clone/output2"]),quantized_input_stats和default_ranges_stats的值经过验证是正确的,这两个参数非常非常重要,设置不对dequantize可能出问题。quantized_input_stats参数含义以及设置参考:python - Understanding tf.contrib.lite.TFLiteConverter quantization parameters - Stack Overflowtensorflow量化训练全过程 - 知乎当然,也可以通过toco工具进行量化

当时使用的TensorFlow-gpu==1.13.1,经过测试是能正常进行量化。

遇到的问题:

 1. 量化使用tensorflow API进行量化,尽量避开toco转tflite,toco不同版本报错不一样,toco会报错某些算子(如resizeBilinear)不支持,其实tflite是支持的

2. tflite转成功并且不报任何错,并不代表量化成功,使用converter.interpreter进行推理时结果会不正确,导致的原因可能是多方面的,比如模型使用relu激活函数,并转tflite成功,但是结果不正确,relu替换为relu6结果就正常

3. softmax,strideslice算子不支持5维量化操作,softmax替换为sigmoid、strideslice使用split然后squeeze最后解决

4. 量化训练需要注意,尽量使用conv+bias+relu组合一起使用,因为量化时会对这三个op进行合并,如果只有conv有可能量化训练时可能conv之后不会插入虚节点,比如conv之后是add操作,如果conv没有relu那么conv后面是不会插入虚节点的,但实际上是需要的,因此,为了避免量化训练后生成虚节点的pb时出错,尽量使用slim.conv2d卷积(默认带有bias+relu),不要使用tf.nn.conv2d(默认没有bias,没有relu),如果使用tf.nn.conv2d进行卷积而忘记加bias+relu,生成带有虚节点pb模型会有问题的,如果某些op需要手动插入虚节点,可以通过下面的方式插入:

         tf.quantize(conv,0.0,255,tf.qint8)

5. 尝试relu6替换relu(视频超分模型替换为relu,会让模型的效果变差),使用relu进行int8量化会出现问题时,尝试relu6进行替换,这一步不是必须,但实验发现确实是有用,不知道为什么

toco工具量化可参考:http://ask.ainoob.cn/article/7804

量化过程参考:Tensorflow Lite的量化工具tf.contrib.quantize的使用(缓慢更新)_chutongz的博客-CSDN博客

量化底层实现参考:【TensorFlow】quantization量化_代码款款的博客-CSDN博客_tensorflow量化

TensorFlow中文社区关于量化问题讨论:https://www.tensorflowers.cn/t/7136

Tensorflow2.0量化:Tensorflow Lite介绍 - SegmentFault 思否

  • 0
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ONNX模型量化int8是一种将模型数据从浮点表示转换为8位整数表示的优化方法。这种量化方法可以带来多个好处。首先,使用8位整数数据进行计算时,NVIDIA GPU可以使用更快更低成本的8位张量核来执行卷积和矩阵乘法运算,从而提高计算吞吐量。其次,将数据从内存移动到计算单元需要时间和能量,并且会产生热量,将激活和参数数据的精度从32位浮点值降低到8位整数可以减少数据量,从而节省能量并减少热量的产生。此外,对于具有带宽限制的层,减少内存占用可以提高缓存利用率和参数更新效率。因此,ONNX模型量化int8是一种有效的优化方法,可以在保持模型准确性的同时提高计算效率和节省资源。\[3\] 要将模型量化int8,可以使用PyTorch的torch.onnx.export函数将模型导出为ONNX格式,并在导出时设置opset_version为13以支持每通道量化(PCQ)。在导出时,还可以将do_constant_folding参数设置为True,以生成更小且可读性更好的模型。以下是导出模型为ONNX并进行量化的示例代码: ``` import torch import torchvision import torch.onnx # 初始化模型 model = torchvision.models.__dict__\[model_name\](pretrained=pretrained) # 导出模型为ONNX dummy_input = torch.randn(1, 3, 224, 224) # 输入的示例数据 onnx_filename = "model.onnx" # 导出的ONNX文件名 opset_version = 13 # 使用的opset版本 torch.onnx.export(model, dummy_input, onnx_filename, verbose=False, opset_version=opset_version, do_constant_folding=True) ``` 通过以上代码,您可以将PyTorch模型导出为ONNX格式,并在导出时进行量化,从而将模型数据转换为int8表示。\[2\] #### 引用[.reference_title] - *1* *2* *3* [利用TensorRT实现INT8量化感知训练QAT](https://blog.csdn.net/zong596568821xp/article/details/120904429)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值