版本: 不详
1. 前言
因为工作关系断断续续阅读了ncnn,mnn的源码,主要是带着学习的想法,去看更多优秀的开源项目。这里对ncnn各种层layer的注册机制进行简单的说明。后面再出mnn的。
我才用的是比较早期的版本,所以可能和最新的版本的有一定的出入。
这里还是推荐使用ncnn的,相对mnn,框架更简洁,二次开发和拓展的难度都要小一些。
2. 具体例子
2.1 注册
整体这就是c++中的动态类注册。
这里我们采用一个简单的网络层relu作为例子。关键代码:
DEFINE_LAYER_CREATOR(ReLU)
ReLU::ReLU()
{
one_blob_only = true;
support_inplace = true;
}
这里关键的就是 DEFINE_LAYER_CREATOR(ReLU)
, 这其实是一个宏定义。具体代码:
#define DEFINE_LAYER_CREATOR(name) \
Layer* name##_layer_creator() { return new name; } // 各类初始化, 这里相当于一个函数
这个宏定义其实就是声明了一个函数,函数没有输入参数, 返回一个指向 layer 的指针。所以,每一个层(conv,relu6,maxpool…)等都会声明一个同样样式的函数。
DEFINE_LAYER_CREATOR(Convolution)
DEFINE_LAYER_CREATOR(Pooling)
DEFINE_LAYER_CREATOR(LSTM)
2.2 使用
前面每个类对应了一个同样样式的函数。在使用的时候,用一个数组存放所有的函数,再配合函数指针来调用不同的类。
这里按ncnn中的调用顺序来说明。
- 从存放函数指针的数组中,取出对应的函数指针:
layer_creator_func layer_creator = layer_registry[index].creator
- layer_registry是一个数组
- layer_creator_func 是一个函数指针类型
typedef Layer* (*layer_creator_func)(); // 函数指针,layer_creator_func是一种新的数据类型
struct layer_registry_entry
{
#if NCNN_STRING
// layer type name
const char* name;
#endif // NCNN_STRING
// layer factory entry
layer_creator_func creator;
};
这里需要看一下c++函数指针,参考:typedef函数指针
- 调用用函数指针,返回layer* 指针
layer_creator_func layer_creator = layer_registry[index].creator; // layer_registry[index].creator相当于函数名,函数指针初始化
if (!layer_creator)
{
fprintf(stderr, "layer index %d not enabled\n", index);
return 0;
}
return layer_creator();
后续再出mnn的解析