神经网络基础与反向传播

掌握神经网络的核心原理

一、神经元模型

人工神经网络(Artificial Neural Network, ANN)的灵感来源于生物神经系统。人脑由约860亿个神经元(Neuron)组成,每个神经元通过突触(Synapse)与其他神经元相连,形成极其复杂的网络结构。当神经元接收到足够的信号刺激时,会产生电脉冲并传递给下游神经元。

感知机(Perceptron)

感知机由 Frank Rosenblatt 于1957年提出,是历史上最早的神经网络模型。它是一个二分类线性模型:接收多个输入信号,经过加权求和后与阈值比较,输出0或1。其数学表达式为:

感知机数学形式

设输入向量为 x = [x₁, x₂, ..., xₙ]ᵀ,权重向量为 w = [w₁, w₂, ..., wₙ]ᵀ,偏置为 b,则输出为:

output = sign(w·x + b) = sign(∑ᵢ wᵢxᵢ + b)

其中 sign(z) = 1 如果 z ≥ 0,否则为 0。

感知机的核心局限在于它只能处理线性可分问题——著名的"异或(XOR)问题"证明了单层感知机无法解决非线性分类。这一发现导致了神经网络研究的第一次寒冬。

M-P神经元模型

1943年,Warren McCulloch 和 Walter Pitts 提出了 M-P 神经元模型,这是人工神经元的理论基础。M-P 模型将神经元抽象为一个"多输入、单输出"的信息处理单元:

激活函数的作用

激活函数是神经网络中至关重要的组成部分。如果没有激活函数(即线性激活),无论网络有多少层,其表达能力都等价于单层线性模型。激活函数引入非线性,使神经网络能够学习复杂的模式和决策边界。激活函数需要满足以下性质:

核心理解:

神经元的本质是一个"非线性函数逼近器"。每个神经元接收多个输入,通过权重调节输入的"重要性",再经过激活函数决定是否"激活"以及激活的程度。多个神经元组合起来就能逼近任意复杂的函数。

二、激活函数

激活函数的选择直接影响网络的训练速度、收敛性以及最终性能。以下是几种最常用的激活函数及其特点:

Sigmoid 函数

Sigmoid 函数是最早使用的激活函数之一,其数学形式为:

Sigmoid 定义

σ(x) = 1 / (1 + e⁻ˣ)

导数:σ'(x) = σ(x)(1 - σ(x))

Sigmoid 将输入映射到 (0,1) 区间,适合表示概率。然而它有两个严重缺陷:

Tanh 双曲正切函数

Tanh 可以看作是 Sigmoid 的改进版本:

Tanh 定义

tanh(x) = (eˣ - e⁻ˣ) / (eˣ + e⁻ˣ)

导数:tanh'(x) = 1 - tanh²(x)

Tanh 将输出映射到 (-1,1) 区间,解决了 Sigmoid 的非零中心问题,但在饱和区仍然存在梯度消失。

ReLU 线性整流函数

ReLU(Rectified Linear Unit)是当前最广泛使用的激活函数:

ReLU 定义

ReLU(x) = max(0, x)

导数:x > 0 时为 1,x ≤ 0 时为 0

ReLU 的优势:计算简单(只需比较大小)、在正区间梯度恒为1(缓解梯度消失)、稀疏激活(负值直接置0)。但 ReLU 也有"神经元死亡"问题——如果学习率过大或参数初始化不当,某些神经元可能永远不再激活。

ReLU 变体

为解决 ReLU 的神经元死亡问题,研究人员提出了多种变体:

Softmax 函数

Softmax 用于多分类问题的输出层,将网络输出转换为概率分布:

Softmax 定义

Softmax(zᵢ) = e^{zᵢ} / Σⱼ e^{zⱼ}

所有输出值在 (0,1) 区间内,且总和为 1。

激活函数对比表

