ncnn源碼分析-004-代碼流程總結


0.調用實例

先看一個調用實例,順着調用流程探尋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;
}

1.blob結構

class Blob
{
public:
    std::string name; //blob名字
    int producer; //指明該blob來自哪個層的輸出,層索引
    std::vector<int> consumers; //指明該blob作為哪個層的輸入,層索引
}

在blob的構造函數中初始化producer=-1

2.layer

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());
}
  • layer進行前向傳播時,根據bottoms索引值找到bottom數據,作為forward的輸入,計算結果存入tops對應的blob里,完成一層的inferecnce
  • load_param和load_model有三種定義
    • 第一個是在net里定義為int load_param(FILE *fp);,主要功能是從param文件中讀取數據,網絡層數,網絡blob個數,每一個輸入輸出blob的類型、名字等信息。涉及到網絡結構的參數(不是訓練參數),例如濾波器個數、padding、stride等信息由ParamDict里的load_param負責讀取。
    • 第二個是在ParamDict里,定義為int load_param(FILE *fp);fp位置接net里的位置,該函數將參數讀取到ParamDict的一個類實例pd里,以pair對的形式存儲,不考慮具體參數含義,只需按照key,value存儲你即可。
    • 第三個是在layer里,定義為int load_param(const ParamDict &pd);這個load_param負責從pair對里根據不同層對key的定義解析成和每一個層對應的參數,參數的不同決定了相同類型層的差異性,比如同樣是卷積層,但是濾波器個數不同。
    • load_model和load_param類似,至此完成了整個網絡的解析工作。

以上內容對應於我們平時使用ncnn的以下代碼形式:

ncnn::Net net;
net.load_param("model.param");
net.load_model("model.bin");

2.net解析

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;
}
  • Net類里的成員變量包含了另一個類create_extractor方法,該方法實際上就是調用Extractor類的構造函數,返回一個Extractor實例。
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)找到對應的blob
    • 調用blob的類成員變量producer來找到該blob是哪個layer的輸出,也就是layer_index
    • 接下來調用forward_layer(layer_index, blob_mats, opt)完成整個網絡的前向傳播,逐層前傳使用遞歸完成,blob_mats里存放真正的blob數據,是net的私有成員變量std::vector<Mat> blob_mats,Mat是自定義類型
    • 完成forward_layer后,feat = blob_mats[blob_index],feat是調用例子中out的引用,將blob數據存放在feat變量中,整個流程結束


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM