Lecture 3:Regularization and Optimization

正则化(Regularization)

为了防止模型过拟合(Overfitting)(即训练数据表现极好,但测试和未见过的数据表现很差),我们需要在损失函数中引入正则化项,惩罚过于复杂的权重 WWW

完整损失函数公式

总损失由数据损失(Data Loss)正则化损失(Regularization Loss)两部分组成:

L=1N∑i=1NLi(f(xi,W),yi)+λR(W)L = \frac{1}{N} \sum_{i=1}^{N} L_i(f(x_i, W), y_i) + \lambda R(W)L=N1i=1NLi(f(xi,W),yi)+λR(W)

  • λ\lambdaλ(正则化强度 / Regularization Strength):一个超参数。λ\lambdaλ 越大,对权重的惩罚越重,模型越简单。

常见正则化类型

  • L2 正则化(权重衰减 / Weight Decay)R(W)=∑k∑lWk,l2R(W) = \sum_k \sum_l W_{k,l}^2R(W)=klWk,l2。倾向于让权重均匀变小,防止单个特征独占过大权重。
  • L1 正则化R(W)=∑k∑l∣Wk,l∣R(W) = \sum_k \sum_l \vert{}W_{k,l}\vert{}R(W)=klWk,l。倾向于产生稀疏权重(Sparse Weights),即让很多权重直接变为 0,起到特征选择的作用。
  • 高级正则化技术:Dropout(随机失活)、Batch Normalization(批归一化)等,在后续复杂网络中应用。

优化(Optimization)

优化的目标是找到使损失函数 LLL 最小化的权重矩阵 WWW。我们通过计算损失函数关于权重的梯度(Gradient),利用梯度下降(Gradient Descent)算法沿着最陡峭的下降方向(负梯度方向)更新参数。

经典优化算法对比与 Python 实现

1. 随机梯度下降(Stochastic Gradient Descent, SGD)
  • 核心思想:不再计算整个数据集的梯度,而是每次随机抽取一个小批量(Mini-batch)的样本来估算梯度,从而大幅提升计算速度。
  • 缺点:遇到鞍点(Saddle Points)或局部极小值时,梯度为 0,训练容易陷入停滞。

Python

# SGD 核心训练循环
while True:
    data_batch = sample_training_data(data, batch_size=256) # 抽取 Mini-batch
    weights_grad = evaluate_gradient(loss_function, data_batch, weights)
    
    # 参数更新:沿负梯度方向迈出一步
    learning_rate = 1e-3
    weights -= learning_rate * weights_grad 
2. 动量随机梯度下降(SGD + Momentum)
  • 核心思想:引入物理学中“动量”的概念。维持一个速度变量 VVV,让模型在梯度更新时具有惯性,从而能够冲过鞍点和局部平缓区域。

Vt+1=ρVt+∇f(Xt)Xt+1=Xt−αVt+1\begin{aligned} V_{t+1} &= \rho V_t + \nabla f(X_t) \\ X_{t+1} &= X_t - \alpha V_{t+1} \end{aligned}Vt+1Xt+1=ρVt+f(Xt)=XtαVt+1

Python

# SGD + Momentum 核心训练循环
v = 0  # 初始化速度为 0
rho = 0.9  # 摩擦系数/动量因子 (通常设为 0.9 或 0.99)
learning_rate = 1e-3

while True:
    data_batch = sample_training_data(data, batch_size=256)
    weights_grad = evaluate_gradient(loss_function, data_batch, weights)
    
    # 更新速度,合并历史动量与当前梯度
    v = rho * v + weights_grad
    # 参数更新
    weights -= learning_rate * v 
3. RMSProp
  • 核心思想:自适应学习率算法。通过计算历史梯度平方的指数移动平均,对每个参数的学习率进行缩放。梯度大的参数步长变小,梯度小的参数步长变大,从而改变步长与步进方向。

Python