函数 公式 输出范围 优点 缺点
Sigmoid 1/(1+e⁻ˣ) (0, 1) 平滑、概率解释 梯度消失、非零中心
Tanh (eˣ-e⁻ˣ)/(eˣ+e⁻ˣ) (-1, 1) 零中心、比Sigmoid强 仍有梯度消失
ReLU max(0, x) [0, ∞) 计算快、缓解梯度消失 神经元死亡
Leaky ReLU max(αx, x) (-∞, ∞) 解决神经元死亡 α 值敏感
ELU x(x>0); α(eˣ-1)(x≤0) (-α, ∞) 输出均值近零 计算稍复杂
Softmax e^{zᵢ}/Σe^{zⱼ} (0, 1) 概率输出 仅用于输出层

选择激活函数的经验规则

三、多层感知机 MLP

多层感知机(Multi-Layer Perceptron, MLP)是最基本的深度神经网络结构,由输入层、若干个隐藏层和输出层组成,每层的神经元与下一层的所有神经元全连接。

网络结构

前向传播(Forward Propagation)

前向传播是信息从输入层逐层传递到输出层的过程。假设第 l 层的输出为 a^{[l]},则该层的计算过程为:

前向传播公式

z^{[l]} = W^{[l]} · a^{[l-1]} + b^{[l]}

a^{[l]} = g^{[l]}(z^{[l]})

其中 W^{[l]} 是权重矩阵,b^{[l]} 是偏置向量,g^{[l]} 是激活函数。

经过 L 层的逐层计算,最终得到网络输出 ŷ = a^{[L]}。前向传播本质上是在做一系列线性变换套非线性变换的复合函数。

万能逼近定理(Universal Approximation Theorem)

万能逼近定理是神经网络的理论基石之一。该定理表明:一个具有足够多神经元的单隐藏层前馈神经网络,在合适的激活函数下,可以以任意精度逼近任意连续函数。关键要点:

深度 vs 宽度

"深度"指网络的层数,"宽度"指每层神经元的数量。两者之间存在权衡:

实践中,一般选择3-5层隐藏层作为"深度"网络的起点,每层神经元数量从256到1024不等,具体根据任务复杂度和数据量调节。

四、反向传播算法

反向传播(Backpropagation, BP)是训练神经网络的核心算法。它通过链式法则高效计算损失函数关于每个参数的梯度,为梯度下降提供方向。

链式法则(Chain Rule)

链式法则是微积分中求复合函数导数的规则,也是反向传播的数学基础。假设有复合函数 y = f(g(x)),则:

链式法则公式

dy/dx = dy/dg · dg/dx

对于多元函数:∂z/∂x = (∂z/∂y) · (∂y/∂x)

在神经网络中,损失函数是关于网络输出的复合函数,输出又是关于每一层权重和输入的复合函数,因此我们可以从输出层开始,逐层向后传播梯度。

计算图(Computational Graph)

计算图是将复杂计算过程可视化为有向图的方法。每个节点代表一个变量或运算,边代表数据流动方向。计算图使得我们可以直观地理解前向传播和反向传播的过程:

现代深度学习框架(TensorFlow、PyTorch等)都基于计算图实现自动求导(Autograd)。

反向传播的四个基本方程

对于 L 层网络,定义损失函数为 C,激活函数为 σ,第 l 层的加权输入为 z^{[l]},激活输出为 a^{[l]}。定义误差 δ^{[l]}_j = ∂C/∂z^{[l]}_j。反向传播的四个基本方程为:

BP1:输出层误差

δ^{[L]} = ∇_a C ⊙ σ'(z^{[L]})

其中 ⊙ 表示逐元素相乘,∇_a C 是损失函数对输出层激活值的梯度。

BP2:误差逐层传播

δ^{[l]} = (W^{[l+1]}ᵀ · δ^{[l+1]}) ⊙ σ'(z^{[l]})

当前层的误差由下一层的误差通过权重矩阵回传计算得到。

BP3:权重梯度

∂C/∂W^{[l]}_{jk} = δ^{[l]}_j · a^{[l-1]}_k

权重梯度等于"传入的误差"乘以"上一层对应神经元的激活值"。

BP4:偏置梯度

∂C/∂b^{[l]}_j = δ^{[l]}_j

偏置梯度直接等于对应神经元的误差。

