http://blog.csdn.net/seven_first/article/details/47378697
https://zhuanlan.zhihu.com/p/25127756?refer=xiaoleimlnote
https://github.com/BUPTLdy/Caffe_Code_Analysis/tree/master/

学习计划

Caffe运行主要流程


caffe.cpp

// A simple registry for caffe commands.
typedef int (*BrewFunction)();
typedef std::map<caffe::string, BrewFunction> BrewMap;
BrewMap g_brew_map;

#define RegisterBrewFunction(func) \
namespace { \
class __Registerer_##func { \
 public: /* NOLINT */ \
  __Registerer_##func() { \
    g_brew_map[#func] = &func; \
  } \
}; \
__Registerer_##func g_registerer_##func; \
}
  • typedef int (*BrewFunction)()
    函数指针:可用于处理一些参数和返回值一致,但是功能不一样一组函数。
    本示例:定义了一组函数指针,函数参数为(),但是返回值为int这样一组函数指针族。
  • typedef std::map<caffe::string, BrewFunction> BrewMap
    定义BrewMap为一个map,key为string,value为函数指针(参数为(),返回为int)。
  • #define RegisterBrewFunction(func)
    该宏命令完成一次注册的初始化操作; 其中在宏中#和##符号表示的意思如下: #:用来把参数转换成字符串;
    ##:用来连接前后两个参数。

以caffe中RegisterBrewFunction(train)为例,上面代码可转换为:

#define RegisterBrewFunction(train) \
namespace { \
class __Registerer_train { \
 public: /* NOLINT */ \
  __Registerer_train() { \
    g_brew_map["train"] = &train; \
  } \
}; \
__Registerer_train g_registerer_train; \
}  //完成了全局变量的初始化操作

接来下看caffe.cpp里的main函数代码

int main(int argc, char** argv) {
  // Print output to stderr (while still logging).
  FLAGS_alsologtostderr = 1;
  // Set version
  gflags::SetVersionString(AS_STRING(CAFFE_VERSION));
  // Usage message.
  gflags::SetUsageMessage("command line brew\n"
      "usage: caffe <command> <args>\n\n"
      "commands:\n"
      "  train           train or finetune a model\n"
      "  test            score a model\n"
      "  device_query    show GPU diagnostic information\n"
      "  time            benchmark model execution time");
  // Run tool or show usage.
  caffe::GlobalInit(&argc, &argv);
  if (argc == 2) {
#ifdef WITH_PYTHON_LAYER
    try {
#endif
      return GetBrewFunction(caffe::string(argv[1]))();
#ifdef WITH_PYTHON_LAYER
    } catch (bp::error_already_set) {
      PyErr_Print();
      return 1;
    }
#endif
  } else {
    gflags::ShowUsageWithFlagsRestrict(argv[0], "tools/caffe");
  }
}

caffe控制台训练示例:caffe train --solver==*.prototxt
输入完全正确的情况下,函数首先进入:

  • return GetBrewFunction(caffe::string(argv[1]))();
static BrewFunction GetBrewFunction(const caffe::string& name) {
  if (g_brew_map.count(name)) {
    return g_brew_map[name];
  } else {
    LOG(ERROR) << "Available caffe actions:";
    for (BrewMap::iterator it = g_brew_map.begin();
         it != g_brew_map.end(); ++it) {
      LOG(ERROR) << "\t" << it->first;
    }
    LOG(FATAL) << "Unknown action: " << name;
    return NULL;  // not reachable, just to suppress old compiler warnings.
  }
}

总结:

  • C++函数指针的应用;函数指针可用于解决 函数参数和返回值一致,但功能不一样的一群函数族
  • 进入主函数前,通过全局变量注册函数的方法;

举例:

#include <iostream>
#include <map>

typedef int (*mathfunc)(int,int);
typedef std::map<std::string, mathfunc> BrepMap;
BrepMap g_brew_map;

#define RegisterMathFunc(func) \
namespace { \
    class __Register_##func{ \
        public: \
            __Register_##func() { g_brew_map[#func] = &func;}};\
    __Register_##func g_register_##func;}

int add(int a, int b){
    return a+b;
}
RegisterMathFunc(add)

int sub(int a, int b){
    return a-b;
}
RegisterMathFunc(sub)

int mul(int a, int b){
    return a*b;
}
RegisterMathFunc(mul)


int main()
{
    std::cout<< "number of register functions: " << g_brew_map.size() << std::endl;
    std::string math_method = "add";
    std::cout << "23 + 12  = " << g_brew_map[math_method](23,12) << std::endl;
    return 1;
}

/*
*******result*******
number of register functions: 3
23 + 12  = 35
*/