拣约 2025-11-21 10:59 采纳率: 33.3%
浏览 5

yolo模型转ncnn

Yolo u版 Ncnn 转换缺少 permute 层

Yolo版本 v5_6.0

onnx2ncnn

通过ncnn这个官方工具尝试转换 这个yolo模型它会出现错误:

Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !

我看nihui da佬说是focus 模块报的错,需要调整这一层,da佬通过 netron 查看focus 层,但是我的focus 层和他的完全不一样,也没法调整,这是我的param:

img

虽然这样看着挺正常的,但是打开 结构文件自己看的话,感觉就是乱的:

img

虽然这个有三个permute ,但是这三个permute 感觉是乱的,然后这个方式我放弃了。

Pnnx

然后nihui da佬新的文章种说,yolo模型 u 版可以使用 pnnx 工具进行转换,然后我按照nihui da佬的文章 pt - torchscript - ncnn 尝试进行了转换。da佬输出的模型结构有3个 permute,我怎么导出都只有一个输出,然后我想看看是不是我自己的模型有问题,我下载了官方预训练的yolov6 模型,导出成yolov5nu.torchscript,格式的模型,再通过pnnx转换导出ncnn,然后打开它的结构文件,依然只有一个permute 层,我看晚上基本都是三个permute 的后处理,一个permute 层的后处理,我尝试编写了c++,但是不行。

这是通过pnnx转出的模型结构:

img

img

我这个模型转换onnx后,通过 onnxruntime可以正常推理的

为什么U版的Yolov5n 通过pnnx导出之后只有一个permute 层,网上能搜到教程的都是三个 permute 层,有da佬能指导一下吗?

如果它输出一个permute 层是正常的话,那么一个 permute 该如何推理呢?

  • 写回答

3条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-11-21 17:27
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案能帮助您,请采纳,非常感谢!
    .
    每日一句正能量,让它带给您好心情:给自己多一点鼓励,少一点否定,你会发现自己很棒。
    .

    YOLOv5模型转NCNN问题分析与解决方案

    问题分析

    从您提供的信息来看,主要问题是YOLOv5 v6.0版本在转换为NCNN时缺少正确的permute层,导致后处理出现问题。

    当前问题总结

    1. ONNX转NCNN失败:出现"Unsupported slice step"错误
    2. PNNX转换后permute层数量异常:只有一个permute层,而正常应该是三个
    3. 后处理无法正常进行

    解决方案

    方案一:使用PNNX转换(推荐)

    根据nihui大佬的最新建议,对于YOLOv5 v6.0+版本,推荐使用PNNX工具链:

    # 1. 导出TorchScript
    python export.py --weights yolov5n.pt --include torchscript
    
    
    # 2. 使用PNNX转换
    pnnx yolov5n.torchscript inputshape=[1,3,640,640]
    

    方案二:手动修复模型结构

    如果PNNX转换后仍然缺少permute层,可以手动修改param文件:

    # 在转换后的.param文件中添加缺失的permute层
    # 通常在输出层附近添加类似以下结构:
    
    
    Permute              permute_0         1 1 output_0 permute_0_output 0=1
    Permute              permute_1         1 1 output_1 permute_1_output 0=1  
    Permute              permute_2         1 1 output_2 permute_2_output 0=1
    

    方案三:修改YOLOv5导出配置

    在导出ONNX时添加特定参数:

    # 在export.py中添加
    import torch
    model = torch.load('yolov5n.pt', map_location=torch.device('cpu'))
    model.model[-1].export = True  # 设置导出模式
    model.model[-1].onnx_export = True  # 启用ONNX导出优化
    
    
    # 导出ONNX
    torch.onnx.export(
        model,
        dummy_input,
        "yolov5n.onnx",
        opset_version=12,
        input_names=['images'],
        output_names=['output'],
        dynamic_axes=None
    )
    

    一个Permute层的推理处理

    如果确实只有一个permute层,需要调整后处理代码:

    // NCNN推理示例
    ncnn::Extractor ex = net.create_extractor();
    
    
    // 前向推理
    ex.input("input", input);
    ncnn::Mat output;
    ex.extract("output", output); // 假设只有一个输出
    
    
    // 后处理 - 针对单输出调整
    std::vector<Object> objects;
    decode_output(output, objects);
    
    
    void decode_output(const ncnn::Mat& output, std::vector<Object>& objects)
    {
        // 根据实际输出形状调整解析逻辑
        // 通常需要重新组织输出数据的维度
        int num_anchors = output.h; // 或其他维度
        int num_classes = 80; // COCO数据集
        
        for (int i = 0; i < num_anchors; i++)
        {
            const float* ptr = output.row(i);
            
            // 解析边界框和类别概率
            float objness = ptr[4];
            if (objness < 0.5) continue;
            
            // 提取坐标和尺寸
            float x = ptr[0];
            float y = ptr[1];
            float w = ptr[2];
            float h = ptr[3];
            
            // 查找最大类别概率
            int label = -1;
            float prob = 0.f;
            for (int c = 0; c < num_classes; c++)
            {
                float class_prob = ptr[5 + c];
                if (class_prob > prob)
                {
                    prob = class_prob;
                    label = c;
                }
            }
            
            if (prob * objness > 0.5)
            {
                Object obj;
                obj.rect.x = x - w * 0.5f;
                obj.rect.y = y - h * 0.5f;
                obj.rect.width = w;
                obj.rect.height = h;
                obj.label = label;
                obj.prob = prob * objness;
                objects.push_back(obj);
            }
        }
    }
    

    验证步骤

    1. 检查模型输出维度
      import onnxruntime as ort
      session = ort.InferenceSession("yolov5n.onnx")
      outputs = session.get_outputs()
      for output in outputs:
          print(f"Output name: {output.name}, Shape: {output.shape}")
    
    1. 对比ONNX和NCNN输出:确保转换前后输出维度一致
    1. 调整后处理逻辑:根据实际输出结构重写解码函数

    注意事项

    • YOLOv5 v6.0的Focus层已被替换为Conv层,这可能是转换问题的原因之一
    • 确保使用最新版本的NCNN和PNNX工具
    • 如果问题持续存在,考虑使用YOLOv5的官方导出脚本的特定版本

    建议优先尝试PNNX方案,这是目前对YOLOv5 v6.0+版本支持最好的转换方式。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月21日