第 4 章:前向传播
把第 1-3 章的知识组装起来,走一遍完整的"输入图片 → 输出概率"过程。
4.1 前向传播的本质
"前向传播"(Forward Propagation)就是数据从左到右流过网络的过程:
图片像素值 隐藏层特征 输出概率
X (n,784) →第一层→ z1 (n,50) →第二层→ y (n,10)每一步都做:线性变换(矩阵乘法 + 偏置)→ 非线性激活。
下面我们一步步推导,假设 batch size = n(同时处理 n 张图片)。
4.2 第一步:输入数据准备
原始图片是 28×28 的灰度图,像素值在 0-255 之间:
原始像素矩阵 (28×28): 展平成向量 (784,):
┌─────────────────────┐ [0, 0, 0, 5, 18, 235, 240, ...]
│ 0 0 0 0 ... │ →
│ 0 12 89 240 ... │ 归一化到 [0,1]:
│ ... │ → [0.0, 0.0, 0.0, 0.02, 0.07, 0.92, 0.94, ...]
└─────────────────────┘当我们处理 n 张图片时,把它们堆叠成一个矩阵:
X = shape (n, 784)
第 1 张图片的像素 → [0.0, 0.0, 0.02, ..., 0.94] 第 1 行
第 2 张图片的像素 → [0.1, 0.0, 0.00, ..., 0.00] 第 2 行
...
第 n 张图片的像素 → [0.0, 0.3, 0.85, ..., 0.12] 第 n 行4.3 第二步:第一层(输入层 → 隐藏层)
线性变换
维度验证:
X @ W1:
(n, 784) @ (784, 50) → (n, 50) ✓ 中间 784=784 消掉
↑ ↑
相等,合法
+ b1:
(n, 50) + (50,) → (n, 50) ✓ 广播:b1 复制 n 份结果含义:
展开来看,
a1[i, j] = X[i, 0]*W1[0, j] + X[i, 1]*W1[1, j] + ... + X[i, 783]*W1[783, j] + b1[j]
↑ ↑
第i张图片的第0个像素乘以 第j个节点的偏置
连接到第j个节点的权重这正是我们在第 1 章说的"加权求和 + 偏置",只不过矩阵乘法一次算出了 n×50 个这样的值。
激活函数(Sigmoid)
逐元素应用 Sigmoid,shape 不变:
a1[i, j] → σ(a1[i, j]) → z1[i, j]
每个元素独立计算:z1[i,j] = 1 / (1 + exp(-a1[i,j]))4.4 第三步:第二层(隐藏层 → 输出层)
线性变换
维度验证:
z1 @ W2:
(n, 50) @ (50, 10) → (n, 10) ✓ 中间 50=50 消掉
+ b2:
(n, 10) + (10,) → (n, 10) ✓ 广播激活函数(Softmax)
注意: Softmax 是行内归一化——对每张图片(每一行)的 10 个值做归一化,让它们之和等于 1:
a2 的第 i 行: [-2.1, 0.5, 3.2, -0.8, 1.1, 0.3, -1.5, 8.7, 0.2, -0.4]
↑ 数字7的分数最高
softmax 之后:
y 的第 i 行: [0.00, 0.00, 0.01, 0.00, 0.01, 0.00, 0.00, 0.97, 0.00, 0.00]
↑ 97% 的概率是数字7
每行之和 = 1 ✓4.5 完整前向传播一览
把所有步骤放在一起,加上详细的维度标注:
输入: X shape: (n, 784)
第一层:
a1 = X @ W1 + b1 shape: (n, 784) @ (784, 50) + (50,) = (n, 50)
z1 = sigmoid(a1) shape: (n, 50) [逐元素,shape不变]
第二层:
a2 = z1 @ W2 + b2 shape: (n, 50) @ (50, 10) + (10,) = (n, 10)
y = softmax(a2) shape: (n, 10) [逐行归一化,shape不变]
输出: y shape: (n, 10)4.6 数值例子(n=2,简化到 3 个像素和 2 个隐藏节点,3 个类别)
用小数字走一遍,看清楚每步在干什么。
参数设置(假设已经训练好):
python
W1 = [[0.1, -0.2], # shape: (3, 2)
[0.3, 0.4],
[-0.1, 0.5]]
b1 = [0.1, -0.1] # shape: (2,)
W2 = [[0.5, -0.3, 0.8], # shape: (2, 3)
[-0.2, 0.6, 0.1]]
b2 = [0.0, 0.1, -0.1] # shape: (3,)输入(2张图片,每张3个像素):
python
X = [[0.5, 0.2, 0.8], # 第1张图片 shape: (2, 3)
[0.1, 0.9, 0.3]] # 第2张图片第一层:
a1 = X @ W1 + b1
X @ W1 的计算:
a1[0,0] = 0.5*0.1 + 0.2*0.3 + 0.8*(-0.1) = 0.05+0.06-0.08 = 0.03
a1[0,1] = 0.5*(-0.2) + 0.2*0.4 + 0.8*0.5 = -0.10+0.08+0.40 = 0.38
a1[1,0] = 0.1*0.1 + 0.9*0.3 + 0.3*(-0.1) = 0.01+0.27-0.03 = 0.25
a1[1,1] = 0.1*(-0.2) + 0.9*0.4 + 0.3*0.5 = -0.02+0.36+0.15 = 0.49
加偏置 b1 = [0.1, -0.1]:
a1 = [[0.03+0.1, 0.38-0.1], = [[0.13, 0.28],
[0.25+0.1, 0.49-0.1]] [0.35, 0.39]]
z1 = sigmoid(a1):
σ(0.13) = 1/(1+e^{-0.13}) ≈ 0.532
σ(0.28) = 1/(1+e^{-0.28}) ≈ 0.570
σ(0.35) = 1/(1+e^{-0.35}) ≈ 0.587
σ(0.39) = 1/(1+e^{-0.39}) ≈ 0.596
z1 = [[0.532, 0.570],
[0.587, 0.596]] shape: (2, 2)第二层:
a2 = z1 @ W2 + b2
z1 @ W2:
a2[0,0] = 0.532*0.5 + 0.570*(-0.2) = 0.266 - 0.114 = 0.152
a2[0,1] = 0.532*(-0.3) + 0.570*0.6 = -0.160 + 0.342 = 0.182
a2[0,2] = 0.532*0.8 + 0.570*0.1 = 0.426 + 0.057 = 0.483
a2[1,0] = 0.587*0.5 + 0.596*(-0.2) = 0.294 - 0.119 = 0.175
a2[1,1] = 0.587*(-0.3) + 0.596*0.6 = -0.176 + 0.358 = 0.182
a2[1,2] = 0.587*0.8 + 0.596*0.1 = 0.470 + 0.060 = 0.530
加偏置 b2 = [0.0, 0.1, -0.1]:
a2 = [[0.152, 0.282, 0.383],
[0.175, 0.282, 0.430]]
softmax 对每行归一化:
第1张图片:
e^0.152 ≈ 1.164, e^0.282 ≈ 1.326, e^0.383 ≈ 1.467
总和 = 3.957
y[0] = [1.164/3.957, 1.326/3.957, 1.467/3.957]
≈ [0.294, 0.335, 0.371] → 预测为类别2(概率37.1%)
第2张图片:
e^0.175 ≈ 1.191, e^0.282 ≈ 1.326, e^0.430 ≈ 1.537
总和 = 4.054
y[1] = [1.191/4.054, 1.326/4.054, 1.537/4.054]
≈ [0.294, 0.327, 0.379] → 预测为类别2(概率37.9%)4.7 前向传播在代码中的实现
python
# model.py 中的 forward 方法
def forward(self, X):
W1, b1 = self.params['W1'], self.params['b1']
W2, b2 = self.params['W2'], self.params['b2']
a1 = X @ W1 + b1 # (n,784)@(784,50) + (50,) = (n,50)
z1 = sigmoid(a1) # (n,50) → (n,50) [逐元素]
a2 = z1 @ W2 + b2 # (n,50)@(50,10) + (10,) = (n,10)
y = softmax(a2) # (n,10) → (n,10) [逐行归一化]
return y代码和数学公式是一一对应的,没有任何"神秘"操作。
4.8 小结
前向传播的每一步:
X (n,784)
↓ @ W1(784,50)
a1 (n,50) ← 50个隐藏节点的加权求和
↓ sigmoid(逐元素)
z1 (n,50) ← 每个值压缩到(0,1),表示"激活程度"
↓ @ W2(50,10)
a2 (n,10) ← 10个类别的原始分数(logits)
↓ softmax(逐行)
y (n,10) ← 概率分布,每行和为1,取最大值即预测类别下一章,我们来解决:怎么衡量网络的预测有多"错"?——损失函数。
← 第 3 章 | 返回目录 | 第 5 章:损失函数 →