代码先锋网 代码片段及技术文章聚合

caffe源码 之 dropout层

本文转载自:http://blog.csdn.net/lanxueCC/article/details/53319872?locationNum=2&fps=1

本文主要解析caffe源码文件/src/caffe/layers/Dropout_layer.cpp,该文件实现的功能是防止过拟合。

综述 
dropout层的作用是防止训练的时候过拟合。在训练的时候,传统的训练方法是每次迭代经过某一层时,将所有的结点拿来做参与更新,训练整个网络。加入dropout层,我们只需要按一定的概率(retaining probability)p 来对weight layer 的参数进行随机采样,将被采样的结点拿来参与更新,将这个子网络作为此次更新的目标网络。这样做的好处是,由于随机的让一些节点不工作了,因此可以避免某些特征只在固定组合下才生效,有意识地让网络去学习一些普遍的共性(而不是某些训练样本的一些特性)这样能提高训练出的模型的鲁棒性!!!

下面记录下我在看dropout层时的注释,如有错误,请指出~~~

Dropout_layer.hpp

#ifndef CAFFE_DROPOUT_LAYER_HPP_
#define CAFFE_DROPOUT_LAYER_HPP_

#include <vector>

#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"

#include "caffe/layers/neuron_layer.hpp"

namespace caffe {

/**
 * @brief During training only, sets a random portion of @f$x@f$ to 0, adjusting
 *        the rest of the vector magnitude accordingly.
 *
 * @param bottom input Blob vector (length 1)
 *   -# @f$ (N \times C \times H \times W) @f$
 *      the inputs @f$ x @f$
 * @param top output Blob vector (length 1)
 *   -# @f$ (N \times C \times H \times W) @f$
 *      the computed outputs @f$ y = |x| @f$
 */
 /*DropoutLayer类继承了类NeuronLayer类*/
template <typename Dtype>
class DropoutLayer : public NeuronLayer<Dtype> {
 public:
  /**
   * @param param provides DropoutParameter dropout_param,
   *     with DropoutLayer options:
   *   - dropout_ratio (\b optional, default 0.5).
   *     Sets the probability @f$ p @f$ that any given unit is dropped.
   */
   /*构造函数*/
  explicit DropoutLayer(const LayerParameter& param)
      : NeuronLayer<Dtype>(param) {}
  /*设置函数*/
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  /*内存分配与输入输出数据形状reshape函数*/
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

  /*返回当前层的类型*/
  virtual inline const char* type() const { return "Dropout"; }

 protected:
  /**
   * @param bottom input Blob vector (length 1)
   *   -# @f$ (N \times C \times H \times W) @f$
   *      the inputs @f$ x @f$
   * @param top output Blob vector (length 1)
   *   -# @f$ (N \times C \times H \times W) @f$
   *      the computed outputs. At training time, we have @f$
   *      y_{\mbox{train}} = \left\{
   *         \begin{array}{ll}
   *            \frac{x}{1 - p} & \mbox{if } u > p \\
   *            0 & \mbox{otherwise}
   *         \end{array} \right.
   *      @f$, where @f$ u \sim U(0, 1)@f$ is generated independently for each
   *      input at each iteration. At test time, we simply have
   *      @f$ y_{\mbox{test}} = \mathbb{E}[y_{\mbox{train}}] = x @f$.
   */
   /*cpu前向传播函数*/
  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  /*gpu前向传播函数*/
  virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  /*cpu返向传播函数*/
  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);

  /*gpu返回传播函数*/
  virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);

  /// when divided by UINT_MAX, the randomly generated values @f$u\sim U(0,1)@f$
  /*blob类型的,保存伯努利二项分布的随机数的变量*/
  Blob<unsigned int> rand_vec_;
  /// the probability @f$ p @f$ of dropping any input
  /*数据被dropout(意思就是迭代的某次训练不用)的概率*/
  Dtype threshold_;
  /// the scale for undropped inputs at train time @f$ 1 / (1 - p) @f$
  /*scale_ == 1 / (1 - threshold_)*/
  Dtype scale_;
  /*没有具体用到,不知其何意*/
  unsigned int uint_thres_;
};

}  // namespace caffe

#endif  // CAFFE_DROPOUT_LAYER_HPP_

Dropout_layer.cpp

// TODO (sergeyk): effect should not be dependent on phase. wasted memcpy.

#include <vector>

#include "caffe/layers/dropout_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

/*设置dropout层对象,先调用NeuronLayer类完成基本设置*/
template <typename Dtype>
void DropoutLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  NeuronLayer<Dtype>::LayerSetUp(bottom, top);
  /*protobuf文件中传入的dropout的概率,也就是当前去除掉threshold_概率个数据不用*/
  /*因为是有放回的随机去除掉threshold_概率个数据,那么每个数据被去除的概率为threshold_*/
  threshold_ = this->layer_param_.dropout_param().dropout_ratio();
  DCHECK(threshold_ > 0.);
  DCHECK(threshold_ < 1.);
  /*(1. - threshold_)是这个数据被取用的概率*/
  scale_ = 1. / (1. - threshold_);
  uint_thres_ = static_cast<unsigned int>(UINT_MAX * threshold_);/*貌似没有用到*/
}

/*形状reshape和内存分配,同理先调用NeuronLayer类的Reshape函数完成基本的top与bottom数据的reshape*/
template <typename Dtype>
void DropoutLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  NeuronLayer<Dtype>::Reshape(bottom, top);
  // Set up the cache for random number generation
  // ReshapeLike does not work because rand_vec_ is of Dtype uint
  //这个类要单独分配一段内存用来存储满足伯努利分布的随机数
  rand_vec_.Reshape(bottom[0]->shape());
}

/*dropout层的前向传播*/
template <typename Dtype>
void DropoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();/*前面一层数据内存地址(输入数据)*/
  Dtype* top_data = top[0]->mutable_cpu_data();/*后面一层数据内存地址(输出数据)*/
  unsigned int* mask = rand_vec_.mutable_cpu_data();/*伯努利分布的随机数的内存地址*/
  const int count = bottom[0]->count();/*输入数据blob个数*/
  if (this->phase_ == TRAIN) {/*当前处在训练阶段*/
    // Create random numbers
    caffe_rng_bernoulli(count, 1. - threshold_, mask); /*产生伯努利随机数*/
    for (int i = 0; i < count; ++i) {
      top_data[i] = bottom_data[i] * mask[i] * scale_;  /*遍历每个数据在满足伯努利分布的下的输出值*/
    }
  } else {
    caffe_copy(bottom[0]->count(), bottom_data, top_data); /*测试阶段每个数据都要输出*/
  }
}

/*dropout层的后向传播*/
template <typename Dtype>
void DropoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down,  /*这个向量记录当前数据了是否进行返向传播*/
    const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[0]) {/*如果进行反向传播*/
    const Dtype* top_diff = top[0]->cpu_diff();/*后面一层梯度(输入数据)*/
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();/*前面一层梯度(输入数据)*/
    if (this->phase_ == TRAIN) {/*训练阶段*/
      const unsigned int* mask = rand_vec_.cpu_data();/*伯努利分布的随机数*/
      const int count = bottom[0]->count();/*输入数据blob个数*/
      for (int i = 0; i < count; ++i) {
        bottom_diff[i] = top_diff[i] * mask[i] * scale_;/*返向传播梯度*/
      }
    } else {
      caffe_copy(top[0]->count(), top_diff, bottom_diff);/*如果不是训练就直接拷贝数据*/
    }
  }
}


#ifdef CPU_ONLY
STUB_GPU(DropoutLayer);
#endif

INSTANTIATE_CLASS(DropoutLayer);
REGISTER_LAYER_CLASS(Dropout);

}  // namespace caffe


http://m.blog.csdn.net/article/details?id=50890473 
http://blog.csdn.net/u012702874/article/details/45030991

版权声明:本文为chinabing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chinabing/article/details/78865103

智能推荐

Caffe源码 - RoI Pooling 层

RoI Pooling 层 caffe prototxt 定义: caffe caffe.proto ROI Pooling 层参数说明: 根据 prototxt 定义可以看出,roi_pool5 的输入有两个,bottom[0] 是 conv5 卷积层出来的 feature map,由于前面进行的 pool 层,conv5 的 feature map 的 height 和 width 分别是原图...

caffe源码阅读之layer(2)——Euclidean_loss_layer层

             因为项目需要作点的定位所以需要用到euclidean_loss_layer 层,这里特别的看了一下该层的实现源码,位置 E:\Caffe\caffe-windows\include\caffe\layers\euclidean_loss_layer.hpp和E:\Caffe\caffe-windows\...

重启caffe源码深入学习7:caffe框架深度神经网络反传代码解析(一)之ReLU层源码解析

重启caffe源码深入学习7:caffe框架深度神经网络反传代码解析(一)之ReLU层源码解析 写在前面 为什么重启三年之前的系列 为什么是caffe 该系列之后的写作计划与打算 ReLU层源码解析 caffe中的梯度 ReLU层源码 ReLU层源码解析 写在前面 为什么重启三年之前的系列 在2016年9月,笔者开始读研之初,曾经对caffe源码进行了一系列解析。随着项目进展与科研的深入,使用的深...

【Tensorflow 大马哈鱼】tf.layers 之 dense层、dropout层、batch_normalization层、pad层

之前写的代码都是基于比较底层的API了,底层的API其实是有好处的,虽然还是调API,但是至少对于原理有小小的理解才能够写出代码。而且在实现一些新的论文或者要实现一个新的点子的时候,这时候是没有API的,因此底层的API非常有存在的必要,且必须经过这一个过程。 但是对于一个非常熟悉底层原理和经过了写底层代码这个过程的人,在有些很常见的任务上,就是用高级封装好的API就行。tf.layers就是提供...

caffe源码解析之solver

Solver:网络的求解策略 Solver 主要是实现了训练模型参数所采用的优化算法,根据优化算法的不同会派生不同的类,而基于这些子类就可以对网络进行正常的训练过程。 Solver的重要成员变量 protected的成员:shared_ptr net_ 是一个指向Net类型的智能指针(shared_ptr),Solver正是通过这个指针来和网络Net来交互并完成模型的优化。不同的子类分别实现了不同...

猜你喜欢

caffe源码解析之net

net:网络的整体骨架 Net是对整个网络的表示,由各种 Layer 前后连接组合而成,Net用容器的形式将多个Layer有序地放在一起,其自身实现的功能主要是对逐层Layer进行初始化,以及提供Update( )的接口(更新网络参数),本身不能对参数进行有效地学习过程。 Net的重要成员变量 Net的重要成员函数 根据NetParameter进行net初始化,简单的来说就是先把网络中所有层的bo...

caffe源码解析之layer

Layer:网络的基础单元 Layer 是对神经网络中各种层的一个抽象,包括我们熟知的卷积层和下采样层,还有全连接层和各种**函数层等等。同时每种 Layer 都实现了前向传播和反向传播,并通过 Blob 来传递数据。 Layer是网络模型和计算的核心,在数据存储上,主要分成bottom_vecs、top_vecs、weights&bias三个部分;在数据传递上,也主要分为LayerSet...

caffe---之scale层

caffe源码中给出了scale层的作用,如下: 就是上面botom和下面bottom相乘, axis = 0 可以看下面   即,按元素计算连个输入的乘积。该过程以广播第二个输入来匹配第一个输入矩阵的大小。 也就是通过平铺第二个输入矩阵来计算按元素乘积(点乘)。...

caffe---之eltwise层

Eltwise : element-wise eltwise layer是caffe提供的按元素操作层。它支持3种基本操作: 1. PROD:按元素乘积 2. SUM:按元素求和(默认) 3. MAX:保存元素大者 进行何种操作可以在layer里面通过定义EltwiseOp : x #x:=0,1,2 除此之外,该层还定义了 coeff 参数,该参数只对SUM操作起作用。 最后,caffe还设定了...

Caffe 源码 - BatchNorm 层与 Scale 层

batch norm layer & scale layer 简述 Batch Normalization 论文给出的计算: 前向计算: 后向计算: BatchNorm 主要做了两部分: [1] 对输入进行归一化,xnorm=x−μσ,其中,μ 和 σ 是计算的均值和方差;—— 对应 Caffe BatchNorm 层...