基于MindStudio的Tensorflow 模型命令行推理一键式精度比对
---以AIPaint为例
对应的视频教程链接:基于MindStudio的Tensorflow模型命令行推理一键式精度比对_哔哩哔哩_bilibili
目录
大家好,模型转换是在推理时常见的一种需求,如在Ascend 310上部署应用需要[1] 使用om模型,然而我们通常使用MindSpore 、Tensorflow 或 Pytorch所开发的模型都不是om模型,从而需要对不同的格式进行转换或者称为翻译。模型文件通常包含两部分构成:1. 模型的图信息(包含节点和边);2. 模型的参数信息(如卷积层kernel的weight)。不同的文件格式代表了其对图信息和参数信息的描述不同,同一个卷积在tensorflow模型格式 pb 和 Pytorch格式的pt中描述不同。
模型转化就是针对不同的格式(或者称为图描述,参数描述)做对应目标的转换。然后这种转换通常会对原始模型做一定程度的优化,如消除一些没用到的图节点,合并算子以及降低数据精度(将fp32转为fp16)。 这种操作可能会使得转换后的模型(om模型)精度不如原始模型(pb模型)。这时候为了找到因为算子转换导致的精度差异,通常会将原始模型(pb模型)和转换后模型(om模型)的全图运算信息获取下来(称为dump过程),进行逐算子对比,从而找到差异.
然而获取全图逐算子运算结果是非常复杂的过程.为此本文会向大家介绍一键精度比对工具,以及如何使用MindStudio实现精度的比对。MindStudio 本文主体由基础知识介绍,环境准备,具体实验和总结四部分组成。实验部分是以官方例子AIPaint做基础演示。最后本文是本文档的总结,以及根据笔者的开发经验,总结出一些tips,希望能帮助到各位开发者。在本文中,tools库中的msquickcmp将用来一键生成对比数据,MindStudio将用于精度对比.
提醒:如果对基础知识以及有了较多的了解或者想尽快浏览实验部分的,可以直接跳过第一部分--前置知识和第二部分—环境准备,直接到第三部分的实验和第四部分的总结。
模型推理与模型保存格式
推理首先需要固定模型,一般是由训练好的模型前向传播图固定成框架对应的格式,其中与训练不同的是除了个别算子的值(如dropout和bathnorm之类的归一化算子)会发生改变,其他与训练时没有差别. 如tensorflow框架下开发的模型,通常需要保存为pb模式, pytorch框架开发的模型通常会保存为pt格式.除了框架相关的格式外,还有统一的格式:onnx(开放神经网络交换,Open Neural Network Exchange ). 保存的文件一般包含:模型的算子图信息和参数信息, 常见的模型包括om模型都可以使用MindStudio的model visualize 模块或者netron打开查看图结构. 这里需要说明一点, 单纯使用torch.save(“model.pt”,model)保存的模型只有参数信息,并不具有算子网络图信息,只有torch脚本定义的高级图信息(图节点为自定义的module name).通过torch.jit.trace()模拟输入dummy_input,调用traced.save()存储成的pt模型才具有算子级网络图信息.如果需要转为om模型,通常会先将pt转为onnx然后转为om.
模型转换(从pb转为om)与图优化
从原始格式模型转换到目标格式模型,过程涉及到算子和图的格式转换. 在华为Atals 服务器(搭载Ascend 910或者Ascend 310芯片)上,模型加速推理的运行时(CANN Compute Architecture for Neural Networks) 依赖om格式的模型。这里的加速推理指的是使用AICore进行推理.
模型转换可以采用算子级别一对一转换,即只针对模型的算子格式做转换,并不更改更多的内容.模型的值运算通常需要在特定的设备(加速卡等)上做矩阵运算,而模型的赋值操作通常涉及到cpu操作,数据在两种设备之间频繁传递. 为了减少这样的传递, 通常会在原始网络模型基础上做进一步优化. 优化主要包括两个部分: 网络图优化和精度优化. 图优化主要包括:节点级优化(消除没有使用的算子或者全等算子,如 dropout在推理时可以直接去掉), 块级优化(包括常数折叠,算子合并等). 这里我们呈现两个例子:
上图右边是pb模型,左边是对应的om模型,如图所示,出现了多个算子合并,如卷积算子合并,将两个算子合并为一个算子,还有后面的多个算子也是合并为单个算子。这样对于算子的描述就会发生改变,下图是om模型中,一个add算子的描述:
attributes表示该算子其实是一个合并算子(fused op),是将add和relu合在一起的算子。
通常这种优化不会对精度产生任何影响,任何一个优化操作原则上不会对计算结果造成偏差,但是会在一定程度上减少数据的搬运和计算的次数. 然而精度优化例外. 精度的优化通常指的是 将fp32的权重值改为fp16的值,从而加速运算. 由于fp32的权重值改为fp16, 部分运算可能会出现精度丢失.一般情况下, fp32的运算改为fp16去算,对结果不会造成太大的影响, 但由于神经网络是由大量的矩阵运算组成,因此很难确保过程中是否会导致较大的值偏移.另外还有一种模型参数精度的优化:将fp32的模型转为int8的模型,从而大大减小模型的参数空间.这一种优化称为模型量化,是另外一个分支.
还有涉及到后端(特定设备)的优化, 如算子调度优化, 内存优化等. 但是这些只影响算子的运行效率,不影响精度. 感兴趣的小伙伴可以参考 The Deep Learning Compiler: A Comprehensive Survey.
华为模型转换工具
将pb, onnx模型转为om模型需要使用到 ATC工具(Ascend Tensor Compiler).该工具集成在 CANN包中, 将开源框架(如 Caffe、TensorFlow、ONNX)和单算子 json 文件的网络模型转换为 Ascend AI Processors 支持的离线模型。在模型转换过程中,可以实现算子调度优化、权重数据重排、内存优化,不依赖设备完成模型预处理。
这里需要说明的是 ATC包含了模型编译的前端和后端。前端指的是将原始格式模型转为高级IR,后端指的是对于设备的代码模型优化,如调度优化和显存优化,从而得到更高的性能。对于后端的调优可以采用auto tune工具。
这里需要说明的是 ATC包含了模型编译的前端和后端。前端指的是将原始格式模型转为高级IR,后端指的是对于设备的代码模型优化,如调度优化和显存优化,从而得到更高的性能。对于后端的调优可以采用auto tune工具。
精度损失与精度比对工具
Om模型推理与pb模型推理的主要精度差异来自俩方面:1. 输入不同导致的精度不同(常见原因有预处理没有对齐),2. 算子精度下降或者算子运算出错。对于第一种精度差异,可以通过对齐预处理来解决。方式是将预处理后的结果直接保存为bin文件,然后pb和om用相同的bin文件作为输入进行推理。注意om模型的输入通常都是32位的,如果保存格式为fp64或者fp16,会导致异常。这里记录一个笔者遇到的问题:transfering gan模型需要输入一个random.normal 的值,np.random.normal得到的是float64类型,如果以此保存为bin文件会导致结果差异较大。
而算子精度下降,需要对比算子的输入输出值,通常需要采集两侧的算子运算过程值。这里采集pb模型推理过程中的算子输入输出可以使用tensorflow.python debug模块,开启debug模型,通过dump得到tensor的信息。Om模型的算子运行结果可以在msame运行时开启dump选项。算子的输入输出值通常都是高维数据,通常采用欧式距离(如l1 距离,l2距离)和相似度(cosine similarity)。 现有的集成在CANN包中的精度对比差异计算方式支持如下算法:
- 0:CosineSimilarity,表示余弦相似度算法。
- 1:MaxAbsoluteError,表示最大绝对误差算法。
- 2:AccumulatedRelativeError,表示累积相对误差算法。
- 3