先看一个调用实例,顺着调用流程探寻ncnn内部具体实现细节。
#include "net.h"
int main(int argc, char **argv)
{
    ncnn::Mat in; 
    ncnn::Mat out;
    
    ncnn::Net net;
    net.load_param("model.param");
    net.load_model("model.bin");
    ncnn::Extractor ex = net.create_extractor();
    ex.set_light_mode(true);
    ex.set_num_threads(4);
    ex.input("data", in);
    ex.extract("output", out);
    return 0;
}
class Blob
{
public:
    std::string name; //blob名字
    int producer; //指明该blob来自哪个层的输出,层索引
    std::vector<int> consumers; //指明该blob作为哪个层的输入,层索引
}
在blob的构造函数中初始化producer=-1
class Layer
{
public:
    int typeindex; //类型ID
    std::string type; //类型名字
    std::string name; //层的名字
    std::vector<int> bottoms; //当前层所有输入blob的索引
    std::vector<int> tops; //当前层所有输出blob索引
    int load_param(const ParamDict &pd);
    int load_model(const ModelBin &mb);
    int forward(const std::vector<Mat> &bottom_blobs, std::vector<Mat> &top_blobs, const Option &opt = get_default_option());
}
int load_param(FILE *fp);,主要功能是从param文件中读取数据,网络层数,网络blob个数,每一个输入输出blob的类型、名字等信息。涉及到网络结构的参数(不是训练参数),例如滤波器个数、padding、stride等信息由ParamDict里的load_param负责读取。int load_param(FILE *fp);fp位置接net里的位置,该函数将参数读取到ParamDict的一个类实例pd里,以pair对的形式存储,不考虑具体参数含义,只需按照key,value存储你即可。int load_param(const ParamDict &pd);这个load_param负责从pair对里根据不同层对key的定义解析成和每一个层对应的参数,参数的不同决定了相同类型层的差异性,比如同样是卷积层,但是滤波器个数不同。以上内容对应于我们平时使用ncnn的以下代码形式:
ncnn::Net net;
net.load_param("model.param");
net.load_model("model.bin");
class Net
{
public:
    int usewinograd_convolution;
    int use_sgemm_convolution;
    int use_int8_inference;
    int use_vulkan_compute;
    
    int load_param(FILE *fp);
    int load_model(FILE *fp);
    Extractor create_extractor();
protected:
    std::vector<Blob> blobs;//网络的所有blob
    std::vector<Layer*> layers;//网络的所有层指针
    
    int forward_layer(int layer_index, std::vector<Mat> &blob_mats, Options &opt);
    int find_blob_index_by_name(const char* name);
    int find_layer_index_by_name(const char *name);
}
class Extractor
{
public:
    int Extractor::input(const char *blob_name, const Mat &in);
    int Extractor::input(int blob_index, VkMat &feat, VkCompute &cmd);
    int Extractor::extract(const char *blob_name, Mat &feat);
    int Extractor::extract(blob_index, const Mat &feat);//次函数直接forward_layer()
protected:
    friend Extractor Net::create_extractor() const;
    Extractor(const Net *net, int blob_count);
private:
    const Net *net;
    std::vector<Mat> blob_mats;
    Option opt;
}
Extractor Net::create_extractor() const
{
    return Extractor(this, blobs.size());
}
调用Extractor::input(const char *blob_name, const Mat &in)设置输入数据,这里比较简单,通过输入blob名字找到对应的索引,然后根据索引取到真实的blob数据。
Extractor::extract(const char *blob_name, Mat &feat)
Extractor::extract(blob_index, const Mat &feat)两个输入参数分别是要获取数据blob索引和存放数据的输出变量,通过blob_index在blobs(net的类成员变量,用于存放整个网络的所有blob)找到对应的blobforward_layer(layer_index, blob_mats, opt)完成整个网络的前向传播,逐层前传使用递归完成,blob_mats里存放真正的blob数据,是net的私有成员变量std::vector<Mat> blob_mats,Mat是自定义类型feat = blob_mats[blob_index],feat是调用例子中out的引用,将blob数据存放在feat变量中,整个流程结束原文:https://www.cnblogs.com/ganchunsheng/p/11686703.html