首页 > 其他分享 >《TencentNCNN系列》 之工作原理简要解析(以LeNet-5为例)

《TencentNCNN系列》 之工作原理简要解析(以LeNet-5为例)

时间:2023-02-11 17:36:57浏览次数:42  
标签:layer Convolution 为例 mats TencentNCNN blob LeNet Net ncnn

PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=068)
  本文发布于 2018-07-19 11:05:52,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=068)

环境说明

  时间:2018.07.19

  ncnn master commit id:b3e24cafc37483dcc97ee61e6f0f6ff1b094300e

前言


  前面两篇文章我们分析了ncnn的加载参数和网络的基本工作流程。其实这一切只是为了给这篇文章做准备。因为我觉得ncnn作为一个前向框架,写的还是比较简单的,方便我们这些小菜鸟对其工作原理进行分析。而分析的方法,还是得从哪里来,从哪里去(读源码)。





前置内容(非常重要的)




本文作为例子的网络
7767517
9 9
Input            data             0 1 data 0=28 1=28 2=1
Convolution      conv1            1 1 data conv1 0=20 1=5 2=1 3=1 4=0 5=1 6=500
Pooling          pool1            1 1 conv1 pool1 0=0 1=2 2=2 3=0 4=0
Convolution      conv2            1 1 pool1 conv2 0=50 1=5 2=1 3=1 4=0 5=1 6=25000
Pooling          pool2            1 1 conv2 pool2 0=0 1=2 2=2 3=0 4=0
InnerProduct     ip1              1 1 pool2 ip1 0=500 1=1 2=400000
ReLU             relu1            1 1 ip1 ip1_relu1
InnerProduct     ip2              1 1 ip1_relu1 ip2 0=10 1=1 2=5000
Softmax          prob             1 1 ip2 prob 0=0



ncnn的基本调用流程
#include "net.h"
ncnn::Net abc_net;
ncnn::Mat in_img;
ncnn::Mat out_img;

abc_net.load_param(param_path);
abc_net.load_model(model_path);

ncnn::Extractor ex = abc_net.create_extractor();

ex.set_num_threads(4);
ex.set_light_mode(true);

ex.input("data", in_img);

ex.extract("prob", out_img);

  这里简要说明一下:

    前两篇文章分别介绍了load_param load_model的基本工作原理,这里要介绍的就是剩下的所有内容。



相关数据结构准备(此小节内容可作为前两篇文章的内容补充)

  在load_param时:

    ncnn::Net::blobs存放着每一个blob的相关信息,主要信息为name、producer、consumers,含义分别为:名字、产生这个blob数据的层、消费这个blob数据的层。

  ncnn::Net::layers存放的是:

  • ncnn::Net::layers::type
  • ncnn::Net::layers::name
  • ncnn::Net::layers::bottoms 存的是此层需要的输入blob的idx
  • ncnn::Net::layers::tops 存的是此层输出的blob的idx

  在load_param中会根据我们读入的type来create_layer,这里建立这个layer也挺有意思的。

rep_img
rep_img
//这里的layer_to_index会去layer_registry去查找对应的层类型的idx,这里的layer_registry数组是我们在编译ncnn的时候初始化的,里面存放的是如下的东西。
#if NCNN_STRING
{"Convolution",Convolution_x86_layer_creator},
#else
{Convolution_x86_layer_creator},

//这个数组的作用就是用来查询具体层的idx和其提供的构造接口creator。每个层都会实现这个creator,比如Convolution层在x86架构下,其构造接口名字叫做Convolution_x86_layer_creator。其原理如下:
DEFINE_LAYER_CREATOR(Convolution_x86)//通过宏定义Convolution_x86_layer_creator这个全局函数
#define DEFINE_LAYER_CREATOR(name) \
    ::ncnn::Layer* name##_layer_creator() { return new name; }


以前文网络为例分析

  这里的分析入口为:

    ncnn::Extractor::input()

rep_img
//图中blob_mats 就是整个框架工作时的数据存放向量。
std::vector<Mat> blob_mats;//blob_mats 定义


//blob_mats的大小初始化在ncnn::Net::create_extractor()中完成,这里唯一需要注意的是,此函数是类Extractor的友元类成员函数,这样写的原因是为了访问其protect的构造函数。
Extractor Net::create_extractor() const
{
    return Extractor(this, blobs.size());
}
Extractor::Extractor(const Net* _net, int blob_count) : net(_net)
{
    blob_mats.resize(blob_count);
    lightmode = true;
    num_threads = 0;
}

//find_blob_index_by_name 就是在ncnn::Net::blobs中去循环遍历,得到其idx。
//然后把输入的mat数据,放入到blob_mats中相应的位置去。到这里,输入数据就填充完了。

    ncnn::Extractor::extract()

