PyTorch导出GoogLeNet为ONNX后推理结果不一致如何解决
问题根因
两端结果不一致核心是预处理、后处理逻辑不对等导致的,和ONNX导出本身关联不大,具体错点如下:
- 图像缩放裁剪逻辑不一致:PyTorch端逻辑是先将图像短边等比例缩放到256像素,再从中心裁剪224×224的区域,不会拉伸图像;ONNX端直接将原图强制resize到224×224,会导致图像变形,输入内容本身就存在偏差。
- 归一化逻辑完全不匹配:PyTorch端
transforms.ToTensor()会先把0-255范围的像素值缩放到0-1区间,再执行(像素值 - 均值)/标准差的归一化,使用的是RGB通道顺序的均值和标准差;你之前观察到的“均值除以256近似”只是数值巧合,ONNX端用的是Caffe风格的预处理,像素值保持0-255范围,只做了减均值操作,完全没有除以标准差的步骤,输入数值差了两个量级,结果必然偏差。 - 通道顺序错误:PyTorch版GoogLeNet训练时输入是RGB通道顺序,ONNX端预处理最后一步把RGB转成了BGR,通道顺序颠倒,输入的颜色信息完全错误。
- 后处理缺失:PyTorch端对模型输出的原始logits做了softmax运算,得到0-1区间的置信度;ONNX端直接拿原始logits排序计算,没有做softmax,置信度数值和PyTorch端没有可比性。
修复方案
第一步:确认ONNX导出环节无问题
导出前确保模型处于eval()模式(你现有代码已经满足要求),如果担心opset兼容性,可以把opset版本升到13以上(10之后的版本对GoogLeNet的算子支持更完善),导出代码不需要做其他大改。
第二步:替换ONNX端预处理逻辑,和PyTorch端严格对齐
把原有preprocess函数替换为以下实现,1:1复刻PyTorch的transforms处理逻辑:
def preprocess(img_path): # 读取图像并转为RGB格式 img = Image.open(img_path).convert('RGB') # 等比例缩放,短边对齐256像素 w, h = img.size if h < w: new_h = 256 new_w = int(256 * w / h) else: new_w = 256 new_h = int(256 * h / w) img = img.resize((new_w, new_h), Image.BILINEAR) # 中心裁剪224x224区域 left = (new_w - 224)/2 top = (new_h - 224)/2 right = left + 224 bottom = top + 224 img = img.crop((left, top, right, bottom)) # 转为numpy数组,将像素值缩放到0-1区间 img = np.array(img).astype(np.float32) / 255.0 # 按PyTorch所用的均值、标准差做归一化,保持RGB通道顺序 mean = np.array([0.485, 0.456, 0.406]).reshape(1,1,3) std = np.array([0.229, 0.224, 0.225]).reshape(1,1,3) img = (img - mean) / std # 转为CHW维度格式,添加batch维度 img = img.transpose(2,0,1) img = np.expand_dims(img, axis=0) return img
第三步:补全后处理逻辑
拿到ONNX模型输出后,先做softmax得到置信度,再取Top5结果,和PyTorch端逻辑完全对齐:
def softmax(x, axis=1): e_x = np.exp(x - np.max(x, axis=axis, keepdims=True)) return e_x / e_x.sum(axis=axis, keepdims=True) def predict(path): img_batch = preprocess(path) outputs = ort_session.run(None, {"input": img_batch.astype(np.float32)}) # 对模型原始输出做softmax得到概率值 probs = softmax(outputs[0], axis=1)[0] # 取置信度最高的5个结果 top5_idx = np.argsort(-probs)[:5] results = {} for i in top5_idx: results[labels[i]] = float(probs[i]) return results
修改完成后两端推理结果的Top5类别和置信度会基本完全一致,仅存在不同框架浮点计算带来的极小数值误差,不会出现结果偏差较大的问题。
内容的提问来源于stack exchange,提问作者Luis Ramon Ramirez Rodriguez
相关产品推荐
相关产品推荐