梯度计算流程

  1. 前向传播: 输入 x,逐层计算 z^{[l]} 和 a^{[l]},直到输出层得到 ŷ
  2. 计算损失: 根据 ŷ 和真实标签 y 计算损失函数 C(如均方误差或交叉熵)
  3. 输出层误差: 使用 BP1 计算 δ^{[L]}
  4. 反向传播误差: 使用 BP2 从第 L-1 层到第 1 层逐层计算 δ^{[l]}
  5. 计算梯度: 使用 BP3 和 BP4 计算所有参数的梯度 ∂C/∂W^{[l]} 和 ∂C/∂b^{[l]}
  6. 参数更新: 使用梯度下降法或其他优化算法更新参数

参数更新(梯度下降)

梯度下降更新公式

W^{[l]} := W^{[l]} - η · ∂C/∂W^{[l]}

b^{[l]} := b^{[l]} - η · ∂C/∂b^{[l]}

其中 η 是学习率(Learning Rate),控制参数更新的步长。

反向传播的直观理解

反向传播的直观含义是:计算输出误差后,将误差"分配"给每个神经元。一个神经元的误差由两部分决定:

可以把反向传播想象成一个"问责链条"——从输出层开始,逐层追问:"你们的权重和偏置对这个误差负多少责任?"然后每个参数根据自身责任大小进行调整。

代码实现简易反向传播

以下是一个单隐藏层神经网络的简易反向传播 Python 实现:

