Skip to content

章节1:神经网络原理


学习目标

  • 理解感知机与多层感知机(MLP)的结构与局限
  • 掌握反向传播算法中的链式法则与梯度计算流程
  • 熟悉常用激活函数的特性与适用场景
  • 理解损失函数与优化器的作用机制
  • 掌握批量归一化与Dropout等正则化技术

1.1 感知机与多层感知机

1.1.1 感知机(Perceptron)

感知机是神经网络的最基本单元,由 Rosenblatt 于 1958 年提出。它接受多个输入,乘以权重后求和,再通过阶跃函数输出。

数学定义:

$$ y = \begin{cases} 1, & \sum_{i=1}^{n} w_i x_i + b > 0 \ 0, & \text{otherwise} \end{cases} $$

其中 $w_i$ 是权重,$b$ 是偏置,$x_i$ 是输入特征。

局限性: 单层感知机只能解决线性可分问题(如 AND、OR),无法解决 XOR 等非线性问题。

1.1.2 多层感知机(MLP)

多层感知机通过在输入层与输出层之间引入一个或多个隐藏层,并使用非线性激活函数,解决了非线性分类问题。

数学定义:

$$ \begin{aligned} h &= f(W_1 x + b_1) \ y &= g(W_2 h + b_2) \end{aligned} $$

其中 $f$ 和 $g$ 为激活函数,$W_1, W_2$ 为权重矩阵。

PyTorch 实现一个简单 MLP:

python
import torch
import torch.nn as nn

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, output_dim)
        )

    def forward(self, x):
        return self.net(x)

# 测试
model = MLP(784, 256, 10)
x = torch.randn(32, 784)  # batch_size=32
print(model(x).shape)      # torch.Size([32, 10])

1.2 反向传播算法(Backpropagation)

1.2.1 链式法则

反向传播的核心是链式法则(Chain Rule):复合函数的导数等于各层导数的乘积。

对于 $L = f(g(h(x)))$,有:

$$ \frac{\partial L}{\partial x} = \frac{\partial L}{\partial f} \cdot \frac{\partial f}{\partial g} \cdot \frac{\partial g}{\partial h} \cdot \frac{\partial h}{\partial x} $$

1.2.2 梯度计算流程

  1. 前向传播:计算每层输出与最终损失值
  2. 反向传播:从输出层向输入层逐层计算梯度
  3. 参数更新:使用梯度下降更新权重

PyTorch 自动梯度示例:

python
import torch

x = torch.tensor([2.0, 3.0], requires_grad=True)
w = torch.tensor([1.5, -0.5], requires_grad=True)
b = torch.tensor([0.1], requires_grad=True)

y = (x * w).sum() + b   # 前向计算
loss = y ** 2           # 假损失

loss.backward()         # 反向传播(自动计算梯度)

print(f"dw: {w.grad}")  # 权重梯度
print(f"db: {b.grad}")  # 偏置梯度

1.3 激活函数

激活函数为神经网络引入非线性,使其能够拟合复杂函数。

1.3.1 Sigmoid

将输入映射到 $(0, 1)$ 区间,常用于二分类输出层。

公式:

$$ \sigma(x) = \frac{1}{1 + e^{-x}} $$

梯度:

$$ \sigma'(x) = \sigma(x)(1 - \sigma(x)) $$

缺点: 当 $x$ 绝对值很大时梯度趋近于 0,导致梯度消失。

1.3.2 Tanh

将输入映射到 $(-1, 1)$ 区间,零中心化。

公式:

$$ \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} $$

梯度:

$$ \tanh'(x) = 1 - \tanh^2(x) $$

1.3.3 ReLU

目前最常用的隐藏层激活函数。

公式:

$$ \text{ReLU}(x) = \max(0, x) $$

优点: 计算简单、缓解梯度消失、稀疏激活。 缺点: 神经元死亡(负半轴梯度为 0)。

1.3.4 LeakyReLU

改进 ReLU 的负半轴问题。

公式:

$$ \text{LeakyReLU}(x) = \max(\alpha x, x), \quad \alpha \text{ 通常取 } 0.01 $$

PyTorch 激活函数对比:

python
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt

x = torch.linspace(-5, 5, 100)

sigmoid = torch.sigmoid(x)
tanh = torch.tanh(x)
relu = F.relu(x)
leaky_relu = F.leaky_relu(x, negative_slope=0.01)

