开发者学堂课程【PAL 平台学习路线:机器学习入门到应用:Blade 模型量化优化实践:模型量化优化实践】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/855/detail/14101
Blade 模型量化优化实践:模型量化优化实践
内容介绍:
一.背景介绍
二.技术简介
三.使用说明
四.最佳实践
五.常见问题
一.背景介绍
如上图是一种模型可以量化的流程,比如一个训练完成的模型,可以经过模型压缩,先将模型变小,结合低精度参数,可以把模型参数和计算量减小,最后结合一系列的系统优化,达到模型推理加速的目的,这里只要说那是低精度优化中的 INT8量化,选择变化后会自动结合系统优化,达到进一步的加速效果。
1. 量化是什么
将浮点精度模型以低比特定点数存储和计算
主要用于模型前向推理
2.量化优化效果
压缩模型大小
提升推理速度、增加吞吐量
减小内存占用
目前大多数的深度学习训练框架默认的参数都是32位浮点表示的,计算也是32位浮点,当然也有支持16位浮点的,而模型量化的基本思想就是用更低的精度来代替原来的浮点精度,比如八位整形数字目前大多是用在模型推理过程的,因为模型参数是8比特存储的,所以很显然的能够减小模型大小,而八位整形数值的计算相比于浮点数,特别是结合硬件加速之后也能够显著的提升推理速度,增加内存,另外还可以减小内存,GPU 显存的占用。
3.PAI-Blade 量化
支持 TensorFlow、PyTorch 等深度学习框架
支持 GPU、CPU、端侧多种目标平台
支持图像识别、物体检测、语音识别、自然语言处理等不同任务模型。
量化面向 GPU,CPU 端侧多种目标平台,能够相对有效的提供各类不同任务的模型量化优化支持。
二.技术简介
1.Post Training Quantization
训练无关量化,直接将正常训练得到的浮点模型进行量化
存在精度损失风险
2.Quantization Aware Training
量化训练,训练时引入伪量化操作,模拟量化行为
能够保证优化效果、减小精度损失
实施量化的手段通常分为两种,在模型训练完成后再进行训练,无关量化操作我们称为后续。直接将正常训练得到的浮点模型进行量化,这种方式相对来说比较简单,但会存在一定的精度损失风险。
另外一种我们称为量化感知训练,就是在训练引入量化操作,模拟量化的行为,好处是能够更好的保证优化效果,减少精度损失,但是因为这一套训练,所以操作相对会比前者要复杂一些,目前 pai blade 主要支持第一种方式,同时对于精度损失问题,也提供了一系列的辅助手段进行弥补。
3.在线量化/Dynamic Quantization
模型推理时,实时根据 activation 数值范围计算 scale
可能会使得量化损失更小,但引入计算 scale 的额外开销。
4.离线量化/Static Quantization
模型优化时,根据校正数据集离线计算所有 scale
无额外开销,校正数据集、计算 scale 方式的选择均影响最终量化结果。
这里说明的是两种量化方式,在线量化和离线方法,这里面有另外一种命名,分别叫做动态量化和静态量化,第一种方式也就是在减量化叫做动态量化,是指实时代化后的模型在推理时是实时根据输入的数据数值范围来计算量化参数的,因为是根据当前输入的数据进行的统计,可能会使得量化损失更小,但有的时候会引入不容忽视的额外的额外开销。第二种方式就是离线量化,也叫做静态量化,是指在模型量化的时候,会预先根据既定的交通数据集线计算出所有的量化参数,好处是在实际模型推理的时候没有额外的开销,但是这种数据集的选择和计算量化参数的方式都会影响最终的量化计算结果。
所以通常情况下,我们建议用户提供和真实场景数据分布相对一致的,比较充分的交通数据集来进行离线量化,再结合有效的量化参数计算方式,取得量化速度和精度都比较理想的优化效果,所以在量化优化过程中,部分情况下为了达到最佳的优化效果,是需要用户结合自身的需求进行一些选择和调整的。
5. 量化实现
将浮点计算图转为定点计算图,并结合图优化等。示例如下
6.量化精度调优
除此以外 pai blade 还提供量化精度调优的方式,通过调整量化方式化参数的计算模型参数以及采用混合精度的方法来减小量化精度损失,下面以调整模型参数为例进行说明:
比如在下面摸模型当中会存在如下的结构,首先对边层进行一个等价的变换,再将浮点计算图转化为 INT八计算图,此时能够看到输出会因为量化而导致误差。为了消除这个误差,我们分别在各个通道上求取误差的均值,再将该误差通过原本的 Bias add 的操作进行弥补,最终达减小量化损失的目的。这种方法在小模型模板的上能够取得相对明显的效果,后面我们也会具体演示这过程,而且也会给出准确的对比。
三.使用说明
1.选择支持 int 8计算的硬件
下面介绍的是 pai blade 量化的使用方式,第一步需要判断我们想要进行模型部署或者说使用的硬件商是否支持INT八的计算。下面列举出来的是一部分知识也很大计算硬件,比如说在 gpu 上是 p4 v100等,在 CPU 上,比如skylake,还有 cascadelake 等信号,在端侧设备上有 vivo X9 i,小米6等都是支持 int 8计算的。
2.准备校正数据集
#准备校正数据集:TensorFlow(可选)
import numpy as np
calib_data list()
for i in range(10):
#需注意,目前f eed dict 中 value 需均为 np.ndarray 的类型
feed_dict ={'input_tensor:0':np.ones((32,224,224,3),dtype=np.float32)}
calib_data.append (feed_dict)
#准备校正数据集:PyTorch
import numpy as np
calib_data list()
for i in range(10):
image torch.ones(32,3,224,224)
calib_data.append(image)
第二部是准备校正数据集,前面我们有提到过,如果选择离线量化,就是静态量化是需要预先准备加装数据集的,在实际优化的过程当中会根据用户是否提供交通数据机来选择是执行离线量化还是在线量化。准备校正的方式其实也比较简单,对tf模型来说,只需要准备若干组用于模型推理的数据,再把这些 data 的组成一个 list,然后传入到calib里面就行.同样的方式,对于 Python 模型来说,也只需要将若干组输入组成一个 list 的就可以了。
3.执行量化优化
quant_config =
'weight._adjustment':True #默认为 False
optimized_model,opt_spec,report blade.optimize(
model=graph_def,
optimization_level='02',
device_type='gpu',
inputs=['input_tensor'],
input_shapes:=[['32*224*224*3']],
test_data=test_data,
calib_data=calib_data,
config=blade.Config(quant_config=quant_config)
第三部是执行量化优化,如果了解pai的基本使用方式,开始量化优化,其实只需要将参数里的 optimization指定成o2就可以了。o2代表的就是打开优化其他的量化参数,比如说 model 用于指定应待优化的模型对象,是用来指定硬件类型,下面的 input 还有 input shapes 是可选参数,data 是用来指定训练数据的,指定上一步准备好的校正数据集。最后一个是用来指定一些高级选项的,这里可以通过它设置变化的高级选项,比如说像示例可以指定为true,就会执行我们刚刚介绍过的通过调整模型参数,减少量化损失的方法。
四.最佳实践
下面执行优化演示:
1.TensorFlow MobileNetV1_O.5模型
使用 Blade 敏捷版面向 GPU 平台优化 TensorFlow
MobileNetV1_O.5模型
安装 Blade 敏捷版
P-DSW 官方镜像中将预装Bde敏捷版,若当前环境中未安装,可通过以下命令安装:
pip install pai blade gpu-f https://pai blade.oss-cn-zhangjiakou.aliyuncs.com/release/repo.htm
GPU 10.0%
(1)准备模型
下载预先训练导出的 rozen pbl 格式模型文件.以及已保存为 numpy 的测试数退、量化校正数据,并加载至pythons对象中:
Wgethttp://paiblade-internals.oss-cn-zhangjiakou.aliyuncs.com/bbs_v2.0/models/tf_mobilenet_v1_050.tar.gz
tar -xzf tf_mobilenet_v1_050.tar.gz
#加载模型
import tensorflow as tf
model_path 'tf_mobilenet_v1_050/frozen.pb'
graph_def tf.GraphDef()
with open(model_path,'rb')as f:
graph_def.ParseFromsString(f.read())
加载测试数据、量化校正数据、测试数据集
import numpy as np
def load_data(data_path):
return np.load(data_path,allow_pickle-True,encoding='bytes')
test_data load_data('tf_mobilenet_v1_050/test_bc32.npy').item()
calib_data Load_data('tf_mobilenet_v1_050/calib_n96_bc32.npy').tolist()
test_dataset load_data('tf_mobilenet_v1_050/test_dataset_n1024_bc32.npy').item()
打开官方,必须安装链接,如果没安装,可以通过下面的命令进行安装,这里已经进行了预先的下载。我们把现在加载完成的模型以及测试数据校正数据集还有用来评估准确率的测试数据都加载。到内存里。使用 blade 量化,这里就是我们刚刚介绍过的使用方式。
2.使用 Blade 量化
调用 blade.optimize0接口优化模型(指定 optm12at1 on_leve 为 o2即可开启量化优化。
import blade
def blade optimize(enable weight_adjustment):
configblade.Config(quant_config{'weight_adjustment':enable_weight_adjustment))opt_model,opt_spec,report =blade.optimize(graph_def,=o2',
device_type='gpu,configconfig,
inputs=【'input'],
nput_shapes=【I'32*160*160*3]】,
outputs-['MobilenetV1/Logits/SpatialSqueeze'],
test_data=[test_datal,
calib_data calib_data
print(f'Optimization Report:\n{report)')
return opt_model,opt_spec
#Blade o2 optimization with weight adjustment.
opt_model_o2_wa,opt_spec_o2_wa blade_optimize(enable_weight_adjustment-True)
Blade o2 optimization without weight adjustment.
opt_model_o2,opt_spec_o2 blade_optimize(enable_weight_adjustment-False)
将优化后的模型保存为 frozen pb 文件
开启了 weight adjustment 开关的优化的结果,然后后面我还会之前我要打开激活,最后我们会进行一次对比。这里可能会有一定的耗时,需要等待一段时间,等量化优化完成。
此时优化完成的优化报告出现我们可以看到最后面我们能够看到最终的断的加速是1.53倍,然后是在 v100的硬件上.
再执行没有打开 weight adjustment 电话开关的优化。最后我们可以对比一下优化速度,这里同样的也是,我们要等待一段的时间.
报告最后看一下,加速倍数是2.43倍,不过因为这模型比较小,可能在 b100的硬件上也会有一定的波动,优化好的模型我们用正常的方式保存就可以了。
这也就是我们对比一下刚刚优化出来的两个模型以及原来的 baseline,我们会先验证他的精度以及他的 latency
最后我们会一直输出 baseline,有打开 weight,优化的结果以及没有 latency 量化的结果,第一组出来的是baseline第二组 weight 优化的结果第三组是没打开的,我们最后对比一下,打开这个优化开关了以后,会明显比打开开关的要高一些,也就是说精度损失少一些,但是 latency 基本上没有什么太大变化.
3.PyTorch ASR Transformer
使用 Blade 敏捷版面向CPU平台优化 PyTorch ASR Transformer 模型安装 Blade 敏捷版
PN-DSw 官方镜像中将预装 blade 敏捷版,若当前环境中未安装,可通过以下命令安装:
]:pip install pai-blade-cpu -f https://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/release/repo.html
(1).准备模型
下载预先训练导出的 torch scripl 格式模型文件,以及已保存为 pth 的测试数据、量化校正数据,并加载至pythons对像中:
tar -xzf pt_espnet_asr_tedlium2.tar.gz
:import torch
script_model torch.jit.load('pt_espnet_asr_tedlium2/cpu_script_model.pt')
test_data torch.load('pt_espnet_asr_tedlium2/cpu_test_841x83_bc1_0.9_48_7.pth',map_location='cpu')
calib_data torch.load('pt_espnet_asr_tedlium2/cpu_calib_n10_bcl.pth',map_locations'cpu')
(2).使用 Blade 量化
调用 bade.optimi2e0接口优化模型详细接口说明参考帮助文档),指定 optn1 zation_leve 为 o2即可开启量化忧化,其中校正数据 caLb.ata 生成方式可参考文格、
import blade
opt_model,opt_spec,report blade.optimize(
script_model,
O2
环境下来执行模型的 CPU 量化实力,同样如果环境中未安装备的敏捷版可以相应的安装 CPU 的版本,这边是预先准备好的模型,是导出存储的,同样的方式,先按照正常的模型把它加载到内存中来然后数据和加重数据然后采用同样的接口来量化,指定设备,这里同样等待一段时间。下面同样的是查看报告,能够看到优化前大概是275毫秒,优化后是145毫秒,加速大概是1.89倍,优化的输入是一个 info,是在 CPU 的 cascadelake 硬件上。
采用同样的方式,可以把意外后的模型保存在本地下面是进行了一组测试,我们对比一下优化前后的模型加速情况,执行。
这边可以看到 baseline latency 执行结果303毫秒。和已经优化后的模型的耗时情况。
下面我们可以对比一下量化前后在测试机上的模型精度情况
import editdistance
import numpy as np
Load test dataset
test_dataset torch.load('pt_espnet_asr_tedtium2/cpu_test_dataset_n1155_bc1.pth',map_location-'cpu')
def test accuracy(model):
with torch.no_grad():
result list()
for data,label in zip(test_dataset['data'],test_dataset['label']):
out model(data)
pred out[0].data.numpy().tolist()
edit_distance=editdistance.eval(label,pred)
result.append([edit_distance,len(pred)])
result np.array(result)
accuracy=1-np.sum(result[:,0])/np.sum(result[:,1])
return accuracy
#Test baseline model
baseline_accuracy test_accuracy(script_model)
print('Baseline model accuracy:{:.2f)%'.format(baseline_accuracy 100))
Test optimized model
with opt_spec:
opt_accuracy test_accuracy(opt_model)
print('Optimized model accuracy:{:.2f)%'.format(opt_accuracy 100))
Baseline 的模型大概是90.22%,还可以观察到优化前后差异不是特别明显
五.常见问题
1:模型量化一定能够提升推理性能吗?
不一定。
通常能够获得一定的性能提升,部分情况下可能存在负优化,但 Blade 优化最终会返回一个最佳性能结果;如果量化没有正收益的时候,会自动回退到浮点型计算。
2:模型量化一定会导致模型准确率下降吗?
不一定。
量化后的模型其计算结果通常会有所变化,但是否会明显影响模型评估指标,需实际验证。此外,若出现精度下降现象,仍可通过调整量化方式、混合精度以及量化训练等途径以缓解该问题。