您现在的位置是: 网站首页 >> 深度学习 深度学习

【转】深度学习笔记9:权值更新的实现

发布时间:2018年8月27日 22:31 作者:Master 来源:转载 点击:831

    权值更新

    在前面的反向传播中我们计算出每一层的权值W和偏置b的偏导数之后,最后一步就是对权值和偏置进行更新了。

    在之前的BP算法的介绍中我们给出了如下公式:

                                                   20160824200926750.png


    其中的α为学习速率,一般学习率并不是一个常数,而是一个以训练次数为自变量的单调递减的函数。使用变化的学习率有以下几点理由:

    1、开始时学习率较大,可以快速的更新网络中的参数,是参数可以较快的达到目标值。而且由于每次更新的步长较大,可以在网络训练前期“跳过”局部最小值点。

    2、当网络训练一段时间后,一个较大的学习率可能使网络的准确率不再上升,即“网络训练不动”了,这时候我们需要减小学习率来继续训练网络。

    在我们的网络中,含有参数的层有卷积层1、卷积层2、全连接层1和全连接层2,一共有4个层有参数需要更新,其中每个层又有权值W和偏置b需要更新。实际中不管权值还是偏置,还有我们前面计算出了的梯度,都是线性存储的,所以我们直接把整个更新过程用到的数据看作对一维数组就可以,不用去关注权值W是不是一个800*500的矩阵,而且这样的话,权值更新和偏置更新的具体实现可以共用一份代码,都是对一维数组进行操作。

    权值更新策略

    在caffe中,使用了随机梯度下降(Stochastic gradient descent)的方法进行权值更新。具体如下公式(即动量更新):20160824201027317.png


    其中Δhistory为多次的梯度的累加:20160824201106083.png



    caffe中的学习率更新策略


    在\src\caffe\solvers\sgd_solver.cpp文件的注释中,caffe给出如下几种学习率更新策略:

    // Return the current learning rate. The currently implemented learning rate
    // policies are as follows:
    //    - fixed: always return base_lr.
    //    - step: return base_lr * gamma ^ (floor(iter / step))
    //    - exp: return base_lr * gamma ^ iter
    //    - inv: return base_lr * (1 + gamma * iter) ^ (- power)
    //    - multistep: similar to step but it allows non uniform steps defined by
    //      stepvalue
    //    - poly: the effective learning rate follows a polynomial decay, to be
    //      zero by the max_iter. return base_lr (1 - iter/max_iter) ^ (power)
    //    - sigmoid: the effective learning rate follows a sigmod decay
    //      return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
    //
    // where base_lr, max_iter, gamma, step, stepvalue and power are defined
    // in the solver parameter protocol buffer, and iter is the current iteration.

    可以看出,学习率的更新有fixed、step、exp、inv、multistep、poly和sigmoid几种方式,看上边的公式可以很清楚的看出其实现过程。

    实际中我们的网络使用的是inv的更新方式,即learn_rate=base_lr * (1 + gamma * iter) ^ (- power)。



    Caffe中权值更新的实现


    在配置文件\examples\mnist\lenet_solver.prototxt中,保存了网络初始化时用到的参数,我们先看一下和学习率相关的参数。

    # The base learning rate, momentum and the weight decay of the network.
    base_lr: 0.01
    momentum: 0.9
    weight_decay: 0.0005
    # The learning rate policy
    lr_policy: "inv"
    gamma: 0.0001
    power: 0.75

    根据上面的参数,我们就可以计算出每一次迭代的学习率learn_rate= base_lr * (1 + gamma * iter) ^ (- power)。




    获取学习率之后,我们需要使用学习率对网络中的参数进行更新。在\src\caffe\solvers\sgd_solver.cpp中包含了进行权值更新的具体函数ApplyUpdate(),下面我们介绍一下这个函数。

    template <typename Dtype>
    void SGDSolver<Dtype>::ApplyUpdate() {
      CHECK(Caffe::root_solver());
      //GetLearningRate()函数获取此次迭代的学习率
      Dtype rate = GetLearningRate();
      if (this->param_.display() && this->iter_ % this->param_.display() == 0) {
        LOG(INFO) << "Iteration " << this->iter_ << ", lr = " << rate;
      }
      ClipGradients();
      //对网络进行更新,一共4个层,每层有W和b2个参数需要更新,故size=8
      for (int param_id = 0; param_id < this->net_->learnable_params().size();
           ++param_id) {
     //归一化,我们的网络没有用到这一函数
        Normalize(param_id);
     //正则化
        Regularize(param_id);
     //计算更新用到的梯度
        ComputeUpdateValue(param_id, rate);
      }
      //用ComputeUpdateValue计算得到的梯度进行更新
      this->net_->Update();
    }


    其中的正则化函数Regularize主要进行了20160824201340368.png的计算。
    ComputeUpdateValue函数分两步,第一步是更新历史偏置值20160824201425072.png


    然后将历史偏置值赋值给偏置值20160824201514104.png


    在ComputeUpdateValue用到了lr_mult学习率因子参数,这个在之前的配置信息里面也见过,同一层中的weight和bias可能会以不同的学习率进行更新,所以也可以有不同的lr_mult。

    最后this->net_->Update()函数使用前边ComputeUpdateValue计算出来的偏导数对参数进行了更新20160824201556331.png


    注:本博文为转载文章,已征得原博主同意

    来源:https://blog.csdn.net/l691899397/article/details/52303606