版本: 不详

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中的调用顺序来说明。

  1. 从存放函数指针的数组中,取出对应的函数指针:
    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函数指针

  1. 调用用函数指针,返回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的解析