深度学习进阶:CNN、RNN、正则化与训练调参实战

从 MLP 走向深度学习的进阶实战:CNN 卷积网络结构、RNN/LSTM 序列建模、Dropout/BatchNorm/数据增强正则化、优化器演进(SGD/Adam)、学习率调度、迁移学习,PyTorch 训练 CIFAR 全流程。

引言

入门篇用 PyTorch 搭了第一个 MLP(/ml-neural-networks-basics/)。进阶要解决两个问题:MLP 处理不了的结构(图像的空间局部性、序列的时序性)与深网络的训练困境(梯度消失、过拟合)。本文先给 CNN 与 RNN 两大家族的结构,再集中解决「怎么把深网络训好」——正则化、优化器、学习率调度、迁移学习,最后用 CIFAR-10 完整跑通。

前置:/ml-neural-networks-basics/(张量/自动求导/训练循环)、/ml-model-evaluation/(过拟合与评估)。


目录


1. 深度学习全景:从 MLP 到三大网络族

网络族擅长典型结构应用
MLP(全连接)表格数据线性层堆叠分类/回归
CNN图像/网格卷积+池化+全连接CV
RNN/Transformer序列循环/注意力NLP、时序
GAN生成生成器+判别器图像生成

为什么 MLP 处理图像不行:

图像 32×32×3 = 3072 维,全连接首层就要 3072×N 参数
且丢失空间结构(像素相邻关系)
→ CNN 用「局部连接 + 权值共享」解决

心智:选网络 = 匹配数据结构的先验——图像要局部性,序列要时序性,表格用 MLP 就够。


2. CNN 卷积网络:空间特征提取

卷积核(Kernel):小窗口在图上滑动,提取局部特征——权值共享大幅减少参数。

输入 32×32×3(RGB 三通道)
  → 卷积层 3×3×3×16(16 个核)→ 输出 30×30×16
  → 激活(ReLU)→ 池化 → ...
  → 展平 → 全连接 → Softmax(10)

PyTorch 定义一个小 CNN:

import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),   # 3→16 通道
            nn.ReLU(),
            nn.MaxPool2d(2),                               # 尺寸减半
            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(32 * 8 * 8, 64),   # 32×8×8 展平
            nn.ReLU(),
            nn.Linear(64, 10),
        )

    def forward(self, x):
        return self.classifier(self.features(x))

卷积层关键参数:kernel_size(核大小)、padding(补零保尺寸)、stride(步长)、channels(通道数)。

参数作用
核大小 3×3 / 5×5感受野大小
padding保持特征图尺寸
stride下采样
通道数特征表达能力

3. 池化与感受野

池化(Pooling):对局部取最大/平均——降维 + 平移不变性:

# 最大池化:取 2×2 区域最大值
nn.MaxPool2d(kernel_size=2, stride=2)
# 平均池化:取均值
nn.AvgPool2d(kernel_size=2)

感受野(Receptive Field):某个输出特征「看到」输入的区域大小:

3 层 3×3 卷积 → 感受野 7×7(3 个 3×3 堆叠 ≈ 1 个 7×7,但参数更少、非线性更多)
设计决策说明
小核堆叠 vs 大核3×3 堆叠参数少、表达力相当
池化时机尺寸减半后通道翻倍(经典 VGG 风格)
全局平均池化替代全连接做分类头(省参数防过拟合)

记忆:感受野 = 模型能「看多远」;堆小核既能看远又省参数,是 CNN 设计的主流。


4. RNN/LSTM:序列建模

RNN:带隐藏状态 h_t 的循环结构,处理「有先后」的数据:

h_t = tanh(W_h h_{t-1} + W_x x_t + b)
输出 y_t = softmax(W_y h_t)

问题:长序列梯度消失——早期信息传不到后面。

LSTM 解决:门控机制(遗忘门/输入门/输出门 + 细胞状态 C):

import torch.nn as nn

# LSTM 层(hidden=64, num_layers=2)
lstm = nn.LSTM(input_size=10, hidden_size=64, num_layers=2, batch_first=True)

# 输入: (batch, seq_len, input_size)
x = torch.randn(32, 50, 10)
out, (h_n, c_n) = lstm(x)   # out: (batch, seq_len, hidden)
组件作用
遗忘门决定丢弃哪些旧记忆
输入门决定写入哪些新信息
输出门决定输出哪些状态
细胞状态长程记忆通道

注意:现代 NLP 已被 Transformer 取代(见 /ml-nlp-basics/);LSTM 仍用于中等长度时序与轻量序列任务。


5. 正则化:Dropout、BatchNorm 与数据增强

深网络必配的三件套——专治过拟合与训练不稳:

nn.Sequential(
    nn.Conv2d(3, 32, 3, padding=1),
    nn.BatchNorm2d(32),        # 归一化每层输入 → 训练更稳、可加学习率
    nn.ReLU(),
    nn.Dropout(0.3),           # 训练时随机丢弃 30% 神经元 → 抗过拟合
    ...
)
正则化机制适用
Dropout随机屏蔽神经元,测试时全开全连接、大模型
BatchNorm层内归一化,加速收敛卷积、MLP
数据增强旋转/翻转/裁剪制造更多样本图像/序列
L1/L2 权重衰减惩罚大权重通用
早停验证集不再提升就停通用

