onnx模型转 ncnn 模型全连接层输出shape不对问题解决

news/2024/7/8 1:40:20

1.简述

最近在把paddleocr 中cls分类模型通过ncnn部署框架部署时,发现onnx -> ncnn 模型的转换过程中出现问题。因为之前的项目都是使用ncnn框架部署的,只能去解决模型转换问题了。

2. 问题描述与分析

模型在onnx推理代码上正常,当把模型转换为ncnn模型之后,发现模型最后的softmax输出的维度不对。模型的为5个分类,onnx的输出为[1, 5] 是正确的,但是跑ncnn模型发现输出为 [1, 8, 5] ,经过打印log分析,是 softmax层前面的 fc层导致的问题。

分析:

通过Netron工具可视化模型,fc层前面的输入维度为 A: [1, 200],权重B的维度为 B: [200, 5],偏置 C为 C: [5]。我们再看到Gemm层的属性,transA = 0, transB = 0,表示矩阵A和B都不需要转置操作。此时全连接操作是可以直接计算的:

A * B + C,对应的维度为 [1, 200] * [200, 5] + [5]  =>  [1, 5] 输出维度正确

 

当把模型转换为ncnn模型时:

看到onnx2ncnn.cpp文件中关于Gemm 这个op的判断,代码中

(alpha == 1.f && beta == 1.f && transA == 0 && transB == 1) 的值为true时,才会跑 InnerProduct-like A * B + C 的流程,否则会进入 gemm矩阵乘法的流程。这样看来我的ncnn模型推理结果不正确 是因为fc层中的transB = 0,导致跑到了gemm的执行流程,没有跑到InnerProduct的执行流程。

跑到gemm矩阵乘法流程为什么输出的维度就不正确呢,我想原因还是矩阵乘法的计算问题,计算的维度:

A * B = [1, 200] * [5, 200] ,这个矩阵是不能正常计算的,由于维度不同不能直接计算,但是在执行代码的时候没出错的原因,可能是由于gemm分块计算的原因,然后最后输出为 [1, 8, 5]

 

3. 解决方法

在onnx2ncnn.cpp代码中加入 transB = 0 时,也跑InnerProduct的流程,然后在代码中把矩阵 B 的数据进行转置一下就可以了。

else if (alpha == 1.f && beta == 1.f && transA == 0 && transB == 0)
{
    // InnerProduct-like A * B + C
    const onnx::TensorProto& B = weights[node.input(1)];
    const onnx::TensorProto& C = weights[node.input(2)];

    fprintf(pp, " 0=%d", get_tensor_proto_data_size(C));
    fprintf(pp, " 1=1");
    fprintf(pp, " 2=%d", get_tensor_proto_data_size(B));

    int weight_data_size = get_tensor_proto_data_size(B);
    int num_output = B.dims(B.dims_size() - 1);
    int num_input = weight_data_size / num_output;

    int quantize_tag = 0;
    fwrite(&quantize_tag, sizeof(int), 1, bp);

    // reorder num_input-num_output to num_output-num_input
    {
        const float* bptr = B.has_raw_data() ? (const float*)B.raw_data().data() : B.float_data().data();

        for (int j = 0; j < num_output; j++)
        {
            for (int k = 0; k < num_input; k++)
            {
                float vb = bptr[k * num_output + j];
                fwrite(&vb, sizeof(float), 1, bp);
            }
        }
    }
    fwrite_tensor_proto_data(C, bp);

}

然后再重新编译一下代码,重新转换一下模型就正常了。

至此,问题终于得以解决,弄了好多天才解决问题,实属不易啊。


http://lihuaxi.xjx100.cn/news/1197886.html

相关文章

绝地求生 压q python版

仅做学习交流&#xff0c;非盈利&#xff0c;侵联删&#xff08;狗头保命) 一、概述 1.1 效果 总的来说&#xff0c;这种方式是通过图像识别来完成的&#xff0c;不侵入游戏&#xff0c;不读取内存&#xff0c;安全不被检测。 1.2 前置知识 游戏中有各种不同的q械&#xf…

这本数智平台白皮书讲透了大型企业数智化升级业务痛点

在以“升级企业数智化底座”为主题的2023用友BIP技术大会上&#xff0c;用友联合全球权威咨询机构IDC共同发布《建设数字中国 升级数智底座——企业数智化底座白皮书》&#xff0c;在这本数智平台白皮书里深入剖析了大型企业的数智化升级痛点。 大型企业普遍具有广域的业务覆盖…

什么是DAS/SAN/NAS

先上图 DAS DAS(Direct-attached Storage) 直连存储&#xff0c;这种存储设备通常是一个磁盘阵列柜&#xff0c;里面有多块磁盘&#xff0c;但不带RAID功能。 它与服务器主机之间的连接通常采用SCSI或者FC连接。DAS只能连接一台服务器&#xff0c;其它服务器无法共享该存储。 …

全民开发|零代码平台搭建库存管理系统,助力企业降本增效

什么是库存管理系统 库存管理系统是一种用于监控和跟踪商业组织存货的系统机软件。它帮助企业管理其库存&#xff0c;确保所需的商品和服务始终可用&#xff0c;并在需要时提供报告和预测。库存管理系统可追踪库存级别、库存周转率、订单、销售和交付等方面的数据&#xff0c;…

嘉兴桐乡外语提升辅导-四级考试倒计时了,还有救吗?

四级考试倒计时了&#xff0c;还有救吗&#xff1f; 即使复习时间再少&#xff0c;也不要放弃历年真题 不要盲目刷题&#xff0c;时间不够的话可以按年份由近到远的做&#xff0c;按考试时间严格要求自己&#xff0c;做完一套之后要及时对答案复盘&#xff0c;总结出自己错误的…

【嵌入式环境下linux内核及驱动学习笔记-(14)linux总线、设备、驱动模型之platform】

目录 1、新驱动架构的导入1.1 传统驱动方式的痛点1.2 总线设备驱动架构 2、platform 设备驱动2.1 platform总线式驱动的架构思想2.2 platform _device相关的数据类型2.2.1 struct platform_device2.2.2 struct platform_device_id2.2.3 struct resource2.2.4 struct device 2.3…

jQuery 基础知识

1.jQuery的使用 要想使用 jQuery 的话&#xff0c;我们必须先要官网上下载&#xff08; http://jquery.com/ &#xff09;3.7 到 4.0的开发版本就可以&#xff0c;下载到文件夹以后桌面都可以 &#xff0c;然后拖动到代码编辑器根目录下即可 在需要使用 jQuery 的页面引入 j…

ts面试总结题

什么是TypeScript? TypeScript 是一门静态类型、弱类型的语言 TypeScript和JavaScript有什么不同? TypeScript 是 JavaScript 的超集&#xff0c;扩展了 JavaScript 的语法&#xff0c;因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改&#xff0c;TypeScrip…