NCNN-Blob_Layer
路径:src/blob.h 和 src/blob.cpp, src/layer.h 和 src/layer.cpp
Blob结构简单,源码也很短, Layer包括层的名称,参数等,层的输入输出节点信息,层的执行流程
源码
class NCNN_EXPORT Blob {
public:
Blob(); // 构造函数为空
public:
std::string name; // 节点的名字
int producer; // 输出该节点的层索引
int consumer; // 输入该节点的层索引
Mat shape; // 节点的形状
};
这里的layer是基类,所以函数不对应任何有意义的实现,不同的层继承Layer,实现对应的虚函数
class layer {
public:
Layer();
virtual ~Layer();
virtual int load_param(const ParamDict& pd); // 加载层参数
virtual int load_model(const ModelBin& mb); // 加载模型layer implementation specific setup权重
virtual int create_pipeline(const Option& opt); // 配置层
virtual int destroy_pipeline(const Option& opt); // 取消配置
public:
blob one_blob_only; // 单输入单输出,有优化
...
public:
// 执行推理
virtual int forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const;
virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const;
virtual int forward_inplace(std::vector<Mat>& bottom_top_blobs, const Option& opt) const;
virtual int forward_inplace(Mat& bottom_top_blob, const Option& opt) const;
public:
void* userdata; // 自定义用户数据
int typeindex; // 层类型索引
std::string type; // 层类型名称
std::string name; // 层名称
std::vector<int> bottoms; // 输入节点索引
std::vector<int> tops; // 输出节点索引
std::vector<Mat> bottom_shapes; // 输入节点形状
std::vector<Mat> top_shapes; // 输出节点形状
}
// 两个宏定义:
// 函数指针layer_creator_func:输入为void*,输出为Layer*
typedef Layer* (*layer_creator_func)(void*);
// 函数指针layer_destroyer_func:输入为Layer* 和 void*, 无输出
typedef void (*layer_destroyer_func)(Layer*, void*);
struct layer_registry_entry {
const char* name; // 层名称
layer_creator_func creator; // 对应的工厂函数
};
struct custom_layer_registry_entry {
const char* name; // 层名称
layer_creator_func creator; // 对应的工厂函数
layer_destroyer_func destroyer; // 对应的工厂函数
void* userdata; // 用户自定义数据
};
struct overwrite_builtin_layer_registry_entry {
int typeindex; // 层索引
layer_creator_func creator; // 对应的工厂函数
layer_destroyer_func destroyer; // 对应的工厂函数
void* userdata; // 用户自定义数据
};
// DEFINE_LAYER_CREATOR(Input_final): Input_layer_creator(void* );
#define DEFINE_LAYER_CREATOR(name) \
::ncnn::Layer* name##_layer_creator(void* /*userdata*/) \
{ \
return new name; \
}
#define DEFINE_LAYER_DESTROYER(name) \
void name##_layer_destroyer(::ncnn::Layer* layer, void* /*userdata*/) \
{ \
delete layer; \
}
// 定义层的个数
static const int layer_registry_entry_count = sizeof(layer_registry) / sizeof(layer_registry_entry);
这里的layer_registry由cmake脚本文件来生成具体有多少中类型的层,
layer_registry是一个layer_registry_entry的数组,所以这里除以layer_registry_entry的大小就是层的个数
int layer_to_index(const char* type) {
for (int i = 0; i < layer_registry_entry_count; i++) {
// 遍历,比较层名称,获取这个层对应于layer_registry_entry_count的索引
if (strcmp(type, layer_registry[i].name) == 0)
return i;
}
return -1;
}
Layer* create_layer(const char* type) {
// 通过layer name, 获取index, 转而调用create_layer(int index)
int index = layer_to_index(type);
if (index == -1)
return 0;
return create_layer(index);
}
Layer* create_layer(int index) {
if (index < 0 || index >= layer_registry_entry_count)
return 0;
else {
layer_creator = layer_registry[index].creator; // layer_registry_entry.creator 宏定义的函数指针
}
Layer* layer = layer_creator(0); // 创建层
layer->typeindex = index; // 层的类型索引,对应是使用layer_to_index获取的索引
return layer;
}
layer_registy.h,由cmake自动生成:
AbsVal = 0,
ArgMax = 1,
BatchNorm = 2,
Bias = 3,
BNLL = 4,
Concat = 5,
Convolution = 6,
Crop = 7,
Deconvolution = 8,
Dropout = 9,
Eltwise = 10,
ELU = 11,
Embed = 12,
Exp = 13,
Flatten = 14,
InnerProduct = 15,
Input = 16,
Log = 17,
LRN = 18,
MemoryData = 19,
MVN = 20,
Pooling = 21,
...
Fold = 95,
Unfold = 96,
GridSample = 97,
CumulativeSum = 98,
CopyTo = 99,
至于更详细的各种层如何实现对应的forward、load_param和load_model等函数,需要去看src/layers/*.cc下不同layer层的具体实现
参考
https://www.jianshu.com/p/3036c17b6b0e