$\large\star$ 回顾:梯度下降与优化器

上一讲的核心:通过梯度下降优化损失函数,找到最优参数 $W$。

数值梯度 与 解析梯度

数值梯度 解析梯度
慢,近似,容易写 快,精确,容易出错

实践中:推导解析梯度,用数值梯度检查实现是否正确。

SGD (随机梯度下降)

全量梯度计算在 $N$ 很大时代价太高,改用 mini-batch(32/64/128/256 个样本)近似:

1
2
3
4
while True:
data_batch = sample_training_data(data, 256)
weights_grad = evaluate_gradient(loss_fun, data_batch, weights)
weights += -step_size * weights_grad

学习率调度

几种常见策略:

  • Step: 在固定轮数处将 LR 乘以 0.1(如 ResNet 在第 30、60、90 epoch)
  • Cosine: $\alpha_t = \frac{1}{2}\alpha_0(1 + \cos(\frac{t\pi}{T}))$
  • Linear: 线性衰减
  • Inverse sqrt: 反平方根衰减

$\large\star$ 一、神经网络

1.1 从线性分类器到神经网络

线性分类器(之前):

2层神经网络(现在):

  • $W_1$:第一层权重(学习中间表示)
  • $\max(0, \cdot)$:非线性激活函数
  • $W_2$:第二层权重(输出分类分数)
  • 实践中每层还会加上可学习的偏置项

1.2 为什么需要非线性?

线性变换的复合仍然是线性的 -> 如果没有非线性,多层网络等价于单层线性分类器

非线性激活函数可以将数据变换到另一个空间,使得原本线性不可分的数据变得可分——类似于特征变换

核心:非线性激活函数打破了”线性复合仍是线性”的束缚,让网络拥有真正的表达能力。

1.3 常用激活函数

函数 形式 说明
Sigmoid $\sigma(x) = \frac{1}{1+e^{-x}}$ 早期常用,有梯度饱和问题
tanh $\tanh(x)$ 零中心,仍有饱和问题
ReLU $\max(0, x)$ 计算简单,收敛快,大多数问题的默认选择
Leaky ReLU $\max(0.1x, x)$ 缓解ReLU的”死亡神经元”问题
ELU $x$ if $x>0$ else $\alpha(e^x-1)$ 更平滑的负半轴
Maxout $\max(w_1^Tx+b_1, w_2^Tx+b_2)$ 更灵活但参数翻倍

默认选择:ReLU — 简单高效,适用于大多数场景。

1.4 网络架构与命名

  • “2层神经网络” = “1个隐藏层的神经网络”(输入→隐藏→输出)
  • “3层神经网络” = “2个隐藏层的神经网络”
  • 这种结构也称作全连接网络(Fully-Connected Network)或多层感知机(MLP)

1.5 前向计算示例

对于一个 $3072 \to 100 \to 10$ 的2层网络:

1
2
3
4
# 前向传播
h = W1 @ x # 3072 -> 100:学习100个模板(而非10个)
h = max(0, h) # ReLU 激活
s = W2 @ h # 100 -> 10:模板到类别的映射

线性分类器直接学10个模板(每个类别一个);2层神经网络学100个模板,并在类别间共享这些模板——表达能力更强。

1.6 训练神经网络的完整流程(~20行代码)

  1. 定义网络:确定层数、每层大小
  2. 前向传播:逐层计算输出
  3. 计算解析梯度:通过反向传播
  4. 梯度下降更新参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 训练2层神经网络
while True:
# 1. 前向传播
h = W1 @ X
h_relu = np.maximum(0, h)
scores = W2 @ h_relu

# 2. 计算损失
loss = softmax_loss(scores, y) + reg * (np.sum(W1**2) + np.sum(W2**2))

# 3. 反向传播(计算梯度)
dscores = softmax_grad(scores, y)
dW2 = dscores @ h_relu.T
dh_relu = W2.T @ dscores
dh = dh_relu * (h > 0) # ReLU梯度
dW1 = dh @ X.T

# 4. 参数更新
W1 -= lr * dW1
W2 -= lr * dW2

1.7 网络容量 vs 正则化

  • 更多神经元 = 更大容量(能拟合更复杂函数)
  • 不要用小网络来充当正则化! 应使用足够大的网络 + 强正则化(如 L2、Dropout)
  • 演示工具:ConvNetJS、TensorFlow Playground

1.8 与生物神经元的类比(谨慎!)

生物神经元 人工神经网络
树突(dendrite)接收信号 加权输入
细胞体(cell body)整合信号 加权和 + 激活函数
轴突(axon)传出信号 输出
复杂的非线性和连接模式 简化为规则的多层结构

⚠️ 谨慎使用类比:生物神经元远比人工神经元复杂——树突能进行复杂非线性计算,突触是复杂的非线性动力系统而非单一权重。不过有趣的是,随机连接的网络也能工作(Xie et al., 2019 “Randomly Wired Neural Networks”)。


$\large\star$ 二、反向传播