# RMSProp 核心训练循环
grad_squared = 0
decay_rate = 0.99  # 衰减率
learning_rate = 1e-3
eps = 1e-8  # 防止除以 0 的平滑值

while True:
    data_batch = sample_training_data(data, batch_size=256)
    weights_grad = evaluate_gradient(loss_function, data_batch, weights)
    
    # 累积梯度的平方
    grad_squared = decay_rate * grad_squared + (1 - decay_rate) * (weights_grad ** 2)
    # 自适应步长更新
    weights -= (learning_rate / (np.sqrt(grad_squared) + eps)) * weights_grad
4. Adam 优化器(Adaptive Moment Estimation)
  • 核心思想:集大成者。几乎是将 Momentum(一阶动量:梯度的平均值)RMSProp(二阶动量:梯度平方的平均值) 结合在一起,并加入了偏差校正(Bias Correction)
  • 超参数推荐β1=0.9\beta_1 = 0.9β1=0.9β2=0.999\beta_2 = 0.999β2=0.999,学习率(Learning rate)通常设为 1×10−31\times10^{-3}1×1035×10−45\times10^{-4}5×104
  • AdamW:Adam 的变体,将权重衰减(L2 正则化)与梯度的更新解耦,现代深度学习(如 Transformer)中更为常用。

Python

# Adam 核心训练循环
first_moment = 0   # 一阶动量(类似 Momentum)
second_moment = 0  # 二阶动量(类似 RMSProp)
beta1 = 0.9
beta2 = 0.999
learning_rate = 1e-3
eps = 1e-8

for t in range(1, num_iterations + 1):
    data_batch = sample_training_data(data, batch_size=256)
    weights_grad = evaluate_gradient(loss_function, data_batch, weights)
    
    # 1. 更新一阶和二阶动量
    first_moment = beta1 * first_moment + (1 - beta1) * weights_grad
    second_moment = beta2 * second_moment + (1 - beta2) * (weights_grad ** 2)
    
    # 2. 偏差校正(由于初始值为 0,在训练初期需要放大)
    first_unbiased = first_moment / (1 - beta1 ** t)
    second_unbiased = second_moment / (1 - beta2 ** t)
    
    # 3. 参数更新
    weights -= (learning_rate / (np.sqrt(second_unbiased) + eps)) * first_unbiased

学习率退火/衰减策略(Learning Rate Schedules)

在训练初期使用大学习率快速下降,后期逐步减小学习率以实现精准收敛。

策略类型 英文 描述
阶梯衰减 Step Decay 运行固定时间或 Epoch 后,将学习率除以 10(或乘以 0.1)。
余弦衰减 Cosine Decay 让学习率按照余弦函数的曲线平滑下降到接近 0 的位置。
线性下降 Linear Decay 学习率随着训练步数呈线性规律直接递减。
线性预热 Linear Warmup 在训练前几个 Epoch,学习率从小线性增加到设定值,防止刚开局时大梯度破坏随机初始化的权重,随后再配合其他衰减策略组合使用。

Lecture 4:Neural Networks and Backpropagation

神经网络(Neural Networks)

如果一个网络中只涉及矩阵乘法(线性变换),它本质上仍是一个单层线性分类器。为了解决复杂的非线性问题,必须在层与层之间引入激活函数(Activation Function)。只涉及全连接乘法和激活函数的结构被称为全连接网络(Fully-Connected Network)或多层感知机(MLP)

激活函数示例

  • ReLU(整流线性单元)f(z)=max⁡(0,z)f(z) = \max(0, z)f(z)=max(0,z)。最常用的经典非线性激活函数。
  • 其他激活函数:Sigmoid, Tanh, SiLU (Swish) 等。

神经网络架构拓扑图解

一个拥有两个隐藏层(Hidden Layers)的三层神经网络结构如下:

[Input Layer] (x)  --> 3072 维输入图像向量
       │        × W1 + b1
