在将 YOLOv5 模型从 ONNX 转换为模型时遇到“Unsupported slice step!”错误,这通常是因为 当前不支持某些特定的 ONNX 操作或参数配置,尤其是带有非标准切片步长的操作。
解决方案
-
修改模型或代码:
- 尝试修改模型中的切片操作,使其使用 支持的步长(通常是步长为1)。
- 检查 YOLOv5 的代码,特别是数据预处理或网络结构中的切片操作,调整这些操作以兼容 。
-
使用 ONNX Simplifier:
- 尝试使用 ONNX Simplifier 来简化 ONNX 模型,这有时可以去除或替换不兼容的操作。
pip install onnx-simplifier python -m onnxsim your_model.onnx simplified_model.onnx
-
手动调整 Focus模型r:
- 使用 ONNX 图形编辑器(如 Netron)来检查并手动调整不兼容的操作。### 具体步骤
-
安装 ONNX Simplifier 并简化模型:
pip install onnx-simplifier python -m onnxsim yolov5_model.onnx yolov5_model_simplified.onnx
-
转换为 NCNN 模型:
onnx2ncnn yolov5_model_simplified.onnx yolov5_model.param yolov5_model.bin
-
手动调整 Focus模型:
在 models
文件夹下的 common.py
文件中找到并修改 Focus
类,以避免使用不受支持的 slice 步长。原始代码如下:
class Focus(nn.Module):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1):
super(Focus, self).__init__()
self.conv = Conv(c1 * 4, c2, k, 1)
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
将上述代码修改为如下代码:
class Focus(nn.Module):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super(Focus, self).__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
with torch.no_grad():
self.conv1 = nn.Conv2d(c1, c1, (2, 2), groups=c1, bias=False, stride=(2, 2))
self.conv1.weight[:, :, 0, 0] = 1
self.conv1.weight[:, :, 0, 1] = 0
self.conv1.weight[:, :, 1, 0] = 0
self.conv1.weight[:, :, 1, 1] = 0
self.conv2 = nn.Conv2d(c1, c1, (2, 2), groups=c1, bias=False, stride=(2, 2))
self.conv2.weight[:, :, 0, 0] = 0
self.conv2.weight[:, :, 0, 1] = 0
self.conv2.weight[:, :, 1, 0] = 1
self.conv2.weight[:, :, 1, 1] = 0
self.conv3 = nn.Conv2d(c1, c1, (2, 2), groups=c1, bias=False, stride=(2, 2))
self.conv3.weight[:, :, 0, 0] = 0
self.conv3.weight[:, :, 0, 1] = 1
self.conv3.weight[:, :, 1, 0] = 0
self.conv3.weight[:, :, 1, 1] = 0
self.conv4 = nn.Conv2d(c1, c1, (2, 2), groups=c1, bias=False, stride=(2, 2))
self.conv4.weight[:, :, 0, 0] = 0
self.conv4.weight[:, :, 0, 1] = 0
self.conv4.weight[:, :, 1, 0] = 0
self.conv4.weight[:, :, 1, 1] = 1
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat([self.conv1(x), self.conv2(x), self.conv3(x), self.conv4(x)], 1))
这样做可以避免使用不受支持的 slice 操作,使模型更兼容 NCNN。完成上述修改后,重新将模型导出为 ONNX 格式,并再次尝试转换为 NCNN 格式。
实在解决不了可采用 自定义算子:
参考:
此博客