import numpy as np def sigmoid(x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(x): return sigmoid(x) * (1 - sigmoid(x)) class SimpleNN: def __init__(self, input_size, hidden_size, output_size): self.W1 = np.random.randn(input_size, hidden_size) * 0.01 self.b1 = np.zeros((1, hidden_size)) self.W2 = np.random.randn(hidden_size, output_size) * 0.01 self.b2 = np.zeros((1, output_size)) def forward(self, X): self.z1 = np.dot(X, self.W1) + self.b1 self.a1 = sigmoid(self.z1) self.z2 = np.dot(self.a1, self.W2) + self.b2 self.a2 = sigmoid(self.z2) return self.a2 def backward(self, X, y, output): m = X.shape[0] # 输出层误差 BP1 dZ2 = output - y # 权重梯度 BP3 dW2 = (1/m) * np.dot(self.a1.T, dZ2) db2 = (1/m) * np.sum(dZ2, axis=0, keepdims=True) # 反向传播到隐藏层 BP2 dA1 = np.dot(dZ2, self.W2.T) dZ1 = dA1 * sigmoid_derivative(self.z1) # 隐藏层梯度 BP3 dW1 = (1/m) * np.dot(X.T, dZ1) db1 = (1/m) * np.sum(dZ1, axis=0, keepdims=True) return dW1, db1, dW2, db2 def update(self, dW1, db1, dW2, db2, lr=0.01): self.W1 -= lr * dW1 self.b1 -= lr * db1 self.W2 -= lr * dW2 self.b2 -= lr * db2 def train(self, X, y, epochs=1000, lr=0.01): for i in range(epochs): output = self.forward(X) dW1, db1, dW2, db2 = self.backward(X, y, output) self.update(dW1, db1, dW2, db2, lr) if i % 100 == 0: loss = np.mean((output - y) ** 2) print(f"Epoch {i}, Loss: {loss:.6f}")

五、损失函数

损失函数(Loss Function)衡量模型预测值与真实值之间的差距,是网络优化的目标函数。

均方误差损失(MSE,回归任务)

MSE 定义

L = (1/m) · Σᵢ (yᵢ - ŷᵢ)²

其中 m 是样本数,yᵢ 是真实值,ŷᵢ 是预测值。

MSE 适合回归任务(房价预测、温度预测等),对大误差惩罚较重,但对异常值敏感。

交叉熵损失(Cross-Entropy,分类任务)

二分类交叉熵

L = -(1/m) · Σᵢ [yᵢ·log(ŷᵢ) + (1-yᵢ)·log(1-ŷᵢ)]

多分类交叉熵

L = -(1/m) · Σᵢ Σⱼ yᵢⱼ·log(ŷᵢⱼ)

交叉熵配合 Softmax 是分类任务的标准配置。其优点是当预测严重错误时产生较大梯度,加速学习。

各种损失函数的适用场景

任务类型 输出层激活 推荐损失函数
回归 无/线性 MSE、MAE、Huber Loss
二分类 Sigmoid 二元交叉熵(BCE)
多分类 Softmax 分类交叉熵(CCE)
多标签分类 Sigmoid 二元交叉熵(BCE)

关键理解:

损失函数的选择与输出层激活函数紧密关联。例如,MSE + Sigmoid 组合会导致学习缓慢(梯度饱和),而交叉熵 + Sigmoid 组合能有效避免这一问题,因为两种函数的导数效应相互抵消。

六、训练技巧

深度学习训练是一门"手艺",以下技巧在实践中被证明非常有效:

权重初始化

良好的权重初始化方法对训练深度网络至关重要:

批量归一化(Batch Normalization)

批量归一化通过对每层输入进行标准化(减均值、除以标准差),稳定训练过程:

BN 通常放在线性变换之后、激活函数之前:BN(Wx + b) → Activation。

学习率调度

学习率是神经网络训练中最重要的超参数之一:

正则化

正则化是防止过拟合的核心技术:

优化器选择

优化器 特点 适用场景
SGD(随机梯度下降) 基础优化器,每次用单个样本更新 小数据集、需要精细调参
Momentum 积累历史梯度动量,加速收敛 大多数场景,比SGD更快更稳
AdaGrad 自适应学习率,对稀疏特征友好 稀疏数据、NLP任务
RMSProp 改进AdaGrad,避免学习率单调递减 非平稳目标、RNN训练
Adam 结合Momentum和RMSProp,自适应学习率+动量 通用首选、快速收敛
Nadam Adam + Nesterov动量 需要更快收敛的场景

实用建议:

  1. 首次尝试时直接使用 Adam,学习率设为默认值 0.001
  2. 网络收敛后可以切换为 SGD + Momentum 进行"精调"
  3. 学习率调度与优化器结合使用效果更佳
  4. 先在小规模数据上确保模型能过拟合,再扩展到全体数据

七、神经网络的挑战

梯度消失/爆炸

随着网络深度增加,梯度在反向传播过程中可能出现指数级衰减(消失)或指数级增长(爆炸)。主要原因和对策:

过拟合

当模型参数过多而训练数据不足时,网络可能"记住"训练数据而非学到泛化规律:

训练时间

深度网络的训练通常需要数小时到数周:

超参数数量

神经网络涉及大量超参数,调参是重要的实践技能:

常见陷阱:

  • 不要同时调整所有超参数——每次只调1-2个,理解其影响
  • 不要只看训练loss——始终关注验证集表现
  • 不要用测试集调参——测试集只能用于最终评估
  • 不要一次性把网络做太深——从浅到深逐步增加

八、核心要点总结

九、进一步思考

掌握神经网络基础是进入深度学习领域的第一步,但更重要的是理解"为什么"而非仅仅"怎么做"

深度学习的本质思考:

  • 表示学习: 神经网络的核心优势在于自动学习数据的层次化特征表示,从底层边缘、纹理到高层语义概念
  • 端到端学习: 传统方法需要手工设计特征,而深度学习可以"从原始数据到最终输出"一体化学习
  • 计算与数据的协同: 大数据 + 大算力 + 大模型 = 突破性性能,这被称为"深度学习三要素"
  • 没有免费午餐: 神经网络并非万能——在小数据场景下传统机器学习方法(如 XGBoost)可能表现更好

学习路线建议

  1. 打好基础: 深入理解本文的每个概念,动手实现前向/反向传播
  2. 框架实践: 使用 PyTorch 或 TensorFlow 完成图像分类(如 MNIST、CIFAR-10)
  3. 进阶结构: 学习 CNN(卷积神经网络)、RNN/LSTM(循环神经网络)、Transformer
  4. 论文阅读: 从 AlexNet (2012) → VGGNet → ResNet → Transformer → ViT 的经典论文路线
  5. 工程实践: 参与 Kaggle 竞赛或开源项目,实践模型训练、部署和优化全流程
神经网络不是魔术,而是数学。反向传播不是黑魔法,而是链式法则。理解核心原理,你就是神经网络的"主人"而非仅仅是"用户"。