📝 复习前言
本篇笔记用于快速回顾多层感知机(MLP)核心知识,涵盖线性模型的局限性、隐藏层作用、激活函数、手动实现与 PyTorch 简洁实现,适配 Fashion-MNIST 分类任务,帮助快速复盘、查漏补缺。
一、为什么需要多层感知机(MLP)?
1. 线性模型的致命缺陷
Softmax 回归是线性模型 ,只能处理线性可分问题,但现实场景中:
- 数据特征关系非线性(如体温与死亡率、图像像素间的关联)
- 线性模型的单调性假设失效,无法拟合复杂函数
- 本质:线性模型只是简单的仿射变换,表达能力极差
2. MLP 的核心思路
在输入层和输出层之间加入隐藏层 ,并在隐藏层后添加非线性激活函数 ,让模型具备拟合任意复杂函数的能力。
3. 关键结论
纯线性层叠加 = 还是线性模型 只有加入激活函数,才能打破线性限制,让 MLP 真正拥有非线性表达能力。
二、核心结构:多层感知机(MLP)
1. 网络架构(单隐藏层)
plaintext
输入层(784维) → 隐藏层(256维)+ReLU → 输出层(10维)
- 输入层:Fashion-MNIST 图像展平为 784 维向量(28×28)
- 隐藏层:全连接层 + 激活函数,提取非线性特征
- 输出层:10 维,对应 10 个分类类别
2. 数学公式
- 隐藏层计算(带激活)H=σ(XW1+b1)
- 输出层计算O=HW2+b2
- σ:激活函数(ReLU)
- W1/b1:隐藏层权重、偏置
- W2/b2:输出层权重、偏置
三、必掌握:三大激活函数
激活函数的唯一核心作用:引入非线性,让模型能拟合复杂关系。
1. ReLU(最常用,首选)
- 公式:ReLU(x)=max(x,0)
- 特点:✅ 实现简单、计算快✅ 缓解梯度消失问题✅ 正区间梯度恒为 1,训练稳定
- 导数:x>0时为 1,x<0时为 0
2. Sigmoid
- 公式:sigmoid(x)=1+e−x1
- 特点:输出
(0,1),可做概率输出 - 缺点:易梯度消失,极少用于隐藏层
3. Tanh(双曲正切)
- 公式:tanh(x)=ex+e−xex−e−x
- 特点:输出
(-1,1),中心对称 - 缺点:仍存在梯度消失问题
四、实战 1:MLP 从零实现(PyTorch)
核心步骤
- 加载 Fashion-MNIST 数据集
- 初始化模型参数(权重 + 偏置)
- 定义 ReLU 激活函数
- 定义模型前向传播
- 定义损失、优化器
- 训练(适配 GPU + 速度统计)
完整代码(带复习注释)
python
运行
import torch
from torch import nn
from d2l import torch as d2l
import time
# 1. 配置设备(自动使用RTX4070 GPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 2. 加载数据集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
# 3. 定义参数
num_inputs, num_outputs, num_hiddens = 784, 10, 256
# 隐藏层参数
W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
# 输出层参数
W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
params = [W1, b1, W2, b2]
# 4. 定义ReLU激活函数
def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)
# 5. 定义模型
def net(X):
X = X.reshape((-1, num_inputs)) # 展平图像
H = relu(X @ W1 + b1) # 隐藏层计算
return H @ W2 + b2 # 输出层计算
# 6. 损失函数+优化器
loss = nn.CrossEntropyLoss(reduction='none')
num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
# 7. 训练函数(修复d2l缺失train_ch3问题)
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater, device):
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=['train loss', 'train acc', 'test acc'])
net.to(device)
total_start = time.time()
for epoch in range(num_epochs):
start = time.time()
# 单轮训练
net.train()
metric = d2l.Accumulator(3)
for X, y in train_iter:
X, y = X.to(device), y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
updater.zero_grad()
l.mean().backward()
updater.step()
metric.add(float(l.sum()), d2l.accuracy(y_hat, y), y.numel())
train_loss, train_acc = metric[0]/metric[2], metric[1]/metric[2]
# 测试集评估
test_acc = d2l.evaluate_accuracy_gpu(net, test_iter, device)
animator.add(epoch+1, (train_loss, train_acc, test_acc))
# 打印速度
speed = 60000/(time.time()-start)
print(f"Epoch {epoch+1} | 训练速度:{speed:.0f} 样本/秒")
print(f"总训练时间:{time.time()-total_start:.2f}s")
# 启动训练
train_ch3(net, train_iter, test_iter, loss, num_epochs, updater, device)
五、实战 2:MLP 简洁实现(PyTorch 高级 API)
用nn.Sequential快速堆叠网络,代码更简洁,适合工程使用。
python
运行
import torch
from torch import nn
from d2l import torch as d2l
import time
# 1. 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 2. 构建模型( Sequential 快速堆叠)
net = nn.Sequential(
nn.Flatten(), # 展平层:28x28 → 784
nn.Linear(784, 256), # 隐藏层
nn.ReLU(), # 激活函数
nn.Linear(256, 10) # 输出层
)
# 3. 权重初始化(正态分布,稳定训练)
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights)
# 4. 超参数设置
batch_size, lr, num_epochs = 256, 0.1, 10
# 5. 损失+优化器
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)
# 6. 加载数据
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
# 7. 训练(复用上面的train_ch3函数)
train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer, device)
六、🔥 复习核心考点(必背)
- 线性模型为什么不行? 只能拟合线性关系,无非线性表达能力。
- MLP 的关键是什么? 隐藏层 + 激活函数(非线性核心)。
- 首选激活函数? ReLU(计算快、梯度稳定)。
- 纯线性层叠加有用吗? 没用,等价于单层线性模型。
- MLP 本质:通用近似器,单隐藏层可拟合任意连续函数。
- 训练技巧:权重正态初始化、小批量 SGD、GPU 加速。
七、⚠️ 常见问题回顾
- 报错:module 'd2l.torch' has no attribute 'train_ch3' 新版 d2l 删除了该函数,手动实现 train_ch3即可解决。
- 如何用 GPU 训练? 模型 + 数据都移到 GPU:
net.to(device)、X.to(device)。 - **训练速度慢?**检查是否启用 GPU,batch_size 设为 256,使用 ReLU 激活函数。
八、总结
多层感知机是深度学习的基础 ,核心是通过隐藏层 + 激活函数打破线性限制,实现非线性拟合。
- 原理:线性变换 → 非线性激活 → 线性输出
- 实战:从零实现理解原理,简洁实现用于工程
- 重点:激活函数的作用、GPU 训练、模型搭建
深度学习速记卡片|多层感知机 (MLP)
(精简版・适合快速复习)
一、核心一句话
线性模型只能画直线,MLP = 隐藏层 + 激活函数,能拟合任意复杂曲线。
二、核心原理
- 线性模型缺陷:只能拟合线性关系,无法处理图像 / 复杂数据
- MLP 关键:必须加激活函数,否则再多层也还是线性模型
- 通用近似定理:单隐藏层 MLP 可逼近任意连续函数
三、激活函数(必背 3 个)
- ReLU(首选默认) 公式:
max(x, 0)优点:快、稳、缓解梯度消失 - Sigmoid 公式:
1/(1+exp(-x)),输出 0~1缺点:易梯度消失 - Tanh 公式:
(exp(x)-exp(-x))/(exp(x)+exp(-x)),输出 - 1~1缺点:梯度消失问题仍存在
四、单隐层 MLP 公式
H = ReLU(X @ W1 + b1)O = H @ W2 + b2
五、PyTorch 极简实现
python
运行
net = nn.Sequential(
nn.Flatten(),
nn.Linear(784, 256), nn.ReLU(),
nn.Linear(256, 10)
)
初始化:权重用正态分布std=0.01
六、训练关键配置
- 损失:
CrossEntropyLoss - 优化器:
SGD(lr=0.1) - 批次:
batch_size=256 - 轮数:
num_epochs=10 - 设备:模型 + 数据都移到 cuda
七、高频报错速解
- no attribute 'train_ch3'→ 新版 d2l 删除了,手动补函数即可
- 速度极慢 → 没开 GPU,把 net 和数据都
.to(device) - 不收敛→ 权重初始化 / 学习率不对
八、必背考点
- 无激活函数 = 线性模型
- 激活函数 = 非线性来源
- ReLU 是隐藏层标配
- MLP 是深度学习入门基础