[Hidden Layer 1] (h1) --> 激活函数 f(W1·x + b1) 引入非线性
       │        × W2 + b2
[Hidden Layer 2] (h2) --> 激活函数 f(W2·h1 + b2)
       │        × W3 + b3
[Output Layer] (out)  --> 最终各类别得分 (Scores)

前向传播(Forward Propagation)的 Python 实现

Python

import numpy as np

# 激活函数定义 (以 ReLU 为例)
def relu(z):
    return np.maximum(0, z)

# 模拟三层全连接前向传播
x = np.random.randn(3072, 1) # 假定输入为 3072 维列向量

# 1. 计算第一隐藏层
h1 = relu(np.dot(W1, x) + b1)
# 2. 计算第二隐藏层
h2 = relu(np.dot(W2, h1) + b2)
# 3. 计算最终输出得分
output = np.dot(W3, h2) + b3

注意:在实际搭建网络时,我们通常调整的是超参数(层数、隐藏层维度)和正则化强度,而不是频繁改动网络本身的结构代码。

反向传播(Backpropagation)

为了计算损失函数对神经网络中每个参数的梯度,我们使用计算图(Computational Graphs)和反向传播技术。

链式法则(Chain Rule)与局部梯度

反向传播的核心是微积分的链式法则。对于计算图中的任意一个门单元(Gate):

    x ───\
          [ 门单元 f ] ───> z
    y ───/
    
   (上游传回梯度: ∂L/∂z)
  1. 前向传播:接收输入 xxxyyy,计算输出 z=f(x,y)z = f(x, y)z=f(x,y)。同时计算并存储局部梯度(Local Gradient)∂z∂x\frac{\partial z}{\partial x}xz∂z∂y\frac{\partial z}{\partial y}yz

  2. 反向传播:接收从上游传回的梯度 ∂L∂z\frac{\partial L}{\partial z}zL,将其与局部梯度相乘,即可得到关于输入的下游梯度:

    ∂L∂x=∂L∂z×∂z∂x\frac{\partial L}{\partial x} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial x}xL=zL×xz

    ∂L∂y=∂L∂z×∂z∂y\frac{\partial L}{\partial y} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial y}yL=zL×yz

参数更新(Parameter Update)

通过反向传播(Backpropagation)利用链式法则计算出损失函数 LLL 关于所有待训练参数(如权重 WWW 和偏置 bbb)的梯度 ∂L∂W\frac{\partial L}{\partial W}WL∂L∂b\frac{\partial L}{\partial b}bL 后,我们便可以使用优化器来执行参数更新。

1. 基础梯度更新(以 SGD 为例)

最基本的更新方式是沿着梯度的反方向(即损失下降最快的方向)迈出一步,步长由学习率(Learning Rate, α\alphaα)控制:

W←W−α∂L∂WW \leftarrow W - \alpha \frac{\partial L}{\partial W}WWαWL

b←b−α∂L∂bb \leftarrow b - \alpha \frac{\partial L}{\partial b}bbαbL

2. 参数更新的完整前向-反向训练循环(PyTorch 风格伪代码)

在实际的大规模训练中,前向传播、反向传播和参数更新是一个循环往复的过程:

Python

# 一个完整的训练 Step
for x_batch, y_batch in train_loader:
    # 1. 前向传播 (Forward Pass):计算预测值和 Loss
    y_pred = forward_pass(x_batch, weights)
    loss = compute_loss(y_pred, y_batch)
    
    # 2. 清空上一轮的梯度 (防止梯度累加)
    optimizer.zero_grad()
    
    # 3. 反向传播 (Backward Pass):从 Loss 开始反向计算所有参数的梯度
    loss.backward()  # 此步会自动利用链式法则计算出 weights.grad
    
    # 4. 更新参数 (Update step):优化器根据计算出的梯度更新 W 和 b
    optimizer.step()  # 相当于执行了 W = W - alpha * dL/dW
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