ncnn源码阅读(二)----网络模型结构和权重参数的加载

news2024/11/26 18:52:07

网络模型结构和权重参数的加载

ncnn推理框架中把模型的结构和权重参数分为两个文件进行存储,实现了结构和权重的分离。在xxx.param中存储了模型的结构信息,在xxx.bin中存储了模型的权重信息。xxx.param的文件结构如下:
xxx.param文件结构
layer:描述网络一共有多少层,例如:ReLU、Conv 都叫一个layer;
blob:表示数据节点,例如一个Conv就有一个输入blob和输出blob;

bottom_count:当前层接收输入blob的层个数
top_count:将当前层的输出作为输入blob的层个数

bottom_name:当前层输入数据的生产层名字
blob_name: 消费当前的输出结果的层名字

模型网络结构的加载

在ncnn中,通过重载实现不同格式的加载。最常见也是最容易看懂的加载方式:
通过输入模型结构的文件,来完成模型的加载,具体的重载如下图:
在这里插入图片描述
两个具体关系如下:

int Net::load_param(const char* protopath) {
	FILE* fp = fopen(protopath, "rb");
	if (!fp) {
		std::cout << "error" << std::endl;
		return -1;
	}
	int ret = load_param(fp);
	fclose(fp);
}

int load_param(FILE* fp)中完成对网络结构的构建,具体的步骤,如下:

  • 读取层数、blob数
  • 逐行读取,层类型和层名字,以及输入blob数据的个数,和将当前层输出作为输入blob的个数
  • 根据层类型得到类型的索引,然后通过该索引得到层实例化的指针;这个地方需要区分内部层和自定义的层;
    • 内部层
    • 自定义层
  • 为当前层设置类型和名字
  • 开始读取bottoms和tops,并构建blob的集合
  • 利用创建的额层实例指针,构建层集合
int Net::load_param(FILE* fp)
{
	//一、读取层数和blob数
    int layer_count = 0;
    int blob_count = 0;
    fscanf(fp, "%d %d", &layer_count, &blob_count);

    layers.resize(layer_count);
    blobs.resize(blob_count);

    int layer_index = 0;
    int blob_index = 0;
    while (!feof(fp))
    {
    //二、逐行读取,层类型和层名字,以及输入blob数据的个数,和将当前层输出作为输入blob的个数
        int nscan = 0;
        char layer_type[256];
        char layer_name[256];
        int bottom_count = 0;
        int top_count = 0;
        nscan = fscanf(fp, "%256s %256s %d %d", layer_type, layer_name, &bottom_count, &top_count);
        if (nscan != 4)
        {
            continue;
        }
	//三、根据层类型得到类型的索引,然后通过该索引得到层实例化的指针;
        int typeindex = layer_to_index(layer_type);
        Layer* layer = create_layer(typeindex);
        if (!layer)
        {
            typeindex = custom_layer_to_index(layer_type);
            layer = create_custom_layer(typeindex);
        }
	//四、为当前层设置类型和名字
        layer->type = std::string(layer_type);
        layer->name = std::string(layer_name);
	//五、开始读取bottoms和tops,并构建blob的集合
        layer->bottoms.resize(bottom_count);
        for (int i=0; i<bottom_count; i++)
        {
            char bottom_name[256];
            nscan = fscanf(fp, "%256s", bottom_name);
            if (nscan != 1)
            {
                continue;
            }
			//根据输入blob的名字,在blob集合中的索引,如果没有找到,就需要构建这个blob
			//并将构建的blob添加到blob中
            int bottom_blob_index = find_blob_index_by_name(bottom_name);
            if (bottom_blob_index == -1)
            {
                Blob& blob = blobs[blob_index];

                bottom_blob_index = blob_index;

                blob.name = std::string(bottom_name);

                blob_index++;
            }
			//在blob集合中找到,将根据索引获取当前的blob实例
			//然后将当前层作为blob的消费者
			//在当前层的bottom中添加输入blobd的索引
            Blob& blob = blobs[bottom_blob_index];

            blob.consumers.push_back(layer_index);

            layer->bottoms[i] = bottom_blob_index;
        }
		//
        layer->tops.resize(top_count);
        for (int i=0; i<top_count; i++)
        {
            Blob& blob = blobs[blob_index];

            char blob_name[256];
            nscan = fscanf(fp, "%256s", blob_name);
            if (nscan != 1)
            {
                continue;
            }

            blob.name = std::string(blob_name);

            blob.producer = layer_index;

            layer->tops[i] = blob_index;

            blob_index++;
        }
		//如果当前层有特殊的参数,则读取特殊的参数
        int lr = layer->load_param(fp);
        if (lr != 0)
        {
            fprintf(stderr, "layer load_param failed\n");
            continue;
        }
		//六、利用创建的额层实例指针,构建层集合
        layers[layer_index] = layer;

        layer_index++;
    }

    return 0;
}

