第一部分:神经网络入门
感知机是最简单的人工神经元模型,接收多个输入信号,产生单一的二进制输出。
核心思想:感知机通过对输入的加权求和,与阈值比较来做出决策。
基本定义
- 输入:x1,x2,x3,…,xn(多个二进制或实数输入)
- 权重:w1,w2,…,wn(表示各输入的重要性)
- 输出:单一的二进制输出(0 或 1)
输出规则
原始形式(使用阈值 threshold):
output={01if ∑jwjxj≤thresholdif ∑jwjxj>threshold
引入偏置 b=−threshold 简化表示:
output={01if w⋅x+b≤0if w⋅x+b>0
逻辑门实现
感知机可以实现基本逻辑门:NAND 门、AND 门、OR 门。由于 NAND 门是通用门(可以组合构建任何逻辑运算),感知机具有通用计算能力。
感知机 vs Sigmoid 神经元 对比
| 特性 | 感知机 | Sigmoid 神经元 |
|---|
| 输出值 | 二进制:0 或 1 | 连续值:0 到 1 之间 |
| 激活函数 | 阶跃函数(step function) | Sigmoid 函数 σ(z) |
| 可微性 | 不可微(不连续) | 处处可微(光滑曲线) |
| 权重微调响应 | 小变化可能导致输出完全翻转 | 小变化仅导致输出的小变化 |
| 学习适用性 | 难以用梯度方法学习 | 适合梯度下降优化 |
感知机的问题
感知机的输出是阶跃函数,权重或偏置的微小变化可能导致输出从 0 突变到 1(或反之)。这使得我们无法通过逐步微调权重来"学习"——因为微小调整的效果不可预测。
Sigmoid 神经元的解决方案
Sigmoid 神经元的输出为:
output=σ(w⋅x+b)
其中 Sigmoid 函数定义为:
σ(z)=1+e−z1
关键性质:由于 σ 是光滑函数,权重和偏置的微小变化只会导致输出的微小变化:
Δoutput≈∑j∂wj∂outputΔwj+∂b∂outputΔb
Sigmoid 函数特性
- 输出范围:(0, 1)
- 当 z→+∞ 时,σ(z)→1
- 当 z→−∞ 时,σ(z)→0
- 处处光滑可微
- 导数:σ′(z)=σ(z)(1−σ(z))
阶跃函数特性
- 输出值:仅 0 或 1
- 当 z>0 时,输出 = 1
- 当 z≤0 时,输出 = 0
- 在 z=0 处不连续
- 导数:除 z=0 外处处为 0
神经网络由多层神经元组成,信息从输入层经过隐藏层最终到达输出层。
- 输入层(Input Layer):接收外部数据,神经元数量由输入特征维度决定
- 隐藏层(Hidden Layers):执行中间计算,可以有一层或多层
- 输出层(Output Layer):产生最终结果
前馈网络(Feedforward Networks):信息仅从前往后流动,没有循环连接。前一层的输出作为下一层的输入。
以 MNIST 手写数字识别为例,展示神经网络的实际应用。
网络结构
- 输入层:784 个神经元(28x28 像素图像,每个像素作为一个输入,灰度值 0.0-1.0)
- 隐藏层:例如 15 或 30 个神经元(可调节)
- 输出层:10 个神经元(对应数字 0-9,哪个神经元激活值最高即为预测结果)
网络结构简记:784 → 隐藏层(15/30) → 10
MNIST 数据集包含 60,000 张训练图像和 10,000 张测试图像。每张图像是 28x28 的灰度图,已经过居中和归一化处理。
梯度下降是训练神经网络的核心优化方法。
代价函数(Cost Function)
均方误差(MSE)代价函数:
C(w,b)=2n1∑x∥y(x)−a∥2
其中 n 是训练样本数,y(x) 是期望输出,a 是网络实际输出。
梯度
∇C=(∂v1∂C,∂v2∂C)T
梯度向量指向函数增长最快的方向,负梯度方向即为下降最快方向。
参数更新规则
v→v′=v−η∇C
对于神经网络的权重和偏置:
wk→wk′=wk−η∂wk∂C
bl→bl′=bl−η∂bl∂C
其中 η 为学习率(learning rate),控制每步更新的幅度。
问题:当训练集很大时,计算所有样本的梯度非常耗时。
解决方案:使用 Mini-batch 随机梯度下降。
- 随机选取 m 个训练样本作为一个 mini-batch
- 用 mini-batch 的平均梯度估计全局梯度:
∇C≈m1∑j=1m∇CXj
更新规则:
wk→wk′=wk−mη∑j∂wk∂CXj
bl→bl′=bl−mη∑j∂bl∂CXj
Epoch:当所有训练样本都被使用过一次(即遍历完所有 mini-batch),称为完成了一个 epoch。之后打乱数据重新划分 mini-batch,开始下一个 epoch 的训练。
第二部分:前向传播和反向传播算法
前向传播就是把输入数据从第一层开始,逐层计算,一直算到输出层得到最终结果的过程。信息只往一个方向流动:输入 → 隐藏层 → 输出。
| 预测时 | 前向传播就是使用网络的全部过程——给输入,算输出 |
|---|
| 训练时 | 前向传播是第一步,算出预测值后才能计算损失,然后才能反向传播求梯度 |
| 计算中间值 | 前向传播过程中保存的每一层的 zl 和 al,在反向传播时要用到 |
对于第 l 层的每个神经元,计算分两步:
第一步:计算加权输入 z
zl=wl⋅al−1+bl
第二步:通过激活函数得到输出 a
al=σ(zl)
合并写成一个简洁形式:
al=σ(wl⋅al−1+bl)
其中:
- al−1:上一层的输出(第一层时就是输入 x)
- wl:第 l 层的权重矩阵
- bl:第 l 层的偏置向量
- σ:激活函数(如 sigmoid)
以一个 3 层网络为例(输入层 → 隐藏层 → 输出层):
Plain输入 x → [第1层计算] → a¹ → [第2层计算] → a² → [第3层计算] → a³ (最终输出)
| 层 | 输入 | 计算 | 输出 |
|---|
| 输入层 | 原始数据 x | 无计算 | a0=x |
| 隐藏层 | a0 | z1=w1a0+b1,a1=σ(z1) | a1 |
| 输出层 | a1 | z2=w2a1+b2,a2=σ(z2) | a2(最终预测) |
示例
一个最简单的网络:2 个输入 → 2 个隐藏神经元 → 1 个输出
参数:
w1=(0.30.40.50.2),b1=(0.1−0.1)
w2=(0.60.7),b2=−0.2
输入: x=(1,0.5)T
第一步:计算隐藏层
z1=w1⋅x+b1=(0.3×1+0.5×0.50.4×1+0.2×0.5)+(0.1−0.1)=(0.55+0.10.50−0.1)=(0.650.40)
a1=σ(z1)=(σ(0.65)σ(0.40))=(0.6570.599)
第二步:计算输出层
z2=w2⋅a1+b2=0.6×0.657+0.7×0.599+(−0.2)=0.394+0.419−0.2=0.613
a2=σ(0.613)=0.649
结果: 输入 (1,0.5),网络输出 0.649
为了精确描述反向传播,首先建立统一的符号体系。
| 符号 | 含义 |
|---|
| wjkl | 从第 (l−1) 层第 k 个神经元到第 l 层第 j 个神经元的权重 |
| bjl | 第 l 层第 j 个神经元的偏置 |
| ajl | 第 l 层第 j 个神经元的激活值 |
| zjl | 第 l 层第 j 个神经元的加权输入 |
| δjl | 第 l 层第 j 个神经元的误差 |
矩阵形式
激活值的递推关系:
al=σ(wl⋅al−1+bl)
定义加权输入(weighted input):
zl=wl⋅al−1+bl
因此 al=σ(zl),即每层的激活值是对加权输入施加激活函数的结果。
以下四个方程是反向传播算法的数学基础,它们给出了计算代价函数关于网络中任意权重和偏置的梯度的完整方法。
定义误差:δjl=∂zjl∂C(代价函数对第 l 层第 j 个神经元加权输入的偏导数)
| 方程 | 公式 | 含义 |
|---|
| BP1 | δjL=∂ajL∂C⋅σ′(zjL) | 输出层误差:代价函数对输出激活的变化率乘以激活函数的导数 |
| BP2 | δl=((wl+1)Tδl+1)⊙σ′(zl) | 误差反向传播:用下一层的误差和权重矩阵计算当前层误差 |
| BP3 | ∂bjl∂C=δjl | 偏置梯度:等于该神经元的误差 |
| BP4 | ∂wjkl∂C=akl−1⋅δjl | 权重梯度:等于前一层激活值乘以当前层误差 |
理解要点
- BP1 是起点:从输出层开始计算误差
- BP2 是递推:将误差从后向前传播(这就是"反向传播"名称的由来)
- BP3 + BP4 是目标:将误差转化为我们需要的梯度信息
- ⊙ 表示 Hadamard 积(逐元素相乘)
反向传播算法结合随机梯度下降的完整步骤:
- 输入:取一个 mini-batch(m 个训练样本)
- 前向传播:对每个样本 x,逐层计算 zl=wlal−1+bl 和 al=σ(zl)
- 计算输出层误差:δL=∇aC⊙σ′(zL)
- 反向传播误差:从 l=L−1,L−2,…,2 逐层计算 δl=((wl+1)Tδl+1)⊙σ′(zl)
- 计算梯度:∂wjkl∂C=akl−1δjl 和 ∂bjl∂C=δjl
- 更新参数:wl→wl−mη∑xδx,l(ax,l−1)T 和 bl→bl−mη∑xδx,l
从直觉上理解反向传播,可以想象对某个权重做一个微小的扰动,然后追踪这个扰动如何"涟漪般"传播到最终的代价函数。
直觉理解
假设对权重 wjkl 做微小变化 Δwjkl:
- 首先引起第 l 层第 j 个神经元激活值的变化:Δajl
- 该变化传播到第 (l+1) 层所有与之连接的神经元
- 继续逐层传播,经过第 (l+2),(l+3),… 层
- 最终到达输出层,引起代价函数的变化 ΔC
路径求和公式
代价函数关于权重的偏导数可以表达为所有从该权重到输出的路径上偏导数乘积的求和:
∂wjkl∂C=∑paths∏edges along path(partial derivatives)
具体展开:
∂wjkl∂C=∑pl,pl+1,…,pL∂apLL∂C⋅σ′(zpLL)⋅wpL,pL−1L⋯σ′(zpl+1l+1)⋅wpl+1,jl+1⋅σ′(zjl)⋅akl−1
总结:反向传播不是什么"魔法"——它本质上就是链式法则的系统应用。通过从输出层开始逐层向后计算误差,我们能高效地获得所有参数的梯度,而不需要对每个参数单独做扰动实验。这使得训练拥有数百万参数的深度网络成为可能。
案例:
示例:2 层网络的完整前向传播与反向传播
Plain输入层(1个) → 隐藏层(1个神经元) → 输出层(1个神经元)
x → a¹ → a²(预测值)
参数:
- 隐藏层:权重 w1,偏置 b1
- 输出层:权重 w2,偏置 b2
- 激活函数:sigmoid σ(z)=1+e−z1
| 参数 | 值 |
|---|
| w1 | 0.4 |
| b1 | 0.1 |
| w2 | 0.6 |
| b2 | 0.2 |
| 输入 x | 2.0 |
| 期望输出 y | 1.0 |
| 学习率 η | 0.5 |
代价函数:C=21(a2−y)2
第 1 层(隐藏层)
z1=w1⋅x+b1=0.4×2.0+0.1=0.9
a1=σ(z1)=σ(0.9)=1+e−0.91=1+0.4071=0.711
第 2 层(输出层)
z2=w2⋅a1+b2=0.6×0.711+0.2=0.427+0.2=0.627
a2=σ(z2)=σ(0.627)=1+e−0.6271=1+0.5341=0.652
计算代价
C=21(a2−y)2=21(0.652−1)2=21(0.348)2=0.0606
前向传播汇总:
| 变量 | 值 |
|---|
| z1 | 0.9 |
| a1 | 0.711 |
| z2 | 0.627 |
| a2 | 0.652 |
| C | 0.0606 |
现在的目标是求:∂w2∂C、∂b2∂C、∂w1∂C、∂b1∂C
求 ∂w2∂C(输出层权重)
依赖链路: w2→z2→a2→C
用链式法则展开:
∂w2∂C=∂a2∂C⋅∂z2∂a2⋅∂w2∂z2
逐项计算:
∂a2∂C=a2−y=0.652−1=−0.348
∂z2∂a2=σ′(z2)=a2(1−a2)=0.652×0.348=0.227
∂w2∂z2=a1=0.711
相乘:
∂w2∂C=(−0.348)×0.227×0.711=−0.0562
求 ∂b2∂C(输出层偏置)
依赖链路: b2→z2→a2→C
∂b2∂C=∂a2∂C⋅∂z2∂a2⋅∂b2∂z2
前两项和上面一样,第三项:
∂b2∂z2=1
相乘:
∂b2∂C=(−0.348)×0.227×1=−0.0790
定义输出层误差: δ2=∂a2∂C⋅σ′(z2)=(−0.348)×0.227=−0.0790
有了 δ2,后面的计算更简洁:
- ∂w2∂C=δ2⋅a1=−0.0790×0.711=−0.0562 ✓
- ∂b2∂C=δ2=−0.0790 ✓
求 ∂w1∂C(隐藏层权重)——链式法则的关键
依赖链路更长了: w1→z1→a1→z2→a2→C
∂w1∂C=∂a2∂C⋅∂z2∂a2⋅∂a1∂z2⋅∂z1∂a1⋅∂w1∂z1
逐项计算:
∂a2∂C=−0.348(已算过)
∂z2∂a2=0.227(已算过)
∂a1∂z2=w2=0.6
∂z1∂a1=σ′(z1)=a1(1−a1)=0.711×0.289=0.205
∂w1∂z1=x=2.0
全部相乘:
∂w1∂C=(−0.348)×0.227×0.6×0.205×2.0
=−0.0790×0.6×0.205×2.0
=−0.0474×0.205×2.0
=−0.00972×2.0=−0.0194
求 ∂b1∂C(隐藏层偏置)
链路: b1→z1→a1→z2→a2→C
与 w1 的链路只有最后一项不同:∂b1∂z1=1(而不是 x=2)
∂b1∂C=(−0.348)×0.227×0.6×0.205×1=−0.00972
隐藏层误差:δ1=w2⋅δ2⋅σ′(z1)=0.6×(−0.0790)×0.205=−0.00972
验证:
- ∂w1∂C=δ1⋅x=−0.00972×2.0=−0.0194 ✓
- ∂b1∂C=δ1=−0.00972 ✓
链式法则 = 路径上所有偏导数连乘:从 C 到任何参数,就是沿着依赖路径把每一步的局部导数相乘
反向传播就是从输出层开始,沿着"C → a² → z² → a¹ → z¹ → 参数"的路径,用链式法则把每一步的局部导数连乘起来,得到代价函数对每个参数的梯度。误差像水流一样从后往前"流淌",每经过一层就被 σ′(z) 和权重"衰减"一些——这既是反向传播的精妙之处,也是深层网络梯度消失的根源。
| 参数 | 梯度 | 更新:θ′=θ−0.5×梯度 | 新值 |
|---|
| w2 | -0.0562 | 0.6−0.5×(−0.0562) | 0.628 |
| b2 | -0.0790 | 0.2−0.5×(−0.0790) | 0.240 |
| w1 | -0.0194 | 0.4−0.5×(−0.0194) | 0.410 |
| b1 | -0.00972 | 0.1−0.5×(−0.00972) | 0.105 |
所有梯度为负,所以所有参数都增大,这意味着网络输出 a2 会增大(更接近目标值 y=1),代价 C 会减小。
梯度的用途:更新参数,让 C 变小。
w←w−η⋅∂w∂C
整个训练过程就是不断重复这个循环:
Plain前向传播:用当前参数算出预测值
↓
计算 C:看预测值和真实值差多少
↓
反向传播:算出每个参数的梯度(C对该参数有多敏感)
↓
更新参数:沿着梯度反方向调整参数,让C减小
↓
回到第一步,重复……直到 C 足够小
C 足够小,说明对于所有训练样本,网络的预测值 a 非常接近真实标签 y。
也就是得到了一组好的参数 w 和 b,使网络 "学会" 了输入到输出的映射规律,预测 ≈ 真实标签
反向传播时,梯度从输出层往输入层逐层传递。如果每经过一层梯度都变小,传到前面几层时梯度就接近于 0,导致前面的层几乎无法更新权重 —— 这就是梯度消失。
越靠近输入,梯度越小
∣∂w2∂C∣=0.0562,∣∂w1∂C∣=0.0194。隐藏层梯度只有输出层的 1/3
回顾反向传播的误差递推公式(BP2)
误差每经过一层就要乘以 σ′(z)(最大值 0.25)和权重,不断缩小,层数越多,前面层的梯度越小,学习越慢,多层连乘后梯度趋近于 0,前面的层几乎学不到东西。这是深层网络训练困难的核心原因,也是 ReLU、残差连接、LSTM 等技术诞生的动机。