查看全课大纲(第 30 / 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

改进目标函数与克服梯度消散

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

在深度神经网络训练中,选择合适的损失函数和激活函数至关重要。本节将深入探讨深度学习为何放弃传统的均方误差,转而采用交叉熵损失函数,以及如何通过改进激活函数(如 ReLU)来有效克服深度网络训练中的“梯度消散”难题,从而为构建更深、更强大的模型奠定基础。

💡 核心导读

  • 目标函数革新:从均方误差(MSE)到交叉熵(Cross-Entropy),理解为何交叉熵能提供更“陡峭”的优化地形,加速模型收敛。
  • Softmax 层的作用:学习如何将网络输出转化为概率分布,并巧妙避免因概率为零带来的计算困难。
  • 梯度消散的根源:分析 Sigmoid 激活函数在深层网络中导致梯度指数级衰减的数学原理。
  • ReLU 的救赎:认识修正线性单元(ReLU)如何以其简单的形式,从根本上缓解梯度消散,并带来稀疏化等额外好处。
  • 历史方案回顾:了解深度学习早期(如2006年)为解决梯度问题曾采用的受限玻尔兹曼机(RBM)预训练方法。

从均方误差到交叉熵

在传统的神经网络中,最常用的目标函数(损失函数)是均方误差。对于一个有 n 个样本的批次,其形式为:

MSE=1n∑i=1n(yi−y^i)2\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2

其中,yiy_i 是第 i 个样本的真实值(标签),y^i\hat{y}_i 是模型预测出的值。我们的优化目标是最小化这个均方误差。

然而,在深度学习中,尤其是在分类任务中,我们普遍采用了交叉熵作为目标函数。对于二分类问题,其形式为:

CE=−1n∑i=1n[yilog⁡(y^i)+(1−yi)log⁡(1−y^i)]\text{CE} = -\frac{1}{n} \sum_{i=1}^{n} [y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i)]

对于多分类问题(假设有 K 个类别),形式为:

CE=−1n∑i=1n∑k=1Kyi,klog⁡(y^i,k)\text{CE} = -\frac{1}{n} \sum_{i=1}^{n} \sum_{k=1}^{K} y_{i,k} \log(\hat{y}_{i,k})

这里,yi,ky_{i,k} 是 one-hot 编码的真实标签,y^i,k\hat{y}_{i,k} 是模型预测的属于第 k 类的概率。

为什么是交叉熵?

交叉熵损失函数有两大核心优势:

  1. 与概率输出的天然契合:深度学习分类网络的输出层通常使用 Softmax 函数,将原始的得分(logits)转化为概率分布。交叉熵衡量的是两个概率分布(真实分布 y 和预测分布 ŷ)之间的差异,这与 Softmax 的输出形式完美匹配。
  2. 提供更陡峭的梯度:这是加速训练的关键。考虑一个极端情况:模型对一个本应属于类别 A(yA=1y_A=1)的样本预测概率极低(y^A≈0\hat{y}_A \approx 0)。此时,交叉熵损失项 −log⁡(y^A)-\log(\hat{y}_A) 会变得非常大(因为 log⁡(0+)→−∞\log(0^+) \to -\infty),并且损失对预测概率的梯度为 −1/y^A-1/\hat{y}_A,幅度极大,这为优化器提供了一个非常强烈的修正信号。相比之下,均方误差 (1−y^A)2(1 - \hat{y}_A)^2 对预测值的梯度约为 −2(1−0)=−2-2(1-0) = -2,信号强度远不如交叉熵。因此,交叉熵损失函数的“优化地形”更陡峭,有利于梯度下降算法快速找到最优解。(注:若输出层接 Softmax,损失对 logits 的梯度会归一化为 y^−y\hat{y}-y,幅度有界,但仍比同错误程度下的 MSE 梯度更大。)

Softmax:从得分到概率

交叉熵损失要求输入是概率。Softmax 层正是负责将网络最后一层线性层的输出(得分)转换为概率分布的函数。对于一个包含 K 个类别的向量 z=[z1,z2,...,zK]\mathbf{z} = [z_1, z_2, ..., z_K],Softmax 的计算如下:

Softmax(zi)=ezi∑j=1Kezj\text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}}

