最近在把训练好的一个图像分类模型(ResNet50)转成ONNX,部署到移动端用。按照文档设了dynamic_axes={‘input’: {0: ‘batch_size’}},导出也成功了。但用onnxruntime推理时,只要batch_size不是1就报错,说“输入形状不匹配”?试了opset版本11和12都一样。是不是导出时少设了什么参数,比如输入尺寸的dynamic_axes必须和模型内部结构对应?还是说模型里有不支持动态batch的层(比如BatchNorm)?求有经验的大佬指点一下,我实在不想把batch固定为1。
PyTorch模型转ONNX时,动态轴设了但推理报错,有老哥踩过坑吗?
全部回复
共 177 条固定batch为1跑通了没?先确认下onnxruntime输入shape是不是带动态维度,之前我也被这坑过。
你这情况我也遇到过,光设input的动态轴确实不够。onnxruntime推理时如果模型内部某些算子的shape推导还是绑死在导出时的尺寸上,换batch就会炸。建议检查下导出时有没有同时给output也设dynamic_axes,另外用onnxsim跑一遍再试试,有时候是图里残留了硬编码的shape常量。BN层本身是支持动态batch的,问题多半出在reshape或view这类操作上。
BatchNorm本身是支持动态batch的,问题多半出在导出时只设了input的dynamic_axes,输出那边没同步。你试试把output的dynamic_axes也加上,比如{'output': {0: 'batch_size'}},不然推理时输出形状对不上也会报错。另外用onnxruntime跑的时候,喂进去的输入得是numpy数组,shape要跟动态轴声明一致,别传了个固定batch的tensor。我之前也卡在这,补上输出动态轴就通了,你可以先拿batch=2试一下。
检查下输出层是不是也写死了batch,光设输入不够,输出动态轴也得加上。
BatchNorm其实支持动态batch,问题大概率不在这儿。你导出的时候有没有把模型设成eval模式?train模式下BN会按当前batch统计,动态轴就容易出幺蛾子。另外onnxruntime报错信息具体是啥,可以说下,一般会提示哪个节点shape对不上。我之前也遇到过类似情况,最后发现是某个reshape写死了维度,不一定是输入那边的问题。
有没有更详细的教程推荐?
我上次也遇到类似情况,导出时dynamic_axes只写了input,结果中间某个reshape或者view把batch维度写死了。你检查下模型里有没有硬编码的batch操作,比如x.view(1, -1)这种。另外onnxruntime推理时最好打印一下实际输入的shape,看看跟模型期望的差在哪。BatchNorm其实支持动态batch,问题多半出在导出时的算子映射上。
BN上动态batch一般没问题,我之前也遇到过类似情况,最后发现是导出时只给了输入动态轴,中间某些reshape或view把batch维度写死了。你可以用onnxruntime的报错日志定位具体是哪个节点形状对不上,或者把模型先跑一遍带随机batch的trace确认。另外opset 11以上对动态支持确实好一些,但还得看导出时有没有把输入尺寸也设成dynamic。
之前也遇到过类似的,导出时dynamic_axes只写了input,没写output,结果onnxruntime直接按固定shape去校验了。你把output的batch维也加上试试,另外确认下模型里有没有reshape或者view硬编码了batch维度,那种层导出后动态轴会失效。还有个坑是onnxruntime版本,1.7之前对动态batch支持挺烂的,升级下再跑跑看。
我之前也遇到过,大概率不是BatchNorm的锅,那玩意对动态batch支持挺好的。你检查下导出时是不是只给input设了动态轴,模型输出那个dynamic_axes也得一起加上,不然输出还是被写死成固定batch。还有种可能是你实际推理时喂进去的shape跟模型expect的对不上,比如H/W被写死了,光改batch没用。建议用onnxruntime的get_inputs()看下真实期望形状,一查就清楚了。
输出也得设dynamic_axes啊,光设输入没用,onnxruntime会按导出时的输出形状校验。
BNS 层本身是支持动态 batch 的,问题大概率不在那儿。你检查一下导出时是不是只给 input 设了 dynamic_axes,output 没设?ONNX Runtime 对输出形状也会校验,输出轴没标 dynamic 的话 batch 一变就炸。另外用 onnxruntime 跑之前可以先用 onnx.checker 和 netron 看一眼输入输出维度到底是不是真的动态,有时候导出成功了但 shape 还是被写死了。
这个坑我去年也踩过,折腾了大半天才找到原因。你dynamic_axes只设了input的batch维度,但输出那边没设,onnxruntime在某些opset下会拿导出时trace到的输出shape去校验,batch一变大就对不上了。建议把output也加上{0: 'batch_size'}试试,很多时候就是这里漏了。另外还得确认你导出时喂进去的dummy input是不是真的按动态方式走的,有人图省事用固定batch去trace,导出来表面有dynamic_axes,实际图里shape还是写死的。BatchNorm本身是支持动态batch的,这个不用担心,除非你模型里有什么reshape或者view用了硬编码的batch维,那种才是真麻烦。还有个容易忽略的点,如果模型里有自适应池化或者跟输入尺寸绑定的操作,最好拿不同batch和分辨率各跑一遍onnxruntime验证下,别只看导出成功就以为没问题。实在不行可以用onnxsim先过一遍,再配合netron看下输入输出的shape标注对不对。
有没有更详细的教程推荐?
这个思路不错,收藏了。
有没有更详细的教程推荐?
我之前也遇到过类似问题,后来换了方案。