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

来源:互联网 发布:网络教学有什么特点 编辑:程序博客网 时间:2024/06/06 09:17

权值更新

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

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


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

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

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

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

权值更新策略

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

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


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.01momentum: 0.9weight_decay: 0.0005# The learning rate policylr_policy: "inv"gamma: 0.0001power: 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主要进行了的计算。
ComputeUpdateValue函数分两步,第一步是更新历史偏置值

然后将历史偏置值赋值给偏置值

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

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