梳理caffe代码common(八)

来源:互联网 发布:周润发占中言论 知乎 编辑:程序博客网 时间:2024/06/06 11:42

由于想梳理data_layer的过程,整理一半发现有几个非常重要的头文件就是题目列出的这几个:

追本溯源,先从根基开始学起。这里面都是些什么鬼呢?

common类

命名空间的使用:google、cv、caffe{boost、std}。然后在项目中就可以随意使用google、opencv、c++的标准库、以及c++高级库boost。caffe采用单例模式封装boost的智能指针(caffe的灵魂)、std一些标准的用法、重要的初始化内容(随机数生成器的内容以及google的gflags和glog的初始化)。 提供一个统一的接口,方便移植和开发。为毛使用随机数?我也不是很清楚,知乎的一个解释:

随机数在caffe中是非常重要的,最重要的应用是权值的初始化,如高斯、xavier等,初始化的好坏直接影响最终的训练结果,其他的应用如训练图像的随机crop和mirror、dropout层的神经元的选择。RNG类是对Boost以及STL中随机数函数的封装,以方便使用。至于想每次产生相同的随机数,只要设定固定的种子即可,见caffe.proto中random_seed的定义:
    // If non-negative, the seed with which the Solver will initialize the Caffe
    // random number generator -- useful for reproducible results. Otherwise,
    // (and by default) initialize using a seed derived from the system clock.
    optional int64 random_seed = 20 [default = -1];

头文件:

#ifndef CAFFE_COMMON_HPP_#define CAFFE_COMMON_HPP_#include <boost/shared_ptr.hpp>#include <gflags/gflags.h>#include <glog/logging.h>#include <climits>#include <cmath>#include <fstream>  // NOLINT(readability/streams)#include <iostream>  // NOLINT(readability/streams)#include <map>#include <set>#include <sstream>#include <string>#include <utility>  // pair#include <vector>#include "caffe/util/device_alternate.hpp"// Convert macro to string// 将宏转换为字符串#define STRINGIFY(m) #m#define AS_STRING(m) STRINGIFY(m)// gflags 2.1 issue: namespace google was changed to gflags without warning.// Luckily we will be able to use GFLAGS_GFLAGS_H_ to detect if it is version// 2.1. If yes, we will add a temporary solution to redirect the namespace.// TODO(Yangqing): Once gflags solves the problem in a more elegant way, let's// remove the following hack.// 检测gflags2.1#ifndef GFLAGS_GFLAGS_H_namespace gflags = google;#endif  // GFLAGS_GFLAGS_H_// Disable the copy and assignment operator for a class.// 禁止某个类通过构造函数直接初始化另一个类// 禁止某个类通过赋值来初始化另一个类#define DISABLE_COPY_AND_ASSIGN(classname) \private:\  classname(const classname&);\  classname& operator=(const classname&)// Instantiate a class with float and double specifications.#define INSTANTIATE_CLASS(classname) \  char gInstantiationGuard##classname; \  template class classname<float>; \  template class classname<double>// 初始化GPU的前向传播函数#define INSTANTIATE_LAYER_GPU_FORWARD(classname) \  template void classname<float>::Forward_gpu( \      const std::vector<Blob<float>*>& bottom, \      const std::vector<Blob<float>*>& top); \  template void classname<double>::Forward_gpu( \      const std::vector<Blob<double>*>& bottom, \      const std::vector<Blob<double>*>& top);// 初始化GPU的反向传播函数#define INSTANTIATE_LAYER_GPU_BACKWARD(classname) \  template void classname<float>::Backward_gpu( \      const std::vector<Blob<float>*>& top, \      const std::vector<bool>& propagate_down, \      const std::vector<Blob<float>*>& bottom); \  template void classname<double>::Backward_gpu( \      const std::vector<Blob<double>*>& top, \      const std::vector<bool>& propagate_down, \      const std::vector<Blob<double>*>& bottom)// 初始化GPU的前向反向传播函数#define INSTANTIATE_LAYER_GPU_FUNCS(classname) \  INSTANTIATE_LAYER_GPU_FORWARD(classname); \  INSTANTIATE_LAYER_GPU_BACKWARD(classname)// A simple macro to mark codes that are not implemented, so that when the code// is executed we will see a fatal log.// NOT_IMPLEMENTED实际上调用的LOG(FATAL) << "Not Implemented Yet"#define NOT_IMPLEMENTED LOG(FATAL) << "Not Implemented Yet"// See PR #1236namespace cv { class Mat; }/*Caffe类里面有个RNG,RNG这个类里面还有个Generator类在RNG里面会用到Caffe里面的Get()函数来获取一个新的Caffe类的实例。然后RNG里面用到了Generator。Generator是实际产生随机数的。*/namespace caffe {// We will use the boost shared_ptr instead of the new C++11 one mainly// because cuda does not work (at least now) well with C++11 features.using boost::shared_ptr;// Common functions and classes from std that caffe often uses.using std::fstream;using std::ios;//using std::isnan;//vc++的编译器不支持这两个函数//using std::isinf;using std::iterator;using std::make_pair;using std::map;using std::ostringstream;using std::pair;using std::set;using std::string;using std::stringstream;using std::vector;// A global initialization function that you should call in your main function.// Currently it initializes google flags and google logging.void GlobalInit(int* pargc, char*** pargv);// A singleton class to hold common caffe stuff, such as the handler that// caffe is going to use for cublas, curand, etc.class Caffe { public:  ~Caffe();  // Thread local context for Caffe. Moved to common.cpp instead of  // including boost/thread.hpp to avoid a boost/NVCC issues (#1009, #1010)  // on OSX. Also fails on Linux with CUDA 7.0.18.//Get函数利用Boost的局部线程存储功能实现  static Caffe& Get();//Brew就是CPU,GPU的枚举类型,这个名字是不是来自Homebrew???Mac的软件包管理器,我猜的。。。。  enum Brew { CPU, GPU };  // This random number generator facade hides boost and CUDA rng  // implementation from one another (for cross-platform compatibility).  class RNG {   public:    RNG();//利用系统的熵池或者时间来初始化RNG内部的generator_    explicit RNG(unsigned int seed);    explicit RNG(const RNG&);    RNG& operator=(const RNG&);    void* generator();   private:    class Generator;    shared_ptr<Generator> generator_;  };  // Getters for boost rng, curand, and cublas handles  inline static RNG& rng_stream() {    if (!Get().random_generator_) {      Get().random_generator_.reset(new RNG());    }    return *(Get().random_generator_);  }#ifndef CPU_ONLY// GPU  inline static cublasHandle_t cublas_handle() { return Get().cublas_handle_; }// cublas的句柄  inline static curandGenerator_t curand_generator() {//curandGenerator句柄    return Get().curand_generator_;  }#endif//下面这一块就是设置CPU和GPU以及训练的时候线程并行数目吧  // Returns the mode: running on CPU or GPU.  inline static Brew mode() { return Get().mode_; }  // The setters for the variables  // Sets the mode. It is recommended that you don't change the mode halfway  // into the program since that may cause allocation of pinned memory being  // freed in a non-pinned way, which may cause problems - I haven't verified  // it personally but better to note it here in the header file.  inline static void set_mode(Brew mode) { Get().mode_ = mode; }  // Sets the random seed of both boost and curand  static void set_random_seed(const unsigned int seed);  // Sets the device. Since we have cublas and curand stuff, set device also  // requires us to reset those values.  static void SetDevice(const int device_id);  // Prints the current GPU status.  static void DeviceQuery();  // Parallel training info  inline static int solver_count() { return Get().solver_count_; }  inline static void set_solver_count(int val) { Get().solver_count_ = val; }  inline static bool root_solver() { return Get().root_solver_; }  inline static void set_root_solver(bool val) { Get().root_solver_ = val; } protected:#ifndef CPU_ONLY  cublasHandle_t cublas_handle_;// cublas的句柄   curandGenerator_t curand_generator_;// curandGenerator句柄#endif  shared_ptr<RNG> random_generator_;  Brew mode_;  int solver_count_;  bool root_solver_; private:  // The private constructor to avoid duplicate instantiation.//避免实例化  Caffe();  // 禁止caffe这个类被复制构造函数和赋值进行构造  DISABLE_COPY_AND_ASSIGN(Caffe);};}  // namespace caffe#endif  // CAFFE_COMMON_HPP_
cpp文件:

#include <boost/thread.hpp>#include <glog/logging.h>#include <cmath>#include <cstdio>#include <ctime>#include "caffe/common.hpp"#include "caffe/util/rng.hpp"namespace caffe {// Make sure each thread can have different values.// boost::thread_specific_ptr是线程局部存储机制// 一开始的值是NULLstatic boost::thread_specific_ptr<Caffe> thread_instance_;Caffe& Caffe::Get() {  if (!thread_instance_.get()) {// 如果当前线程没有caffe实例    thread_instance_.reset(new Caffe());// 则新建一个caffe的实例并返回  }  return *(thread_instance_.get());}// random seeding// linux下的熵池下获取随机数的种子int64_t cluster_seedgen(void) {  int64_t s, seed, pid;  FILE* f = fopen("/dev/urandom", "rb");  if (f && fread(&seed, 1, sizeof(seed), f) == sizeof(seed)) {    fclose(f);    return seed;  }  LOG(INFO) << "System entropy source not available, "              "using fallback algorithm to generate seed instead.";  if (f)    fclose(f);  // 采用传统的基于时间来生成随机数种子  pid = getpid();  s = time(NULL);  seed = std::abs(((s * 181) * ((pid - 83) * 359)) % 104729);  return seed;}// 初始化gflags和glogvoid GlobalInit(int* pargc, char*** pargv) {  // Google flags.  ::gflags::ParseCommandLineFlags(pargc, pargv, true);  // Google logging.  ::google::InitGoogleLogging(*(pargv)[0]);  // Provide a backtrace on segfault.  ::google::InstallFailureSignalHandler();}#ifdef CPU_ONLY  // CPU-only Caffe.Caffe::Caffe()    : random_generator_(), mode_(Caffe::CPU),// shared_ptr<RNG> random_generator_;   Brew mode_;      solver_count_(1), root_solver_(true) { }// int solver_count_;   bool root_solver_;Caffe::~Caffe() { }//  手动设定随机数生成器的种子void Caffe::set_random_seed(const unsigned int seed) {  // RNG seed  Get().random_generator_.reset(new RNG(seed));<span style="font-family:Microsoft YaHei;">}</span>void Caffe::SetDevice(const int device_id) {  NO_GPU;}void Caffe::DeviceQuery() {  NO_GPU;}// 定义RNG内部的Generator类class Caffe::RNG::Generator { public:  Generator() : rng_(new caffe::rng_t(cluster_seedgen())) {}// linux下的熵池生成随机数种子,注意typedef boost::mt19937 rng_t;这个在utils/rng.hpp头文件里面  explicit Generator(unsigned int seed) : rng_(new caffe::rng_t(seed)) {}// 采用给定的种子初始化  caffe::rng_t* rng() { return rng_.get(); }// 属性 private:  shared_ptr<caffe::rng_t> rng_;// 内部变量};// 实现RNG内部的构造函数Caffe::RNG::RNG() : generator_(new Generator()) { }Caffe::RNG::RNG(unsigned int seed) : generator_(new Generator(seed)) { }// 实现RNG内部的运算符重载Caffe::RNG& Caffe::RNG::operator=(const RNG& other) {  generator_ = other.generator_;  return *this;}void* Caffe::RNG::generator() {  return static_cast<void*>(generator_->rng());}#else  // Normal GPU + CPU Caffe.// 构造函数,初始化cublas和curand库的句柄Caffe::Caffe()    : cublas_handle_(NULL), curand_generator_(NULL), random_generator_(),    mode_(Caffe::CPU), solver_count_(1), root_solver_(true) {  // Try to create a cublas handler, and report an error if failed (but we will  // keep the program running as one might just want to run CPU code).  // 初始化cublas并获得句柄  if (cublasCreate(&cublas_handle_) != CUBLAS_STATUS_SUCCESS) {    LOG(ERROR) << "Cannot create Cublas handle. Cublas won't be available.";  }  // Try to create a curand handler.  if (curandCreateGenerator(&curand_generator_, CURAND_RNG_PSEUDO_DEFAULT)      != CURAND_STATUS_SUCCESS ||      curandSetPseudoRandomGeneratorSeed(curand_generator_, cluster_seedgen())      != CURAND_STATUS_SUCCESS) {    LOG(ERROR) << "Cannot create Curand generator. Curand won't be available.";  }}Caffe::~Caffe() {  // 销毁句柄  if (cublas_handle_) CUBLAS_CHECK(cublasDestroy(cublas_handle_));  if (curand_generator_) {    CURAND_CHECK(curandDestroyGenerator(curand_generator_));  }}// 初始化CUDA的随机数种子以及cpu的随机数种子void Caffe::set_random_seed(const unsigned int seed) {  // Curand seed  static bool g_curand_availability_logged = false;// 判断是否log了curand的可用性,如果没有则log一次,log之后则再也不log,用的是静态变量  if (Get().curand_generator_) {    // CURAND_CHECK见/utils/device_alternate.hpp中的宏定义    CURAND_CHECK(curandSetPseudoRandomGeneratorSeed(curand_generator(),        seed));    CURAND_CHECK(curandSetGeneratorOffset(curand_generator(), 0));  } else {    if (!g_curand_availability_logged) {        LOG(ERROR) <<            "Curand not available. Skipping setting the curand seed.";        g_curand_availability_logged = true;    }  }  // RNG seed  // CPU code  Get().random_generator_.reset(new RNG(seed));}// 设置GPU设备并初始化句柄以及随机数种子void Caffe::SetDevice(const int device_id) {  int current_device;  CUDA_CHECK(cudaGetDevice(¤t_device));// 获取当前设备id  if (current_device == device_id) {    return;  }  // The call to cudaSetDevice must come before any calls to Get, which  // may perform initialization using the GPU.  // 在Get之前必须先执行cudasetDevice函数  CUDA_CHECK(cudaSetDevice(device_id));  // 清理以前的句柄  if (Get().cublas_handle_) CUBLAS_CHECK(cublasDestroy(Get().cublas_handle_));  if (Get().curand_generator_) {    CURAND_CHECK(curandDestroyGenerator(Get().curand_generator_));  }  // 创建新句柄  CUBLAS_CHECK(cublasCreate(&Get().cublas_handle_));  CURAND_CHECK(curandCreateGenerator(&Get().curand_generator_,      CURAND_RNG_PSEUDO_DEFAULT));  // 设置随机数种子  CURAND_CHECK(curandSetPseudoRandomGeneratorSeed(Get().curand_generator_,      cluster_seedgen()));}// 获取设备信息void Caffe::DeviceQuery() {  cudaDeviceProp prop;  int device;  if (cudaSuccess != cudaGetDevice(&device)) {    printf("No cuda device present.\n");    return;  }  // #define CUDA_CHECK(condition) \  /* Code block avoids redefinition of cudaError_t error */ \  //do { \  //  cudaError_t error = condition; \  //  CHECK_EQ(error, cudaSuccess) << " " << cudaGetErrorString(error); \  //} while (0)  CUDA_CHECK(cudaGetDeviceProperties(&prop, device));  LOG(INFO) << "Device id:                     " << device;  LOG(INFO) << "Major revision number:         " << prop.major;  LOG(INFO) << "Minor revision number:         " << prop.minor;  LOG(INFO) << "Name:                          " << prop.name;  LOG(INFO) << "Total global memory:           " << prop.totalGlobalMem;  LOG(INFO) << "Total shared memory per block: " << prop.sharedMemPerBlock;  LOG(INFO) << "Total registers per block:     " << prop.regsPerBlock;  LOG(INFO) << "Warp size:                     " << prop.warpSize;  LOG(INFO) << "Maximum memory pitch:          " << prop.memPitch;  LOG(INFO) << "Maximum threads per block:     " << prop.maxThreadsPerBlock;  LOG(INFO) << "Maximum dimension of block:    "      << prop.maxThreadsDim[0] << ", " << prop.maxThreadsDim[1] << ", "      << prop.maxThreadsDim[2];  LOG(INFO) << "Maximum dimension of grid:     "      << prop.maxGridSize[0] << ", " << prop.maxGridSize[1] << ", "      << prop.maxGridSize[2];  LOG(INFO) << "Clock rate:                    " << prop.clockRate;  LOG(INFO) << "Total constant memory:         " << prop.totalConstMem;  LOG(INFO) << "Texture alignment:             " << prop.textureAlignment;  LOG(INFO) << "Concurrent copy and execution: "      << (prop.deviceOverlap ? "Yes" : "No");  LOG(INFO) << "Number of multiprocessors:     " << prop.multiProcessorCount;  LOG(INFO) << "Kernel execution timeout:      "      << (prop.kernelExecTimeoutEnabled ? "Yes" : "No");  return;}class Caffe::RNG::Generator { public:  Generator() : rng_(new caffe::rng_t(cluster_seedgen())) {}  explicit Generator(unsigned int seed) : rng_(new caffe::rng_t(seed)) {}  caffe::rng_t* rng() { return rng_.get(); } private:  shared_ptr<caffe::rng_t> rng_;};Caffe::RNG::RNG() : generator_(new Generator()) { }Caffe::RNG::RNG(unsigned int seed) : generator_(new Generator(seed)) { }Caffe::RNG& Caffe::RNG::operator=(const RNG& other) {  generator_.reset(other.generator_.get());  return *this;}void* Caffe::RNG::generator() {  return static_cast<void*>(generator_->rng());}// cublas的geterrorstringconst char* cublasGetErrorString(cublasStatus_t error) {  switch (error) {  case CUBLAS_STATUS_SUCCESS:    return "CUBLAS_STATUS_SUCCESS";  case CUBLAS_STATUS_NOT_INITIALIZED:    return "CUBLAS_STATUS_NOT_INITIALIZED";  case CUBLAS_STATUS_ALLOC_FAILED:    return "CUBLAS_STATUS_ALLOC_FAILED";  case CUBLAS_STATUS_INVALID_VALUE:    return "CUBLAS_STATUS_INVALID_VALUE";  case CUBLAS_STATUS_ARCH_MISMATCH:    return "CUBLAS_STATUS_ARCH_MISMATCH";  case CUBLAS_STATUS_MAPPING_ERROR:    return "CUBLAS_STATUS_MAPPING_ERROR";  case CUBLAS_STATUS_EXECUTION_FAILED:    return "CUBLAS_STATUS_EXECUTION_FAILED";  case CUBLAS_STATUS_INTERNAL_ERROR:    return "CUBLAS_STATUS_INTERNAL_ERROR";#if CUDA_VERSION >= 6000  case CUBLAS_STATUS_NOT_SUPPORTED:    return "CUBLAS_STATUS_NOT_SUPPORTED";#endif#if CUDA_VERSION >= 6050  case CUBLAS_STATUS_LICENSE_ERROR:    return "CUBLAS_STATUS_LICENSE_ERROR";#endif  }  return "Unknown cublas status";}// curand的getlasterrorstringconst char* curandGetErrorString(curandStatus_t error) {  switch (error) {  case CURAND_STATUS_SUCCESS:    return "CURAND_STATUS_SUCCESS";  case CURAND_STATUS_VERSION_MISMATCH:    return "CURAND_STATUS_VERSION_MISMATCH";  case CURAND_STATUS_NOT_INITIALIZED:    return "CURAND_STATUS_NOT_INITIALIZED";  case CURAND_STATUS_ALLOCATION_FAILED:    return "CURAND_STATUS_ALLOCATION_FAILED";  case CURAND_STATUS_TYPE_ERROR:    return "CURAND_STATUS_TYPE_ERROR";  case CURAND_STATUS_OUT_OF_RANGE:    return "CURAND_STATUS_OUT_OF_RANGE";  case CURAND_STATUS_LENGTH_NOT_MULTIPLE:    return "CURAND_STATUS_LENGTH_NOT_MULTIPLE";  case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED:    return "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED";  case CURAND_STATUS_LAUNCH_FAILURE:    return "CURAND_STATUS_LAUNCH_FAILURE";  case CURAND_STATUS_PREEXISTING_FAILURE:    return "CURAND_STATUS_PREEXISTING_FAILURE";  case CURAND_STATUS_INITIALIZATION_FAILED:    return "CURAND_STATUS_INITIALIZATION_FAILED";  case CURAND_STATUS_ARCH_MISMATCH:    return "CURAND_STATUS_ARCH_MISMATCH";  case CURAND_STATUS_INTERNAL_ERROR:    return "CURAND_STATUS_INTERNAL_ERROR";  }  return "Unknown curand status";}#endif  // CPU_ONLY}  // namespace caffe

0 0
原创粉丝点击