Softmax 的精妙之处在于:

  • 突出最大值:通过指数运算,放大得分间的差异,使最大得分对应的概率显著高于其他。
  • 归一化为概率:所有输出概率之和为 1,符合概率公理。
  • 避免零概率:即使某个得分 ziz_i 非常小(负很大),其指数 ezie^{z_i} 也是一个大于 0 的极小正数,从而保证 log⁡(y^i)\log(\hat{y}_i) 不会出现计算错误(log(0) 未定义)。

下面我们用一个小例子来直观感受 Softmax 的作用:

import numpy as np

# 假设网络最后一层输出三个类别的得分
logits = np.array([3.0, 1.0, -3.0])
print("原始得分 (logits):", logits)

# 计算 Softmax
exp_logits = np.exp(logits)
probabilities = exp_logits / np.sum(exp_logits)
print("Softmax 概率:", probabilities)
print("概率总和:", np.sum(probabilities))
原始得分 (logits): [ 3.  1. -3.]
Softmax 概率: [0.87887824 0.11894324 0.00217852]
概率总和: 1.0

可以看到,得分 3 被放大为约 0.88 的高概率,得分 -3 则被压缩为约 0.0022(约 0.22%)的极小概率,但绝非零。这正好满足了交叉熵损失计算的要求。

梯度消散:深度网络的“拦路虎”

在深度学习兴起之前,神经网络通常只有 3-5 层。一个关键的限制因素是 梯度消散:在误差反向传播过程中,梯度从输出层向输入层传递时,其幅度会指数级地衰减,导致靠近输入层的权重几乎得不到有效的更新。

根源:Sigmoid 激活函数

梯度消散问题与传统的 Sigmoid 激活函数密切相关。Sigmoid 函数及其导数如下:

σ(x)=11+e−x,σ′(x)=σ(x)(1−σ(x))\sigma(x) = \frac{1}{1 + e^{-x}}, \quad \sigma'(x) = \sigma(x)(1 - \sigma(x))

Sigmoid 导数的最大值出现在 x=0x=0 处,σ′(0)=0.25\sigma'(0) = 0.25。在大部分定义域内,其导数值都远小于 1。

现在,我们结合反向传播公式来理解问题。考虑一个简化场景,我们计算损失函数 CC 对某一层偏置 blb^l 的梯度。根据链式法则,这个梯度可以表示为后续各层权重 Wl+1,Wl+2,...W^{l+1}, W^{l+2}, ... 和激活函数导数 σ′(zl),σ′(zl+1),...\sigma'(z^{l}), \sigma'(z^{l+1}), ... 的连乘积形式。

假设权重按较小的随机值初始化(绝对值通常小于 1)。那么,在反向传播路径上,每经过一层,梯度就要乘以一个小于 1 的权重 WW 和一个小于等于 0.25 的激活函数导数 σ′\sigma'。

例如,对于一个 3 层隐藏层的网络,梯度从输出层传回第一层隐藏层时,至少会被乘以 (某值<1)×0.25(\text{某值} < 1) \times 0.25 这个过程三次。即使忽略权重的影响,仅激活函数导数部分就会引入 (0.25)3=1/64(0.25)^3 = 1/64 的衰减因子。如果网络更深,衰减将是指数灾难性的 (0.25)n(0.25)^n,导致底层梯度几乎消失。

import numpy as np

# 模拟一个简单的反向传播梯度计算(概念性展示)
np.random.seed(42)
# 假设有三层,每层的“梯度衰减因子”由权重(假设为0.5)和sigmoid导数(假设为0.25)构成
layer_factor = 0.5 * 0.25  # 每层的复合衰减因子
num_layers = 3

# 输出层初始梯度假设为 1.0
gradient_at_output = 1.0
# 传播回第一层隐藏层
gradient_at_first_hidden = gradient_at_output * (layer_factor ** num_layers)
print(f"经过 {num_layers} 层 Sigmoid 网络反向传播后,梯度衰减为: {gradient_at_first_hidden:.6f}")
print(f"这相当于初始梯度的 {gradient_at_first_hidden * 100:.2f}%")
经过 3 层 Sigmoid 网络反向传播后,梯度衰减为: 0.001953
这相当于初始梯度的 0.20%

历史方案:受限玻尔兹曼机预训练

在 2006 年左右,Geoffrey Hinton 等人提出了使用 受限玻尔兹曼机 进行无监督预训练的方法来缓解梯度消散。其核心思想是“分层训练”:

  1. 从最接近输入的第一层开始,训练一个 RBM,使其能够较好地重建输入数据。
  2. 固定第一层的权重,将其输出作为第二层 RBM 的输入,再训练第二层。
  3. 如此逐层训练,初始化整个网络的权重。
  4. 最后,使用有标签数据和反向传播对整个网络进行微调。

