计算机视觉与深度学习-Lecture3 and Lecture4
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=1∑NLi(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)=∑k∑lWk,l2。倾向于让权重均匀变小,防止单个特征独占过大权重。
- L1 正则化:R(W)=∑k∑l∣Wk,l∣R(W) = \sum_k \sum_l \vert{}W_{k,l}\vert{}R(W)=∑k∑l∣Wk,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×10−3 或 5×10−45\times10^{-4}5×10−4。
- 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)
-
前向传播:接收输入 xxx 和 yyy,计算输出 z=f(x,y)z = f(x, y)z=f(x,y)。同时计算并存储局部梯度(Local Gradient):∂z∂x\frac{\partial z}{\partial x}∂x∂z 和 ∂z∂y\frac{\partial z}{\partial y}∂y∂z。
-
反向传播:接收从上游传回的梯度 ∂L∂z\frac{\partial L}{\partial z}∂z∂L,将其与局部梯度相乘,即可得到关于输入的下游梯度:
∂L∂x=∂L∂z×∂z∂x\frac{\partial L}{\partial x} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial x}∂x∂L=∂z∂L×∂x∂z
∂L∂y=∂L∂z×∂z∂y\frac{\partial L}{\partial y} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial y}∂y∂L=∂z∂L×∂y∂z
参数更新(Parameter Update)
通过反向传播(Backpropagation)利用链式法则计算出损失函数 LLL 关于所有待训练参数(如权重 WWW 和偏置 bbb)的梯度 ∂L∂W\frac{\partial L}{\partial W}∂W∂L 和 ∂L∂b\frac{\partial L}{\partial b}∂b∂L 后,我们便可以使用优化器来执行参数更新。
1. 基础梯度更新(以 SGD 为例)
最基本的更新方式是沿着梯度的反方向(即损失下降最快的方向)迈出一步,步长由学习率(Learning Rate, α\alphaα)控制:
W←W−α∂L∂WW \leftarrow W - \alpha \frac{\partial L}{\partial W}W←W−α∂W∂L
b←b−α∂L∂bb \leftarrow b - \alpha \frac{\partial L}{\partial b}b←b−α∂b∂L
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
更多推荐




所有评论(0)