plt.figure(figsize=(10, 6))
plt.plot(x, sigmoid, label='Sigmoid')
plt.plot(x, tanh, label='Tanh')
plt.plot(x, relu, label='ReLU')
plt.plot(x, leaky_relu, label='LeakyReLU')
plt.legend()
plt.grid()
plt.show()

1.4 损失函数与优化器

1.4.1 交叉熵损失(Cross-Entropy Loss)

用于分类任务,衡量预测分布与真实分布的差异。

公式(多分类):

$$ \mathcal{L} = -\sum_{i=1}^{C} y_i \log(\hat{y}_i) $$

其中 $y_i$ 是真实标签的 one-hot 编码,$\hat{y}_i$ 是预测概率。

1.4.2 均方误差(MSE Loss)

用于回归任务。

公式:

$$ \mathcal{L} = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 $$

1.4.3 SGD(随机梯度下降)

每次用单个样本(或 mini-batch)更新参数。

$$ \theta_{t+1} = \theta_t - \eta \nabla_{\theta} L(\theta_t) $$

1.4.4 Adam 优化器

结合 Momentum(动量)与 RMSProp(自适应学习率),是深度学习中最常用的优化器。

$$ \begin{aligned} m_t &= \beta_1 m_{t-1} + (1-\beta_1) g_t \ v_t &= \beta_2 v_{t-1} + (1-\beta_2) g_t^2 \ \hat{m}_t &= m_t / (1-\beta_1^t) \ \hat{v}t &= v_t / (1-\beta_2^t) \ \theta &= \theta_t - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} \end{aligned} $$

PyTorch 损失与优化器示例:

python
import torch
import torch.nn as nn
import torch.optim as optim

# 定义模型
model = nn.Linear(10, 2)

# 损失函数
criterion = nn.CrossEntropyLoss()   # 分类
# criterion = nn.MSELoss()           # 回归

# 优化器
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# optimizer = optim.Adam(model.parameters(), lr=0.001)

# 模拟训练一步
x = torch.randn(16, 10)
y = torch.randint(0, 2, (16,))

output = model(x)
loss = criterion(output, y)

optimizer.zero_grad()
loss.backward()
optimizer.step()

print(f"Loss: {loss.item():.4f}")

1.5 批量归一化与 Dropout 正则化

1.5.1 批量归一化(Batch Normalization)

对每个 mini-batch 进行归一化,使激活值分布在合理范围内,加速训练并缓解过拟合。

公式:

$$ \hat{x}^{(k)} = \frac{x^{(k)} - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} $$

$$ y^{(k)} = \gamma^{(k)} \hat{x}^{(k)} + \beta^{(k)} $$

其中 $\mu_B, \sigma_B$ 分别是 mini-batch 的均值和方差,$\gamma, \beta$ 是可学习参数。

1.5.2 Dropout

训练时以概率 $p$ 随机丢弃神经元,迫使网络学习冗余特征,防止过拟合。

python
import torch.nn as nn

class RegularizedMLP(nn.Module):
    def __init__(self, input_dim=784, hidden_dim=512, output_dim=10):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.BatchNorm1d(hidden_dim),   # 批量归一化
            nn.ReLU(),
            nn.Dropout(0.5),              # 50% Dropout
            nn.Linear(hidden_dim, output_dim)
        )

    def forward(self, x):
        return self.net(x)

model = RegularizedMLP()
print(model)

小结

概念关键要点
感知机线性分类器,无法解决 XOR
多层感知机引入隐藏层 + 激活函数解决非线性
反向传播链式法则逐层计算梯度
激活函数ReLU 默认首选,Sigmoid 用于二分类输出
损失函数CrossEntropy(分类)、MSE(回归)
优化器Adam 最常用,SGD + Momentum 也有效
正则化BatchNorm 加速训练,Dropout 防过拟合

练习

  1. 代码填空:手写一个 3 层 MLP(输入 784 → 隐藏 256 → 隐藏 128 → 输出 10),使用 ReLU 激活和 Adam 优化器。
  2. 推导题:画出反向传播中 $L = (wx + b)^2$ 的计算图,并写出 $\partial L / \partial w$ 的链式展开。
  3. 对比分析:分别用 Sigmoid 和 ReLU 作为隐藏层激活函数训练 MLP,观察收敛速度差异并解释原因。
  4. 调优实验:在同一个 MLP 上对比不加正则化、加 BatchNorm、加 Dropout(p=0.5) 三种情况下的验证集准确率。

Python 学习资料