Caffe源码(caffe version:09868ac , date: 2015.08.15)中的一些重要头文件如caffe.hpp、blob.hpp等或者外部调用Caffe库使用时,一般都会include<caffe/common.hpp>文件,下面分析此文件的内容:
1. include的文件:
boost中的智能指针头文件<boost/shared_ptr.hpp>,作用类似于C++11中的模板类shared_ptr,通过引用计数方式自动释放所指的对象,不用显示执行delete,关于C++11中shared_ptr的使用可以参考http://blog.****.net/fengbingchun/article/details/52202007 .
在Caffe中,封装boost的智能指针using boost::shared_ptr,不使用C++11中的shared_ptr。
GFlags库的<gflags/gflags.h>,它是google的一个开源的处理命令行参数的库,其使用可以参考 http://blog.****.net/fengbingchun/article/details/48768039 。
GLog库的<glog/logging.h>,它是google的一个开源的日志库,其使用可以参考 http://blog.****.net/fengbingchun/article/details/48768039 。
一些系统头文件,如<climits>、<cmath>、<utility>等。
< caffe/util/device_alternate.hpp >文件。
2. caffe/util/device_alternate.hpp文件:
定义了一些在CPU或GPU+CPU模式下使用的宏和函数。
在CPU模式下(通过#ifdef CPU_ONLY)定义了四个宏用于提示在CPU模式下如果调用GPU函数给出error信息:
#define NO_GPU #define STUB_GPU(classname) #define STUB_GPU_FORWARD(classname, funcname) #define STUB_GPU_BACKWARD(classname, funcname)
在GPU+CPU模式下定义了五个cuda宏、三个函数和一个常量:
#define CUDA_CHECK(condition) #define CUBLAS_CHECK(condition) #define CURAND_CHECK(condition) #define CUDA_KERNEL_LOOP #define CUDA_POST_KERNEL_CHECK const char* cublasGetErrorString(cublasStatus_t error); const char* curandGetErrorString(curandStatus_t error); inline int CAFFE_GET_BLOCKS(const int N); const int CAFFE_CUDA_NUM_THREADS;
3. common.hpp文件中定义的宏:
#define DISABLE_COPY_AND_ASSIGN(classname) #define INSTANTIATE_CLASS(classname) #define INSTANTIATE_LAYER_GPU_FORWARD #define INSTANTIATE_LAYER_GPU_BACKWARD #define INSTANTIATE_LAYER_GPU_FUNCS #define NOT_IMPLEMENTED
其中宏DISABLE_COPY_AND_ASSIGN的作用是禁用指定类的拷贝和赋值操作;宏NOT_IMPLEMENTED的作用是标记没有实现的代码,并给出fatal log;宏INSTANTIATE_CLASS的作用是用于实例化指定的模板类(类模板显示实例化);剩余的三个宏的作用是用于GPU模式下实例化指定的模板类的函数(GPU forward/backward,类似于函数模板显示实例化)。
关于模板显示实例化的介绍可以参考:http://blog.****.net/fengbingchun/article/details/51339659
4. GlobalInit函数:
全局初始化函数,用于初始化google开源库gflags(gflags::ParseCommandLineFlags)和glog(google::InitGoogleLogging)。
5. Caffe类:
(1)、采用单例模式(singleton)实现,封装了boost和cuda的一些操作,提供了一套统一的接口,关于单例模式的内容可以参考: http://blog.****.net/fengbingchun/article/details/22584107 。
(2)、内部定义了嵌套类RNG,RNG类内部又定义了私有嵌套类Generator,Generator类用于产生随机数.RNG类为随机数生成器,隐藏了boost和CUDA的rng实现,对外提供了一套统一的RNG类。
(3)、构造函数为private,防止直接通过构造函数创建对象,也可防止重复实例化。
(4)、禁止执行拷贝和赋值操作。
(5)、通过Get方法来创建或获取实例。
(6)、枚举类型Brew,指定运行模式:CPU、GPU。
以下是common文件的测试代码:
int test_caffe_common() { // 1. test macro NOT_IMPLEMENTED //NOT_IMPLEMENTED; // error, fatal log // 2. test global initialization function GlobalInit int argc = 2; char** argv = nullptr; argv = new char*[2]; #ifdef _DEBUG argv[0] = "E:/GitCode/Caffe_Test/lib/dbg/x64_vc12/Caffe_Test.exe"; #else argv[0] = "E:/GitCode/Caffe_Test/lib/rel/x64_vc12/Caffe_Test.exe"; #endif argv[1] = "caffe_test"; caffe::GlobalInit(&argc, &argv); delete[] argv; // 3. test caffe class // caffe::Caffe caffe_; // error, can't create Caffe object directly // verify Caffe is a singleton class caffe::Caffe& caffe1 = caffe::Caffe::Get(); caffe::Caffe& caffe2 = caffe::Caffe::Get(); fprintf(stderr, "caffe1 addr: %p\n", &caffe1); fprintf(stderr, "caffe2 addr: %p\n", &caffe2); auto addr_caffe1 = std::addressof(caffe1); auto addr_caffe2 = std::addressof(caffe2); if (addr_caffe1 != addr_caffe2) { fprintf(stderr, "caffe1 and caffe2 addr are different: caffe1 addr: %p, caffe2 addr: %p\n", &caffe1, &caffe2); return -1; } // get run mode: CPU or GPU caffe::Caffe::Brew run_mode = caffe1.mode(); fprintf(stderr, "0: CPU, 1: GPU, run_mode: %d\n", run_mode); // set solver_count caffe::Caffe::set_solver_count(5); // get solver_count int solver_count = caffe::Caffe::solver_count(); fprintf(stderr, "solver count: %d\n", solver_count); // set root_solver caffe::Caffe::set_root_solver(false); // get root_solver bool root_solver = caffe::Caffe::root_solver(); fprintf(stderr, "root solver: %d\n", root_solver); // set device // caffe::Caffe::SetDevice(2); // error, fatal log: Cannot use GPU in CPU-only Caffe: check mode. // device query // caffe::Caffe::DeviceQuery(); // error, fatal log: Cannot use GPU in CPU-only Caffe: check mode. // RNG: generate random number caffe::SyncedMemory data_a(10 * sizeof(int)); caffe::Caffe::set_random_seed(8888); caffe::caffe_rng_bernoulli(10, 0.5, static_cast<int*>(data_a.mutable_cpu_data())); caffe::SyncedMemory data_b(10 * sizeof(int)); caffe::Caffe::set_random_seed(8888); caffe::caffe_rng_bernoulli(10, 0.5, static_cast<int*>(data_b.mutable_cpu_data())); for (int i = 0; i < 10; ++i) { fprintf(stderr, "%d, %d\n", static_cast<const int*>(data_a.cpu_data())[i], static_cast<const int*>(data_b.cpu_data())[i]); if (static_cast<const int*>(data_a.cpu_data())[i] != static_cast<const int*>(data_b.cpu_data())[i]) { fprintf(stderr, "same seed should be generate same random number\n"); return - 1; } } // set run mode caffe::Caffe::set_mode(caffe::Caffe::GPU); run_mode = caffe1.mode(); fprintf(stderr, "0: CPU, 1: GPU, run_mode: %d\n", run_mode); return 0; }
执行结果如下图: