DeepLearning(基于caffe)优化策略(2)--防拟合篇:Dropout

        DeepLearning,甚至机器学习,都或多或少的会出现过拟合的现象。防止过拟合,就成为了一个大家普遍关注的话题。

        过拟合的原因,大致分为这几种:数据量过小、数据有噪声、学习的网络模型更复杂(例如:本来是二次的方程,如果过于拟合成三次甚至更高,导致训练的loss特别小,测试时则不然,会比较大)。

一、什么是dropout?

        Dropout是深度学习中一种防拟合的方法,是指在模型训练时随机让网络中某个隐含层结点的权重不工作(暂时将这些隐藏层的结点权值保留但不工作不更新权值,下次工作的时候再工作更新权值)

      二、公式推导

        

              公式如下:

        

         通过公式,可以看到,r就是随机让某些权值不起作用。

      三、分析为什么会收到这样的效果

        详细请见原文章:https://arxiv.org/pdf/1207.0580.pdf

        由于每次“丢弃”的部分节点是随机出现的,因此这时候的权值更新不再依赖固定的样式,(这时候让我想到了随机森林的算法思想),阻止某些特征仅仅在特殊的特征下起作用的情况。

      四、Caffe中的dropout_layer

// 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.);
  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);
  //这个类要单独分配一段内存用来存储满足伯努利分布的随机数
  rand_vec_.Reshape(bottom[0]->shape());
}

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); /*测试阶段每个数据都要输出*/
  }
}

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

      五、caffe中的应用

        在网络配置中增加以下层:

layer {
  name: "drop1"
  type: "dropout"
  bottom: "ip1"
  top: "ip1"
  dropout_param {
    dropout_ratio: 0.5     //参数调整
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值