Caffe代码解析(4)
Caffe代码解析(4)
在上文对Command Line Interfaces进行了简单的介绍之后,本文将对caffe的Solver相关的代码进行分析。
本文将主要分为四部分的内容:
Solver
的初始化(Register宏和构造函数)SIGINT
和SIGHUP
信号的处理Solver::Solve()
具体实现SGDSolver::ApplyUpdate
具体实现
Solver的初始化(Register宏和构造函数)
shared_ptr<caffe::Solver<float> >
solver(caffe::SolverRegistry<float>::CreateSolver(solver_param));
caffe.cpp中的train函数中通过上面的代码定义了一个指向Solver<float>
的shared_ptr。其中主要是通过调用SolverRegistry
这个类的静态成员函数CreateSolver
得到一个指向Solver
的指针来构造shared_ptr类型的solver
。而且由于C++多态的特性,尽管solver
是一个指向基类Solver
类型的指针,通过solver
这个智能指针来调用各个成员函数会调用到各个子类(SGDSolver
等)的函数。具体的过程如下面的流程图所示:
Create solver
下面我们就来具体看一下SolverRegistry
这个类的代码,以便理解是如何通过同一个函数得到不同类型的Solver:
1 class SolverRegistry {
2 public:
3 typedef Solver<Dtype>* (*Creator)(const SolverParameter&);
4 typedef std::map<string, Creator> CreatorRegistry;
5 static CreatorRegistry& Registry() {
6 static CreatorRegistry* g_registry_ = new CreatorRegistry();
7 return *g_registry_;
8 }
9 static void AddCreator(const string& type, Creator creator) {
10 CreatorRegistry& registry = Registry();
11 CHECK_EQ(registry.count(type), 0)
12 << "Solver type " << type << " already registered.";
13 registry[type] = creator;
14 }
15 static Solver<Dtype>* CreateSolver(const SolverParameter& param) {
16 const string& type = param.type();
17 CreatorRegistry& registry = Registry();
18 CHECK_EQ(registry.count(type), 1) << "Unknown solver type: " << type
19 << " (known types: " << SolverTypeListString() << ")";
20 return registry[type](param);
21 }
22 static vector<string> SolverTypeList() {
23 CreatorRegistry& registry = Registry();
24 vector<string> solver_types;
25 for (typename CreatorRegistry::iterator iter = registry.begin();
26 iter != registry.end(); ++iter) {
27 solver_types.push_back(iter->first);
28 }
29 return solver_types;
30 }
31 private:
32 SolverRegistry() {}
33