文章目录
由于有些操作是没法支持的
如5维的操作:
Unsupported slice axes !
Unsupported slice axes !
Unsupported slice axes !
Unsupported slice axes !
Unsupported slice axes !
Unsupported slice axes !
参考:
解决方案1
修改模型Detect层设计
这可能是由于ncnn会把一个5维张量捏成4维(假设batch=1),但是YOLO5Face的坐标反算逻辑基本上是在5维上做slice,所以导致了NCNN在转换这段反算逻辑时出现了slice错误。那么怎么解决这个问题呢?那就是不使用5维张量,把Detect中关于坐标反算的那段拿到C++中做实现。如果你理解了Detect的细节,以及张量在内存中的分布,这个实现其实不难做。首先,我们来看看,在YOLO5Face中这个代码怎么改。
# x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() 原来的处理
x[i] = x[i].view(bs, 3, 16, -1).permute(0, 1, 3, 2).contiguous() # e.g (b,3,20x20,16) for NCNN
# ... 注释掉坐标反算的逻辑
# return torch.cat(z, 1) # (bs,?,16) 原来的返回
return x # 修改后的返回 for NCNN
其实就是不展开最后(ny,no)这两个维度,把这2个维度flatten成一个维度。由于后续的处理都是基于5维的张量,所以,坐标反算那段逻辑也要注释掉,直接返回这个修改后的4维张量,把坐标反算这部分放在C++里面实现。为了顺利export出ONNX文件,还需要对应地修改export.py,因为现在输出是一个list了,里面有3个维度不一样的张量,而原来是被torch.cat在一起,只有一个张量。
# torch.onnx.export(model, img, f, verbose=False, opset_version=12,
# input_names=input_names,
# output_names=output_names,
# dynamic_axes={'input': {0: 'batch'},
# 'output': {0: 'batch'}
# } if opt.dynamic else None)
torch.onnx.export(model, img, f,
verbose=False,
opset_version=12,
input_names=['input'],
output_names=["det_stride_8", "det_stride_16", "det_stride_32"],
) # for ncnn
转换
python export.py --weights weights/yolov5n-face.pt --img_size 640 640 --batch_size 1
python -m onnxsim weights/best.onnx weights/plate-sim.onnx
~ ncnn_models onnx2ncnn yolov5n-face-640x640-for-ncnn.onnx yolov5n-face-640x640.param yolov5n-face-640x640.bin
~ ncnnoptimize yolov5n-face-640x640.param yolov5n-face-640x640.bin yolov5n-face-640x640.opt.param yolov5n-face-640x640.opt.bin 0
Input layer input without shape info, shape_inference skipped
Input layer input without shape info, estimate_memory_footprint skipped
后处理
再根据需要实现nms等
优质文章
https://www.zhihu.com/question/62871439/answer/2285654278?utm_id=0