2.1 问题:如何计算梯度?

对于一个2层网络:

  • 手推 $\frac{\partial L}{\partial W_1}, \frac{\partial L}{\partial W_2}$?—— 极其繁琐、换损失函数需重推、对复杂模型不可行
  • 解决方案:计算图 + 反向传播

2.2 核心思想:计算图 + 链式法则

将任意复杂函数表示为计算图(computational graph),然后用链式法则沿图反向传播梯度。

反向传播 = 链式法则的递归应用:

即:

2.3 标量反向传播:一个简单例子

设 $f(x, y, z) = (x + y)z$,给定 $x = -2, y = 5, z = -4$:

前向传播

1
2
x=-2 + y=5 → q=3
q=3 × z=-4 → f=-12

反向传播(从输出往输入方向计算梯度):

  • $\frac{\partial f}{\partial f} = 1$ (基准情况)
  • $\frac{\partial f}{\partial z} = q = 3$
  • $\frac{\partial f}{\partial q} = z = -4$
  • $\frac{\partial f}{\partial x} = \frac{\partial f}{\partial q} \cdot \frac{\partial q}{\partial x} = -4 \cdot 1 = -4$
  • $\frac{\partial f}{\partial y} = \frac{\partial f}{\partial q} \cdot \frac{\partial q}{\partial y} = -4 \cdot 1 = -4$

2.4 梯度流的模式(Patterns in Gradient Flow)

门(Gate) 前向 反向梯度行为
Add 门 $x + y$ 梯度分发器:上游梯度原样传递给两个输入分支
Mul 门 $x \times y$ 交换乘法器:上游梯度×另一个输入。$x$ 的梯度 = 上游梯度 $\times y$
Copy 门 分叉到多路 梯度累加器:多条路径传来的梯度求和
Max 门 $\max(x, y)$ 梯度路由器:上游梯度只传给较大的输入,较小者得 0

💡 直觉记忆

  • Add:梯度均分,来多少传多少
  • Mul:梯度放大/缩小取决于另一个输入的值(类似”开关”)
  • Max:梯度的”独木桥”——只通过最大值那条路

2.5 Sigmoid 作为复合门的简写

Sigmoid 可以分解为多个基本门的组合,但其局部梯度可以一步完成:

技巧:计算图的表示不唯一——选择一个局部梯度容易表达的!

2.6 模块化实现:forward / backward API

现代深度学习框架都遵循这种设计模式:

1
2
3
4
5
6
7
8
9
10
class MultiplyGate:
def forward(self, x, y):
self.x = x
self.y = y # 缓存前向值,供反向使用
return x * y

def backward(self, dout):
dx = dout * self.y # 上游梯度 × 局部梯度
dy = dout * self.x
return dx, dy

每个节点实现:

  • forward():计算结果并缓存反向所需中间值
  • backward():应用链式法则计算损失对输入的梯度

2.7 扩展到向量/张量

关键点:损失 $L$ 始终是标量!梯度变量始终与原始变量形状相同

标量→标量:$(x) \to (y)$,导数 $\frac{dy}{dx}$

向量→标量:$(x_1,…,x_D) \to (y)$,梯度 $\nabla_x y = [\frac{\partial y}{\partial x_1}, …, \frac{\partial y}{\partial x_D}]$

向量→向量:$(x1,…,x_D) \to (y_1,…,y_M)$,雅可比矩阵 $J{M \times D}$

反向传播中:

示例:ReLU 的向量反向传播

1
2
3
4
5
6
7
# 前向
x = [1, -2, 3, -1]
z = max(0, x) # → [1, 0, 3, 0]

# 反向:dL/dz = [4, -1, 5, 9](上游梯度)
# 雅可比 dz/dx 是对角矩阵 diag([1, 0, 1, 0])(稀疏!)
# dL/dx = [4×1, -1×0, 5×1, 9×0] = [4, 0, 5, 0]

⚠️ 关键:雅可比矩阵非常稀疏——永远不要显式构造雅可比,而是隐式地进行矩阵-向量乘法!

2.8 矩阵级别的反向传播

对于矩阵乘法 $Y = XW$($X: N\times D$, $W: D\times M$, $Y: N\times M$):

🧠 记忆技巧:这两个公式是唯一能让形状匹配的写法!不需要记公式,只需确保矩阵维度对齐。

以 $N=64, D=M=4096$ 为例,雅可比将占据 ~256 GB 内存——必须隐式处理!


$\large\star$ 三、总结

概念 核心要点
全连接神经网络 线性函数 + 非线性激活的堆叠,表达能力远超线性分类器
激活函数 打破线性复合;ReLU 是默认首选
反向传播 沿计算图递归应用链式法则,计算所有输入的梯度
实现模式 图结构 + 节点 forward()/backward() API
向量/矩阵扩展 梯度形状始终等于原变量形状;不要显式构造雅可比

下一讲:卷积神经网络(Convolutional Neural Networks)!

[[CS231n(伍)——卷积神经网络]]