ncnn源码分析_2
ncnn 源码分析(二) Extractor
前面大致总结了一下ncnn模型载入的流程,模型载入之后,就是新建一个Extractor,然后设置输入,获取输出:
ncnn::Extractor ex = net.create_extractor();
ex.set_num_threads(4);
ex.input("data", in);
ncnn::Mat out;
ex.extract("detection_out", out);
现在可以看一下Extractor的定义了:
class Extractor
{
public:
// enable light mode, intermediate blob will be recycled when enabled
// enabled by default
// 设置light模式,启用时中间 blob 将会循环利用
void set_light_mode(bool enable);
// set thread count for this extractor, 设置线程数
void set_num_threads(int num_threads);
// set blob memory allocator, 设置blob的内存分配器
void set_blob_allocator(Allocator* allocator);
// set workspace memory allocator, 设置工作空间的内存分配器
void set_workspace_allocator(Allocator* allocator);
#if NCNN_STRING
// set input by blob name
// return 0 if success
// 设置网络输入:字符串layer名
int input(const char* blob_name, const Mat& in);
// get result by blob name
// return 0 if success
// 设置提取器的输入:得到对应输出
int extract(const char* blob_name, Mat& feat);
#endif // NCNN_STRING
// set input by blob index
// return 0 if success
// 设置int类型blob索引及输入
int input(int blob_index, const Mat& in);
// get result by blob index
// return 0 if success
// 设置int类型blob索引及输出
int extract(int blob_index, Mat& feat);
protected:
// 对外提供create_extractor接口
friend Extractor Net::create_extractor() const;
Extractor(const Net* net, int blob_count);
private:
// 网络
const Net* net;
// blob的 mat
std::vector<Mat> blob_mats;
// 选项
Option opt;
};
除了设置option的接口之外,就只剩下我们需要使用的几个接口函数了:
(1) Extractor
// 创建Extractor
Extractor Net::create_extractor() const
{
return Extractor(this, blobs.size());
}
内部调用了接口为,就是将blob_mat数组resize到网络的blob数目大小,然后设置了一下选项:
// 执行器
Extractor::Extractor(const Net* _net, int blob_count) : net(_net)
{
blob_mats.resize(blob_count);
opt = net->opt;
}
(2) input接口:
// 设置输入
int Extractor::input(const char* blob_name, const Mat& in)
{
// 获取输入模块对应index
int blob_index = net->find_blob_index_by_name(blob_name);
if (blob_index == -1)
return -1;
// 调用直接用index的设置input方法
return input(blob_index, in);
}
内部调用的接口为:
// 输入为index的输入接口
int Extractor::input(int blob_index, const Mat& in)
{
if (blob_index < 0 || blob_index >= (int)blob_mats.size())
return -1;
// 设置blob_index对应 Mat
blob_mats[blob_index] = in;
return 0;
}
(3) extract接口:
// 将输入string类型name转换成对应的索引
int Extractor::extract(const char* blob_name, VkMat& feat, VkCompute& cmd)
{
int blob_index = net->find_blob_index_by_name(blob_name);
if (blob_index == -1)
return -1;
return extract(blob_index, feat, cmd);
}
这里调用的接口为:
// 提取特征
int Extractor::extract(int blob_index, Mat& feat)
{
if (blob_index < 0 || blob_index >= (int)blob_mats.size())
return -1;
int ret = 0;
if (blob_mats[blob_index].dims == 0) // 如果输出blob为空
{
int layer_index = net->blobs[blob_index].producer; // 查找输出blob对应的生产者
ret = net->forward_layer(layer_index, blob_mats, opt); // 前向推理
}
feat = blob_mats[blob_index]; // 输出特征
if (opt.use_packing_layout) // 对特征进行unpack
{
Mat bottom_blob_unpacked;
convert_packing(feat, bottom_blob_unpacked, 1, opt);
feat = bottom_blob_unpacked;
}
return ret;
}
这里就是调用各层前向推理forward_layer方法来进行推理的,这个对应于特定层的推理过程,后面总结各个层的时候再说。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!