西瓜书之误差逆传播公式推导、源码解读及各种易混淆概念

本文深入探讨了反向传播算法在深度学习中的应用,详细解析了卷积神经网络(CNN)的前向传播和反向传播过程,通过公式推导和Caffe源码解读,阐述了sigmoid函数与ReLU函数在神经网络中的作用,以及如何通过反向传播更新权重和偏置。同时,介绍了im2col技术在加速卷积运算中的应用,并对比了上池化、上采样和反卷积的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关键词:反向传播(BP);caffe源码;im2col;卷积;反卷积;上池化;上采样

公式推导

以前看到一长串的推导公式就想直接跳过,今天上午莫名有耐心,把书上的公式每一步推导自己算一遍,感觉豁然开朗。遂为此记。
在这里插入图片描述

sigmoid函数求导比relu复杂一点。如果采用relu,神经元输入和输出的导数就为1,计算更方便。
因为更新的原则是朝着损失降低最快的方向更新,可以把w看成是自变量,系数的计算就是反向传播的过程,系数越大,降低越快。


Caffe 源码解读

前向传播源码:

//前向传播
template <typename Dtype>
void ConvolutionLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  //blobs_[0]保存权值, blobs_[1]保存偏置
  const Dtype* weight = this->blobs_[0]->cpu_data();
  //bottom.size()是bottom中blob的数量,等于top中blob的数量,一般情况下为1
  for (int i = 0; i < bottom.size(); ++i) {
    //获取输入,输出数据指针
    const Dtype* bottom_data = bottom[i]->cpu_data();
    Dtype* top_data = top[i]->mutable_cpu_data();
	//第n张图片
    for (int n = 0; n < this->num_; ++n) {
      //卷积操作,采用矩阵乘积实现
     // bottom_dim_ =3*28*28
     // kernel = 20*5*5
     // top_dim_ = 20*24*24
      this->forward_cpu_gemm(bottom_data + n * this->bottom_dim_, weight,
          top_data + n * this->top_dim_);
      if (this->bias_term_) {
        const Dtype* bias = this->blobs_[1]->cpu_data();
		//加上偏置
        this->forward_cpu_bias(top_data + n * this->top_dim_, bias);
      }
    }
  }
}

反向传播源码:

//反向传播
template <typename Dtype>
void ConvolutionLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down/*是否反传*/, const vector<Blob<Dtype>*>& bottom) {
  const Dtype* weight = this->blobs_[0]->cpu_data();
  Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff();
  for (int i = 0; i < top.size(); ++i) {
	//上一层传下来的导数
    const Dtype* top_diff = top[i]->cpu_diff();
    const Dtype* bottom_data = bottom[i]->cpu_data();
	//传给下一层的导数
    Dtype* bottom_diff = bottom[i]->mutable_cpu_diff();
    // Bias gradient, if necessary.
	// 更新偏置,直接加上残差(每个偏置所对应的图内所有残差之和)
    if (this->bias_term_ && this->param_propagate_down_[1]) {
      Dtype* bias_diff = this->blobs_[1]->mutable_cpu_diff();
      for (int n = 0; n < this->num_; ++n) {
        this->backward_cpu_bias(bias_diff, top_diff + n * this->top_dim_);
      }
    }
    if (this->param_propagate_down_[0] || propagate_down[i]) {
      for (int n = 0; n < this->num_; ++n) {
        // gradient w.r.t. weight. Note that we will accumulate diffs.
		// 对weight 计算导数(用来更新weight)
        // /将下一层残差与weight进行相关计算,得到卷积层的残差
        if (this->param_propagate_down_[0]) {
          this->weight_cpu_gemm(bottom_data + n * this->bottom_dim_,
              top_diff + n * this->top_dim_, weight_diff);
        }
        // gradient w.r.t. bottom data, if necessary.
		// 对bottom数据计算导数(传给下一层)
		// bottom_data与top_diff做相关计算,得到w权值更新量
        if (propagate_down[i]) {
          this->backward_cpu_gemm(top_diff + n * this->top_dim_, weight,
              bottom_diff + n * this->bottom_dim_);
        }
      }
    }
  }
}

所以也就更好理解为什么
bottom_data * top_diff = weight_diff
top_diff * weight = bottom_diff

真实的过程应该是一个不断的循环

bottom_data * top_diff = weight_diff(用于更新当前层的权值)
top_diff * weight = bottom_diff (传递到下一层)
(上一层的bottom_diff 是下一层的top_diff )
bottom_data * top_diff = weight_diff (用于更新当前层的权值)
top_diff * weight = bottom_diff(继续传递到下一层)


关于提升卷积速度(im2col)

在这里插入图片描述

卷积核横向展开为1行

在这里插入图片描述

将多个通道应用卷积核的相同位置区域(3维数据)纵向展开为一列

案例1: 前向传播
在这里插入图片描述kernel size:20 * 5 * 5
input blob:1 * 28 * 28
output blob:20 * 24 * 24(576)

在这里插入图片描述

kernel size:50 * 5 * 5
input blob:20 * 12 * 12
output blob:50 * 8 * 8

参考链接

案例2(前向传播、计算bottom_diff、计算weight_diff):
在这里插入图片描述
核心思想:
将卷积核展开成行。
将不同图片相同位置的卷积区域提取成列。
定格位置的数目即输出特征图像的大小。

反向传播过程中pad的问题
假设输入特征图 m * m,输出特征图 n * n
卷积过程pad(p) ,stride(s) =1 ,kernel (k)
n = (m+2p-k)/ s +1
m - n = k -1-2p
若 p = (k-1)/ 2,m = n
若 p != (k-1)/ 2,要考虑补边。


卷积与反卷积

卷积过程:
在这里插入图片描述

反卷积过程:
在这里插入图片描述

卷积 | 反向传播 | 反卷积 | 导向反向传播 | 的区别

在这里插入图片描述

  • 反向传播要记录先前输入大于0的位置,反卷积只考虑梯度
  • 反卷积的参数需要学习,反向传播用的是既有参数。

上池化 | 上采样 | 反卷积 | 的区别

上池化(UnPooling)、上采样(UnSampling)、反卷积(Deconvolution)
在这里插入图片描述

图(a)表示UnPooling的过程,特点是在Maxpooling的时候保留最大值的位置信息,之后在unPooling阶段使用该信息扩充Feature Map,除最大值位置以外,其余补0。
与之相对的是图(b),两者的区别在于UnSampling阶段没有使用MaxPooling时的位置信息,而是直接将内容复制来扩充FeatureMap。从图中即可看到两者结果的不同。
图(c)为反卷积的过程,反卷积是卷积的逆过程,又称作转置卷积。最大的区别在于反卷积过程是有参数要进行学习的(类似卷积过程),理论是反卷积可以实现UnPooling和unSampling,只要卷积核的参数设置的合理。

backward propagation:记录输入大于0的位置
unpooling:记录最大值信息(如果池化采用的是平均池化,那么UnPooling和unSampling类似)

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值