这种方法相当于为网络提供了一个较好的初始权重点,使其在微调阶段不至于陷入梯度太小的区域。然而,它的训练流程复杂、调参经验性强,随着更简单有效的技术出现,已不再是主流。

ReLU:简单而有效的解决方案

2010 年后,修正线性单元 迅速成为深度学习中最主流的激活函数,它从根本上改变了局面。

ReLU 函数的定义极其简单: ReLU(x)=max⁡(0,x)\text{ReLU}(x) = \max(0, x) 其导数为: ReLU′(x)={1if x>00if x<0\text{ReLU}'(x) = \begin{cases} 1 & \text{if } x > 0 \\ 0 & \text{if } x < 0 \end{cases}

ReLU 如何克服梯度消散?

关键在于其导数。在激活区域(x>0x > 0),ReLU 的导数为常数 1。

回顾梯度消散的分析,现在反向传播路径上的激活函数导数项不再是小于 0.25 的 σ′\sigma',而是等于 1(对于处于激活状态的神经元)。这意味着,梯度在通过 ReLU 层时,在激活路径上不再有衰减。梯度衰减的主要来源只剩下权重 WW 的连乘。虽然权重初始化值通常仍小于 1,但衰减速度从原来的 (<1)×(≤0.25)(<1) \times (\le 0.25) 变成了单纯的 (<1)(<1),极大地缓解了梯度消散问题。

此外,ReLU 还有两大优势:

  1. 计算高效:仅涉及比较和取最大值操作,比计算指数函数的 Sigmoid/Tanh 快得多。
  2. 引入稀疏性:当输入为负时,ReLU 输出为零。这使得网络中的一部分神经元在训练过程中被“关闭”,整个网络变得“更瘦”。这可以看作一种隐式的正则化,有助于防止过拟合。

下面我们通过一个简单的对比,直观感受 ReLU 和 Sigmoid 在梯度上的差异:

import numpy as np

# 定义函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    s = sigmoid(x)
    return s * (1 - s)

def relu(x):
    return np.maximum(0, x)

def relu_derivative(x):
    return np.where(x > 0, 1.0, 0.0)

# 在[-5, 5]区间采样
x = np.linspace(-5, 5, 11)
print("输入值 x:", x)
print("Sigmoid 导数:", np.round(sigmoid_derivative(x), 4))
print("ReLU 导数:   ", np.round(relu_derivative(x), 4))
输入值 x: [-5. -4. -3. -2. -1.  0.  1.  2.  3.  4.  5.]
Sigmoid 导数: [0.0066 0.0177 0.0452 0.105  0.1966 0.25   0.1966 0.105  0.0452 0.0177
 0.0066]
ReLU 导数:    [0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1.]

可以看到,Sigmoid 的导数在 0 附近最大也只有 0.25,并向两侧迅速衰减。而 ReLU 在正半轴的导数恒为 1,为梯度流动提供了“高速公路”。

ReLU 的变体

尽管 ReLU 非常成功,但它也存在“神经元死亡”问题:一旦某个神经元的输入永久落入负半轴,其梯度将永远为零,该神经元再也不会被激活。为此,研究者提出了几种变体:

  • Leaky ReLU:f(x)=max⁡(αx,x)f(x) = \max(\alpha x, x),给负半轴一个小的斜率 α\alpha(如 0.01),让梯度不至于完全为零。
  • Parametric ReLU (PReLU):将负半轴的斜率 α\alpha 也作为可学习的参数。
  • Exponential Linear Unit (ELU):f(x)={xif x>0α(ex−1)if x≤0f(x) = \begin{cases} x & \text{if } x > 0 \\ \alpha(e^x - 1) & \text{if } x \le 0 \end{cases},试图让激活的均值更接近零,加速收敛。

这些变体在不同场景下各有优劣,但标准 ReLU 因其简单和可靠,仍然是大多数架构的首选起点。

📝 动手练一练

  1. 概念辨析:假设一个三分类网络的最后一层输出 logits 为 [2.0, -1.0, 0.5]。 a) 请手动计算(或心算估算)经过 Softmax 层后的概率分布。 b) 如果真实标签是第二类(index=1,one-hot 编码为 [0, 1, 0]),请估算此时的交叉熵损失值大约是多少?
