【Atlas 200 DK玩转系列】【模型转换】模型转换失败时该怎么做(一)
OMG是Framework的一个模型转换工具,OMG处理流程包含Parse解析->Optimize优化->Quantization量化->Build构建->Fusion融合和获取Task信息这几个步骤。
Parse解析中,Framework对原始网络文件及权重数据进行解析。如果网络本身有不满足Framework处理的要求的地方,会在此阶段打印错误日志。
Optimize优化中,Framework会对整个网络进行不同形式的优化,且当前的优化实际上是会在整个模型转换过程多个阶段的中进行,包括Scope融合,Pattern融合,节点删除等等。此阶段较少出现终止转换的报错,可能会出现一些不影响模型转换的ERROR,例如Pattern融合失败。
量化是模型转换中的可选流程,仅在转换命令中携带了量化配置才会进行量化。量化的过程是使用校准集作为输入,在host上进行量化推理,并根据结果计算量化参数,最终保存到模型中。量化过程基本与其他流程独立,所支持的算子也只是整个D平台支持算子的子集。
Build阶段是模型转换出错较多的阶段。此阶段将已经优化、量化完成的模型,按照模型拓扑结构,逐个算子进行build,完成om模型中的算子构建。此过程将根据算子输入shape和算子参数,计算算子输出shape并进行权重数据转换。此阶段常见问题是shape信息与Davinci要求的不匹配,或者算子参数组合不支持。
Fusion融合和获取Task信息阶段将build完成的算子进行底层优化融合,然后进行一次“假推理”,获得算子推理task信息。此阶段出错,主要还是底层校验算子报错,不满足其推理的要求。需要结合算子实际情况,根据整个模型转换的处理过程,分析出错原因。
Serialize阶段,将om算子,task信息等全部序列化保存为om模型文件,几乎不会报错。
当前Framework与具体的算子和网络存在一定耦合性,定位问题需要先明确Framework在业务流程各个阶段的动作和目标,然后结合具体问题场景进行分析!
当然在模型转换时,必须知道如下约束(在昇腾社区网站资料中也有):
只支持原始框架类型为Caffe和TensorFlow的模型转换,当原始框架类型为Caffe时,输入数据类型为float32;当原始框架类型为TensorFlow时,输入数据类型为int32、bool、uint8、float32。
当原始框架类型为Caffe时,模型文件(.prototxt)和权重文件(.caffemodel)的op name、op type必须保持名称一致(包括大小写)。
当原始框架类型为Caffe时,除了top与bottom相同的layer以外(例如BatchNorm,Scale,ReLU等),其他layer的top名称需要与其name名称保持一致。
当原始框架类型为TensorFlow时,只支持FrozenGraphDef格式。
不支持动态shape的输入,例如:NHWC输入为[?,?,?,3]多个维度可任意指定数值。模型转换时需指定固定数值。
输入数据最大支持四维,转维算子(reshape、expanddim等)不能输出五维。
模型中的所有层算子除const算子外,输入和输出需要满足dim!=0。
模型转换不支持含有训练算子的模型。
量化(uint8)后的模型不支持模型转换。
模型中的算子只支持2D卷积,暂不支持3D卷积。
只支持《算子规格说明Ascend 310 算子规格说明Atlas 200 AI加速模块 1.0.2 算子清单 (型号 3000)Atlas 300 AI加速卡 1.0.2 算子清单(型号 3000, 3010)Atlas 500 智能小站 1.0.2
算子清单(型号 3000, 3010)》中的算子算子规格说明中的算子, 并需满足算子限制条件。
那么接下来,我们随机给出一些案例,来实际看下该如何处理;
案例一:caffe模型转换失败,报错信息如下:
[ERROR] FMK:2019-06-21-06:05:57.729.503 GetOutputDesc:framework/domi/omg/../omg/model/op_builder/concat_op_builder.cpp:181:"all input must have the same dim value except concat_axis,out_desc.dim(2):31,input_desc(1).dim(2):32 Error Code:0xFFFFFFFF()"
[ERROR] FMK:2019-06-21-06:05:57.729.522 Build:framework/domi/omg/../omg/model/op_builder/op_builder.cpp:41:""Get output descriptors" failed. Node: concat1."
[ERROR] FMK:2019-06-21-06:05:57.729.536 SetInputOutputDesc:framework/domi/omg/../omg/model/model_builder.cpp:594:"Op build failed. Node: concat1."
[ERROR] FMK:2019-06-21-06:05:57.729.555 Build:framework/domi/omg/../omg/model/model_builder.cpp:2868:"SetInputOutputDesc Failed!"
[ERROR] FMK:2019-06-21-06:05:57.729.568 Generate:framework/domi/omg/omg.cpp:800:"OMG builder Build() return fail."
[ERROR] FMK:2019-06-21-06:05:57.732.193 main:framework/domi/omg_main/main.cpp:815:"OMG Generate execute failed!!"
分析:
从上面的日志中明显可以看出,在Build阶段报错,我们知道此阶段将已经优化、量化完成的模型,按照模型拓扑结构,逐个算子进行build,完成om模型中的算子构建。此过程将根据算子输入shape和算子参数,计算算子输出shape并进行权重数据转换。此阶段常见问题是shape信息与Davinci要求的不匹配,或者算子参数组合不支持。所以着重看该阶段的输入shape是否ok?
从上面的出错信息可以看出,是因为网络中的某一层的输入维度不对导致无法进行计算,又由于报错文件是concat_op_builder.cpp,可推断是concat计算时的两个输入维度不匹配导致转换失败。
此网络的第一个输入数据的维度是31, 第二个数据维度的输入时32,那么需要从日志中分析是从网络中的哪一层开始不匹配的。
步骤1 将模型文件****.prototxt用Netron打开来分析。
最后一层concat的输入是一个卷积操作的输出和一个pooling的输出。
步骤2 查看模型转换日志,从后往前进行分析。
concat层的输入是【1,24,31,31】和【1,512,32,32】,显然无法进行计算。
然后继续往前查找,如下图所示,发现在左边分支最后一个pooling层的输入是【1,512,32,32】,经过计算后输出变成了【1,512,31,31】,是在该层导致了维度的变化(后面的几层卷积操作维度都没有发生变化)。
接下来需要查看pooling层是否有错误。
步骤3 查看prototxt文件,stride为1代表步长为1,两次MAX操作之间的数据存在重叠,输出数据维度少1,所以怀疑模型文件多了这一层pooling或者是右边分支少了这一层pooling。
步骤4 根据模型文件的确认结果将左侧pooling层删除,或者在右侧增加pooling层,也可以重新在caffe下训练并给出正确的模型文件再进行模型转换。
----结束
ok,在下一个博客,我们继续讨论更多案例。
- 点赞
- 收藏
- 关注作者
评论(0)