数据增强(图像):

from torchvision import transforms

train_tf = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.RandomRotation(10),
    transforms.ColorJitter(brightness=0.2),
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,)),
])

记忆:Dropout 防过拟合、BN 稳训练、增强造数据——深网络默认配置。


6. 优化器演进:SGD、Momentum 与 Adam

优化器就是「怎么沿着梯度走」:

优化器思想特点
SGD沿负梯度走固定步长稳,可能陷局部极小
SGD+Momentum带惯性,冲过平坦区收敛更快更稳
Adagrad按历史梯度调步长学习率自动衰减
Adam自适应学习率 + 动量默认首选,快而稳
AdamWAdam + 解耦权重衰减大模型主流
import torch.optim as optim

# 首选
optimizer = optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)

# 需要精细控制时
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9,
                      weight_decay=5e-4)

选型建议:

  • 起步/默认 → Adam/AdamW
  • 结果欠佳想调 → 换回 SGD+Momentum(有时更好泛化)
  • 大模型/预训练 → AdamW + 余弦退火

记忆:Adam 快而稳是默认,SGD 慢但可能更好泛化——训练好坏的锅多在学习率,不在优化器本身。


7. 训练技巧:学习率调度、早停与梯度裁剪

学习率是最重要的超参——三大调度:

# 1. 阶梯下降:每 N 轮减半
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)

# 2. 余弦退火:平滑下降到最低
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50)

# 3. 预热 + 退火(大模型常用)
scheduler = optim.lr_scheduler.OneCycleLR(optimizer, max_lr=1e-3, epochs=50)

早停(Early Stopping)——验证集不再改善就停,防过拟合:

best_val, patience, counter = float('inf'), 5, 0
for epoch in range(epochs):
    train(model, loader)
    val = evaluate(model, val_loader)
    if val < best_val:
        best_val = val
        torch.save(model.state_dict(), 'best.pth')
        counter = 0
    else:
        counter += 1
        if counter >= patience:
            print('早停'); break

梯度裁剪(防梯度爆炸,RNN 必配):

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

训练四板斧:监控学习曲线 → 早停 → 调度学习率 → 必要时裁剪梯度。


8. 迁移学习与微调

迁移学习:用预训练权重起步,大幅降低数据需求与训练时间。

策略:

数据量策略
很少(<1k)冻结主干,只训分类头
中等(1k-10k)微调深层,冻结浅层
充足(>10k)全量微调 + 小学习率

PyTorch 微调:

import torchvision.models as models

# 用预训练 ResNet18
model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)

# 冻结所有层
for param in model.parameters():
    param.requires_grad = False

# 替换分类头(ImageNet 1000 类 → 目标 N 类)
model.fc = nn.Linear(model.fc.in_features, num_classes)

# 分类头用较大学习率,主干用小学习率
optimizer = optim.AdamW([
    {'params': model.fc.parameters(), 'lr': 1e-3},
    {'params': (p for p in model.parameters() if p.requires_grad), 'lr': 1e-4},
])

记忆:迁移 = 「站在巨人肩膀上」——预训练学的是通用特征,微调学的是你的任务。


9. PyTorch 实战:CIFAR-10 完整流程

端到端训练(含上面所有技巧):

import torch, torch.nn as nn, torchvision
from torchvision import datasets, transforms

# 1. 数据(增强 + 归一化)
train_tf = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.RandomCrop(32, padding=4),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
])
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_tf)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

# 2. 模型(复用上面 SimpleCNN)
model = SimpleCNN()

# 3. 优化器 + 调度 + 损失
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=30)
criterion = nn.CrossEntropyLoss()

# 4. 训练循环
for epoch in range(30):
    model.train()
    for images, labels in trainloader:
        optimizer.zero_grad()
        loss = criterion(model(images), labels)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer.step()
    scheduler.step()
    # 每轮评估验证集、早停判断...
    print(f'epoch {epoch}: loss={loss.item():.4f}')

训练闭环清单:数据增强 → 模型 → AdamW + 权重衰减 → 余弦调度 → 早停 → 存最佳模型。


10. 速查表

需求做法
图像分类CNN(卷积+池化)
序列/时序LSTM 或 Transformer
防过拟合Dropout + 权重衰减 + 早停
训练不稳BatchNorm + 预热
数据不足数据增强
优化器默认 AdamW
学习率余弦退火 / 阶梯
数据少但有预训练迁移学习微调
梯度爆炸梯度裁剪

一句话记忆:图像用 CNN、序列用 LSTM、默认 AdamW;Dropout 防过拟合、BN 稳训练、增强造数据、调度管学习率;数据少就迁移微调——深网络的工程四件套齐活。


延伸阅读

  • /ml-neural-networks-basics/ — 张量、自动求导与第一个网络
  • /ml-nlp-basics/ — Transformer 与 NLP 进阶
  • /ml-cv-basics/ — 计算机视觉实战
  • /ml-model-evaluation/ — 过拟合与调参评估
  • [[ai-ml]] — 算法原理深度专题

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「ml」更多文章

  1. 集成学习实战:Bagging、随机森林、梯度提升与 Stacking
  2. 迁移学习实战:预训练模型、特征提取与微调全流程
  3. 计算机视觉入门实战:图像处理与 CNN 图像分类