查看全课大纲(第 36 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

CNN的误差反向传播_卷积层

卷积层的误差反向传播

小象实战讲义 · 基于深度学习的计算机视觉

在第 5 章中,我们学习了全连接神经网络的误差反向传播(Backpropagation, BP)算法。然而,卷积神经网络(CNN)的核心是卷积层,其连接方式(局部连接、权重共享)与全连接层截然不同。本节我们将深入探讨卷积层的误差反向传播机制,理解梯度是如何通过卷积层传递到前一层(通常是池化层或另一个卷积层)的,这是理解CNN训练过程的关键一步。

💡 核心导读

  • 从全连接到卷积:回顾全连接层BP公式,建立符号体系,理解卷积层可视为一种特殊的、参数共享的连接层。
  • 卷积运算的展开:通过将卷积操作展开为全连接形式的矩阵乘法,直观理解卷积层反向传播的数学本质。
  • 核心公式推导:推导出卷积层误差反向传播的核心公式:δ^(l-1) = δ^(l) * rot180(W^(l)) ⊙ σ'(z^(l-1)),其中rot180表示将卷积核旋转180度。
  • 多通道处理:理解当卷积层有多个输出通道(特征图)时,前一层某个通道的残差需要汇总所有输出通道的贡献。
  • 实例演算:通过一个具体的数值例子,手算验证卷积层反向传播的过程,加深理解。

复习:全连接网络的误差反向传播

在深入卷积层之前,我们先快速回顾一下全连接神经网络中误差反向传播的核心公式,并统一本节将使用的符号体系。

对于一个全连接神经网络,我们定义:

  • a^(l):第 l 层的输出(激活值)。a^(0) 是网络的原始输入。
  • z^(l):第 l 层的总输入(加权和),即 z^(l) = W^(l) a^(l-1) + b^(l)。
  • σ(·):非线性激活函数(如Sigmoid, ReLU)。
  • C:损失函数(Cost Function)。
  • δ^(l):第 l 层的残差(误差敏感项),定义为损失函数对当前层总输入的偏导:δ^(l) = ∂C / ∂z^(l)。

符号约定说明:本节采用 δ = ∂C/∂z 的标准定义;第 5 章为贴合课件“残差 = 误差 × 激活导数”的写法,把负号放进了权重更新式(δ = (t - z)f',Δw = +ηδy)。两种约定只差一个符号,本质完全一致。这里用 ∂C/∂z,可以让后续递推公式不带负号。

根据链式法则和全连接网络的结构,我们可以推导出相邻两层残差之间的递推关系(BP算法的核心):

δ^(l-1) = ( (W^(l))^T δ^(l) ) ⊙ σ'(z^(l-1))

公式解读:

  1. (W^(l))^T δ^(l):将更靠近输出层(第 l 层)的残差 δ^(l),乘以当前层权重矩阵 W^(l) 的转置。这实现了误差从后一层向前一层的“加权反传”。
  2. ⊙:表示Hadamard积(逐元素相乘)。
  3. σ'(z^(l-1)):第 l-1 层激活函数在其输入 z^(l-1) 处的导数。
  4. 整个结果就是第 l-1 层的残差 δ^(l-1)。

这个公式是我们推导卷积层反向传播的基础。在卷积层中,W^(l) 不再是稠密的矩阵,而变成了具有特殊结构(局部连接、权重共享)的卷积核。

卷积层:一种特殊的连接层

为了理解卷积层的反向传播,我们首先需要将卷积操作“翻译”成我们熟悉的全连接语言。

考虑一个简单的例子:一个 3x3 的输入 a^(l-1),使用一个 2x2 的卷积核 W 进行无填充(padding)、步长为1的卷积,得到一个 2x2 的输出 z^(l)。

import numpy as np

# 假设的输入 (l-1层输出)
a_l_minus_1 = np.array([[1, 2, 3],
                         [4, 5, 6],
                         [7, 8, 9]], dtype=np.float32)

# 假设的卷积核权重
W = np.array([[0.1, 0.2],
              [0.3, 0.4]], dtype=np.float32)

# 手动进行卷积运算 (无padding, stride=1)
z_l = np.zeros((2, 2))
for i in range(2):
    for j in range(2):
        z_l[i, j] = np.sum(a_l_minus_1[i:i+2, j:j+2] * W)

print("输入 a^(l-1):")
print(a_l_minus_1)
print("\n卷积核 W:")
print(W)
print("\n卷积输出 z^(l):")
print(z_l)
输入 a^(l-1):
[[1. 2. 3.]
 [4. 5. 6.]
 [7. 8. 9.]]

卷积核 W:
[[0.1 0.2]
 [0.3 0.4]]

卷积输出 z^(l):
[[3.70000005 4.69999981]
 [6.69999981 7.70000076]]

这个卷积操作可以等价地展开为一个全连接运算。我们将 3x3 的输入 a^(l-1) 展平为一个 9x1 的列向量,将 2x2 的输出 z^(l) 展平为一个 4x1 的列向量。那么,连接它们的权重矩阵 W_full 将是一个 4x9 的稀疏矩阵。

# 概念上的全连接权重矩阵 W_full (4x9)
# 每一行对应一个输出神经元z_l[i,j],每一列对应一个输入神经元a_l_minus_1[p,q]
# 非零权重的位置由卷积核的滑动决定,且权重值共享。

# 例如,输出 z_l[0,0] = a[0,0]*W[0,0] + a[0,1]*W[0,1] + a[1,0]*W[1,0] + a[1,1]*W[1,1]
# 对应 W_full 的第一行:[W[0,0], W[0,1], 0, W[1,0], W[1,1], 0, 0, 0, 0]

# 输出 z_l[0,1] = a[0,1]*W[0,0] + a[0,2]*W[0,1] + a[1,1]*W[1,0] + a[1,2]*W[1,1]
# 对应 W_full 的第二行:[0, W[0,0], W[0,1], 0, W[1,0], W[1,1], 0, 0, 0]

# 以此类推...

从这个展开视图可以清晰地看到卷积层的两个核心特性:

  1. 局部连接:每个输出神经元只与输入层的局部区域(感受野)相连,而不是全部。
  2. 权重共享:连接不同输出神经元和其对应感受野的权重是相同的,即卷积核 W 的值。

因此,卷积层本质上是一种具有特殊稀疏性和参数共享约束的全连接层。理解了这一点,我们就可以将全连接BP的思想迁移过来。

卷积层误差反向传播公式推导

我们的目标是求第 l-1 层(卷积层的前一层)的残差 δ^(l-1)。已知第 l 层(卷积层)的残差 δ^(l)。

根据链式法则和全连接BP的启示,关键是要计算 ∂z^(l) / ∂a^(l-1)。在全连接中,这就是权重矩阵 W^(l)。在卷积的展开视图中,它对应那个稀疏的、共享权重的矩阵 W_full^(l)。

经过严谨的数学推导(详细过程可参考课程配套PDF),我们可以得到一个非常简洁且直观的结论:

卷积层的误差反向传播公式:

δ^(l-1) = δ^(l) * rot180(W^(l)) ⊙ σ'(z^(l-1))

其中:

  • * 表示卷积操作(注意,不是矩阵乘法)。
  • rot180(W^(l)) 表示将第 l 层的卷积核 W^(l) 旋转180度。
  • ⊙ 是逐元素相乘。
  • σ'(z^(l-1)) 是第 l-1 层激活函数的导数。如果 l-1 层是池化层等无参数层,通常视其激活函数为恒等映射,即 σ'(z) = 1。

公式解读:

  1. 旋转180度:这是“互相关”与严格数学卷积之间的差异造成的。深度学习框架的前向传播通常实现的是互相关(核不翻转,直接滑动相乘);而在反向传播中,要把后一层的残差正确散射回前一层,等价于做一次严格卷积,也就是用旋转180度后的核做互相关。所以这个旋转不是额外技巧,而是把前向的互相关“逆回去”的必然结果。
  2. 卷积操作:将后一层(l层)的残差 δ^(l) 作为“输入”,与旋转后的卷积核进行卷积操作。这实现了误差从后一层特征图向前一层特征图的传播,并且自然地处理了局部连接和权重共享。
  3. 激活函数导数:与全连接BP一样,需要乘上当前层(l-1层)激活函数的导数。

一个重要细节:多通道情况 上述公式描述的是单输入通道、单输出通道的情况。在实际CNN中,每一层通常有多个通道(特征图)。

  • 假设第 l-1 层有 P 个通道。
  • 第 l 层(卷积层)有 Q 个输出通道(即 Q 个卷积核)。
  • 那么,对于第 l-1 层的第 p 个通道的残差 δ^(l-1, p),它需要接收来自第 l 层所有 Q 个通道的残差的贡献。

因此,多通道下的公式为:

δ^(l-1, p) = ∑_{q=1}^{Q} ( δ^(l, q) * rot180(W^(l, q, p)) ) ⊙ σ'(z^(l-1, p))

其中:

  • W^(l, q, p) 是连接第 l-1 层第 p 个通道到第 l 层第 q 个通道的卷积核。
  • 求和 ∑ 表示将所有输出通道 q 的贡献累加到输入通道 p 上。

实例演算:从卷积层到池化层的反向传播

让我们通过一个具体的数值例子来验证上述公式。假设网络结构如下:

  • 第 l-1 层:池化层,输出为单个 3x3 的特征图 a^(l-1)。池化层通常无激活函数,我们设 σ'(z^(l-1)) = 1。
  • 第 l 层:卷积层,有 2 个卷积核,每个核大小为 2x2。因此输出 z^(l) 是 2 个 2x2 的特征图。

已知:

  1. 两个卷积核的权重:
    • W^(l, 1) = [[0.1, 0.2], [0.3, 0.4]]
    • W^(l, 2) = [[0.5, 0.6], [0.7, 0.8]] (为简化,我们假设输入是单通道;输出有 2 个通道,所以有 2 个卷积核。多输入通道的原理相同,只是还要对输入通道求和,计算更繁琐)。
  2. 卷积层(第 l 层)的残差 δ^(l):
    • δ^(l, 1) = [[1, 2], [3, 4]] (对应第一个输出特征图)
    • δ^(l, 2) = [[5, 6], [7, 8]] (对应第二个输出特征图)

目标:计算池化层(第 l-1 层)的残差 δ^(l-1)。

计算步骤:

  1. 对每个卷积核进行180度旋转。
  2. 将每个通道的残差 δ^(l, q) 与对应的旋转后的核进行全填充(full padding)卷积。为什么是full padding?因为前向是 3x3 → 2x2 的 valid 卷积,反向需要把 2x2 的残差“散射”回 3x3,只有 full 卷积的尺寸关系(2+2-1=3)才能还原。
  3. 将两个通道的卷积结果相加。
  4. 因为 l-1 是池化层,σ' = 1,所以结果就是 δ^(l-1)。
import numpy as np

# 已知数据
delta_l1 = np.array([[1, 2],
                     [3, 4]], dtype=np.float32) # 第l层,第1个通道的残差
delta_l2 = np.array([[5, 6],
                     [7, 8]], dtype=np.float32) # 第l层,第2个通道的残差

W_l1 = np.array([[0.1, 0.2],
                 [0.3, 0.4]], dtype=np.float32) # 第1个卷积核
W_l2 = np.array([[0.5, 0.6],
                 [0.7, 0.8]], dtype=np.float32) # 第2个卷积核

# 1. 旋转卷积核180度
def rot180(kernel):
    return np.rot90(kernel, 2)

W_l1_rot = rot180(W_l1)
W_l2_rot = rot180(W_l2)

print("旋转后的卷积核 W_l1_rot:")
print(W_l1_rot)
print("\n旋转后的卷积核 W_l2_rot:")
print(W_l2_rot)

# 2. 进行全填充(full)卷积
# 我们可以通过手动计算或利用信号处理中的“互相关”概念来理解。
# 全填充卷积:在残差图边界外补零,使旋转后核的右下角能与残差图左上角对齐开始计算。
# 对于2x2的核和2x2的输入,全填充输出是3x3。
# 手动计算其中一个元素:delta_l1的左上角元素1,只与W_l1_rot的右下角元素0.1相乘。
# 我们可以用更直观的方式:将残差图用0填充到4x4(上下左右各补一圈0),然后用旋转后的核进行有效(valid)卷积。

def full_convolution(input_map, kernel):
    """实现全填充卷积,输入和核都是2D,输出大小 = input_size + kernel_size -1"""
    k_h, k_w = kernel.shape
    # 对输入进行填充,上下左右各填充 (k_h-1, k_w-1)
    padded_input = np.pad(input_map, ((k_h-1, k_h-1), (k_w-1, k_w-1)), mode='constant')
    # 进行有效的互相关(不旋转核,因为我们的kernel已经是rot180后的)
    # 注意:这里我们使用互相关,因为我们的kernel已经是旋转后的。
    # 对于互相关,我们直接用kernel在padded_input上滑动计算。
    output_h = padded_input.shape[0] - k_h + 1
    output_w = padded_input.shape[1] - k_w + 1
    output = np.zeros((output_h, output_w))
    for i in range(output_h):
        for j in range(output_w):
            output[i, j] = np.sum(padded_input[i:i+k_h, j:j+k_w] * kernel)
    return output

# 计算每个通道的贡献
contrib1 = full_convolution(delta_l1, W_l1_rot)
contrib2 = full_convolution(delta_l2, W_l2_rot)

print("\n第1个通道的贡献 contrib1:")
print(contrib1)
print("\n第2个通道的贡献 contrib2:")
print(contrib2)

# 3. 求和得到最终的 δ^(l-1)
delta_l_minus_1 = contrib1 + contrib2
print("\n计算得到的池化层残差 δ^(l-1):")
print(delta_l_minus_1)
旋转后的卷积核 W_l1_rot:
[[0.4 0.3]
 [0.2 0.1]]

旋转后的卷积核 W_l2_rot:
[[0.8 0.7]
 [0.6 0.5]]

第1个通道的贡献 contrib1:
[[0.1        0.40000001 0.40000001]
 [0.60000002 2.         1.60000002]
 [0.90000004 2.4000001  1.60000002]]

第2个通道的贡献 contrib2:
[[ 2.5         6.          3.60000014]
 [ 7.         16.39999962  9.60000038]
 [ 4.9000001  11.19999981  6.4000001 ]]

计算得到的池化层残差 δ^(l-1):
[[ 2.6         6.40000001  4.00000015]
 [ 7.60000002 18.39999962 11.20000041]
 [ 5.80000013 13.5999999   8.00000012]]

通过这个实例,我们清晰地看到了:

  1. 卷积核确实被旋转了180度。
  2. 反向传播过程是一个卷积操作(这里是全填充卷积)。
  3. 多通道的贡献被求和。

这个 3x3 的 δ^(l-1) 就是传递到前一层(池化层)的残差,池化层将根据其自身的反向传播规则(例如,平均池化将残差平均分配回原位置)继续向前传递。

📝 动手练一练

  1. 概念辨析:在全连接层和卷积层的误差反向传播公式中,都需要将后一层的残差与前一层到后一层的权重矩阵进行运算。请问这两个公式中,权重矩阵的处理有什么关键区别?(提示:转置 vs 旋转)
👉 点击查看参考答案

关键区别:

  • 全连接层:使用权重矩阵 W^(l) 的转置 (W^(l))^T。这是因为在全连接中,误差从后一层神经元反传到前一层神经元时,需要乘以连接它们的权重值,而转置操作正好实现了这种对应关系的翻转。
  • 卷积层:使用卷积核 W^(l) 的180度旋转 rot180(W^(l))。这是因为卷积操作本身具有空间局部性和权重共享性。在数学上,为了保持梯度计算的正确性(即与将卷积展开为稀疏矩阵乘法后的梯度一致),必须对卷积核进行旋转。这也是严格数学定义中的卷积(Convolution)与神经网络中常用的互相关(Cross-correlation)操作之间的区别在反向传播中的体现。
  1. 动手计算:假设一个卷积层,其单个 2x2 卷积核为 W = [[a, b], [c, d]],该层输出的残差为 δ = [[δ11, δ12], [δ21, δ22]]。前一层为ReLU激活函数,且已知在前向传播中,该层所有输入 z^(l-1) 均大于0。请根据公式 δ^(l-1) = δ^(l) * rot180(W^(l)) ⊙ σ'(z^(l-1)),写出计算 δ^(l-1) 中左上角元素 δ^(l-1)_11 的具体表达式。
👉 点击查看参考答案

计算过程:

  1. 旋转卷积核:rot180(W) = [[d, c], [b, a]]。
  2. 因为前一层使用ReLU且输入>0,所以 σ'(z^(l-1)) = 1(所有位置)。
  3. 计算 δ * rot180(W) 的左上角元素。这是全填充卷积:在残差图边界外补零,使旋转核的右下角与残差图左上角 δ11 对齐,此时只有这一对元素重叠,得到输出的第一个元素。
    • 此时,只有旋转核的右下角 a 与残差图的左上角 δ11 重合。
    • 因此,(δ * rot180(W))_11 = a * δ11。
  4. 所以,δ^(l-1)_11 = a * δ11 * 1 = a * δ11。

表达式:δ^(l-1)_11 = a * δ11

本章小结

本节我们深入剖析了卷积神经网络中卷积层的误差反向传播机制,这是理解CNN如何通过梯度下降进行训练的核心。

  • 核心思想迁移:卷积层可视为具有局部连接和权重共享特性的特殊全连接层。因此,其反向传播的核心思想与全连接BP一脉相承——利用链式法则,将后一层的残差通过权重关系传递到前一层。
  • 关键公式:我们推导并理解了卷积层反向传播的最终公式:δ^(l-1) = δ^(l) * rot180(W^(l)) ⊙ σ'(z^(l-1))。特别要注意卷积核需要旋转180度这一关键操作,它源于卷积的严格数学定义。
  • 多通道处理:在实际网络中,每一层通常包含多个特征图(通道)。前一层某个通道的残差,由后一层所有通道的残差分别与对应的卷积核进行反向卷积后,再求和得到。
  • 连接前后文:本节推导的是从卷积层(第 l 层)到其前一层(第 l-1 层,本例中为池化层)的误差传播。完整的CNN训练需要交替进行卷积层和池化层的反向传播。

📋 行动清单

  • 默写并理解卷积层误差反向传播的核心公式,明确每个符号的含义。
  • 在纸上复现本节中的数值演算例子,确保能独立完成从 δ^(l) 计算 δ^(l-1) 的过程。
  • 思考:如果前一层(l-1层)也是一个卷积层,那么公式中的 σ'(z^(l-1)) 应该如何计算?(提示:取决于该卷积层使用的激活函数,如ReLU的导数为0或1)。

—— 小象教研组