rep_img
//此调用的开始时,根据名字通过find_blob_index_by_name 查找我们需要的输出层的idx,然后把blob_mats(携带输入数据)、lightmode、我们需要的输出层的idx一起传入给ncnn::Net::forward_layer()。然后将上述调用处理好的数据放入feature返回。一个网络的前向计算就完成了。

    ncnn::Net::forward_layer()

rep_img

  上图这个if语句是这层网络只有一个输入和输出

rep_img

  此图的else是这层网络非一个输入和输出

//这里我只分析只有一个输入和输出的情况,另外一种和它非常相近。
//图中line 637-line 642,这里通过递归调用一层层倒推回去,直到我们的网络输入层。因为这一层在input的时候给blob_mats赋值,其dims不为零。

//图中line646-line 655是set_light_mode的作用,其作用为是否释放计算过程中,存入blob_mats中,在前面层计算的得到的数据

//图中line 658-line 691是开始前向计算。这里的计算分为两类,一类是在输入数据上计算,并把输出数据放入到输入数据的变量中。另外一种就是分别传入两个变量,一个存输入,一个存输出。至于为啥这样写,不知道,节约内存?

//后续只会分析一种情况,分别传入两个变量,一个存输入,一个存输入。这里以前文网络中的第二层Convolution层为例。在line 677-line 690中,layer->forward()就是执行具体层的计算。

    ncnn::Convolution::forward()

rep_img
//这里只分析kernel为1*1*1的这种卷积
//这里构造了一个InnerProduct层操作,这里简短的几句话,其实就是我前面几篇文章中的部分内容,load_param做了什么,load_model做了什么

    ncnn::InnerProduct::forward()

rep_img

  这里核心是计算两个向量的内积。

  到这里为止,一个卷积操作就完成了。然后forward_layer会从递归中一级级返回,最后得到我们需要的那一层的值。





后记


  无

参考文献




打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
qrc_img

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

标签:layer,Convolution,为例,mats,TencentNCNN,blob,LeNet,Net,ncnn
From: https://www.cnblogs.com/Iflyinsky/p/17112158.html

相关文章

  • LeNet5网络
    Pytorch搭建LeNet-5网络PyTorch实战:经典模型LeNet5实现手写体识别https://github.com/chuanqi305/LeNet5https://github.com/IQ250/LeNet-by-Numpy......
  • vue中静态数据怎么分页(以el-table为例子)
    背景:从别处选择一些数据在界面上用列表展示,列表为静态数据,故需要做分页处理。解决方案:Array.prototype.slice()截取数据,slice(begin,end),从begin开始到end结束,不包括end,返......
  • 新闻文本分类——以央广网新闻文本为例【Python】
    目录1项目简介2机器学习新闻文本分类2.1jieba分词2.2TfidfVectorizer2.3sklearn机器学习2.4实验源代码2.5实验心得3深度学习新闻文本分类3.1MLP3.2实验源代码3.3......
  • 怎样通过explain执行计划,来优化SQL(以hive为例)
    适用场景HiveSQL在执行之前会将SQL转换为MapReduce任务,因此需要了解具体的转换过程。可以通过explain关键字来查看具体的执行计划。通过执行计划能看到SQL程序转换成相应......
  • 新闻文本爬取——以央广网为例
    目录crawlingcrawling1.xcrawling1.0crawling2.xcrawling2.0crawling2.1crawling3.xcrawling3.0crawling3.1crawling3.2crawling3.3crawlingcrawling1.xcrawling1.0imp......
  • 如何重装Windows系统——以Windows10为例
    写在重装前重装前注意备份系统盘(一般是C盘)中的数据你需要一个U盘可以把操作系统看做成一个软件软件运行的时候无法删除软件一般情况下系统盘是C盘步骤重装系统主......
  • 干货|以Vue为例,如何提升小程序开发效率?
    小程序的交付过程是这样的:一般小程序从idea到发布,安装小程序开发者工具→新建模板小程序→开发→编译→发布,且整个过程为可视化操作,只需写核心逻辑代码即可。小程序框架本......
  • flutter:安装使用第三方库:以dio为例(flutter 3.7.0 / dio 4.0.6)
    一,dio库的地址:国外:https://pub.dev/packages/dio国内:https://pub.flutter-io.cn/packages/dio如图:可以看到最新版本是4.0.6说明:刘宏缔的架构森林是一个......
  • 判断网站是否更新数据(tp6项目为例)
    1.获取数据库中所有数据表的条数累加去判断(多项目时)2.选取新闻表和栏目表,获取总条数,与下次作比较判断(单项目时)建议选取第一种:3.连接数据库代码:functiondatabasecon......
  • gRPC介绍(以Java为例)
    1.简介1.1gRPC的起源RPC是RemoteProcedureCall的简称,中文叫远程过程调用。用于解决分布式系统中服务之间的调用问题。通俗地讲,就是开发者能够像调用本地方法一样调用......