2023年11月29日发(作者:)

opencvpytorch-onnx-opencv模型推理

opencv的DNN推理模块是不直接⽀持pytorch训练出来的pth⽂件。⼀般来说,可以将pth⽂件转成onnx格式,再⽤opencv调⽤onnx⽂

件,即可实现推理。

pth⽂件转onnx⽂件时,因为onnx对于pth中某些定义的层是不⽀持的,难免会碰到⼀些问题。近期,对⼀些分割⽹络进⾏了部署,碰到的

⼀些问题记录在下。

RuntimeError: ONNX export failed: Couldn’t export operator aten::adaptive_avg_pool2d

onnx不⽀持pytorch中的veAvgPool2d(),需要改成普通的l2d()。修改之后不会对⽹络精度造成很⼤的影响。

据了解,veAvgPool2d()的kernel⼤⼩是⾃适应变化的,stride也是⾃适应的,转成普通的l2d就要⾃⼰计算

kernel⼤⼩和stride,计算公式如下:

stride = floor ( (input_size / (output_size) )

kernel_size = input_size − (output_size−1) * stride

RuntimeError: Failed to export an ONNX attribute, since it’s not constant, please try to make things (e.g., kernel size)

static if possible

说明pytorch模型中有些层的参数是变量,onnx识别不了,需要改成常量。

def pool(self, x, size):

th, tw = size, size

xh, xw = x.size()[2:]

stride_h = xh // th

stride_w = xw // tw

kernel_h = xh - (th - 1) * stride_h

kernel_w = xw - (tw - 1) * stride_w

avgpool = nn.AvgPool2d((kernel_h, kernel_w), stride=(stride_h, stride_w))

# avgpool = veAvgPool2d(size)

return avgpool(x)

通过调试发现,我的池化层kernel_h、kernel_w是变

xxxxxxxxxx/python3.6/site-packages/torch/onnx/symbolic_

量,onnx不认可。因此,将其改成固定的阿拉伯数字。

RuntimeError: ONNX export failed: Couldn’t export operator aten::upsample_bilinear2d

onnx不⽀持aten::upsample_bilinear2d。

解决办法:

1. pytorch版本升级⾄1.3+,转onnx的时候设置opset_version=11

torch_out = torch.onnx._export(net, inputs, output_onnx, export_params=True, verbose=True,

input_names=input_names, output_names=output_names, opset_version=11)

2.如果第⼀种不⾏,就修改上采样层的模式为,不过这样会对模型的效果打⼀些折扣。

nearest

x = F.interpolate(x, size, mode='bilinear', align_corners=True)

# model=‘nearest’

修改为

x = F.interpolate(x, size, mode='nearest')

opencv读取onnx失败

net = cv2.dnn.readNetFromONNX('./fastscnn_')

上述代码读取onnx⽂件,出现以下报错

: OpenCV(4.4.0) /tmp/pip-req-build-qacpj5ci/opencv/modules/dnn/src/onnx/onnx_:1410: error: (-2:Unspecified error) in function '

void cv::dnn::dnn4_v20200609::ONNXImporter::populateNet(cv::dnn::dnn4_v20200609::Net)'

> (expected: '() == CV_32S'), where

> '()' is 5 (CV_32FC1)

> must be equal to

> 'CV_32S' is 4 (CV_32SC1)

暂不知道是什么原因造成的,据说是Upsampling层造成的;将opencv版本升级⾄4.5+,bug消失。

Can’t create layer “122” of type “ReduceL2” in function 'getLayerInstance’

例如我的⽹络中其中有⼀层是对张量进⾏归⼀化:

dn = torch.norm(desc, p=2, dim=1) # dim=1 [1, 256, 30, 60]-->[1, 30, 60]

维计算⼆范数

desc = desc.div(torch.unsqueeze(dn, 1))

转成onnx之后⽤opencv进⾏推理,出现对ReduceL2未识别的错误;对层进⾏修改,如下即可:

dn = torch.norm(desc, p=2, dim=1, keepdim=True) #dim=1 [1, 256, 30, 60]-->[1, 1, 30, 60]

维计算⼆范数

desc = desc.div(dn) # Divide by norm to normalize. [1, 256, 30, 60]