ncnn源码学习(二):参数字典paramdict

本文深入探讨了NCNN框架中参数解析的过程,包括如何通过ParamDict结构解析.param文件中的单个值和数组,以及如何根据不同的index标识处理整型、浮点型数据和数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        上一节讲到,在使用load_param接口载入参数时,需要用参数字典ParamDict来解析.param文件中的特定参数,如:

 0=64 1=3 11=3 5=1 6=1728

        那么参数字典具体如何进行解析的?我们首先看一下paramdict.h文件中定义的数据成员变量:

    // parameters
    struct
    {
        // 是否已经被载入:1表示已载入
        int loaded;
        // 单个值可能为整形也有可能为浮点型
        union { int i; float f; };
        // 还有可能是数组
        Mat v;
    } params[NCNN_MAX_PARAM_COUNT];

        这里,NCNN_MAX_PARAM_COUNT大小为32,params是一个大小为32的结构体数组,即一行中特定参数数量不能超过32,当然,一般情况下也不会超过32。

        然后,我们看一下paramdict.cpp源码,可以看到,这里会解析出当前行的index(id),也即是等号左边部分:        

    while (fscanf(fp, "%d=", &id) == 1)
    {
        ...
    }

        再结合ncnn关于param和bin文件的wiki,链接为参考资料[1],有:

    index:0~19 对应整形或浮点型数据
    index:-23000 减去0~19 对应整形或浮点型数组

        具体代码如下:

       (1)根据读取的index判断,如果小于-23300,表示为数组,那么等号右边第一个参数就是数组长度,后面顺序就是数组内容,[array size],int,int,...,int或[array size],float,float,...,float,例如:

0=1 1=2.5 -23303=2,2.0,3.0

        index为-23303,表明当前参数为数组,等号右边第一个参数为2,表明数组长度为2,后面2.0,3.0就是数组的内容:

        // index <= -23300:数组
        bool is_array = id <= -23300;
        // 如果是数组
        if (is_array)
        {
            // 计算id
            id = -id - 23300;
        }

        // 如果当前参数是数组类型
        if (is_array)
        {
            int len = 0;
            // 数组长度
            int nscan = fscanf(fp, "%d", &len);
            // 等于1才表示读取成功
            if (nscan != 1)
            {
                fprintf(stderr, "ParamDict read array length failed\n");
                return -1;
            }

            // 创建数组:就是一个Mat
            params[id].v.create(len);

            for (int j = 0; j < len; j++)
            {
                char vstr[16];
                // 从二值文件中读取string
                nscan = fscanf(fp, ",%15[^,\n ]", vstr);
                // 如果读取失败
                if (nscan != 1)
                {
                    fprintf(stderr, "ParamDict read array element failed\n");
                    return -1;
                }

                // 是否为浮点型:看解析的字符串中是否存在'.'或'e'
                // 小数点计数法和科学计数法
                bool is_float = vstr_is_float(vstr);

                // 如果是浮点数
                if (is_float)
                {
                    // vstr赋值给params[id].v[j]
                    float* ptr = params[id].v;
                    nscan = sscanf(vstr, "%f", &ptr[j]);
                }
                else
                {
                  // vstr赋值给params[id].v[j]
                    int* ptr = params[id].v;
                    nscan = sscanf(vstr, "%d", &ptr[j]);
                }
                // 赋值失败
                if (nscan != 1)
                {
                    fprintf(stderr, "ParamDict parse array element failed\n");
                    return -1;
                }
            }
        }

        这里有个vstr_is_float函数,原理很简单,就是判断数字对应字符串中是否存在小数点'.'或字母'e',对应小数的两种写法,一种正常的小数点表示法,一种是科学计数法。

        如果不是数组,直接读取即可:

        else
        {
            // 不是数组
            char vstr[16];
            // 直接将字符串赋值给vstr
            int nscan = fscanf(fp, "%15s", vstr);
            // 赋值失败
            if (nscan != 1)
            {
                fprintf(stderr, "ParamDict read value failed\n");
                return -1;
            }

            // 判断是否为浮点数
            bool is_float = vstr_is_float(vstr);

            // 将字符串中的值赋给参数字典
            if (is_float)
                nscan = sscanf(vstr, "%f", &params[id].f);
            else
                nscan = sscanf(vstr, "%d", &params[id].i);
            // 赋值失败
            if (nscan != 1)
            {
                fprintf(stderr, "ParamDict parse value failed\n");
                return -1;
            }
        }

        // 载入成功
        params[id].loaded = 1;

        这里参数字典解析特定参数的流程就走完了。

参考资料:

[1] https://github.com/Tencent/ncnn/wiki/param-and-model-file-structure

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值