Caffe框架源码剖析(7)—全连接层InnerProductLayer

全连接层InnerProductLayer的原理很简单,说白了就是矩阵乘法运算。正向传导时输出数据等于输入数据乘上权重,如果有偏置项就再加上偏置项。写成公式就是:


    矩阵乘法在CPU端采用OpenBLAS实现,在GPU端则采用NVIDIA cuBLAS实现加速。

    inner_product_layer.hpp定义如下,

[cpp] view plain copy
  1. template <typename Dtype>  
  2. class InnerProductLayer : public Layer {  
  3.  public:  
  4.   explicit InnerProductLayer(const LayerParameter& param)  
  5.       : Layer(param) {}  
  6.   virtual void LayerSetUp(const vector*>& bottom,  
  7.       const vector*>& top);  
  8.   virtual void Reshape(const vector*>& bottom,  
  9.       const vector*>& top);  
  10.   
  11.   virtual inline const char* type() const { return "InnerProduct"; }  
  12.   virtual inline int ExactNumBottomBlobs() const { return 1; }  
  13.   virtual inline int ExactNumTopBlobs() const { return 1; }  
  14.   
  15.  protected:  
  16.   virtual void Forward_cpu(const vector*>& bottom,  
  17.       const vector*>& top);  
  18.   virtual void Forward_gpu(const vector*>& bottom,  
  19.       const vector*>& top);  
  20.   virtual void Backward_cpu(const vector*>& top,  
  21.       const vector<bool>& propagate_down, const vector*>& bottom);  
  22.   virtual void Backward_gpu(const vector*>& top,  
  23.       const vector<bool>& propagate_down, const vector*>& bottom);  
  24.   
  25.   // 矩阵乘法参数(M, K) * (K, N) = (M, N)  
  26.   int M_;  // 输入数据的数量, 即patch_size  
  27.   int K_;  // 单个输入数据包含的元素个数  
  28.   int N_;  // 输出层的神经元个数  
  29.   // 是否包含偏置项  
  30.   bool bias_term_;  
  31.   // 偏置项乘子  
  32.   Blob bias_multiplier_;  
  33.   // 是否转置  
  34.   bool transpose_;  ///< if true, assume transposed weights  
  35. };  

inner_product_layer.cpp定义如下,

[cpp] view plain copy
  1. template <typename Dtype>  
  2. void InnerProductLayer::LayerSetUp(const vector*>& bottom,  
  3.       const vector*>& top) {  
  4.   const int num_output = this->layer_param_.inner_product_param().num_output();  
  5.   bias_term_ = this->layer_param_.inner_product_param().bias_term();  
  6.   transpose_ = this->layer_param_.inner_product_param().transpose();  
  7.   N_ = num_output;  
  8.   const int axis = bottom[0]->CanonicalAxisIndex(  
  9.       this->layer_param_.inner_product_param().axis());  
  10.   // 如果输入图像的维度是(N, C, H, W),则K_ = C * H * W  
  11.   K_ = bottom[0]->count(axis);  
  12.   // 确认是否需要初始化权重  
  13.   if (this->blobs_.size() > 0) {  
  14.     LOG(INFO) << "Skipping parameter initialization";  
  15.   } else {  
  16.     if (bias_term_) {  
  17.       // 如果包含偏置项,则将blobs_的size设为2  
  18.       this->blobs_.resize(2);  
  19.     } else {  
  20.       this->blobs_.resize(1);  
  21.     }  
  22.     // 设置权重的维度  
  23.     vector<int> weight_shape(2);  
  24.     if (transpose_) {  
  25.       weight_shape[0] = K_;  
  26.       weight_shape[1] = N_;  
  27.     } else {  
  28.       weight_shape[0] = N_;  
  29.       weight_shape[1] = K_;  
  30.     }  
  31.     this->blobs_[0].reset(new Blob(weight_shape));  
  32.     // 初始化权重(使用xavier初始化方法)  
  33.     shared_ptr > weight_filler(GetFiller(  
  34.         this->layer_param_.inner_product_param().weight_filler()));  
  35.     weight_filler->Fill(this->blobs_[0].get());  
  36.     // 如果包含偏置项,则将偏置项初始化为0  
  37.     if (bias_term_) {  
  38.       vector<int> bias_shape(1, N_);  
  39.       this->blobs_[1].reset(new Blob(bias_shape));  
  40.       shared_ptr > bias_filler(GetFiller(  
  41.           this->layer_param_.inner_product_param().bias_filler()));  
  42.       bias_filler->Fill(this->blobs_[1].get());  
  43.     }  
  44.   }  // parameter initialization  
  45.   this->param_propagate_down_.resize(this->blobs_.size(), true);  
  46. }  
  47.   
  48. template <typename Dtype>  
  49. void InnerProductLayer::Reshape(const vector*>& bottom,  
  50.       const vector*>& top) {  
  51.   // 确认维度  
  52.   const int axis = bottom[0]->CanonicalAxisIndex(  
  53.       this->layer_param_.inner_product_param().axis());  
  54.   const int new_K = bottom[0]->count(axis);  
  55.   CHECK_EQ(K_, new_K)  
  56.       << "Input size incompatible with inner product parameters.";  
  57.   // M_等于patch_size  
  58.   M_ = bottom[0]->count(0, axis);  
  59.   // 将输出项top[0]的维度置为(patch_size, N_)  
  60.   vector<int> top_shape = bottom[0]->shape();  
  61.   top_shape.resize(axis + 1);  
  62.   top_shape[axis] = N_;  
  63.   top[0]->Reshape(top_shape);  
  64.   // 设置偏置项乘子  
  65.   if (bias_term_) {  
  66.     vector<int> bias_shape(1, M_);  
  67.     bias_multiplier_.Reshape(bias_shape);  
  68.     // 将偏置项乘子bias_multiplier_初始化为1  
  69.     caffe_set(M_, Dtype(1), bias_multiplier_.mutable_cpu_data());  
  70.   }  
  71. }  
  72.   
  73. // CPU正向传导  
  74. template <typename Dtype>  
  75. void InnerProductLayer::Forward_cpu(const vector*>& bottom,  
  76.     const vector*>& top) {  
  77.   const Dtype* bottom_data = bottom[0]->cpu_data();  
  78.   Dtype* top_data = top[0]->mutable_cpu_data();  
  79.   const Dtype* weight = this->blobs_[0]->cpu_data();  
  80.   // bottom_data为M*K矩阵,权重为K*N矩阵,top_data为M*N矩阵  
  81.   // top_data = bottom_data * weight  
  82.   caffe_cpu_gemm(CblasNoTrans, transpose_ ? CblasNoTrans : CblasTrans,  
  83.       M_, N_, K_, (Dtype)1.,  
  84.       bottom_data, weight, (Dtype)0., top_data);  
  85.   // 如果包含有偏置项  
  86.   if (bias_term_) {  
  87.     // top_data += bias_multiplier * bias  
  88.     caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype)1.,  
  89.         bias_multiplier_.cpu_data(),  
  90.         this->blobs_[1]->cpu_data(), (Dtype)1., top_data);  
  91.   }  
  92.   // 因此两步合并的结果就是 top_data = bottom_data * weight + bias_multiplier * bias  
  93. }  
  94.   
  95. // CPU反向传导  
  96. template <typename Dtype>  
  97. void InnerProductLayer::Backward_cpu(const vector*>& top,  
  98.     const vector<bool>& propagate_down,  
  99.     const vector*>& bottom) {  
  100.   if (this->param_propagate_down_[0]) {  
  101.     const Dtype* top_diff = top[0]->cpu_diff();  
  102.     const Dtype* bottom_data = bottom[0]->cpu_data();  
  103.     // 求权重的偏导,weight_diff += top_diff * bottom_data  
  104.     if (transpose_) {  
  105.       caffe_cpu_gemm(CblasTrans, CblasNoTrans,  
  106.           K_, N_, M_,  
  107.           (Dtype)1., bottom_data, top_diff,  
  108.           (Dtype)1., this->blobs_[0]->mutable_cpu_diff());  
  109.     } else {  
  110.       caffe_cpu_gemm(CblasTrans, CblasNoTrans,  
  111.           N_, K_, M_,  
  112.           (Dtype)1., top_diff, bottom_data,  
  113.           (Dtype)1., this->blobs_[0]->mutable_cpu_diff());  
  114.     }  
  115.   }  
  116.   // 求偏置项的偏导,bias_diff += top_diff * bias_multiplier  
  117.   if (bias_term_ && this->param_propagate_down_[1]) {  
  118.     const Dtype* top_diff = top[0]->cpu_diff();  
  119.     // Gradient with respect to bias  
  120.     caffe_cpu_gemv(CblasTrans, M_, N_, (Dtype)1., top_diff,  
  121.         bias_multiplier_.cpu_data(), (Dtype)1.,  
  122.         this->blobs_[1]->mutable_cpu_diff());  
  123.   }  
  124.   if (propagate_down[0]) {  
  125.     const Dtype* top_diff = top[0]->cpu_diff();  
  126.     // 求bottom数据的偏导,bottom_data_diff = top_diff * weight  
  127.     if (transpose_) {  
  128.       caffe_cpu_gemm(CblasNoTrans, CblasTrans,  
  129.           M_, K_, N_,  
  130.           (Dtype)1., top_diff, this->blobs_[0]->cpu_data(),  
  131.           (Dtype)0., bottom[0]->mutable_cpu_diff());  
  132.     } else {  
  133.       caffe_cpu_gemm(CblasNoTrans, CblasNoTrans,  
  134.           M_, K_, N_,  
  135.           (Dtype)1., top_diff, this->blobs_[0]->cpu_data(),  
  136.           (Dtype)0., bottom[0]->mutable_cpu_diff());  
  137.     }  
  138.   }  
  139. }  
  140.   
  141. // 如果CPU_ONLY模式则禁止Forward_gpu和Backward_gpu函数  
  142. #ifdef CPU_ONLY  
  143. STUB_GPU(InnerProductLayer);  
  144. #endif 

你可能感兴趣的:(deep,learning)