模型量化
Quantization-Tools简介
Qantization-Tools是算能自主开发的网络模型量化工具, 它解析各种不同框架已训练好的32bit浮点网络模型,生成8bit的定点网络模型。 该8bit定点网络模型,可用于算能SOPHON系列AI运算平台。在SOPHON运算平台上, 网络各层输入、输出、系数使用8bit来表示,并支持混合精度计算, 从而在保证网络精度的基础上,大幅减少功耗和内存占用以及数据传输延迟,大幅提高运算速度。
Quantization-Tools由三部分组成:Parse-Tools、Calibration-Tools以及U-FrameWork。如 Quantization-Tools结构图 所示:
Parse-Tools:
解析各深度学习框架下已训练好的网络模型,生成统一格式的网络模型文件—umodel, 支持的深度学习框架包括: Caffe、TensorFlow、MxNet、PyTorch、Darknet、ONNX以及PaddlePaddle。
Calibration-Tools:
分析float32格式的umodel文件,默认基于熵损失最小算法(可选MAX等其他算法),将网络系数定点化成8bit,最后 将网络模型保存成int8格式的umodel文件。
U-FrameWork:
自定义的深度学习推理框架,集合了各开源深度学习框架的运算功能,提供的功能包括:
作为基础运算平台,为定点化提供基础运算。
作为验证平台,可以验证fp32,int8格式的网络模型的精度。
作为接口,通过bmnetu,可以将int8umodel编译成能在SOPHON运算平台上运行的bmodel。
示例程序
量化程序提供了较多的示例程序,涵盖了制作lmdb,转化不同框架的网络和量化过程,以及可视化调试工具。可以参考 量化demo。
量化步骤
此版本Quantization-Tools包含了一键式量化工具,其中集成了量化需要的多个步骤,将其分步骤描述可以对量化过程有更直接的了解。
使用Quantization-Tools量化网络流程如下图:
具体量化步骤的说明如下:
量化数据集准备
Quantization-tools作为Post-Training量化工具,对已经训练好的float32网络进行量化。此过程需要一定 数量的真实数据用float32网络进行推理,推理过程中会统计每层的输入输出数据范围作为量化参考。 如果使用一键量化接口,对于常见的CV类推理任务,设置量化图片的路径和前处理会在一键量化的过程中生成lmdb,分步量化的时候可以直接使用; 如果简单的前处理设置不能满足需求或者对于非CV类的网络输入可能是各种shape,可以参考和修改create_lmdb例子中的python代码,自己制作lmdb。
float32网络转换
需要将基于不同框架的网络转换为float32 Umodel之后进行量化,此过程中可以指定第一步准备好的数据作为推理输入。 此步骤使用到的工具为ufw.tools.*_to_umodel,或者在一键量化时候根据指定的模型和参数文件后缀判断是何种开源框架的模型自动调用 这些接口转换。
对齐预处理
分步量化需要用户确认网络训练时候进行的前处理,依据此修改上一步产生的prototxt文件,对齐网络训练预处理,或者更加推荐在 制作lmdb阶段直接制作包含预处理之后数据的lmdb。
量化网络
通过一定次数的推理统计和计算量化参数,将float32 Umodel转化为int8 Umodel。此步骤使用到的工具为calibration_use_pb二进制工具或者其python形式接口。
精度测试与调优
此步骤可能与量化网络一起进行多轮,通过验证量化后网络是否满足精度或者速度要求,对量化参数进行调节,然后再次量化,达到预期目标。 此步骤使用到的工具为ufw test_fp32/ufw test_int8以及可视化工具,或者多数情况下需要用户自己开发精度测试程序验证精度。
网络部署
量化完成后部署,与float32网络部署类似。使用bmnetu工具将int8 Umodel转换成最终能部署到SOPHON相关设备上的int8 Bmodel。
分步量化 中有具体步骤的详细描述。
以上提到的所有工具均随SophonSDK一起发布。
auto-cali量化
对于常见以图片作为输入的CV类推理网络,推荐使用auto_cali一键量化工具。这个工具是分步量化的整合,操作更加简单,可以减少分步量化过程中手工输入引起的错误等,其功能如下:
一键完成从原始框架(TensorFlow/PyTorch/Caffe/Darknet/MxNet/PaddlePaddle/ONNX)到BM168X芯片bmodel的转换
可根据预设的优化参数组合根据int8模型精度结果自动进行量化策略搜索,找到满足精度要求的最佳量化策略
使用tpu-nntc发布包启动docker环境后,进入模型以及量化数据集存放目录。
以YOLOv5s模型为例,详细的操作步骤可以参考 使用auto-cali一键量化工具量化
量化数据集准备
auto-cali可使用lmdb数据集和原始图片作为量化数据集。
准备lmdb数据集
以lmdb作为量化数据集需要先将原始图片使用ufwio转换为lmdb数据集,具体介绍见 准备lmdb数据集
准备图片数据集
auto-cali也可使用--cali_image_path参数指定图片数据集,并使用--cali_image_preprocess参数可对数据集进行预处理,在此过程中,auto-cali会自动将处理好的图片保存为lmdb数据集,供后续调用。
一键量化参数说明
ufw.cali.cali_model模块可一键完成从原始框架到168x芯片的bmodel的量化转换
$ python3 -m ufw.cali.cali_model \ --net_name resnet18 \ --model test_models/pytorch/resnet18.pt \ --cali_lmdb test_models/imagenet_preprocessed_by_pytorch_100/ \ #使用已做预处理的lmdb文件, 若使用图片数据配置参数:cali_image_path和cali_image_preprocess参数,见后面示例 --input_shapes '[1,3,224,224]' \ --test_iterations 10 \ --postprocess_and_calc_score_class topx_accuracy_for_classify \ --cali_iterations=100
主要参数说明
参数名 |
是否必需 |
描述 |
net_name |
Y |
模型/网络的名字,此名字会用于生成的umodel的文件名 |
model |
Y |
模型文件路径,tensorflow的pb文件、pytorch的pt文件、mxnet的json文件、caffe和U-FrameWork中prototxt文件 |
weights |
N(当有描述中的文件时必需) |
模型weights文件路径,caffe中caffemodel文件、U-FrameWork中fp32umodel文件、mxnet中params文件 |
input_names |
N |
网络输入tensor名,格式如:‘input_tensor1_name,input_tensor2_name’,中间以逗号分割 |
input_shapes |
Y |
网络输入tensor shape,格式如:‘[input_shape];[input_shape]’,中间以分号分割,比如:‘[4, 3, 224, 224];[4, 1]’, 如果有输入名,需要和输入名对应 |
input_descs |
Y |
网络输入tensor的数据类型和取值范围描述,格式如:“[serial number, data type, lower bound, upper bound]”, e.g., “[0, uint8, 0, 256]”, default “[x, float, 0, 1]” |
input_structure |
Y |
网络输入tensor的层次结构,部分框架,比如pytorch部分可能需要,格式如: “0,1,(2,3)” |
output_names |
N |
网络输出tensor名,格式如:“output_tensor1_name, output_tensor2_name”,中间以分号分割 |
cali_lmdb |
Y |
量化校准图片集lmdb文件路径,默认为空串,若不设置,则要求设置cali_image_path从文件目录中读取校准图片 |
cali_image_path |
Y |
量化校准图片集目录,默认为空串,若不设置,则要求设置cali_lmdb从lmdb中读取校准数据 |
cali_iterations |
N |
量化校准图片数量,默认值为0表示从lmdb或图片目录中获取真实数量,可以设置小于实际数量的图片数,一般推荐使用200张图片校准 |
可选参数说明
cali_image_preprocess
用户自定义的图像预处理,各个预处理op间以分号分隔,op内各参数间以逗号分隔, 比如: –cali_image_preprocess “resize_side=256; crop_h=224,crop_w=224; mean_value=103.94:116.78:123.68, scale=1.0, bgr2rgb=True”
fp32_layer_list
指定某些层固定采用fp32计算,按格式:“层1名,层2名,……,层n名”指定,用逗号分隔
layer_param_list
可对层的layer_param进行设置,层之间用“;”分号分割,层名和层参数用“:”冒号分割,层的各个参数间用“,”逗号分隔,参数名和值用“=”分隔,比如:层1名:参数1=1,参数2=xx;层2名:参数1=3,参数2=yy
convert_bmodel_cmd_opt
指定输出bmodel的命令参数,提供给bmnetu使用,默认为空,可使用bmnetu –help查看支持的选项,比如:配置为“-dyn 1 -opt 2 -enable_profile”,会直接将这3个参数传给bmnetu命令
自动量化参数说明
开启以下参数,可以在一定程度上尝试用不同的量化选项测试量化效果,选优提高量化精度。量化效果目前是以浮点网络的输出和定点网络的输出的余弦距离作为判断依据(因为网络形式多种多样,这个标准并非绝对准确,量化选优还是以实际部署后的真实环境测试结果为准)。 Auto-cali自动量化会自动进行一些尝试,所以会循环进行量化和测试精度的过程,叠加每次进行多次iteration的推理,可能会进行很长时间,用户也可根据经验自行分步量化。
以下参数类型均为string,且可选
postprocess_and_calc_score_class
指定auto_cali/usr目录下文件作为网络后处理和精度计算的类,默认为None:支持分类模型的topx_accuracy_for_classify,当前支持:[detect_accuracy、topx_accuracy_for_classify、feature_similarity、None],即:支持目标检测模型的detect_accuracy、支持对提取特征进行cos相似度计算的feature_similarity;若设置None,表示不进行任何后处理和精度计算
try_cali_accuracy_op
直接指定calibration工具的量化参数,不再使用自动搜素的量化参数,默认为空串,方便调试用,可使用calibration_use_pb –help查看支持的选项;可以指定为default,此时就完全使用默认calibration_use_pb最基本默认参数进行测试,方便基本调试。例如: –try_cali_accuracy_opt=“-per_channel=True;-th_method=SYMKL”
test_iterations
测试集上测试的迭代数,默认为0表示从lmdb或图片目录中获取真实数量, 可以设置小于实际数量的图片数;若是网络发送测试数据方式,则必须设置该参数
feature_compare_layer_list
有时候网络的输出不适合作为余弦距离比较标准,可以用此参数指定用来比较余弦距离的层,也可以设置为use_the_conv_at_the_end,表示用各输出分支的倒数第1个conv的输出来计算cos
auto_cali一键量化结果
生成芯片端运行的可执行文件:compilation.bmodel
量化质量评估,可参考 view_demo
如量化精度不满足需求,自动搜索或手工配置量化策略可参考 量化技巧
Auto-cali一键量化作为一套合并多个步骤的量化接口,如果用户想在其基础上进一步调优或者一键量化不能满足要求,用户可以在每个步骤中进行定制和尝试,具体参考 分步量化
分步量化
对于常见以图片作为输入的CV类推理网络,推荐使用auto_cali一键量化工具。自动量化是一系列量化步骤的集成和包装,本节介绍每个步骤,有助于对量化过程更清晰的了解。 在自动量化结果不够满意需要尝试特殊的量化技巧,或者网络不同于常见的CV类网络,比如输入较为特殊,或者在自动量化生成的中间结果的基础上进行一些尝试和研究,可以使用以下的分步量化进行量化:
以下以YOLOv5s模型为例进行介绍,详细的操作步骤可以参考 分步量化YOLOv5s
准备lmdb数据集
lmdb数据集有两种制作方式
Quantization-tools的要求:
Quantization-tools对输入数据的格式要求是[N,C,H,W] (即先按照W存放数据,再按照H存放数据,依次类推)
Quantization-tools对输入数据的C维度的存放顺序与原始框架保持一致。例如caffe框架要求的C维度存放顺序是BGR;tensorflow要求的C维度存放顺序是RGB
运用U-FrameWork接口,在网络推理过程中或编写脚本将网络推理输入抓取存成lmdb,方法如下
在U-FrameWork中,网络的输入数据使用lmdb形式保存,作为data layer的数据来源。对于一般简单的情况,只需将量化输入图片进行解码和格式转换即可, 推荐在制作lmdb过程中即进行减均值除方差等操作,lmdb中保存前处理后的数据。而对于前处理不能精确表达的复杂处理, 或者在级联网络中需要把中间结果作为下一级网络的输入进行训练的情况,用户可以自己开发预处理脚本,直接生成lmdb。
与lmdb相关的功能已经独立成为ufwio包,该安装包不再依赖Sophgo的SDK,可以在任何Python3.7及以上环境下运行。
lmdb API组成
lmdb = ufwio.LMDB_Dataset(path, queuesize=100, mapsize=20e6) # 建立一个 LMDBDataset对象,
path: 建立lmdb的路径(会自建文件夹,并将数据内容存储在文件夹下的data.mdb) queuesize: 缓存队列,指缓存图片数据的个数。默认为100,增加该数值会提高读写性能,但是对内 存消耗较大 mapsize: lmdb建立时开辟的内存空间,LMDBDataset会在内存映射不够的时候自动翻倍
put(data, labels=None, keys=None) # 存储图片和标签信息
data: tensor数据,只接受numpy.array格式或是含多个numpy.array的python list。数据类型可以是int8/uint8/int16/uint16/int32/uint32/float32。数据会 以原始shape存储。 lables: 图片的lable,需要是int类型,如果没有label不填该值即可。 keys: lmdb的键值,可以使用原始图片的文件名,但是需要注意lmdb数据会对存储的数据按 键值进行排序,推荐使用唯一且递增的键值。如果不填该值,LMDB_Dataset会自动维护一个递增的键值。
close()
将缓存取内容存储,并关闭数据集。如果不使用该方法,程序会在结束的时候自动执行该方法。 但是如果python解释器崩溃,则会导致缓存区数据丢失。
with Blocks
LMDB_Dataset支持使用python with语法管理资源。
LMDB API使用方式
import ufwio
txn = ufwio.LMDB_Dataset(‘to/your/path’)
txn.put(images) # 放置在循环中
在pytorch和tensorflow中,images通常是xxx.Tensor,可以使用images.numpy(),将其转化为numpy.array格式
txn.close()
示例代码
使用对象方法存储数据
import ufwio import torch images = torch.randn([1, 3, 100, 100]) path = "test_01" txn = ufwio.LMDB_Dataset(path) for i in range(1024): txn.put(images.numpy()) txn.close()
使用with语法来管理存储过程
import ufwio import torch images = torch.randn([1, 3, 100, 100]) path = "test_02" with ufwio.LMDB_Dataset(path) as db: for i in range(1024): db.put(images.numpy())
读取lmdb数据
import ufwio path = "test_02" for key, arr in ufwio.lmdb_data(path): print("{0} : {1}".format(key, arr)) # arr is an numpy.array
命令行查看lmdb内容
python3 -m ufwio.lmdb_info /path/to/your/lmdb/path
注意事项
此功能不会检查给定路径下是否已有文件,如果之前存在lmdb文件,直接往里添加新的内容往往会因为key重复等造成混乱,建议每次调用此功能前先将目标lmdb删除重新创建和添加。
使用重复的key会导致数据覆盖或污染,使用非递增的key会导致写入性能下降。
解析该lmdb的时候需要使用Data layer。
如何使用生成的lmdb在 using-lmdb 中描述,配合其中描述的前处理为量化期间的推理准备好数据。
生成fp32umodel
为了将第三方框架训练后的网络量化,需要先将它们转化为fp32umodel。本阶段会生成一个*.fp32umodel文件以及一个*.prototxt文件。 prototxt文件的文件名一般是net_name_bmnetX_test_fp32.prototxt,其中X代表原始框架名的首字母, 比如Tensorflow的网络转为umodel后prototxt文件名会是net_name_bmnett_test_fp32.prototxt,PyTorch转换的网络会是net_name_bmnetp_test_fp32.prototxt等。 此阶段生成的fp32umodel文件是量化的输入, using-lmdb 中修改预处理就是针对此阶段生成的prototxt文件的修改。
注意 :BM1684芯片基于精度方面考虑输入Calibration-tools的fp32umodel一般需要保持Batchnorm层以及 Scale层独立。有时候客户可能会利用第三方工具对网络图做一些等价转换,这个过程中请 确保Batchnorm层以及Scale层不被提前融合到Convolution。
转换生成fp32umodel的工具为一系列名为ufw.tools.*_to_umodel的python脚本,存放于ufw包中,*号代表不同框架的缩写。可以通过以下命令查看使用帮助:
python3 -m ufw.tools.cf_to_umodel --help # Caffe模型转化fp32umodel工具 python3 -m ufw.tools.pt_to_umodel --help # PyTorch模型转化fp32umodel工具 python3 -m ufw.tools.tf_to_umodel --help # TensorFlow模型转化fp32umodel工具 python3 -m ufw.tools.dn_to_umodel --help # Darknet模型转化fp32umodel工具 python3 -m ufw.tools.mx_to_umodel --help # MxNet模型转化fp32umodel工具 python3 -m ufw.tools.on_to_umodel --help # ONNX模型转化fp32umodel工具 python3 -m ufw.tools.pp_to_umodel --help # PaddlePaddle模型转化fp32umdoel工具
详细参数说明针对不同框架可能稍有区别,具体参考下文示例中各框架下的参数解释。
以下示例中模型生成命令已经保存为简单的python脚本,用户可以在这些脚本的基础上修改其中的少量参数完成自己的模型转换,也可以 在命令行直接使用python3 -m ufw.tools.xx_to_umodel加参数进行转换。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 本示例脚本存放于上述项目的examples/calibration/caffemodel_to_fp32umodel_demo/ resnet50_to_umodel.py 中,对于用户网络,可以以此为基础,修改其中的-m -w -s 参数:
1import ufw.tools as tools 2 3cf_resnet50 = [ 4 '-m', './models/ResNet-50-test.prototxt', 5 '-w', './models/ResNet-50-model.caffemodel', 6 '-s', '(1,3,224,224)', 7 '-d', 'compilation', 8 '-n', 'resnet-50', 9 '--cmp' 10] 11 12if __name__ == '__main__': 13 tools.cf_to_umodel(cf_resnet50)
可选参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.prototxt文件的路径 |
-w |
string |
Y |
指向*.caffemodel文件的路径 |
-s |
string |
Y |
输入blob的维度,(N,C,H,W) |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-n |
string |
N |
网络名字 |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
--dyn |
string |
N |
指定是否以动态网络类型转换模型 |
运行命令:
例如: 调用转换脚本:python3 resnet50_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.cf_to_umodel \ -m './models/ResNet-50-test.prototxt' \ -w './models/ResNet-50-model.caffemodel' \ -s '(1,3,224,224)' \ -d 'compilation' \ -n 'resnet-50' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹用来存放输出的*.fp32umodel 与 *_bmnetc_test_fp32.prototxt。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 本示例可以参考examples/calibration/tf_to_fp32umodel_demo/ resnet50_v2_to_umodel.py,修改其中的-m,-i,-s等 参数:
1import ufw.tools as tools 2 3tf_resnet50 = [ 4 '-m', './models/frozen_resnet_v2_50.pb', 5 '-i', 'input', 6 '-o', 'resnet_v2_50/predictions/Softmax', 7 '-s', '(1, 299, 299, 3)', 8 '-d', 'compilation', 9 '-n', 'resnet50_v2', 10 '-D', './dummy_lmdb/', 11 '--cmp' 12] 13 14if __name__ == '__main__': 15 tools.tf_to_umodel(tf_resnet50)
可选参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.pb文件的路径 |
-i |
string |
N |
输入tensor的名称,多输入以逗号分隔,比如:“input_ids,input_mask” |
-o |
string |
N |
输出tensor的名称 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-n |
string |
N |
网络名字 |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
--dyn |
string |
N |
指定是否以动态网络类型转换模型 |
--descs |
string |
N |
根据原始模型可能需要输入的数据类型等描述信息,比如 “[0,uint8,0,256]”,多个输入之间用“,”分隔,比如:“[0,int32,0,256],[1, int32, 0, 2]” |
运行命令:
例如: 调用转换脚本:python3 resnet50_v2_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.tf_to_umodel \ -m './models/frozen_resnet_v2_50.pb' \ -i 'input' \ -o 'resnet_v2_50/predictions/Softmax' \ -s '(1, 299, 299, 3)' \ -d 'compilation' \ -n 'resnet50_v2' \ -D './dummy_lmdb/' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的*.fp32umodel 与*_bmnett_test_fp32.prototxt。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 可以以examples/calibration/pt_to_fp32umodel_demo/yolov5s_to_umodel.py为基础,修改其中的-m,-s等 参数。
1import ufw.tools as tools 2 3pt_mobilenet = [ 4 '-m', 'path/to/yolov5s_jit.pt', 5 '-s', '(1,3,640,640)', 6 '-d', 'compilation', 7 '--cmp' 8] 9 10if __name__ == '__main__': 11 tools.pt_to_umodel(pt_mobilenet)
可选参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.pt文件的路径 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-n |
string |
N |
网络名字 |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
--dyn |
string |
N |
指定是否以动态网络类型转换模型 |
--descs |
string |
N |
根据原始模型可能需要输入的数据类型等描述信息,比如 “[0,uint8,0,256]”,多个输入之间用“,”分隔,比如:“[0,int32,0,256],[1, int32, 0, 2]” |
运行命令:
例如: 调用转换脚本:python3 yolov5s_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.pt_to_umodel \ -m '.path/to/yolov5s_jit.pt' \ -s '(1,3,640,640)' \ -d 'compilation' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的 *.fp32umodel 与 *_bmnetp_test_fp32.prototxt
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 以examples/calibration/mx_to_fp32umodel_demo/mobilenet0.25_to_umodel.py 为基础,修改其中的-m,-w,-s等 参数:
1import ufw.tools as tools 2 3mx_mobilenet = [ 4 '-m', './models/mobilenet0.25-symbol.json', 5 '-w', './models/mobilenet0.25-0000.params', 6 '-s', '(1,3,128,128)', 7 '-d', 'compilation', 8 '-D', '../classify_demo/lmdb/imagenet_s/ilsvrc12_val_lmdb_with_preprocess', 9 '--cmp' 10] 11 12if __name__ == '__main__': 13 tools.mx_to_umodel(mx_mobilenet)
参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.json文件的路径 |
-w |
string |
Y |
指向*params文件的路径 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
--dyn |
string |
N |
指定是否以动态网络类型转换模型 |
--descs |
string |
N |
根据原始模型可能需要输入的数据类型等描述信息,比如 “[0,uint8,0,256]”,多个输入之间用“,”分隔,比如:“[0,int32,0,256],[1, int32, 0, 2]” |
运行命令:
例如: 调用转换脚本:python3 mobilenet0.25_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.mx_to_umodel \ -m './models/mobilenet0.25-symbol.json' \ -w './models/mobilenet0.25-0000.params' \ -s '(1,3,128,128)' \ -d 'compilation' \ -D '../classify_demo/lmdb/imagenet_s/ilsvrc12_val_lmdb_with_preprocess' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的 *.fp32umodel 与 *_bmnetm_test_fp32.prototxt。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 以examples/calibration/dn_to_fp32umodel_demo/yolov3_to_umodel.py为 基础,修改其中的-m,-w,-s等 参数:
1import ufw.tools as tools 2 3dn_darknet = [ 4 '-m', './models/yolov3.cfg', 5 '-w', './models/yolov3.weights', 6 '-s', '[[1,3,416,416]]', 7 '-d', 'compilation' 8] 9 10if __name__ == '__main__': 11 tools.dn_to_umodel(dn_darknet)
参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.cfg文件的路径 |
-w |
string |
Y |
指向*.weights文件的路径 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
运行命令:
此示例程序发布时为了减少发布包体积,原始网络没有随SDK一块发布,要运行此示例需要先下载原始网络:
get_model.sh # download model 调用转换脚本:python3 yolov3_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.dn_to_umodel \ -m './models/yolov3.cfg' \ -w './models/yolov3.weights' \ -s '[[1,3,416,416]]' \ -d 'compilation'
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的 *.fp32umodel 与 *_bmnetd_test_fp32.prototxt。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 以examples/calibration/on_to_fp32umodel_demo/postnet_to_umodel.py为 基础,修改其中的-m,-i,-s等 参数:
1import ufw.tools as tools 2 3on_postnet = [ 4 '-m', './models/postnet.onnx', 5 '-s', '[(1, 80, 256)]', 6 '-i', '[mel_outputs]', 7 '-d', 'compilation', 8 '--cmp' 9] 10 11if __name__ == '__main__': 12 tools.on_to_umodel(on_postnet)
参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.onnx文件的路径 |
-i |
string |
N |
输入tensor的名称 |
-o |
string |
N |
输出tensor的名称 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-n |
string |
N |
网络名字 |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
--dyn |
string |
N |
指定是否以动态网络类型转换模型 |
--descs |
string |
N |
根据原始模型可能需要输入的数据类型等描述信息,比如 “[0,uint8,0,256]”,多个输入之间用“,”分隔,比如:“[0,int32,0,256],[1, int32, 0, 2]” |
运行命令:
调用转换脚本:python3 postnet_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.on_to_umodel \ -m './models/postnet.onnx' \ -s '[(1, 80, 256)]' \ -i '[mel_outputs]' \ -d 'compilation' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的 *.fp32umodel 与 *_bmneto_test_fp32.prototxt。
参数修改
示例都存放于github项目https://github.com/sophon-ai-algo/中,请自行前往选择正确的分支下载。 以examples/calibration/pp_to_fp32umodel_demo/ppocr_rec_to_umodel.py为 基础,修改其中的-m,-i,-s等 参数:
1import ufw.tools as tools 2 3ppocr_rec = [ 4 '-m', './models/ppocr_mobile_v2.0_rec', 5 '-s', '[(1,3,32,100)]', 6 '-i', '[x]', 7 '-o', '[save_infer_model/scale_0.tmp_1]', 8 '-d', 'compilation', 9 '--cmp' 10] 11 12if __name__ == '__main__': 13 tools.pp_to_umodel(ppocr_rec)
参数解释
参数名 |
参数类型 |
是否必需 |
描述 |
-m |
string |
Y |
指向*.pdiparams文件所在的路径 |
-i |
string |
N |
输入tensor的名称 |
-o |
string |
N |
输出tensor的名称 |
-s |
string |
Y |
输入tensor的维度,(N,H,W,C),多输入网络以逗号分隔,需要和输入的顺序一致,比如:“[1,384],[1,384],[1,384]” |
-d |
string |
N |
输出文件夹的名字,默认compilation |
-n |
string |
N |
网络名字 |
-D |
string |
N |
lmdb数据集的位置,没有的话,可以不设置此参数,然后在手动编辑prototxt文件的时候,根据实际的路径来添加 |
--cmp |
string |
N |
指定是否测试模型转化的中间文件 |
运行命令:
调用转换脚本:python3 ppocr_rec_to_umodel.py 或者自行配置转换参数:python3 -m ufw.tools.pp_to_umodel \ -m './models/ppocr_mobile_v2.0_rec' \ -s '[(1, 3,32,100)]' \ -i '[x]' \ -o '[save_infer_model/scale_0.tmp_1]' \ -d 'compilation' \ --cmp
输出:
若不指定-d参数,则在当前文件夹下,默认新生成compilation文件夹存放输出的 *.fp32umodel 与 *_bmpaddle_test_fp32.prototxt。
此阶段的参数设置需要注意:
如果指定了-D (-dataset )参数,那么需要保证 -D参数下的路径正确,同时指定的数据集兼容该网络,否则会有运行错误。
若指定了-D参数,则按照章节 using-lmdb 方法修改prototxt。
使用data layer作为输入
正确设置数据预处理
正确设置lmdb的路径
在不能提供合法的数据源时,不应该使用-D参数(该参数是可选项,不指定会使用随 机数据测试网络转化的正确性,可以在转化后的网络中再手动修改数据来源)。
转化模型的时候可以指定参数--cmp,使用该参数会比较模型转化的中间格式与原始框 架下的模型计算结果是否一致,增加了模型转化的正确性验证。
量化,生成int8umodel
网络量化过程包含下面两个步骤:
对输入浮点网络图进行优化,这一步在量化步骤中已经包含,也可单独进行。可参考 optimize_nets。
对浮点网络进行量化得到int8网络图及系数文件。可参考 quantize_nets。
量化需要用到 准备lmdb数据集 中产生的lmdb数据集,而正确使用数据集尤为重要,所以先说明如何使用数据集。
对于post-training量化方法,通过将训练后的模型进行一定次数的推理,来统计每层的输入输出数据范围,从而确定量化参数。 为了使统计尽可能准确, 推理时候必须保证输入的数据为实际训练/验证时候的有效数据,前处理也保证和训练时候的一致 。
因此U-FrameWork中提供了简单的前处理接口,可通过修改产生fp32umodel时候生成的*_test_fp32.prototxt文件 来配置前处理算法,生成的lmdb数据在输入网络前会按照此处的配置进行计算后再进行真正的网络推理,完整的前处理可以视为制作lmdb时进行的cv转换 和prototxt中定义的前处理算法的组合。
完整定义前处理一般需要做以下三方面的修改:
使用Data layer作为网络的输入。
使Data layer的参数data_param指向生成的lmdb数据集的位置。
修改Data layer的transform_param参数以对应网络对图片的预处理。
data_layer的典型结构如下例所示:
layer { name: "data" type: "Data" top: "data" top: "label" include { phase: TEST } transform_param { transform_op { op: RESIZE resize_h: 331 resize_w: 331 } transform_op { op: STAND mean_value: 128 mean_value: 128 mean_value: 128 scale: 0.0078125 } } data_param { source: "/my_lmdb" batch_size: 0 backend: LMDB } }
特别注意,2.7.0版本开始ufwio相较于以前版本在lmdb中有新的辅助信息存储,所以格式和以前版本的lmdb有不同,制作lmdb使用python形式的接口,示例程序create_lmdb提供了可在其基础上修改的例程。推荐在python代码中将预处理一并包含,生成已经预处理过的数据供量化使用,这样就不必在prototxt中定义前处理。
制作lmdb时候需要生成与网络输入shape一致的数据,对于常见的CV类的模型数据,示例程序默认生成的lmdb是4维,当此lmdb用作转换fp32umodel命令的-D参数的输入时,上述prototxt的data layer的batch_size参数会自动设置为0,如果转换fp32umodel过程中没有指定-D参数,则手工修改prototxt指定数据源时需要注意将batch_size设置为0。
旧版SDK二进制convert_imageset工具生成的lmdb配合以前的prototxt是兼容的,它生成的lmdb为3维,如果使用新的工具创建lmdb用于以前已经转换好的fp32umodel,可能存在维度不同的现象,需要手工修改data layer的batch_size为0。旧版本的prototxt和lmdb仍然是兼容的,使用新生成的lmdb作为dataset参数转换fp32umodel也无须手工修改。
1 model_type: BMNETT2UModel 2 output_whitelist: "vgg_16/fc8/squeezed" 3 inputs: "input" 4 outputs: "vgg_16/fc8/squeezed" 5 layer { 6 name: "input(data_will_be_transposed)" 7 type: "Data" 8 top: "input(data_will_be_transposed)" 10 include { 11 phase: TEST 12 } 13 transform_param { 14 transform_op { 15 op: RESIZE 16 resize_side: 256 17 } 18 transform_op { 19 op: CROP 20 crop_h: 224 21 crop_w: 224 22 } 23 transform_op { 24 op: STAND 25 mean_value: 103.94000244140625 26 mean_value: 116.77999877929688 27 mean_value: 123.68000030517578 28 scale: 1.0 29 bgr2rgb: True 30 } 31 } 32 data_param { 33 source: "/my_lmdb" // 设置为data layer的source 34 batch_size: 0 35 backend: LMDB 37 } 38 } 修改source指向正确的lmdb位置
在量化网络前,需要修改网络的*_test_fp32.prototxt文件,在datalayer(或者AnnotatedData layer) 添加其数据预处理的参数,以保证送给网络的数据与网络在原始框架中训练时的预处理一致。
Calibration-tools量化工具在Caffe数据预处理表示形式基础上进行了改进。 Caffe自带的TransformationParameter参数表示方法各个参数的执行顺序相对固定, 但很难完善表达Tensorflow、Pytorch等基于Python的框架里面灵活多变的预处理方式,仅适用于Caffe模型的默认数据预处理方式。本工具改进为自定义TransformOp 数组表示方法,通过定义transform_op结构,将需要进行的预处理分解为不同的transform_op,按照顺序列在transform_param中,程序会按照顺序分别执行各 项计算,各个op的定义可以参考 transform_op。
message TransformOp { enum Op { RESIZE = 0; CROP = 1; STAND = 2; NONE = 3; } optional Op op = 1 [default = NONE]; //resize parameters optional uint32 resize_side = 2 ; optional uint32 resize_h = 3 [default = 0]; optional uint32 resize_w = 4 [default = 0]; //crop parameters optional float crop_fraction = 5; optional uint32 crop_h = 6 [default = 0]; optional uint32 crop_w = 7 [default = 0]; optional float padding = 8 [default = 0];//for resize_with_crop_or_pad //mean substraction(stand) repeated float mean_value = 9; optional string mean_file = 10; repeated float scale = 11; repeated float div = 12; optional bool bgr2rgb = 13 [default = False]; }
目前支持缩放(RESIZE),剪裁(CROP)和归一化(STAND)操作。
缩放(RESIZE)参数 |
参数说明 |
---|---|
resize_side |
图片缩放的短边的长度,图片较短的宽/高缩放到此数值,另一边按此边比例缩放,输入此参数则resize_h和resize_w被忽略 |
resize_h |
图片目标高度 |
resize_w |
图片目标宽度 |
剪裁(CROP)参数 |
参数说明 |
---|---|
crop_fraction |
图片剪裁比例,输入图片按照此比例以中心点为参考点剪裁,如果输入此参数,则crop_h和crop_w参数被忽略 |
crop_h |
图片剪裁目标高度 |
crop_w |
图片剪裁目标宽度 |
归一化(STAND)参数 |
参数说明 |
---|---|
mean_value |
图片均值,可以输入一个或者多个,多个情况下需要和channel数量对应。 |
mean_file |
以文件形式输入的均值 |
scale |
图片乘系数,输入数据会乘以此系数,可以输入多个,多个输入情况需要和channel数量对应。 |
div |
图片除系数,输入数据会除以此系数,可以输入多个,多个输入情况需要和channel数量对应,此参数会和scale组合计算,一般可以折算到scale中。 |
bgr2rgb |
当lmdb内的数据是bgr格式的,但是net需要输入为rgb格式时,将bgr2rgb设置为ture |
$ cd <release dir> $ calibration_use_pb \ quantize \ #固定参数 -model= PATH_TO/*.prototxt \ #描述网络结构的文件 -weights=PATH_TO/*.fp32umodel #网络系数文件 -iterations=200 \ #迭代次数 -winograd=False \ #可选参数 -graph_transform=False \ #可选参数 -save_test_proto=False #可选参数
这里给出了使用二进制量化工具量化网络用到的所有必要参数及部分最常用的可选参数,同时sdk中也提供了python形式的量化接口,可以参考帮助文件输入参数量化:
python3 -m ufw.cali --help -target: 目标量化芯片,可以是BM1684或者BM1684X -model: 量化输入网络 -weights: 量化网络的权重文件 -dump_dist: 量化过程中将统计的每层的数据分布保存在文件中,下次量化可以直接load,跳过 推理统计的过程加速量化 -load_dist: 将上次量化保存的layer的数据分布加载进来跳过再次推理,提高推理速度,需要 注意只能使用结构完全没有变化的网络保存的分布 -th_method: 计算门限的算法,可以为KL(default),SYMKL,JSD,ADMM,ACIQ,MAX,PERCENTILE9999 -th_binnum: 使用KL量化算法时候可选的数据bin的个数,512-4096之间的2的幂次数值 -save_test_proto: 保存测试网络,此网络包含data layer,可用于可视化工具比较量化效果 -iterations: 量化推理次数,较多的推理次数统计的数据分布往往更准确,但是需要更多的时间 -graph_transform: 是否进行图优化,默认打开 -accuracy_opt: 是否开启精度优化选项,开启后deptwise卷积会用浮点推理,默认关闭 -bitwidth: 量化后数据宽度,默认为int8: TO_INT8 -conv_group: 是否对卷积的channel进行分组,对于一些channel间数据差异大的channel按照范围 排序分组,可以减少量化误差 -fold_concat_scale: 将concat和scale系数合并,将concat不同输入之间的门限差别转移到scale 的系数中 -fpfwd_blocks: 将某layer开始到下一个计算layer为止的区块用浮点推理 -fpfwd_inputs: 从网络输入到列出的layer之间的layers用浮点推理,用“,”分隔多个层 -fpfwd_outputs: 从某些layer到网络输出之间的layers用浮点推理 -merge_depwise_scale: 将depthwise的卷积和之后的scale合并,打开accuracy_opt会默认进行 此操作 -merge_scale_to_conv: 将卷积之后的scale合并到卷积中 -notmerge_conv_layer: 当合并卷积和scale时候这些layer排除在外不要合并 -pad_value: 有pad的层的pad值 -per_channel: 对卷积尝试每channel量化 -random_input_compare: 优化网络时默认随机输入对比,对有些网络随机输入会造成崩溃,打开此开关 用网络中data layer的源数据作为输入比较,首先需要保证网络的输入设置正确 -winograd: 是否使用winograd算法,是否真正使用需要在转bmodel时再次指定 -fuse_preprocess: 是否进行前处理融合。对于fp32_protoxt定义的STAND类 前处理,如果网络第一层为卷积,将这些前处理折算到卷积的权重中,生成 bmodel输入直接使用图片解码的uint8数据范围。 -asym_threshold: 仅限于目标为BM1684X芯片,是否使用非对称量化方式,默认False -fp16_opt: 仅限于目标为BM1684X芯片,对于已经设置为使用浮点推理的Convolution/Eltwise/ EltwiseBinary/ReLU/BatchMatmul层是否使用FP16以提高性能。默认"-"为不替换为FP16,可以用"," 分隔期望替换的类型的层,或者输入"*"将上述五种layer都用FP16推理。
注意:对于不同的量化目标芯片,有些参数是不可以选择的或者默认已经包含。对于BM684X芯片,量化过程已经默认打开了accuracy_opt和 per_channel,merge_scale_to_conv以及graph_transform(并且不再提供单独的网络优化步骤,命令选择graph_transform会直接进行量化)。而对于fuse_preprocess, 因为涉及prototxt的修改,只在分步量化中支持。
更多网络量化相关的参 数选项参见后面 量化技巧 章节。
Quantization-tools进行网络量化的常用输入参数包括6部分:
quantize: 固定参数
-model= PATH_TO/*.prototxt:描述网络结构的文件,该prototxt文件的datalayer指向 准备好的数据集
-weights=PATH_TO/*.fp32umodel:保存网络系数的文件,
这两个文件由 生成fp32umodel 章节生成。
-iteration=200:该参数描述了在定点化的时候需要统计多少张图片的信息,默认200
-winograd:可选参数,针对3x3 convolution开启winograd功能,默认值为False
-graph_transform:可选参数,开启网络图优化功能,本参数相当于在量化前先执行上面的graph_transform 命令,默认值为True
-save_test_proto:可选参数,存储测试用的prototxt文件,默认值False
Quantization-tools的输出包括5部分:
*.int8umodel: 即量化生成的int8格式的网络系数文件
*_test_fp32_unique_top.prototxt:
*_test_int8_unique_top.prototxt: 分别为fp32, int8格式的网络结构文件, 该文件包括datalayer 与原始prototxt文件的差别在于,各layer的输出blob是唯一的,不存在in-place的情况,当-save_test_proto为True时会生成这两个文件。
*_deploy_fp32_unique_top.prototxt:
*_deploy_int8_unique_top.prototxt:分别为fp32,int8格式的网络结构文件,该文件不包括datalayer
以上几个文件存放位置与通过参数-weights=PATH_TO/*.fp32umodel指定的文件位置相同。
量化过程中会首先对输入浮点网络进行优化,包括batchnorm与scale合并和替换等基础操作和参数中指定的其他附加图优化选项,比如前处理融合 到网络,算子合并,删除推理过程中不必要的算子等功能。对于量化目标为BM1684芯片的量化,可以使用graph_transform参数关闭附加图优化。 默认配置下更多对浮点网络图进行优化的选项参见后面 量化技巧 章节。单独进行基础网络优化的命令如下:
$ calibration_use_pb \ graph_transform \ #固定参数 -model= PATH_TO/*.prototxt \ #描述网络结构的文件 -weights=PATH_TO/*.fp32umodel #网络系数文件
Quantization-tools进行网络图优化的输入参数包括3部分:
graph_transform: 固定参数
-model= PATH_TO/*.prototxt:描述网络结构的文件,该prototxt文件的datalayer指向准备好的数据集,如 data_source_set 所示。
-weights=PATH_TO/*.fp32umodel:保存网络系数的文件。
这两个文件由 生成fp32umodel 章节生成。
Quantization-tools进行网络图优化的输出包括2部分:
PATH_TO/*.prototxt_optimized
PATH_TO/*.fp32umodel_optimized
为了和原始网络模型做区分,新生成的网络模型存储的时候以“optimized”为后缀。以上两 个文件存放在与通过参数“-weights=PATH_TO/*.fp32umodel”指定的文件相同的路径下。
级联网络的量化需要对每个网络分别进行量化,对每个网络分别准备lmdb和量化调优。
精度测试(optional)
精度测试是一个可选的操作步骤,用以验证经过int8量化后,网络的精度情况。该步骤可以安排在 部署 描述的网络部署之前, 并配合 quantize_nets 反复进行,以达到预期的精度。精度测试往往也利用部署后的测试环境测试,根据实际精度结果进行量化效果的评估。
根据不同的网络类型,精度测试可能是不同的,精度测试常常意味着要进行完整的前处理和后处理以及精度计算程序开发。Calibration-tools 对外提供了U-FrameWork的应用接口,可以对umodel进行float32或者int8推理,从而计算网络推理精度。
对于传统的分类网络和检测网络,Calibration-tools提供了两个示例,以演示如何进行精度验证。
测试原始float32网络的精度
$ cd <release dir> $ ufw test_fp32 \ #固定参数 -model=PATH_TO/\*_test_fp32_unique_top.prototxt \ #章节量化网络中 输出的文件 -weights= PATH_TO/\*.fp32umodel \ #fp32格式的umodel -iterations=200 #测试的图片个数
测试转换后的int8网络的精度
$ cd <release dir> $ ufw test_int8 \ #固定参数 -model=PATH_TO/\*test_int8_unique_top.prototxt \ #章节量化网络中输出的文件 -weights= PATH_TO/\*.int8umodel \ #章节量化网络中输出的文件,量化后int8umodel -iterations=200 #测试的图片个数
本工具提供接口函数供外部程序调用,以方便精度测试程序搜集到网络推理结果,进而得到 最后的精度。本工具提供python接口供用户调用。完整的python接口,见章节附录 U-FrameWork python接口。
一个python接口的精度测试程序的框架如图 python接口形式精度测试框架
载入ufw
import ufw
设置模式
fp32模式时:
ufw.set_mode_cpu()
int8模式时:
ufw.set_mode_cpu_int8()
指定网络模型文件
运行fp32网络时候,用
model = './models/ssd_vgg300/ssd_vgg300_deploy_fp32.prototxt' weight = './models/ssd_vgg300/ssd_vgg300.fp32umodel'
运行int8网络时候,用
model = './models/ssd_vgg300/ssd_vgg300_deploy_int8.prototxt' weight = './models/ssd_vgg300/ssd_vgg300.int8umodel'
建立网络
ssd_net = ufw.Net(model, weight, ufw.TEST)
读入图片,预处理
该步骤与待测的检测网络本身特性有关。采用原始网络的处理代码即可
给网络填充数据
将经过预处理的图片数据填充给网络
ssd_net.fill_blob_data({blob_name: input_data})
网络推理
ssd_net.forward()
搜集网络推理结果
ssd_net.get_blob_data(blob_name)
对推理结果的后处理
该步骤与待测的检测网络本身特性有关。采用原始网络的处理代码即可。
章节 view_demo 作为示例程序,描述了如何使用calibration可视化分析工具查看网络量化误差,此工具通过运行fp32和int8网络, 并对其每层的输出进行比较,以图形化界面形式直观显示每层数据的量化损失。
注意: 使用可视化分析工具的时候,需要在量化工具的配置参数中添加 “-save_test_proto=True”,以保证有可以用来与浮点计算对比的int8网络模型。默认配置 下该int8测试模型不会被保存。
该工具使用MAPE(Mean Abusolute Percentage Error)和COS (Cosine Similarity)作为误差评价标准,其计算定义为:
\[\text{MAPE} = \frac{1}{n}\left( \sum_{i=1}^n \frac{|Actual_i - Forecast_i|}{|Actual_i|} \right)\]\[\text{COS} = \frac{\sum_{i=1}^n{a_i*b_i}}{\lVert A \rVert_2 \cdot \lVert B \rVert_2 + \text{eps}}\]\[\text{DIST} = \frac{1}{1 + \sqrt{ \sum_{i=1}^n (a_i - b_i)^2}}\]
由于int8网络部分层进行了合并计算,例如会将relu与batchnorm合并,所以此时batchnorm 层的评价参数值无效。
此量化工具以Web App形式提供,由于量化工具在Docker中运行,使用此量化工具时候可能需要在Docker启动脚本中增加端口 映射选项,如 Docker端口映射启动 所示,在启动docker时增加端口映射选项-p,Docker内端口8000被 映射为主机端口8000。根据启动Docker时的配置,使用ufw.tools.app时,其“--port” 参数需要与Docker内端口映射匹配。
可视化工具的示例存放于https://github.com/sophon-ai-algo/examples/calibration/yolov5s_demo/view_demo中,该用例程序以resnet18为例,描述如何分析量化后int8模型与原始float模型的精度差异。
在Docker的SDK环境中运行命令:
$ cd <release dir>/examples/calibration/yolov5s_demo/view_demo $ python3 -m ufw.tools.app --port 8080 # default port:8050
运行结果如 可视化分析工具 所示。
根据建立docker时设置的端口号(这里以8080为例),在浏览器中输入localhost:8080(对 应图中位置1),即 可进入可视化分析工具界面。在模型路径(对应图中位置2)中输入 ./models/然后回车,就可以在Graph显示区域中看到网络结构图。使用Forward按钮 (对应图中3)对网络执行前向推理,完成后可以看到Graph上的信息得到更行,包括: Tensor的shape,该网络在浮点和定点模式下对应Tensor的计算方式。相关说明见图 可视化分析工具 中的标注。
在评价参数区域中点选相应的数据,此时Graph和数据对比区域会同步更新。
在 数据对比图 中使用滑动条控制抽值采样的点数。增加采样点会让数据显示的更加 丰富和真实,但是较多的采样点会影响app的响应速度。相关的操作见图中的提示。
Display菜单可以控制app中的元素显示方式,如控制Graph的Layout效果,隐藏悬浮窗口。 抓取悬浮窗口的顶端可以把它拖动到其他位置。数据过滤器支持>,<,=,!=运算方式。
部署
部署指的是用int8umodel,生成SOPHON系列AI平台指令集。网络部署时,涉及到以下两个文 件:
**.int8umodel, **_deploy_int8_unique_top.prototxt
以上两个文件会送给bmnetu,最终生成可在SOPHON系列AI运算平台上运行的bmodel,具体步骤请参考文档NNToolChain.pdf中bmnetu相关的部分及sophonsdk下的相关example。
BMNETU 使用
编译UFW模型
BMNETU是针对BM168X的UFW(Unified Framework)模型编译器,可将某网络的umodel(Unified Model)和 prototxt编译成BMRuntime所需要的文件。而且在编译的同时,支持每一层的NPU模型计算结 果和CPU的计算结果进行对比,保证正确性。下面介绍该编译器的使用方式。
安装需求
python 3.x
linux
使用方法
方式一:命令形式
Command name: bmnetu - BMNet compiler command for UFW model
/path/to/bmnetu [--model=<path>] \ [--weight=<path>] \ [--shapes=<string>] \ [--net_name=<name>] \ [--opt=<value>] \ [--dyn=<bool>] \ [--outdir=<path>] \ [--cmp=<bool>]
参数介绍如下:
参数dyn=False表示使用静态编译,dyn=True表示使用动态编译。静态编译意思是model编译后,在runtime时只能运行编译所设置的shapes。 动态编译意思是model编译后,runtime时可以运行任意shapes,只要实际shapes中的数值小于等于编译所设置shapes中的数值。 一般来说,动态编译后神经网络在芯片上的性能要小于等于静态编译。所以一般建议动态编译用于实际网络的shapes会大范围变化的情况, 如果shapes固定或者只需要几种shapes,建议采用静态编译。关于静态编译下如何支持若干种shapes,请见bmodel说明。
args
type
Description
model
string
Necessary. UFW prototxt path
weight
string
Necessary. Umodel(weight) path
target
string
Optional. BM1684 or BM1684X; default: BM1684
outdir
string
Optional. Output directory, default “compilation”
shapes
string
Optional. Shapes of all inputs, default use the shape in prototxt, format [x,x,x,x],[x,x]…, these correspond to inputs one by one in sequence
net_name
string
Optional. Name of the network, default use the name in prototxt
opt
int
Optional. Optimization level. Option: 0, 1, 2, default 1.
dyn
bool
Optional. Use dynamic compilation, default False.
cmp
bool
Optional.Check result during compilation. Default: True
use_wino
bool
Optional. Use winograd convolution. If not given, the flag value will be determined by model files. Note that it’s a global flag for all conv layers, and it can be overridden by the layer-level flag use_winograd (which is False by default).
examples:
以下是编译int8的umodel命令示例
/path/to/bmnetu --model=/path/to/prototxt --weight=/path/to/umodel --shapes=[1,3,224,224] --net_name=resnet18 --outdir=./resnet18
方式二:python接口
bmnetu的python接口如下, 需要pip3 install –user bmnetu-x.x.x-py2.py3-none-any.whl。
以下是编译int8的umodel的python接口。
import bmnetu ## compile int8 model bmnetu.compile( model = "/path/to/prototxt", ## Necessary weight = "/path/to/caffemodel", ## Necessary target = "BM1684", ## Necessary outdir = "xxx", ## optional, default 'compilation' shapes = [[x,x,x,x], [x,x,x]], ## optional, if not set, default use shape in prototxt net_name = "name", ## optional, if not set, default use the network name in prototxt opt = 2, ## optional, if not set, default equal to 2 dyn = False, ## optional, if not set, default equal to False cmp = True ## optional, if not set, default equal to True )
以下是使用bmnetu python的例子:
import bmnetu model = r'../../../umodel/tf_models/accuracy_test/inception/inception_v1_bmnett_deploy_int8_unique_top.prototxt' weight = r'../../../umodel/tf_models/accuracy_test/inception/inception_v1_bmnett.int8umodel' export_dir = r"./compilation" shapes = [[1,3,224,224]] bmnetu.compile(model = model, weight = weight, outdir = export_dir, shapes = shapes)
bmnetu输出和log
bmnetu若成功,输出的log最后会看到以下信息。
###################################### # Store bmodel of BMCompiler. ######################################
bmnetu成功后,将在指定的文件夹中生成一个compilation.bmodel的文件,该文件则是转换成功的bmodel,用户可以重命名。
若用户在bmnetu时使用了cmp=True模式,则会在指定的文件夹中生成一个input_ref_data.dat和一个output_ref_data.dat, 分别是UFW产生的网络输入参考数据和网络输出参考数据,可用于bmrt_test验证生成的bmodel在芯片运行时结果是否正确。
若没有上述信息,则bmnetu失败。目前失败的话,用户可以修改opt优化选项,可能其它优化级别会成功,从而不会耽误用户部署。 然后请用户将失败的问题告知我们的客户支持。
示例——YOLOv5s量化
在本章节将以YOLOv5s为例,分别介绍使用auto-cali一键量化工具和分步量化的方式对YOLOv5s模型进行量化及调优。
对于auto-cali一键量化工具的详细介绍可参考 auto-cali量化
对于分步量化详细介绍可参考 分步量化
使用auto-cali一键量化工具量化
以下章节将以量化Pytorch框架下的yolov5s网络为例,说明auto-cali量化步骤
auto-cali可使用图片数据集和lmdb数据集,在本章节我们以图片数据集为例进行讲解,对于lmdb数据集的具体制作步骤可参考下面示例:
首先下载量化数据集coco128,可使用 https://github.com/sophon-ai-algo/examples/calibration/create_lmdb_demo 下的脚本进行下载
cd examples/calibration/create_lmdb_demo bash ./download_coco128.sh
进入 https://github.com/sophon-ai-algo/examples/calibration/auto_cali_demo/yolov5s_demo/,使用如下命令进行量化,auto-cali会自动处理图片数据集将其转为lmdb数据集,并使用不同量化策略量化多次,自动生成bmodel。
python3 -m ufw.cali.cali_model \ --net_name 'yolov5s' \ --model ./yolov5s_jit.pt \ --cali_image_path ../../create_lmdb_demo/coco128/images/train2017/ \ --cali_image_preprocess 'resize_h=640,resize_w=640;scale=0.003921569,bgr2rgb=True' \ --input_shapes '[1,3,640,640]'
等待量化结束后即可在 ./yolov5s_bmnetp_test_fp32/ 目录下看到生成的 compilation.bmodel。
我们可以使用可视化工具初步查看量化精度
python3 -m ufw.tools.app --port 8001
在浏览器中打开localhost:8001,点击forward,等待程序运行完成,可以看到如下结果:
以余弦相似度看精度较好,但这个结果仅供参考,具体精度还是得以测试程序以及相关测试指标为准。
下面进行精度测试,首先安装测试用的Python包,并下载标注文件
pip3 install pycocotools pip3 install dfn python3 -m dfn --url http://219.142.246.77:65000/sharing/ivVtP2yIg
运行精度测试的命令,要特别注意的是,本次精度测试数据集使用coco128,所得出的mAP的结果并不能与YOLOv5s论文中的mAP精度完全等价。
bash ./regression.sh ./yolov5s_bmnetp_test_fp32/compilation.bmodel ./result.json
运行结束之后可得到如下结果(可能会与实际结果略有偏差,以实际结果为准):
可以看到精度较差,这是因为YOLOv5s网络最后三层卷积结构输出得分以及坐标点等关键信息,对精度要求较高。下面我们将最后三个卷积及之后的层使用fp32进行量化。
下列命令中的 try_cali_accuracy_opt 代表将后面fpfwd_outputs参数传入 calibration_use_pb 工具,可以使用 calibration_use_pb -help查看具体参数说明。
python3 -m ufw.cali.cali_model \ --net_name 'yolov5s' \ --model ./yolov5s_jit.pt \ --cali_image_path ../../create_lmdb_demo/coco128/images/train2017/ \ --cali_image_preprocess 'resize_h=640,resize_w=640;scale=0.003921569,bgr2rgb=True' \ --input_shapes '[1,3,640,640]' \ --postprocess_and_calc_score_clas=feature_similarity \ --try_cali_accuracy_opt='-fpfwd_outputs=< 24 >14,< 24 >51,< 24 >82' # 或直接运行下列脚本,结果等价 bash ./auto_cali.sh
运行精度测试的命令。
bash ./regression.sh ./yolov5s_bmnetp_test_fp32/compilation.bmodel ./result.json
得到下列结果:
可以看到相比于最后三个卷积层使用fp32推理相比用int8量化提升了精度。
分步量化YOLOv5s
分步量化时只能使用lmdb作为量化数据集,在此章节同样使用coco128作为量化数据集。
首先参考 coco128 下载数据集,然后在https://github.com/sophon-ai-algo/examples/calibraton/create_lmdb_demo/目录下,调用脚本直接生成
python3 convert_imageset.py \ --imageset_rootfolder=./coco128/images/train2017 \ --imageset_lmdbfolder=./lmdb \ --resize_height=640 \ --resize_width=640 \ --shuffle=True \ --bgr2rgb=False \ --gray=False
进入https://github.com/sophon-ai-algo/examples/calibraton/pt_to_fp32umodel_demo/
python3 ./yolov5s_to_umodel.py
程序运行结束之后会在当前文件夹下生成compilation文件夹,compilation文件夹下即为fp32umodel和prototxt。
下面我们将修改上一步生成的prototxt,此处要对其YOLOv5s模型的前处理,并将数据输入指向lmdb文件,要注意,此处lmdb文件的路径要写绝对路径。具体修改内容如下:
上一步我们修改了prototxt,这一步我们将使用修改后的prototxt和fp32umodel,量化生成int8umodel。由 使用auto-cali一键量化工具量化 的经验可知,我们需要将最后三层卷积及之后的层使用fp32推理。
calibration_use_pb quantize \ --model=./compilation/yolov5s_jit_bmnetp_test_fp32.prototxt --weights=./compilation/yolov5s_jit_bmnetp.fp32umodel \ -save_test_proto=True --bitwidth=TO_INT8 -fpfwd_outputs="< 24 >14,< 24 >51,< 24 >82"
量化程序运行结束之后可以在compilation文件夹得到 yolov5s_jit_bmnetp_deploy_int8_unique_top.prototxt和yolov5s_jit_bmnetp.int8umodel。
使用bmnetu工具,以上一步得到的为输入:
bmnetu --model=./compilation/yolov5s_jit_bmnetp_deploy_int8_unique_top.prototxt --weight=./compilation/yolov5s_jit_bmnetp.int8umodel
运行结束之后得到compilation.bmodel。
参照 使用auto-cali一键量化工具量化 的测试mAP步骤,可以得到如下结果,可以看到精度损失较小。
量化技巧
结合1684芯片的特点这里给出了3类优化网络量化效果的技巧:
阈值计算
混合执行
网络图优化
结合BM1684X芯片的特点,还有以下两种精度/性能调优选项:
非对称量化
FP16混合量化
阈值计算
分布统计
calibration_use_pb命令行添加如下参数:
-dump_dist: 指向一个输出文件的路径。将网络各层统计的最大值及feature的分布信息保存到文件。
-load_dist: 指向一个-dump_dist参数生成的文件的路径。从-dump_dist参数生成的文件 中读取网络各个层的最大值及feature分布信息。
针对有些网络需要量化调优进行多次量化的场景,采用此参数可以只统计一次分布信息并多 次使用。可以大大加快量化调优的速度。
注:选择使用ADMM方法不支持保存和加载feature分布。
阈值调整
阈值的选取对于网络量化效果有很大的影响,这里给出两种方式来对量化阈值进行调整。
calibration_use_pb命令行添加如下参数:
-th_method:可选参数,指定计算各个层量化阈值的方法,可选参数:KL,SYMKL,JSD,ADMM,ACIQ,MSE,PERCENTIL9999,PERCENTIL99999以及MAX,默认值为KL。
为了更精细地对某个具体层的阈值进行调整,在layer_parameter中增加了部分参数,可以通 过下面方式在prototxt文件中进行使用。
th_strategy:设置当前layer的量化阈值计算策略。
可选参数:USE_DEFAULT,USE_KL,USE_MAX等,默认值为USE_DEFAULT。
USE_DEFAULT:采用calibration-tools量化程序内部定义的规则来计算当前 layer的阈值。
USE_KL:采用求KL分布的方式来计算当前layer的阈值,这里的KL是相对MAX 而言,具体的阈值计算策略可能是KL,SYMKL或者JSD。
USE_MAX:采用统计的最大值做为当前layer的最大值。
th_scale:在计算得到的阈值上面乘以缩放系数th_scale,默认值为1.0。
threshold:设置当前layer的量化阈值,无默认值。
混合执行
BM1684芯片内部集成了FP32浮点计算单元,可以高效地利用浮点进行计算。BM1684X芯片内部一些计算除int8/uint8之外可以支持FP32,FP16等 数据类型,根据芯片的这些特点,这里提供了一种混合执行的方式来运行网络,允许部分层用定点进行计算,部分层用浮点进 行计算。通过允许部分层用浮点进行计算,可以有效地提高网络的整体量化精度。
复杂网络的前处理/ 后处理
Tensorflow及Pytorch等基于python的框架灵活度较大,从这些框架转过来的网络模型中可 能包含前后处理相关的算子。对于这些算子做量化将很大程度上影响网络的量化精度。这里 提供了一种方式在网络中标记出前处理、后处理相关的层,并允许这些层以浮点运行。在calibration_use_pb命令行中使用如下参数:
-fpfwd_inputs:用逗号分隔开的网络layer name,在网络中这些layer及它们之前的layer 被标记为网络前处理。网络前处理不算做正式网络的一部分,在calibration过程中不被 量化,在推理过程中保持使用浮点进行计算。
-fpfwd_outputs:用逗号分隔开的网络layer name,在网络中这些layer及它们之后的 layer被标记为网络后处理。网络后处理不算做正式网络的一部分,在calibration过程中 不被量化,在推理过程中保持使用浮点进行计算。
对量化损失敏感的层
通过命令行参数指定: 在calibration_use_pb命令行中使用如下参数:
-fpfwd_blocks:用逗号分隔开的网络layer name,在网络中每个layer及它们之后直到下一 个进行数据计算的层在calibration过程中都不被量化,在推理过程中保持使用浮点进行计算。
calibration-tools程序会根据指定的layer name自动判断这个layer后面有多少个layer需 要用浮点进行计算,把网络的这个block做为一个整体用浮点进行计算,来达到提高量化精 度的目的。如下图所示在命令行中用-fpfwd_blocks指定Softmax层的layer name, calibration-tools程序会将图中红色框中的layer都标识为用浮点进行计算。 calibration-tools程序会在此block的输入处自动将输入数据转换成浮点格式,在输出位置 转换为int8数据格式。
通过配置prototxt指定:
forward_with_float:将当前layer用浮点进行计算,可选参数为True,False,默认值为False。
具体使用方法参考如下面图 prototxt文件中设置forward_with_float 所示,这里的*_test_fp32.prototxt文件是指 calibration_use_pb命令的输入prototxt文件,见 生成fp32umodel 。
网络图优化
在calibration_use_pb命令行对量化目标为BM1684的网络可以尝试使用如下参数进行图优化以尝试提高精度,其效果根据网络特点不同可能不同, 以实测为准。对于量化目标为BM1684X的网络,accuracy_opt和per_channel默认打开,使用per_channel的量化方式:
-accuracy_opt:将网络中depthwise卷积采用浮点推理以提高精度,默认为False,关闭。
-conv_group:将conv的输出channel按照输出幅值进行分组并拆分成不同的组分别进行量化,默认为False,关闭。
-per_channel:开启convolution计算的per_channel功能,默认为False,关闭。
为了提高精度和速度,量化过程中会进行简单的网络优化。 使用Parse-tools转换前端网络为fp32U-model的过程中会自动将batchnorm和bias转换为scale层,并且如果有相邻的scale层会合并为一个。 量化命令调用时不提前使用graph-transform参数进行网络优化直接进行量化的时候也会进行网络优化,比如打开accuracy_opt参数会触发网络优化。
非对称量化
此选项适用于BM1684X芯片。 神经网络中每一层输出的数据分布可能多种多样,对于常见的Conv+Batchnorm组合,其输出在训练过程中往往可以得到相对0值比较对称的分布,此时 使用对称量化可以省去一些层内计算对于数据的零点的处理,减少计算量从而提高性能;对于常见的xxlayer+ReLU的组合,其输出都是正数,则自动采用 了无符号数进行量化,芯片内部实现也有较高效率;如果网络中存在较多的激活层,其数据分布负值范围很小而正值较大,此时采用对称量化则会丢失一定 的精度,采用非对称量化可能充分利用8bit数据的宽度,往往对性能的影响也并不明显,可以尝试非对称量化观察是否对精度有提升。 - 分步量化时候可以在calibration_use_pb的参数中使能asym_threshold: “-asym_threshold=True” - 或者将此参数加入自动量化的try_cali_accuracy_op中: –try_cali_accuracy_opt=”-asym_threshold=True”
FP6混合计算
此选项适用于BM1684X芯片。 BM1684X芯片中一些算子实现可以支持FP16数据类型的计算,相对于FP32性能有成倍的提升,特别是对于卷积和Batchmatmul这样的计算密集型算子,在 使用int8量化精度不能达到要求的时候,设置为浮点推理的混合网络其推理性能往往会有一定程度的下降,在BM1684X芯片中则可以将Convolution/Eltwise/ EltwiseBinary/ReLU/BatchMatmul这几种已经指定为FP32推理的层用FP16进行推理,一定程度上可以提升性能。 使用此参数前提是有以上类型的层已经经过手动修改prototxt或者在量化参数中使用fpfwd_inputs,fpfwd_outputs,fpfwd_bloks等指定了浮点推理, 然后配合fp16_opt参数,如果只想替换其中某种类型的算子,则将类型列为参数,比如: -fp16_opt=”Eltwise,ReLU”,或者 -fp16_opt=”*”,将支持的 类型都使用fp16推理替代fp32。
auto_cali量化优化策略
auto_cali可以自动尝试一些量化优化策略,提升网络量化效果,以下是自动搜索量化的例子:
Caffe框架下的MobileNet SSD自动搜索量化策略
Caffe框架下的MobileNet SSD手工配置量化策略
Caffe框架下的MobileNet SSD自动搜索量化策略
如果在 auto-cali量化 使用中出现量化效果不满足要求的情况,可配置参数postprocess_and_calc_score_class打开精度测试功能 并在阈值计算,混合执行,网络图优化等方法中搜索出最优的量化策略
$ python3 -m ufw.cali.cali_model \ --net_name 'MobileNetSSD' \ --model ./test_models/caffe/MobileNetSSD_deploy.prototxt \ --weight ./test_models/caffe/MobileNetSSD_deploy.caffemodel \ --cali_image_path ./test_models/detect_pic/ \ #使用原始图片, 若使用lmdb数据配置参数:calib_lmdb_path --cali_image_preprocess='resize_h=512,resize_w=512;mean_value=127.5:127.5:127.5, scale=0.007843' \ --input_shapes '[1,3,512,512]' \ --test_iterations 10 \ --postprocess_and_calc_score_class detect_accuracy #该参数支持4类可选项[detect_accuracy、topx_accuracy_for_classify、feature_similarity、None]
Caffe框架下的MobileNet SSD手工配置量化策略
由于自动搜索量化策略较为耗时,可根据后续章节的内容,通过配置参数try_cali_accuracy_opt,在auto_cali中手工调用相应的量化优化策略, 可选量化策略均来自calibration_use_pb模块,可以参考calibration_use_pb --help
$ python3 -m ufw.cali.cali_model \ --net_name 'MobileNetSSD' \ --model ./test_models/caffe/MobileNetSSD_deploy.prototxt \ --weight ./test_models/caffe/MobileNetSSD_deploy.caffemodel \ --cali_image_path ./test_models/detect_pic/ \ #使用原始图片, 若使用lmdb数据配置参数:calib_lmdb_path --cali_image_preprocess='resize_h=512,resize_w=512;mean_value=127.5:127.5:127.5, scale=0.007843' \ --input_shapes '[1,3,512,512]' \ --postprocess_and_calc_score_class detect_accuracy \ --try_cali_accuracy_opt='-per_channel=True,-th_method=ADMM' #直接指定使用-per_channel=True,-th_method=ADMM量化参数进行量化,更多策略可参考calibration_use_pb模块,可以参考calibration_use_pb --help
常见异常
没有正确设置lmdb数据集的路径
出现以上信息,说明没有正确设置lmdb数据集的路径,请按照章节 准备lmdb数据集 的方法设置lmdb数据集的路径。
在 view_demo 中所示可视化工具运行网络时发现数据集不可用的提示,可能是因为jupyter-notebook运行的起始路径不同 或者lmdb在启动Docker时映射的路径不同等原因造成,可以使用绝对路径指定lmdb位置。
有不支持的层
出现以下信息,说明当前正在转换的网络中有Quantization-tools不支持的层,请联系算能技术人员,予以解决。
当前Quantization-tools支持的layer见本章附录 支持的layer 。
整个网络输入为0
出现以上信息,说明某个层的输出最大值为0,有可能是整个网络输入的问题,请检查是否正确配置了网络的输入。也有可能是有些层的计算 比较特殊,比如并没有数据计算或者本来就是零值的常量输出等,可以分情况对待。
量化demo
量化相关示例都存放于github项目https://github.com/sophon-ai-algo/中的examples/calibration目录,请自行前往选择正确的分支下载。包含的示例如下:
examples |--- calibration | `-- examples | |--- classify_demo | |--- create_lmdb_demo | |--- face_demo | |--- object_detection_python_demo | |--- caffemodel_to_fp32umodel_demo | |--- tf_to_fp32umodel_demo | |--- pt_to_fp32umodel_demo | |--- mx_to_fp32umodel_demo | |--- dn_to_fp32umodel_demo | |--- on_to_fp32umodel_demo | |--- pp_to_fp32umodel_demo | |--- auto_cali_demo | |--- yolov5s_demo | |--- view_demo
示例1:classify_demo
该用例将caffe框架下的resnet18网络转换成int8umodel,并测试float32原始网络的精度、测试转换后的int8网络的精度。
转换成int8umodel
$ cd <release dir>/examples/calibration/classify_demo $ source classify_demo.sh $ convert_to_int8_demo
运行完毕,结果如 resnet18转化int8umodel成功结果 所示。
测试原始的float32网络精度
$ test_fp32_demo
运行完毕,结果如 resnet18 fp32umodel精度结果 所示。
测试转换生成的int8网络的精度
$ test_int8_demo
运行完毕,结果如 resnet18 int8umodel精度结果 所示。
示例2:create_lmdb_demo
该用例将jpg图片转换成lmdb数据集,使用示例的代码可以将指定目录下的图片转换后存入lmdb中,用户可以修改此示例代码添加自己的前处理操作。
$ cd <release dir>/examples/calibration/yolov5s_demo/create_lmdb_demo $ bash download_coco128.sh $ python3 convert_imageset.py \ --imageset_rootfolder=./coco128/images/train2017 \ --imageset_lmdbfolder=./lmdb \ --resize_height=640 \ --resize_width=640 \ --shuffle=True \ --bgr2rgb=False \ --gray=False
运行完毕,结果如下所示。
original shape: (323, 481, 3) read image resized dimensions: (640, 640, 3) <class 'numpy.ndarray'> cv_imge after resize (640, 640, 3) save lmdb once /sdk/examples/create_lmdb_demo/images/cat_gray.jpg original shape: (360, 480, 3) read image resized dimensions: (640, 640, 3) <class 'numpy.ndarray'> cv_imge after resize (640, 640, 3) save lmdb once /sdk/examples/create_lmdb_demo/images/cat.jpg original shape: (360, 480, 3) read image resized dimensions: (640, 640, 3) <class 'numpy.ndarray'> cv_imge after resize (640, 640, 3) save lmdb once /sdk/examples/create_lmdb_demo/images/cat gray.jpg original shape: (360, 480, 3) read image resized dimensions: (640, 640, 3) <class 'numpy.ndarray'> cv_imge after resize (640, 640, 3) save lmdb once生成lmdb数据成功
同时,在examples/calibration/yolov5s_demo/create_lmdb_demo/lmdb下会生成data.mdb文件。
示例3:face_demo
该用例将caffe框架下的人脸检测网络squeezenet转换成int8umodel,并测试float32原始网络, int8网络对图片的检测结果。
建立环境
$ cd <release dir>/examples/calibration/face_demo $ source face_demo.sh
用float32网络检测图片
$ detect_squeezenet_fp32
运行完毕,结果如 squeezenet fp32umodel运行成功结果 所示。
同时在examples/calibration/face_demo生成检测之后的图片detection.png,如 squeezenet fp32umodel检测效果: (如在docker内运行,看不到detection.png,请刷新目录)
c)转换成int8umodel
$ convert_squeezenet_to_int8
d)用int8网络检测图片
$ detect_squeezenet_int8
运行完毕,结果如 squeezenet int8umodel检测运行成功输出
同时在examples/calibration/face_demo生成检测之后的图片detection_int8.png,如 squeezenet int8umodel检测效果 所示。
示例4:object_detection_python_demo
该用例以ssd_vgg300为例,描述python接口的使用方法,以方便用fp32umodel或者int8umodel建立框架程序,用于精度测试或者用于应用程序。
用float32网络检测图片
$ cd <release dir>/examples/calibration/object_detection_python_demo $ python3 ssd_vgg300_fp32_test.py
运行完毕,结果如 ssd vgg300 fp32umodel运行成功输出 所示。
同时在examples/calibration/object_detection_python_demo生成检测之后的图片 person_fp32_detected.jpg,如 ssd vgg300 fp32umodel检测效果 所示。
用int8网络检测图片
python3 ssd_vgg300_int8_test.py
运行完毕,结果如 ssd vgg300转化int8umodel成功输出 所示。
同时在examples/calibration/object_detection_python_demo生成检测之后的图片 person_int8_detected.jpg,如 ssd vgg300 int8umodel检测效果 所示。
示例5:caffemodel_to_fp32umodel_demo
该用例程序以resnet50为例,描述如何将caffe框架下的模型文件(*.caffemodel, *prototxt)转换成fp32umodel。
运行命令
$ cd <release dir>/examples/calibration/caffemodel_to_fp32umodel_demo $ python3 resnet50_to_umodel.py
运行结果如 Caffe模型转化fp32umodel成功结果 所示。
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt:
示例6:tf_to_fp32umodel_demo
该用例程序以resnet50_v2为例,描述如何将tensorflow框架下的模型文件(*.pb)转换成 fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/tf_to_fp32umodel_demo $ python3 create_dummy_quant_lmdb.py $ python3 resnet50_v2_to_umodel.py
运行结果如 Tensorflow模型转化fp32umodel成功结果 所示。
在当前文件夹下,生成dummy_lmdb随机量化数据目录,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt:
注意:此例中首先生成了随机量化数据作为转换数据源参数,此数据仅为示例,不能用于后续量化此网络
示例7:pt_to_fp32umodel_demo
该用例程序以yolov5s为例,描述如何将pytorch框架下的模型文件(*.pt)转换成 fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/pt_to_fp32umodel_demo $ python3 yolov5s_to_umodel.py
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt。 更详细的转化流程和细节请参考 pytorch-to-umodel 节内容。
示例8:mx_to_fp32umodel_demo
该用例程序以mobilenet0.25为例,描述如何将mxnet框架下的模型文件(*.json, *.params)转换成 fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/mx_to_fp32umodel_demo $ python3 mobilenet0.25_to_umodel.py
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt。 更详细的转化流程和细节请参考 mxnet-to-umodel 节内容。
示例9:dn_to_fp32umodel_demo
该用例程序以yolov3为例,描述如何将darknet框架下的模型文件(*.cfg, *.weights)转换成 fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/dn_to_fp32umodel_demo $ get_model.sh # download model $ python3 yolov3_to_umodel.py
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt。 更详细的转化流程和细节请参考 darknet-to-umodel 节内容。
示例10:on_to_fp32umodel_demo
该用例程序以postnet为例,描述如何将onnx模型文件(*.onnx)转换成fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/on_to_fp32umodel_demo $ python3 postnet_to_umodel.py
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt。 更详细的转化流程和细节请参考 onnx-to-umodel 节内容。
示例11:pp_to_fp32umodel_demo
该用例程序以PaddleOCR文字识别网络为例,描述如何将PaddlePaddle模型文件(*.pdiparams)转换成fp32umodel。
运行命令:
$ cd <release dir>/examples/calibration/pp_to_fp32umodel_demo $ python3 ppocr_rec_to_umodel.py
在当前文件夹下,新生成compilation文件夹,存放新生成的*.fp32umodel 与*.prototxt。 更详细的转化流程和细节请参考 paddlepaddle-to-umodel 节内容。
示例11:auto_cali_demo
auto-cali是一键式自动量化工具,可以完成整个量化、自动调试及精度测试流程,优先推荐客户使用,它具有如下优势: 1) 一键式完成从原始框架模型到BM168X芯片 bmodel的转换。 2) 方便用户对int8模型的精度进行大批量的验证,形成质量优化提升闭环流程。 3) 可自动进行量化策略搜索,找到满足精度要求的最佳量化策略。 4) 方便用户将BM168X的量化流程整合到自有训练流程。
以下示例使用图片来校准和测试
$ python3 -m ufw.cali.cali_model \ --model='./test_models/pytorch/yolov5s.torchscript.pt' \ #对pytorch模型进行量化 --cali_image_preprocess='resize_h=1280,resize_w=1280;scale=0.0039215' \ #校准和测试的图片预处理都用这个配置 --cali_image_path='./test_models/yolov5_image/' \ --input_shapes='[1,3,1280,1280]' \ --test_iterations 10 \ --net_name yolov5s \ --postprocess_and_calc_score_class feature_similarity #对提取特征进行cos相似度计算的feature_similarity;
以下示例使用lmdb文件来校准和测试,并通过postprocess_and_calc_score_class参数配置不同类型模型的后处理和精度计算
$ python3 -m ufw.cali.cali_model \ --model='./test_models/pytorch/resnet18.pt' \ --cali_lmdb='test_models/imagenet_preprocessed_by_pytorch_100/' \ --input_shapes='[1,3,224,224]' \ --test_iterations 10 \ --net_name resnet18 \ --cali_iterations=20 \ --postprocess_and_calc_score_class topx_accuracy_for_classify #当前支持分类模型的topx_accuracy_for_classify、目标检测模型的detect_accuracy,若设置None,表示不进行任何后处理和精度计算;
以下示例对多输入的paddlepaddle模型进行量化:
$ python3 -m dfn --url https://disk.sophgo.vip/sharing/OzFNMbTvT #若dfn未安装,执行pip3 install dfn安装 $ tar xzvf models.tar.gz $ python3 -m ufw.cali.cali_model \ --net_name 'ppmodel_demo' \ --model ./models/model.pdmodel \ --cali_image_path ./yolov5_image \ --cali_image_preprocess='image_shape|resize_h=640,resize_w=640;scale=0.0039215;\ mean_value=0.485:0.456:0.406,div=0.229:0.224:0.225,bgr2rgb=True|image_scale_factor' \ --input_shapes '[1,2];[1,3,640,640];[1,2]' \ --output_name 'matrix_nms_0.tmp_0,matrix_nms_0.tmp_2' \ --input_descs '[0,fp32,640,640];[2,fp32,1,1]' \ --input_name 'im_shape,image,scale_factor' \ --postprocess_and_calc_score_class feature_similarity \ --feature_compare_layer_list 'use_the_conv_at_the_end' \ #对各输出分支的倒数第1个conv的输出进行cos比较 --test_iterations 5 \ --cali_iterations 10 \ --fp32_layer_list 'conv2d_210.tmp_0' \ #将转换得到的ppmodel_demo_bmpaddle_test_fp32.prototxt文件中层名为model/mish/mul这层设置为fp32计算 --layer_param_list 'conv2d_203.tmp_0:per_channel_flag=True' \ #设置该层的per_channel使能 --convert_bmodel_cmd_opt '--v=4 --enable_profile=True' \ #将该命令内容作为bmentu命令的一部分,更多参数见bmnetu --help
示例12:yolov5s_demo
详细的例子可参考 示例——YOLOv5s量化
示例13:view_demo
详细的例子可参考 view_demo
U-FrameWork python接口
ufw.set_mode_cpu()
功能:设置网络工作在fp32 cpu模式下
输入参数:
Parameter |
Type |
Description |
无 |
ufw.set_mode_cpu_int8()
功能:设置网络工作在int8 cpu模式下
输入参数:
Parameter |
Type |
Description |
无 |
ufw.Net(model, weight)
功能:采用model,weight建立网络
输入参数:
Parameter |
Type |
Description |
model |
string |
表示网络结构的prototxt文件名 |
weight |
string |
表示网络系数的文件名 |
net.fill_blob_data({blob_name: input_data})
功能:
输入参数:
Parameter |
Type |
Description |
input |
dict |
输入blob名字和数据组成的字典 |
net.get_blob_data(blob_name)
功能:
输入参数:
Parameter |
Type |
Description |
blob_name |
string |
欲获取数据的blob的名字 |
net. forward (blobs=None, start=None, end=None, **kwargs)
功能: 进行网络推理,一般参数为空,进行整个网络推理
输入参数:
Parameter |
Type |
Description |
blobs |
string |
网络输出之外希望输出的blob的名字 |
start |
int |
推理开始的层的索引,一般不填 |
end |
int |
推理结束的层的索引,一般不填 |