“人脑有大约 860 亿个神经元,而现代神经网络可能只有几百万个参数。 但我们已经能用它识别图像、翻译语言、生成文本—— 这不是因为网络像大脑,而是因为我们找到了一种通用的函数逼近方式。” ——深度学习的工程哲学
一、为什么需要神经网络?
在前六章中,我们系统学习了线性模型、决策树、集成方法(随机森林、XGBoost) 等经典机器学习算法。它们在结构化数据(表格数据)上表现卓越,具备良好的可解释性和工程稳定性。
然而,当我们面对以下任务时,传统方法开始力不从心:
- 图像识别:像素之间存在复杂的局部与全局空间关系;
- 语音识别:音频信号是高维、时序、非平稳的;
- 自然语言处理:词语组合具有高度上下文依赖性;
- 高维非线性模式:特征交互呈指数级增长(如“用户点击 A 且未购买 B 且浏览 C”)。
这些任务的共同特点是:输入维度极高、特征间存在深层非线性交互、且难以通过人工特征工程有效表达。
🎯 本章目标:
- 理解神经网络如何通过“层叠非线性变换”实现通用函数逼近;
- 掌握前向传播、反向传播、梯度下降的核心机制;
- 从零实现一个全连接神经网络(MLP);
- 深入探讨激活函数、损失函数、优化器的选择逻辑;
- 辩证看待神经网络的“黑箱”属性,探索可解释性工具;
- 对比神经网络与传统模型的适用边界。
二、神经网络的直觉:从感知机到多层网络
2.1 感知机:神经网络的起点
1957 年,Frank Rosenblatt 提出感知机(Perceptron),这是最早的神经网络模型。
对于输入
x
=
[
x
1
,
x
2
,
.
.
.
,
x
n
]
⊤
\\mathbf{x} = [x_1, x_2, …, x_n]^\\top
x=[x1,x2,…,xn]⊤,感知机计算:
z
=
w
⊤
x
+
b
=
∑
i
=
1
n
w
i
x
i
+
b
z = \\mathbf{w}^\\top \\mathbf{x} + b = \\sum_{i=1}^{n} w_i x_i + b
z=w⊤x+b=i=1∑nwixi+b
然后通过阶跃函数输出:
y
^
=
{
1
,
if
z
≥
0
0
,
otherwise
\\hat{y} = \\begin{cases} 1, & \\text{if } z \\geq 0 \\\\ 0, & \\text{otherwise} \\end{cases}
y^={1,0,if z≥0otherwise
这本质上是一个线性分类器——它只能解决线性可分问题(如 AND、OR),但无法解决 XOR(异或)问题。
❌ 局限性:单层感知机无法表示非线性决策边界。
2.2 多层感知机(MLP):引入隐藏层
为突破线性限制,我们在输入和输出之间加入隐藏层(Hidden Layer):
输入层 → 隐藏层 → 输出层
每一层由多个神经元(Neuron)组成,每个神经元执行:
a
j
(
l
)
=
σ
(
∑
k
w
j
k
(
l
)
a
k
(
l
−
1
)
+
b
j
(
l
)
)
a^{(l)}_j = \\sigma \\left( \\sum_{k} w^{(l)}_{jk} a^{(l-1)}_k + b^{(l)}_j \\right)
aj(l)=σ(k∑wjk(l)ak(l−1)+bj(l))
其中:
-
a
j
(
l
)
a^{(l)}_j
aj(l):第l
l
l 层第j
j
j 个神经元的激活值(activation); -
w
j
k
(
l
)
w^{(l)}_{jk}
wjk(l):从第l
−
1
l-1
l−1 层第k
k
k 个神经元到第l
l
l 层第j
j
j 个神经元的权重; -
b
j
(
l
)
b^{(l)}_j
bj(l):第l
l
l 层第j
j
j 个神经元的偏置; -
σ
(
⋅
)
\\sigma(\\cdot)
σ(⋅):激活函数(非线性函数)。
🔑 关键洞见: 只要激活函数是非线性的,多层网络就能逼近任意连续函数(Universal Approximation Theorem)。
2.3 通用逼近定理(Universal Approximation Theorem)
1989 年,George Cybenko 证明:
对于任意连续函数
f
:
R
n
→
R
m
f: \\mathbb{R}^n \\to \\mathbb{R}^m
f:Rn→Rm,在紧集上,存在一个单隐藏层的前馈神经网络,使用 Sigmoid 激活函数,可以以任意精度逼近
f
f
f。
这意味着:神经网络不是某种神秘的“智能”,而是一种极其灵活的函数拟合器。
✅ 它的强大不在于“像人脑”,而在于通过组合简单非线性单元,构建复杂映射。
三、数学基础:前向传播与损失函数
3.1 前向传播(Forward Propagation)
设网络有
L
L
L 层(含输入和输出),第
l
l
l 层有
n
l
n_l
nl 个神经元。
定义:
-
A
(
0
)
=
X
∈
R
m
×
n
0
\\mathbf{A}^{(0)} = \\mathbf{X} \\in \\mathbb{R}^{m \\times n_0}
A(0)=X∈Rm×n0:输入矩阵(m
m
m 个样本,n
0
n_0
n0 个特征); -
W
(
l
)
∈
R
n
l
−
1
×
n
l
\\mathbf{W}^{(l)} \\in \\mathbb{R}^{n_{l-1} \\times n_l}
W(l)∈Rnl−1×nl:第l
l
l 层权重矩阵; -
b
(
l
)
∈
R
1
×
n
l
\\mathbf{b}^{(l)} \\in \\mathbb{R}^{1 \\times n_l}
b(l)∈R1×nl:偏置向量(广播); -
Z
(
l
)
=
A
(
l
−
1
)
W
(
l
)
+
b
(
l
)
\\mathbf{Z}^{(l)} = \\mathbf{A}^{(l-1)} \\mathbf{W}^{(l)} + \\mathbf{b}^{(l)}
Z(l)=A(l−1)W(l)+b(l):线性变换; -
A
(
l
)
=
σ
(
l
)
(
Z
(
l
)
)
\\mathbf{A}^{(l)} = \\sigma^{(l)}(\\mathbf{Z}^{(l)})
A(l)=σ(l)(Z(l)):激活输出。
最终输出为
A
(
L
)
\\mathbf{A}^{(L)}
A(L)。
💡 向量化计算使得一次前向传播可处理整个批量(batch),极大提升效率。
3.2 激活函数:引入非线性
若没有激活函数,多层网络等价于单层线性变换(因为矩阵乘法满足结合律)。
常用激活函数:
| Sigmoid |
σ ( z ) = 1 1 + e − z \\sigma(z) = \\frac{1}{1 + e^{-z}} σ(z)=1+e−z1 |
输出
( 0 , 1 ) (0,1) (0,1),适合概率;但易饱和、梯度消失 |
| Tanh |
tanh ( z ) = e z − e − z e z + e − z \\tanh(z) = \\frac{e^z – e^{-z}}{e^z + e^{-z}} tanh(z)=ez+e−zez−e−z |
输出
( − 1 , 1 ) (-1,1) (−1,1),零中心;仍会饱和 |
| ReLU |
ReLU ( z ) = max ( 0 , z ) \\text{ReLU}(z) = \\max(0, z) ReLU(z)=max(0,z) |
最常用;计算快、缓解梯度消失;但有“死神经元”问题 |
| Leaky ReLU |
LReLU ( z ) = max ( 0.01 z , z ) \\text{LReLU}(z) = \\max(0.01z, z) LReLU(z)=max(0.01z,z) |
解决死神经元 |
| Softmax |
softmax ( z i ) = e z i ∑ j e z j \\text{softmax}(z_i) = \\frac{e^{z_i}}{\\sum_j e^{z_j}} softmax(zi)=∑jezjezi |
多分类输出层专用,保证概率和为1 |
✅ 现代实践:隐藏层用 ReLU 或其变体,输出层根据任务选择(Sigmoid/Softmax)。
3.3 损失函数:衡量预测误差
损失函数需与任务匹配:
回归任务:均方误差(MSE)
L
MSE
=
1
m
∑
i
=
1
m
(
y
^
i
−
y
i
)
2
\\mathcal{L}_{\\text{MSE}} = \\frac{1}{m} \\sum_{i=1}^{m} (\\hat{y}_i – y_i)^2
LMSE=m1i=1∑m(y^i−yi)2
二分类:二元交叉熵(Binary Cross-Entropy)
L
BCE
=
−
1
m
∑
i
=
1
m
[
y
i
log
(
y
^
i
)
+
(
1
−
y
i
)
log
(
1
−
y
^
i
)
]
\\mathcal{L}_{\\text{BCE}} = -\\frac{1}{m} \\sum_{i=1}^{m} \\left[ y_i \\log(\\hat{y}_i) + (1 – y_i) \\log(1 – \\hat{y}_i) \\right]
LBCE=−m1i=1∑m[yilog(y^i)+(1−yi)log(1−y^i)]
其中
y
^
i
=
σ
(
z
i
)
∈
(
0
,
1
)
\\hat{y}_i = \\sigma(z_i) \\in (0,1)
y^i=σ(zi)∈(0,1)。
多分类:分类交叉熵(Categorical Cross-Entropy)
L
CE
=
−
1
m
∑
i
=
1
m
∑
k
=
1
K
y
i
k
log
(
y
^
i
k
)
\\mathcal{L}_{\\text{CE}} = -\\frac{1}{m} \\sum_{i=1}^{m} \\sum_{k=1}^{K} y_{ik} \\log(\\hat{y}_{ik})
LCE=−m1i=1∑mk=1∑Kyiklog(y^ik)
其中
y
i
\\mathbf{y}_i
yi 是 one-hot 标签,
y
^
i
=
softmax
(
z
i
)
\\hat{\\mathbf{y}}_i = \\text{softmax}(\\mathbf{z}_i)
y^i=softmax(zi)。
⚠️ 注意:不要对 Softmax 输出再加 Sigmoid!Softmax 已确保输出为概率分布。
四、核心算法:反向传播(Backpropagation)
反向传播是神经网络训练的基石,它高效地计算损失函数对所有参数的梯度。
4.1 链式法则(Chain Rule)回顾
设
L
=
f
(
g
(
h
(
x
)
)
)
L = f(g(h(x)))
L=f(g(h(x))),则:
d
L
d
x
=
d
L
d
g
⋅
d
g
d
h
⋅
d
h
d
x
\\frac{dL}{dx} = \\frac{dL}{dg} \\cdot \\frac{dg}{dh} \\cdot \\frac{dh}{dx}
dxdL=dgdL⋅dhdg⋅dxdh
神经网络的损失是参数的复合函数,链式法则是计算梯度的自然工具。
4.2 反向传播的推导(以两层网络为例)
考虑一个简单网络:
- 输入:
x
∈
R
n
\\mathbf{x} \\in \\mathbb{R}^n
x∈Rn - 隐藏层:
h
=
ReLU
(
W
1
x
+
b
1
)
\\mathbf{h} = \\text{ReLU}(\\mathbf{W}_1 \\mathbf{x} + \\mathbf{b}_1)
h=ReLU(W1x+b1) - 输出:
y
^
=
σ
(
w
2
⊤
h
+
b
2
)
\\hat{y} = \\sigma(\\mathbf{w}_2^\\top \\mathbf{h} + b_2)
y^=σ(w2⊤h+b2) - 损失:
L
=
BCE
(
y
,
y
^
)
\\mathcal{L} = \\text{BCE}(y, \\hat{y})
L=BCE(y,y^)
我们希望计算
∂
L
∂
W
1
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{W}_1}
∂W1∂L,
∂
L
∂
W
2
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{W}_2}
∂W2∂L 等。
步骤 1:计算输出层梯度
令
z
2
=
w
2
⊤
h
+
b
2
z_2 = \\mathbf{w}_2^\\top \\mathbf{h} + b_2
z2=w2⊤h+b2,则:
∂
L
∂
z
2
=
y
^
−
y
(这是 BCE + Sigmoid 的优雅性质!)
\\frac{\\partial \\mathcal{L}}{\\partial z_2} = \\hat{y} – y \\quad \\text{(这是 BCE + Sigmoid 的优雅性质!)}
∂z2∂L=y^−y(这是 BCE + Sigmoid 的优雅性质!)
于是:
∂
L
∂
w
2
=
∂
L
∂
z
2
⋅
∂
z
2
∂
w
2
=
(
y
^
−
y
)
⋅
h
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{w}_2} = \\frac{\\partial \\mathcal{L}}{\\partial z_2} \\cdot \\frac{\\partial z_2}{\\partial \\mathbf{w}_2} = (\\hat{y} – y) \\cdot \\mathbf{h}
∂w2∂L=∂z2∂L⋅∂w2∂z2=(y^−y)⋅h
∂
L
∂
b
2
=
y
^
−
y
\\frac{\\partial \\mathcal{L}}{\\partial b_2} = \\hat{y} – y
∂b2∂L=y^−y
步骤 2:传播到隐藏层
令
z
1
=
W
1
x
+
b
1
\\mathbf{z}_1 = \\mathbf{W}_1 \\mathbf{x} + \\mathbf{b}_1
z1=W1x+b1,
h
=
ReLU
(
z
1
)
\\mathbf{h} = \\text{ReLU}(\\mathbf{z}_1)
h=ReLU(z1)。
首先计算
∂
L
∂
h
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{h}}
∂h∂L:
∂
L
∂
h
=
∂
L
∂
z
2
⋅
∂
z
2
∂
h
=
(
y
^
−
y
)
⋅
w
2
⊤
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{h}} = \\frac{\\partial \\mathcal{L}}{\\partial z_2} \\cdot \\frac{\\partial z_2}{\\partial \\mathbf{h}} = (\\hat{y} – y) \\cdot \\mathbf{w}_2^\\top
∂h∂L=∂z2∂L⋅∂h∂z2=(y^−y)⋅w2⊤
然后,由于 ReLU 的导数为:
d
d
z
ReLU
(
z
)
=
{
1
,
z
>
0
0
,
z
≤
0
=
I
(
z
>
0
)
\\frac{d}{dz} \\text{ReLU}(z) = \\begin{cases} 1, & z > 0 \\\\ 0, & z \\leq 0 \\end{cases} = \\mathbb{I}(z > 0)
dzdReLU(z)={1,0,z>0z≤0=I(z>0)
所以:
∂
L
∂
z
1
=
∂
L
∂
h
⊙
I
(
z
1
>
0
)
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{z}_1} = \\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{h}} \\odot \\mathbb{I}(\\mathbf{z}_1 > 0)
∂z1∂L=∂h∂L⊙I(z1>0)
其中
⊙
\\odot
⊙ 表示逐元素相乘(Hadamard product)。
最后:
∂
L
∂
W
1
=
∂
L
∂
z
1
⋅
x
⊤
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{W}_1} = \\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{z}_1} \\cdot \\mathbf{x}^\\top
∂W1∂L=∂z1∂L⋅x⊤
∂
L
∂
b
1
=
∂
L
∂
z
1
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{b}_1} = \\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{z}_1}
∂b1∂L=∂z1∂L
✅ 反向传播的本质: 从输出层开始,逐层反向计算“误差信号”(即
∂
L
∂
z
(
l
)
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{z}^{(l)}}
∂z(l)∂L),再用它计算当前层参数的梯度。
4.3 一般形式:向量化反向传播
对第
l
l
l 层,定义误差项(error term):
δ
(
l
)
=
∂
L
∂
Z
(
l
)
\\boldsymbol{\\delta}^{(l)} = \\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{Z}^{(l)}}
δ(l)=∂Z(l)∂L
则:
-
输出层(假设用 Softmax + CE):
δ
(
L
)
=
A
(
L
)
−
Y
\\boldsymbol{\\delta}^{(L)} = \\mathbf{A}^{(L)} – \\mathbf{Y}
δ(L)=A(L)−Y
-
隐藏层(
l
<
L
l < L
l<L):
δ
(
l
)
=
(
W
(
l
+
1
)
δ
(
l
+
1
)
)
⊙
σ
′
(
l
)
(
Z
(
l
)
)
\\boldsymbol{\\delta}^{(l)} = \\left( \\mathbf{W}^{(l+1)} \\boldsymbol{\\delta}^{(l+1)} \\right) \\odot \\sigma'^{(l)}(\\mathbf{Z}^{(l)})
δ(l)=(W(l+1)δ(l+1))⊙σ′(l)(Z(l))
-
参数梯度:
∂
L
∂
W
(
l
)
=
A
(
l
−
1
)
⊤
δ
(
l
)
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{W}^{(l)}} = \\mathbf{A}^{(l-1)\\top} \\boldsymbol{\\delta}^{(l)}
∂W(l)∂L=A(l−1)⊤δ(l)
∂
L
∂
b
(
l
)
=
∑
i
=
1
m
δ
i
(
l
)
(按样本求和)
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{b}^{(l)}} = \\sum_{i=1}^{m} \\boldsymbol{\\delta}^{(l)}_i \\quad \\text{(按样本求和)}
∂b(l)∂L=i=1∑mδi(l)(按样本求和)
🔑 反向传播的计算复杂度与前向传播同阶,这是它被广泛采用的关键原因。
五、动手实现:从零构建一个全连接神经网络
我们将用 NumPy 实现一个支持任意层数的 MLP,并用于手写数字分类(MNIST 简化版)。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
class MLP:
def __init__(self, layer_sizes, learning_rate=0.01, epochs=1000):
"""
layer_sizes: list, e.g., [64, 32, 10] for input=64, hidden=32, output=10
"""
self.layer_sizes = layer_sizes
self.lr = learning_rate
self.epochs = epochs
self.weights = []
self.biases = []
self.losses = []
# 初始化参数(Xavier 初始化)
for i in range(len(layer_sizes) – 1):
w = np.random.randn(layer_sizes[i], layer_sizes[i+1]) * np.sqrt(2.0 / layer_sizes[i])
b = np.zeros((1, layer_sizes[i+1]))
self.weights.append(w)
self.biases.append(b)
def relu(self, z):
return np.maximum(0, z)
def relu_derivative(self, z):
return (z > 0).astype(float)
def softmax(self, z):
exp_z = np.exp(z – np.max(z, axis=1, keepdims=True)) # 防止溢出
return exp_z / np.sum(exp_z, axis=1, keepdims=True)
def cross_entropy(self, y_true, y_pred):
m = y_true.shape[0]
log_likelihood = –np.log(y_pred[range(m), y_true.argmax(axis=1)] + 1e-8)
return np.sum(log_likelihood) / m
def forward(self, X):
activations = [X]
z_values = []
for i in range(len(self.weights)):
z = np.dot(activations[–1], self.weights[i]) + self.biases[i]
z_values.append(z)
if i == len(self.weights) – 1: # 输出层
a = self.softmax(z)
else: # 隐藏层
a = self.relu(z)
activations.append(a)
return activations, z_values
def backward(self, X, y, activations, z_values):
m = X.shape[0]
grads_w = [None] * len(self.weights)
grads_b = [None] * len(self.biases)
# 输出层误差
dz = activations[–1] – y # Softmax + CE 的梯度
grads_w[–1] = np.dot(activations[–2].T, dz) / m
grads_b[–1] = np.sum(dz, axis=0, keepdims=True) / m
# 反向传播隐藏层
for l in range(len(self.weights) – 2, –1, –1):
dz = np.dot(dz, self.weights[l+1].T) * self.relu_derivative(z_values[l])
grads_w[l] = np.dot(activations[l].T, dz) / m
grads_b[l] = np.sum(dz, axis=0, keepdims=True) / m
# 更新参数
for i in range(len(self.weights)):
self.weights[i] -= self.lr * grads_w[i]
self.biases[i] -= self.lr * grads_b[i]
def fit(self, X, y):
for epoch in range(self.epochs):
activations, z_values = self.forward(X)
loss = self.cross_entropy(y, activations[–1])
self.losses.append(loss)
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
self.backward(X, y, activations, z_values)
def predict(self, X):
activations, _ = self.forward(X)
return np.argmax(activations[–1], axis=1)
# 加载数据:sklearn digits(1797 张 8×8 手写数字)
digits = load_digits()
X, y = digits.data, digits.target
# 标准化(对神经网络很重要!)
scaler = StandardScaler()
X = scaler.fit_transform(X)
# 转换标签为 one-hot
y_onehot = np.eye(10)[y]
# 划分数据
X_train, X_test, y_train, y_test, y_train_oh, y_test_oh = train_test_split(
X, y, y_onehot, test_size=0.2, random_state=42
)
# 训练模型
mlp = MLP(layer_sizes=[64, 32, 16, 10], learning_rate=0.1, epochs=1000)
mlp.fit(X_train, y_train_oh)
# 评估
y_pred = mlp.predict(X_test)
accuracy = np.mean(y_pred == y_test)
print(f"\\nTest Accuracy: {accuracy:.4f}")
# 可视化损失
plt.plot(mlp.losses)
plt.title("Training Loss")
plt.xlabel("Epoch")
plt.ylabel("Cross-Entropy Loss")
plt.show()
✅ 关键实现细节:
- 使用 Xavier 初始化(np.sqrt(2.0 / fan_in))缓解梯度消失;
- 标准化输入(StandardScaler)加速收敛;
- Softmax + Cross-Entropy 的梯度简化为 pred – true;
- 向量化实现高效批量计算。
六、训练神经网络的挑战与解决方案
尽管原理清晰,但训练神经网络常面临以下挑战:
6.1 梯度消失与爆炸(Vanishing/Exploding Gradients)
在深层网络中,反向传播的梯度是多个矩阵乘积:
∂
L
∂
W
(
1
)
∝
W
(
2
)
W
(
3
)
⋯
W
(
L
)
\\frac{\\partial \\mathcal{L}}{\\partial \\mathbf{W}^{(1)}} \\propto \\mathbf{W}^{(2)} \\mathbf{W}^{(3)} \\cdots \\mathbf{W}^{(L)}
∂W(1)∂L∝W(2)W(3)⋯W(L)
若权重初始化不当:
-
∣
W
∣
<
1
|\\mathbf{W}| < 1
∣W∣<1 → 梯度指数级衰减(消失); -
∣
W
∣
>
1
|\\mathbf{W}| > 1
∣W∣>1 → 梯度指数级增长(爆炸)。
解决方案:
- 合理初始化:Xavier(Sigmoid/Tanh)、He(ReLU);
- 使用 ReLU:避免 Sigmoid/Tanh 的饱和区;
- Batch Normalization:对每层输入标准化,稳定分布;
- 残差连接(ResNet):允许梯度直接跨层流动。
6.2 过拟合(Overfitting)
神经网络参数量大,极易过拟合小数据集。
正则化技术:
- L2 正则化(Weight Decay):
L
total
=
L
data
+
λ
∑
l
∥
W
(
l
)
∥
F
2
\\mathcal{L}_{\\text{total}} = \\mathcal{L}_{\\text{data}} + \\lambda \\sum_{l} \\|\\mathbf{W}^{(l)}\\|_F^2
Ltotal=Ldata+λl∑∥W(l)∥F2 - Dropout:训练时随机“关闭”一部分神经元(如 50%),强制网络不依赖特定路径;
- 早停(Early Stopping):监控验证集损失,不再下降时停止;
- 数据增强:对图像旋转、裁剪、加噪等。
6.3 优化困难:局部极小与鞍点
高维损失 landscape 存在大量鞍点(saddle points),而非局部极小。
现代优化器:
-
SGD with Momentum:
v
t
=
β
v
t
−
1
+
(
1
−
β
)
∇
L
t
θ
t
=
θ
t
−
1
−
η
v
t
\\mathbf{v}_t = \\beta \\mathbf{v}_{t-1} + (1 – \\beta) \\nabla \\mathcal{L}_t \\\\ \\theta_t = \\theta_{t-1} – \\eta \\mathbf{v}_t
vt=βvt−1+(1−β)∇Ltθt=θt−1−ηvt 动量帮助穿越平坦区域。
-
Adam(Adaptive Moment Estimation):
m
t
=
β
1
m
t
−
1
+
(
1
−
β
1
)
∇
L
t
v
t
=
β
2
v
t
−
1
+
(
1
−
β
2
)
(
∇
L
t
)
2
m
^
t
=
m
t
1
−
β
1
t
,
v
^
t
=
v
t
1
−
β
2
t
θ
t
=
θ
t
−
1
−
η
m
^
t
v
^
t
+
ϵ
\\mathbf{m}_t = \\beta_1 \\mathbf{m}_{t-1} + (1 – \\beta_1) \\nabla \\mathcal{L}_t \\\\ \\mathbf{v}_t = \\beta_2 \\mathbf{v}_{t-1} + (1 – \\beta_2) (\\nabla \\mathcal{L}_t)^2 \\\\ \\hat{\\mathbf{m}}_t = \\frac{\\mathbf{m}_t}{1 – \\beta_1^t}, \\quad \\hat{\\mathbf{v}}_t = \\frac{\\mathbf{v}_t}{1 – \\beta_2^t} \\\\ \\theta_t = \\theta_{t-1} – \\eta \\frac{\\hat{\\mathbf{m}}_t}{\\sqrt{\\hat{\\mathbf{v}}_t} + \\epsilon}
mt=β1mt−1+(1−β1)∇Ltvt=β2vt−1+(1−β2)(∇Lt)2m^t=1−β1tmt,v^t=1−β2tvtθt=θt−1−ηv^t
+ϵm^t Adam 自适应调整每个参数的学习率,是目前最常用的优化器。
七、使用 PyTorch 构建现代神经网络
在实践中,我们使用深度学习框架(如 PyTorch)而非手动实现。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 转换数据为 PyTorch 张量
X_train_t = torch.tensor(X_train, dtype=torch.float32)
y_train_t = torch.tensor(y_train, dtype=torch.long)
X_test_t = torch.tensor(X_test, dtype=torch.float32)
y_test_t = torch.tensor(y_test, dtype=torch.long)
train_loader = DataLoader(TensorDataset(X_train_t, y_train_t), batch_size=32, shuffle=True)
# 定义模型
class Net(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(64, 32)
self.fc2 = nn.Linear(32, 16)
self.fc3 = nn.Linear(16, 10)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(0.2)
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout(x)
x = self.relu(self.fc2(x))
x = self.dropout(x)
x = self.fc3(x) # 无需 Softmax,CrossEntropyLoss 内部处理
return x
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练循环
for epoch in range(100):
model.train()
for batch_x, batch_y in train_loader:
optimizer.zero_grad()
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
loss.backward()
optimizer.step()
if epoch % 20 == 0:
model.eval()
with torch.no_grad():
test_outputs = model(X_test_t)
pred = test_outputs.argmax(dim=1)
acc = (pred == y_test_t).float().mean().item()
print(f"Epoch {epoch}, Test Acc: {acc:.4f}")
✅ PyTorch 优势:
- 自动微分(loss.backward());
- GPU 加速(.to('cuda'));
- 丰富的预定义层(Linear, Conv2d, LSTM 等);
- 动态计算图,调试友好。
八、可解释性:揭开神经网络的黑箱
神经网络常被诟病为“黑箱”,但近年来出现了多种解释方法。
8.1 全局可解释性
- 特征重要性:通过扰动输入特征,观察输出变化;
- 激活可视化:对隐藏层神经元,找出使其激活最大的输入(如 DeepDream)。
8.2 局部可解释性:LIME 与 SHAP
-
LIME(Local Interpretable Model-agnostic Explanations):
- 在预测点附近生成扰动样本;
- 用简单模型(如线性回归)拟合局部行为;
- 解释该简单模型的系数。
-
SHAP(SHapley Additive exPlanations):
- 基于博弈论,计算每个特征对预测的边际贡献;
- 对神经网络,可用 DeepSHAP 或 Integrated Gradients 近似。
# 使用 SHAP 解释 PyTorch 模型
import shap
explainer = shap.DeepExplainer(model, X_train_t[:100]) # 背景数据
shap_values = explainer.shap_values(X_test_t[:1])
shap.image_plot(shap_values, –X_test_t[:1].reshape(1, 8, 8)) # 对图像 reshape
8.3 注意力机制(Attention)
在 NLP 和 CV 中,注意力权重本身提供了解释性:
“模型关注了句子中的‘not’,因此将情感判断为负面。”
九、神经网络 vs 传统模型:何时选择谁?
| 数据类型 | 图像、文本、语音、图、序列 | 结构化表格数据 |
| 数据规模 | 需大量数据(>10k 样本) | 小数据也能 work |
| 特征工程 | 自动学习特征表示 | 依赖人工特征工程 |
| 可解释性 | 黑箱(需额外工具) | 相对透明(树路径、系数) |
| 训练资源 | 需 GPU、调参复杂 | CPU 即可,调参简单 |
| 默认性能 | 在非结构化数据上碾压 | 在表格数据上 often 更优 |
✅ 经验法则:
- 结构化数据:先试 XGBoost/LightGBM;
- 图像/文本/语音:直接上 CNN/Transformer;
- 混合数据:用神经网络处理非结构化部分,传统模型处理表格部分,再融合。
十、进阶方向:从 MLP 到现代架构
全连接网络(MLP)只是起点,现代深度学习包含:
- 卷积神经网络(CNN):利用局部性和平移不变性处理图像;
- 循环神经网络(RNN/LSTM):处理序列数据;
- Transformer:通过自注意力机制统一处理各类序列;
- 图神经网络(GNN):处理图结构数据;
- 自监督学习:在无标签数据上预训练(如 BERT、SimCLR)。
这些架构的核心思想仍是:堆叠可微模块 + 端到端训练。
十一、结语:函数逼近的艺术
神经网络不是魔法,而是一种工程化的函数逼近技术。它的力量源于:
- 通用逼近能力:理论上可拟合任意函数;
- 端到端学习:从原始输入到最终输出,无需中间表示;
- 可扩展性:增加层数/宽度即可提升容量。
但也要清醒认识到:
- 它需要大量数据和算力;
- 它缺乏因果推理能力;
- 它的决策过程难以审计。
最好的实践,是在理解其原理的基础上,审慎选择工具,负责任地应用。
下一篇文章,我们将进入无监督学习的世界——那里没有标签,只有数据自身的结构等待发现。
但在那之前,请记住:
模型的价值,不在于它有多深,而在于它解决了什么问题。
行动建议
真正的理解,始于亲手实现,成于反复实验。

