Tic商业评论

关注微信公众号【站长自定义模块】,定时推送前沿、专业、深度的商业资讯。

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

  • QQ空间
  • 回复
  • 收藏

caffe 里的工厂模式

lijingle 深度学习 2022-5-12 15:54 1477人围观

在caffe里总共使用了3次工厂模式,一次是开始训练时的train,test函数中使用的,第二次是layer注册的使用,第三次是调用solver时使用的。这里我们来介绍下layer注册时的工厂模式。使用工厂模式主要是对layer层可以很好的管理,在添加新的层时,不需要关注其他的代码,只需要添加自己添加的层的代码,方便代码扩展。但是也有缺点,就是在阅读代码时,让很多新手读不懂。里面使用了很多c++高级语言特性,这里稍微介绍下。


1.什么是工厂模式

工厂模式简单来说就是,封装通用的东西,不同的东西进入工厂,可以生产不同的产品。例如,有一个基类product,两个子类shoes,clothes,都继承product。现在需要一个函数,要求返回product的实例,同时要求:传入shoes返回shoes类对象,传入clothes返回clothes对象。这样我们使用if就可以了:

class Product{};
class shoes:Product{};
class clothes:Product{};
Product* make(string what){
    if(what=="shoes") return new shoes();
    if(what=="clothes") return new clothes();
    return null;
}


这就是工厂模式,函数能跟进不同的参数,实例化不同的子类对象,但是如果子类比较多,就会比较乱。就会对目前的简单工厂模式进行改进。


2,layer注册REGISTER_LAYER_CLASS(XXX)

在每个XXXLayer的cpp中,都有一个REGISTER_LAYER_CLASS的宏,正是这个宏,才使得caffe能找到并实例化相应的layer类。定义是在layer_factory.hpp中,是这样的:

#define REGISTER_LAYER_CLASS(type)                                             \
  template <typename Dtype>                                                    \
  shared_ptr<Layer<Dtype> > Creator_##type##Layer(const LayerParameter& param) \
  {                                                                            \
    return shared_ptr<Layer<Dtype> >(new type##Layer<Dtype>(param));           \
  }                                                                            \
  REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)


这里##是宏的一些语法,表示把宏参数和##前后的内容连起来。例如我们自己定义MyAwesomeLayer层,就会加上REGISTER_LAYER_CLASS(MyAwesome)。代码相当于:

template <typename Dtype>                                                    
shared_ptr<Layer<Dtype> > Creator_MyAwesomeLayer(const LayerParameter& param){                                                                            
	return shared_ptr<Layer<Dtype> >(new MyAwesomeLayer<Dtype>(param));           
}


REGISTER_LAYER_CREATOR(MyAwesome, Creator_MyAwesomeLayer)


上面两个代码块,第一个是实例化相应的层,第二块是定义了一个宏:

#define REGISTER_LAYER_CREATOR(type, creator)                                  \
  static LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \
  static LayerRegisterer<double> g_creator_d_##type(#type, creator<double>);   \


这里#它代表把宏的参数变成字符串。具体到这里,就等于写了以下代码:

static LayerRegisterer<float> g_creator_f_MyAwesome("MyAwesome", Creator_MyAwesomeLayer<float>);
static LayerRegisterer<double> g_creator_d_MyAwesome("MyAwesome", Creator_MyAwesomeLayer<double>);


这里创建了两个LayerRegisterer类的静态对象,给构造函数传了两个参数。一个是字符串,是我们的Layer的名字,另一个是刚刚创建的Creator_MyAwesomeLayer方法的函数指针。创建这两个对象是在做什么呢?看它们的定义:

template <typename Dtype>
class LayerRegisterer {
public:
  LayerRegisterer(const string& type,
                  shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) {
    // LOG(INFO) << "Registering layer type: " << type;
    LayerRegistry<Dtype>::AddCreator(type, creator);
  }
};


其实创建它们的过程不过是调用了AddCreator这个函数,把传入的字符串和函数指针又传给了它。

// Adds a creator.
  static void AddCreator(const string& type, Creator creator) {
    CreatorRegistry& registry = Registry();
    CHECK_EQ(registry.count(type), 0)
        << "Layer type " << type << " already registered.";
    registry[type] = creator;
  }


这里面是通过Registry方法拿到了一个registry指针,关键步骤是:registry["MyAwesome"] = creator。这看着像是一个类似Python里的字典的东西,也就是个哈希表,键是Layer的类型,值是一个能返回这个Layer对象的函数。继续找Registry的定义:

typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&);
  typedef std::map<string, Creator> CreatorRegistry;
 
  static CreatorRegistry& Registry() {
    static CreatorRegistry* g_registry_ = new CreatorRegistry();
    return *g_registry_;
  }

这里我们看到static CreatorRegistry* g_registry_ = new CreatorRegistry();是进行实例化,但是前面添加了static。最初执行了一次,g_registry_放在静态内存里,函数结束了是不会消失的!后面每次调用并不会执行new,返回的都是同一个东西的指针!

另外,typedef shared_ptr<Layer<Dtype>> (*Creator)(const LayerParameter&)这句话也有点莫名其妙,这个typedef是啥意思。其实,这和typedef int MYINT是类似的。后者是给int类起了个别名叫MYINT,然后就能这样写:MYINT a=10; 前者其实是给一类函数指针起了个别名,这类函数指针都是以LayerParameter&做参数,返回shared_ptr<<Layer<Dtype>>。 假如这样写: Creator pcreator;, 那pcreator就是一个这样的函数指针了。


路过

雷人

握手

鲜花

鸡蛋
我有话说......
电话咨询: 135xxxxxxx
关注微信