权重参数的加载

加载模型参数同样通过了一个重载:
在这里插入图片描述
具体的说下int load_model(FILE* fp)

int Net::load_model(FILE* fp)
{
    // load file
    int ret = 0;
	//遍历所有的层,然后每个层根据自己实现的load_model方法,读取对应的权重参数
    for (size_t i=0; i<layers.size(); i++)
    {
        Layer* layer = layers[i];

        int lret = layer->load_model(fp);
        if (lret != 0)
        {
            fprintf(stderr, "layer load_model %d failed\n", (int)i);
            ret = -1;
            break;
        }
    }

    return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/724472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python_dir+getattr_获取模块下所有属性对象

目录 dir() 执行结果 执行结果 dir() 该方法不带参数时&#xff0c;以列表类型返回当前范围内的变量名&#xff0c;变量包括常量、方法、类等。 带参数时&#xff0c;以列表类型返回参数的属性、方法的变量名。如果参数包含方法__dir__()&#xff0c;该方法将被调用。如果…

软件测试 |网页frame与多窗口如何处理

简介 当我们要定位一个元素时&#xff0c;怎么都定位不到的时候就要考虑是不是浏览器内嵌里一个 frame 窗口或者要找的元素在新打开的窗口里。这时候就需要将进行 frame 的切换以及窗口的切换。 frame 类似于在原有主 html 的基础上又嵌套一个 html&#xff0c;而且嵌套的 ht…

如何打包arch软件并且打包到arch仓库中(超详细教程)

如何打包arch软件并且打包到arch仓库中(超详细教程) 前提一:注册arch账号 略,官网是:https://archlinux.org/ 前提二:将本地的ssh-key放入arch账号的ssh秘钥中 终端执行 生成ssh秘钥 ssh-keygen cd ~/.ssh cat id_rsa.pub将该段复制到arch账号中ssh中 更新 写PKGBUILD&a…

Spring Boot 中的授权是什么,如何使用

Spring Boot 中的授权是什么&#xff0c;如何使用 在现代 Web 应用程序开发中&#xff0c;授权是一项至关重要的安全措施。授权是指在用户登录后&#xff0c;对用户进行身份验证&#xff0c;并授予用户访问应用程序特定资源的权限。在 Spring Boot 中&#xff0c;授权是通过 S…

集群 第三章

1. keepalived 功能

UE5打包SDK未正确安装的问题

正文 Windows&#xff08;笔者之前用的电脑是windows10&#xff0c;最新电脑使用的是windows11&#xff09;下UE5打包项目的需要安装Visual Studio。 而且安装的时候需要选择上C 游戏开发相关模块。如下图所示&#xff1a; 有时候安装了Visual Studio 之后&#xff0c;还是不能…

使用Stable Diffusion生成艺术二维码

在数字艺术的世界中&#xff0c;二维码已经从单纯的信息承载工具转变为可以展示艺术表达的媒介。这是通过使用Stable Diffusion的技术实现的&#xff0c;它可以将任何二维码转化为独特的艺术作品。接下来&#xff0c;我们将一步步教你如何使用Stable Diffusion生成艺术二维码。…

有私域和无私域的区别?

公域流量和私域流量的区别 (1)渠道区别&#xff1a;私域流量的流量池是个体独有的&#xff0c;而公域流量的流量池是公共的。简单说&#xff0c;私域流量是借助个人平台直接获取用户的渠道&#xff0c;而公域流量是要凭借一个公共的平台&#xff0c;依托平台的流量来获取用户。…

极智开发 | 教你gitlab管理员密码忘了怎么办

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多经验分享 大家好&#xff0c;我是极智视界&#xff0c;本文介绍一下 教你gitlab管理员密码忘了怎么办。 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码和资源下载&#xff0c;链接&…

Ubuntu系统下用VSCode断点调试C++代码

文章目录 0 引言1 创建vsdebug工程1.1 创建文件夹和文件1.2 C代码1.3 CMakeLists.txt1.4 build.sh脚本 2 VSCode配置文件2.1 tasks.json2.2 launch.json 3 编译运行和调试3.1 编译运行3.2 调试 0 引言 Ubuntu下不能像Windows下使用Visual Studio那样方便Debug调试C代码&#x…

C++图形开发(9):静止的矩形(fillrectangle函数)

我们的graphics库提供了一个用于绘制矩形的函数&#xff0c;它就是…… fillectangle();其格式为&#xff1a; fillectangle(矩形左上角的x坐标,矩形左上角的y坐标&#xff0c;x方向的距离&#xff0c;y方向的距离);举个栗子&#xff1a; #include<graphics.h> #inclu…

Feign 调用报 RequestParam.value() was empty on parameter 0

详细报错: FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0 背景 最近在使用 RequestParam、RequestBody 注解定义 feign 接口的时候出现一些使用上的问题&#xff…

Ceph:关于Ceph 集群中数据分布和容灾理论的一些笔记

写在前面 准备考试&#xff0c;整理 Ceph 相关笔记博文内容涉及,Ceph 集群中数据如何分布以及不同的容灾池介绍理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有…

【MySQL系列】数据库基础学习_简单认识数据库

「前言」文章内容大致是数据库基础&#xff0c;以及数据库的基本知识。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 我见青山多妩媚&#xff0c;料青山、见我应如是。 ——辛弃疾《贺新郎》 目录 一、连接MySQL服务器二…

hcip第三次作业

1、合理规划IP地址&#xff0c;启用OSPF单区域。 2、R1-R2之间启用PPP的PAP单向认证。 把R1作为主认证方 然后在R2处做添加——帐号、密码 接口处于双UP的状态&#xff0c;证明认证成功 3、R2-R3之间启用PPP的chap双向认证 R2作为主认证方。 此时4/0/1口处于up - down状态 然…

Zabbix6.0 的部署、自定义监控服务

目录 一、概述 二、 zabbix 1.zabbix简介 2.zabbix监控原理 3. Zabbix 6.0 新特性 3.1Zabbix server高可用防止硬件故障或计划维护期的停机 3.2 Zabbix 6.0 LTS新增Kubernetes监控功能&#xff0c;可以在Kubernetes系统从多个维度采集指标 4. Zabbix 6.0 功能组件 4.1…

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/

-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathD:/在内存溢出时导出整个堆信息 指定导出堆的存放路径(D:/java_customName.hprof)&#xff0c;可以自定义dump名字&#xff1b;自定义名字时重复执行dump文件貌似不会覆盖(D:/)&#xff0c;只指定路径会自动生成Dump文件&…

10G CWDM和DWDM的优势和应用场景解析

10G CWDM和10G DWDM光模块都是用于光纤通信系统的传输技术&#xff0c;它们在光纤网络中使用不同的光波分复用技术。本期文章我们通过分析10G CWDM SFP和10G DWDM SFP两种光模块进行区别对比。 一、10G CWDM和DWDM光模块参数区别对比 二、易天光通信10G CWDM和DWDM光模块优势对…