【NumPy】MNIST上深度学习计算过程理解:四、激活函数和Dropout

一、背景

基于对应链接示例上的深度学习过程,对每一步进行详细的说明,方便数据和实例的结合理解深度学习的过程。

示例的简单介绍:提供0-9的数字灰度照片进行深度学习训练,数据包括6万张训练图像和1万张测试图像以及对应的标签(即0-9的标签)。图像的像素为28*28,大小为784。

续:前向传播内部说明

二、激活函数(神经网络的”灵魂“)

激活函数是神经网络能够学习复杂模式的关键所在,其主要作用包括:

  1. 引入非线性:如果没有激活函数,无论神经网络有多少层,都只是线性变换的组合,最终仍然等价于一个线性模型。激活函数的非线性使网络能够逼近任意复杂函数。
  2. 决定神经元是否激活:根据输入信号的强度,决定神经元是否被激活(输出非零值)。
  3. 控制输出范围:不同激活函数将输出值限制在不同范围内(如Sigmoid在0-1,Tanh在-1到1,ReLU在0到正无穷)。

数学证明

假设我们有一个3层无激活函数的网络:

  1. 第1层:h₁ = W₁·x + b₁
  2. 第2层:h₂ = W₂·h₁ + b₂ = W₂·(W₁·x + b₁) + b₂
  3. 第3层:y = W₃·h₂ + b₃ = W₃·(W₂·(W₁·x + b₁) + b₂) + b₃

展开并重新组合:

y = W₃·W₂·W₁·x + W₃·W₂·b₁ + W₃·b₂ + b₃
  = (W₃·W₂·W₁)·x + (W₃·W₂·b₁ + W₃·b₂ + b₃)
  = W_combined·x + b_combined

其中:W_combined = W₃·W₂·W₁b_combined = W₃·W₂·b₁ + W₃·b₂ + b₃

结论:无论多少层,最终都可以合并为单个线性变换 y = W·x + b,这就是线性回归模型!

三、Dropout(防止过拟合的"正则化大师")

Dropout是一种在训练期间随机"丢弃"(置零)部分神经元输出的技术,其核心作用包括:

  1. 防止过拟合:通过随机丢弃神经元,阻止网络过度依赖某些特定特征或神经元组合。
  2. 促进鲁棒性:迫使每个神经元都能独立发挥作用,而不是依赖于其他特定神经元。
  3. 实现模型平均:Dropout训练相当于训练了大量共享权重的子网络,测试时相当于这些子网络的集合预测。

扩展之前的实例,加入Dropout机制:

原始前向传播(无Dropout)

z1 = [0.18, 0.26]
a1 = relu(z1) = [0.18, 0.26]  # 两个神经元都激活
z2 = a1 · W2 = [0.192, -0.064]

加入Dropout(丢弃率50%)
假设随机生成的Dropout掩码为[1, 0](丢弃第二个神经元):

python

# 前向传播(训练时)
z1 = [0.18, 0.26]
a1 = relu(z1) = [0.18, 0.26]
dropout_mask = [1, 0]  # 随机生成,50%概率为0
a1_dropout = a1 * dropout_mask = [0.18, 0]  # 第二个神经元被"丢弃"

# 继续前向传播
z2_dropout = a1_dropout · W2 
           = [0.18, 0] · [[0.2, -0.5], [0.6, 0.1]]
           = [0.18*0.2 + 0*0.6, 0.18*(-0.5) + 0*0.1]
           = [0.036, -0.09]  # 与无Dropout的结果不同!

反向传播的影响
由于第二个神经元被丢弃,其梯度也为0:

python

# 反向传播时,被丢弃神经元的梯度为0
∂L/∂a1_dropout = [0.5522, -0.0874]  # 正常计算的梯度
∂L/∂a1 = ∂L/∂a1_dropout * dropout_mask = [0.5522, 0]  # 第二个神经元的梯度被屏蔽

多次迭代中的Dropout效果展示

让我们通过一个简单表格展示不同训练迭代中Dropout的影响:

迭代次数 Dropout掩码 激活的神经元 网络行为 学习效果
第1次 [1, 0] 仅神经元1 学习特征A 神经元1的权重被调整
第2次 [0, 1] 仅神经元2 学习特征B 神经元2的权重被调整
第3次 [1, 1] 两个神经元 综合学习 两个神经元协同工作
第4次 [1, 0] 仅神经元1 巩固特征A 神经元1进一步优化

Dropout的核心思想:通过强迫不同神经元在不同时间独立工作,防止它们形成复杂的共适应关系(co-adaptation),从而增强泛化能力。

四、实例(激活函数与Dropout的协同作用)

1. 实例场景

考虑一个识别猫耳朵的简单任务:

  • 神经元1:检测"三角形形状"
  • 神经元2:检测"毛茸茸纹理"
  • 神经元3:检测"尖尖的顶端"

2. 无Dropout的问题

在没有Dropout的情况下,网络可能学会:

如果(神经元1 AND 神经元3) -> 猫耳朵

这种依赖特定神经元组合的模式容易过拟合训练数据中的偶然模式。

3. 有Dropout的健壮学习

加入Dropout后,网络被迫学习:

  • 当神经元1被丢弃时:必须用神经元2和3判断
  • 当神经元3被丢弃时:必须用神经元1和2判断
  • 最终学会:神经元1 OR 神经元2 OR 神经元3 都能提供部分证据

4. 数值模拟

# 模拟10次训练迭代中Dropout的影响
training_iterations = 10
dropout_rate = 0.5
neurons = ['N1(形状)', 'N2(纹理)', 'N3(尖端)']

for i in range(training_iterations):
    # 随机生成Dropout掩码
    mask = np.random.binomial(1, 1-dropout_rate, size=3)
    
    # 模拟网络激活
    activated = [neurons[j] for j in range(3) if mask[j]==1]
    
    print(f"迭代 {i+1}: 掩码={mask}, 激活的神经元={activated}")
    print(f"  学习模式: 基于{' + '.join(activated) if activated else '无'}判断猫耳朵")
    print()

输出示例:

迭代 1: 掩码=[1 0 1], 激活的神经元=['N1(形状)', 'N3(尖端)']
  学习模式: 基于N1(形状) + N3(尖端)判断猫耳朵

迭代 2: 掩码=[0 1 1], 激活的神经元=['N2(纹理)', 'N3(尖端)']
  学习模式: 基于N2(纹理) + N3(尖端)判断猫耳朵

迭代 3: 掩码=[1 1 0], 激活的神经元=['N1(形状)', 'N2(纹理)']
  学习模式: 基于N1(形状) + N2(纹理)判断猫耳朵

4. 效果对比:有无激活函数和Dropout

网络配置 训练准确率 测试准确率 泛化能力 训练稳定性
无激活函数 稳定但性能有限
有ReLU无Dropout 中等 一般 可能不稳定
有ReLU有Dropout 中等偏高 优秀 更稳定

更多推荐