caffe源码阅读(二) common

  • 主要参考

http://blog.csdn.net/xizero00/article/details/50889126

  • 主要作用
    common的主要作用其实就对caffe的一些部件做初始化,包括实例化caffe,初始化随机数(通过提供随机数生成器)、gflasgs和glog的初始化。这其中,最重要的是随机数生成器的内容
    (1)Generator类
    两个构造函数:
    Generator();用系统的熵池或者时间来初始化随机数
    explicit Generator(unsigned int seed); 用给定的种子初始化
    (2)RNG类
    RNG类内部有generator_,而generator是Generator类的实例,这相当于在类的内部调用其它的类的实例。
    三个构造函数:
    RNG();利用系统的尚池来初始化RNG内部的generator_
    explicit RNG(unsigned int seed);//利用给定的seed来初始化内部的generator_
    explicit RNG(const RNG&);//用其他的RNG内部的generator_设置为当前的generator,这个有什么意义?
    (3)caffe类
    caffe实例到底是一个什么样的实例?难道就是指整个caffe进程吗?
    在caffe::Get()函数中,用了Boost的局部线程存储来初始化caffe实例
    caffe类中的其他函数:
    SetDevice
    DeviceQuery
    mode
    set_mode
    set_random_seed
    solver_count
    set_solver_count
    root_solver
    set_root_solver
    可见在caffe类中,还实现了计算设备的设置,查询等。
    此外,solver_count,set_solver_count,root_solver,set_root_solver这几个和solver相关的变量有什么意义?
    至2016年10月23日,先暂时不解读common部分的代码。以后再说
  • common.hpp部分代码
#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 #1236  
namespace cv { class Mat; }  

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.  
  static Caffe& Get();  

  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();  
    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  

  // 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_
  • common.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是线程局部存储机制  
// 一开始的值是NULL  
static 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和glog  
void 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));  
}  

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的geterrorstring  
const 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的getlasterrorstring  
const 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值