1. 程式人生 > >Caffe原始碼解讀:防止梯度爆炸的措施-梯度裁剪

Caffe原始碼解讀:防止梯度爆炸的措施-梯度裁剪

 梯度裁剪是一種在非常深度的網路(通常是迴圈神經網路)中用於防止梯度爆炸(exploding gradient)的技術。

執行梯度裁剪的方法有很多,但常見的一種是當引數向量的 L2 範數(L2 norm)超過一個特定閾值時對引數向量的梯

度進行標準化,這個特定閾值根據函式:新梯度=梯度 * 閾值 / 梯度L2範數

                         new_gradients = gradients * threshold / l2_norm(gradients)。

Caffe實現程式碼如下:

//梯度裁剪,用來防止梯度爆炸
template <typename Dtype>
void SGDSolver<Dtype>::ClipGradients() {
  const Dtype clip_gradients = this->param_.clip_gradients();
  if (clip_gradients < 0) { return; }
  const vector<Blob<Dtype>*>& net_params = this->net_->learnable_params();
  Dtype sumsq_diff = 0;
  //diff進行累加
  for (int i = 0; i < net_params.size(); ++i) {
    sumsq_diff += net_params[i]->sumsq_diff();
  }
  //sqrt(sumsq_diff)
  const Dtype l2norm_diff = std::sqrt(sumsq_diff);
  //如果梯度的L2範數大於clip_gradients
  //diff = diff *  clip_gradients / l2norm_diff
  if (l2norm_diff > clip_gradients) {
    Dtype scale_factor = clip_gradients / l2norm_diff;
    LOG(INFO) << "Gradient clipping: scaling down gradients (L2 norm "
        << l2norm_diff << " > " << clip_gradients << ") "
        << "by scale factor " << scale_factor;
    for (int i = 0; i < net_params.size(); ++i) {
      net_params[i]->scale_diff(scale_factor);
    }
  }
}