👉 点击查看参考答案

a) Softmax 计算: 首先计算指数:e2≈7.389e^2 \approx 7.389, e−1≈0.368e^{-1} \approx 0.368, e0.5≈1.649e^{0.5} \approx 1.649。 求和:7.389+0.368+1.649≈9.4067.389 + 0.368 + 1.649 \approx 9.406。 概率:p1≈7.389/9.406≈0.785p_1 \approx 7.389 / 9.406 \approx 0.785, p2≈0.368/9.406≈0.039p_2 \approx 0.368 / 9.406 \approx 0.039, p3≈1.649/9.406≈0.175p_3 \approx 1.649 / 9.406 \approx 0.175。 所以概率分布约为 [0.785, 0.039, 0.175]。

b) 交叉熵损失: 真实标签为第二类,所以只有 y2=1y_2=1,其他为 0。 损失 L=−(0⋅log⁡(0.785)+1⋅log⁡(0.039)+0⋅log⁡(0.175))=−log⁡(0.039)L = - (0 \cdot \log(0.785) + 1 \cdot \log(0.039) + 0 \cdot \log(0.175)) = -\log(0.039)。 由于 log⁡(0.039)≈−3.24\log(0.039) \approx -3.24,所以 L≈3.24L \approx 3.24。 这是一个相对较大的损失值,因为模型对正确类别的预测概率很低(0.039),符合交叉熵惩罚错误预测的特性。

  1. 梯度计算思考:在一个使用 Sigmoid 激活函数的 10 层全连接网络中,假设每层的权重绝对值约为 0.8,每层 Sigmoid 激活函数的导数平均值约为 0.2。请估算,从输出层传播到第一层的梯度,大约会衰减为初始梯度的多少倍?这说明了什么问题?
👉 点击查看参考答案

每层的“梯度衰减因子”约为 0.8×0.2=0.160.8 \times 0.2 = 0.16。 经过 10 层传播,总衰减因子为 0.16100.16^{10}。 计算:0.1610=(0.165)20.16^{10} = (0.16^5)^2。0.162=0.02560.16^2=0.0256, 0.164=0.000655360.16^4=0.00065536, 0.165≈0.00010485760.16^5 \approx 0.0001048576。再平方得到 0.1610≈1.1×10−80.16^{10} \approx 1.1 \times 10^{-8}。 这意味着初始梯度传到第一层时,只剩下约 一亿分之一(1.1×10−81.1 \times 10^{-8})。如此微小的梯度几乎无法有效更新底层网络的权重,这就是典型的“梯度消散”问题。它解释了为什么使用 Sigmoid 的深层网络难以训练。

本章小结

本节深入剖析了深度学习在基础组件上对传统神经网络的重大改进。首先,我们看到了目标函数从均方误差到交叉熵的转变,后者与 Softmax 概率输出层相结合,为分类任务提供了更清晰、更陡峭的优化路径,极大地加速了训练收敛。其次,我们揭示了困扰深层网络训练的梯度消散问题的根源——Sigmoid 类激活函数导数值过小且在深层连乘。最后,我们认识了 ReLU 激活函数如何以其简洁的形式(正区间导数为1)有效缓解了梯度消散,并带来了计算高效和网络稀疏化的额外好处,从而成为推动深度学习走向“深度”的关键技术之一。

今天,交叉熵 + Softmax 仍是分类任务的默认组合,ReLU 及其变体(Leaky ReLU、GELU、SiLU 等)仍是绝大多数网络的第一选择。后续的 BatchNorm/LayerNorm、残差连接与更好的初始化,进一步把“深层难训练”这件事系统性地解决了;但“让梯度在反传路上不掉得太快”这一核心思路,正是从本节这几个改动开始的。

📋 行动清单

  • 理解交叉熵的优越性:能够用自己的话解释为什么在分类任务中,交叉熵损失比均方误差损失更有效。
  • 掌握 Softmax 计算:给定一组 logits,能手动或编程计算出对应的概率分布,并理解其避免零概率的意义。
  • 明晰梯度消散与 ReLU 的关系:能清晰阐述 Sigmoid 导致梯度消散的数学原理,以及 ReLU 是如何解决这个问题的。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第6章《深度学习基础》配套课件(PDF)
    PDF · 2.9MB · 原课教辅
    下载
  • 第6章《深度学习基础》配套代码包
    ZIP · 11.4MB · 原课教辅
    下载