最近在把训练好的一个图像分类模型(ResNet50)转成ONNX,部署到移动端用。按照文档设了dynamic_axes={‘input’: {0: ‘batch_size’}},导出也成功了。但用onnxruntime推理时,只要batch_size不是1就报错,说“输入形状不匹配”?试了opset版本11和12都一样。是不是导出时少设了什么参数,比如输入尺寸的dynamic_axes必须和模型内部结构对应?还是说模型里有不支持动态batch的层(比如BatchNorm)?求有经验的大佬指点一下,我实在不想把batch固定为1。
PyTorch模型转ONNX时,动态轴设了但推理报错,有老哥踩过坑吗?
全部回复
共 165 条我之前也遇到过类似的问题,后来发现是模型里有些自定义层或者reshape操作在导出时没显式把动态维度传进去,建议检查一下onnx图里输入输出的shape是不是真的动态的。另外BatchNorm在推理时是不依赖batch size的,应该不是它的问题,可能跟中间某个全连接层或flatten操作有关,试试在导出前把模型设成eval模式。
遇到过类似问题,大概率不是BatchNorm的锅,而是模型里有些reshape或view操作在动态batch下没处理好,ONNX导出时会把那个维度固定成常量。你可以试试把输入张量先搞成动态shape再导出,或者在导出前用torch.onnx.export时加上input_names和output_names,再显式指定一下dynamic_axes里面的每个维度。另外检查下模型里有没有用torch.squeeze或者flatten这种隐含固定维度的操作,改写成-1索引能绕过去。
这个问题我之前也遇到过,大概率不是dynamic_axes没设对,而是模型里某些算子本身就不支持动态形状。像ResNet里的View或Reshape操作,如果写死了形状,导出时就会把动态轴给固定住。建议你导出时用onnxruntime的shape_inference检查一下,或者把input的shape设成(None, 3, 224, 224)再试,有些opset版本对动态batch支持确实不够好。另外BatchNorm在推理模式下是没问题的,不用太担心。
我之前也遇到过类似问题,最后发现是模型里有个reshape操作把batch维度写死了,动态轴设了但实际推理时形状被硬编码了。你检查下ResNet50里有没有自定义的view或者reshape,ONNX对这类操作的动态支持不太友好。另外BatchNorm本身不影响动态batch,但得确认导出时是不是把训练模式和推理模式搞混了。
遇到过类似问题,检查下模型里有没有reshape或flatten操作,动态batch时这些层容易出形状不匹配。
这个问题我遇到过,很可能是模型里某些算子真的不支持动态batch,比如reshape或者view操作在运行时绑死了具体维度。你试试用onnxruntime的inference_session.run时把输入形状显式写对,或者导出后先netron看一眼onnx的输入形状是不是真的成动态了。另外BatchNorm本身不影响动态batch,但建议你检查下模型里有没有用torch.flatten或者view时写死了batch维度的代码。
我之前也踩过这个坑,光是设dynamic_axes不够,还得检查一下模型里有没有像reshape或view这种硬编码了固定batch_size的操作,ONNX导出时不会自动帮你变。另外BatchNorm本身是支持动态batch的,问题大概率出在其他层,建议用onnxruntime的shape_inference跑一下看看中间节点的shape变化。还有个笨办法,导出时把batch_size设成动态维度的同时,把输入样本的shape写个可变范围试试。
这个问题我遇到过两次,核心原因通常是模型里某个算子对动态batch的支持不完整。你可以检查下有没有用torch.nn.Upsample或者插值层,这类操作在ONNX里有时会把batch维度写死。另外导出的onnx文件用netron打开看看,确认下所有节点的输入输出shape是不是都标记成了动态。还有个土办法,把opset升到13以上试试,有时候低版本对动态轴的兼容性确实差点。
这个坑我当初也踩过,动态轴设完只是第一步,问题很可能出在模型内部有reshape或view操作,它们会对输入shape做硬编码,导致动态batch传进去就崩了。你可以用onnx-simplifier跑一遍,或者手动检查下导出后的onnx图里有没有Flatten这类固定维度的节点。另外BatchNorm在推理模式下其实不影响动态batch,问题大概率不在它身上。
试试把onnxruntime的session选项里加入optimization_level=0,可能是图优化把动态轴给写死了。
我之前也遇到过类似问题,后来发现是模型里有个reshape操作写死了shape,动态轴传进去后它没跟着变。你可以导出后用onnxsim或netron看一眼图结构,重点关注reshape、flatten这些层,很可能就是它们把batch维度写死了。另外BatchNorm本身是支持动态batch的,问题大概率不在它身上。
检查下onnxruntime的session配置,动态轴导出后推理时输入shape要显式指定,别用默认值。
我也遇到过类似问题,折腾了半天发现是ResNet里的BatchNorm在作怪,这层在推理时虽然不依赖batch维度但对形状检查很严格。建议你导出时把opset版本调到13或更高,有些老版本对动态轴支持不完整。另外可以试试用onnx-simplifier简化一下模型,有时候能自动修复形状不匹配。如果还不行,手动在torch.onnx.export里加上input_names和output_names,并确保所有中间层都显式声明了动态轴。
这坑我也踩过,动态轴设置本身没错,但ResNet里的BatchNorm在推理时确实会固定住运行均值和方差,不过这不影响动态batch,问题更可能出在onnxruntime的session配置上——它默认会做输入shape的静态优化,你导出时虽然设了动态轴,但导出的onnx文件里可能还残留了某个具体shape的约束,可以试试用onnx-simplifier清理一下,或者导出时显式指定一下输入的具体shape(比如1,3,224,224)再动态化。另外检查下onnxruntime的版本,有些旧版对动态batch支持有bug,升级到1.15以上能解决不少。还有个冷门点:如果模型里用了view或reshape操作,并且维度参数写死了数字而不是-1,那动态batch传进来就会崩,得手动改onn图或者重写导出逻辑。实在不行就固定batch为1吧,移动端推理其实单张图效率更高,批处理反而容易爆内存。
这种情况我也遇到过,问题大概率不在dynamic_axes设置上,而是模型里某些算子对动态batch支持不完善,比如reshape或view操作会硬编码形状。你可以用onnx-simplifier简化一下模型,或者检查下导出时有没有把batch维度写死到某些层里。另外,试试把opset版本调到13或更高,有些动态shape的bug在新版本里修复了。
遇到过类似问题,动态轴设了但导出的onnx里可能某些算子还是把batch维度写死了,比如reshape或者flatten操作。建议导出后用netron看一下图,确认所有节点输入输出的shape里batch位置是不是都是动态的。另外BatchNorm本身不影响动态batch,但某些自定义层或者onnx不支持的操作会强制固定形状。可以试试把opset升到13以上,或者导出时加上dynamic_axes里每个输出轴的定义。
这个问题我也遇到过,当时卡了好久。你试试在导出时把输入张量的形状设成动态维度,比如torch.onnx.export时加上input_names和output_names,并且检查下模型里有没有reshape或view操作依赖了静态batch size。另外BatchNorm层其实不影响动态batch,但如果你用了torchvision的预训练模型,它内部可能有些硬编码的形状检查。建议先用onnx-simplifier简化一下模型,再检查下onnx图里有没有固定shape的节点。
BatchNorm层确实不影响动态batch,问题大概率出在reshape或view这些操作上,它们会写死形状信息。你可以用onnx-simplifier过一遍模型,或者导出时加个dynamic_axes={‘output’: {0: ‘batch_size’}}试试,有时候输出也得一起设。另外检查下模型里有没有用flatten,那个在动态batch下容易翻车。
检查下模型里有没有reshape或view操作硬编码了形状,ONNX导出时这些层容易把batch维度锁死。
这坑我也踩过,动态batch设了但ONNX导出时如果模型里用了Flatten或Reshape这类依赖固定形状的操作,推理就会报形状不匹配。你可以先查一下模型里有没有这些层,或者试试在torch.onnx.export里加上dynamic_axes的同时,把输入样例的batch_size设成你需要的最大值,比如1和4都试一遍。另外BatchNorm本身不限制batch,但某些算子的实现可能有隐含的固定维度要求,建议用onnx-simplifier简化一下图结构看看。