深度学习与神经网络
深度学习与神经网络
简介
深度学习是机器学习的子领域,使用多层神经网络自动提取特征。相比传统 ML 需要手工设计特征,深度学习通过端到端训练自动学习数据表示。在图像识别、语音处理、自然语言理解等领域取得突破性进展。
深度学习的理论基础源于多层感知机(MLP)和反向传播算法(1986 年 Hinton 等人重新发现)。但直到 2006 年 Hinton 提出深度信念网络,以及 2012 年 AlexNet 在 ImageNet 上的突破,深度学习才真正开始崛起。此后,GPU 计算能力的提升、大规模数据集的可用性以及算法创新(批归一化、残差连接、注意力机制等)共同推动了深度学习的快速发展。
从计算的角度看,深度学习是一种通过多层非线性变换来学习数据表示的方法。每一层都将输入变换到一个新的表示空间,使得后续层可以更容易地完成最终任务。深层网络可以学习到非常复杂的特征层次结构:从低级的边缘和纹理到高级的语义概念。
特点
万能近似定理
万能近似定理(Universal Approximation Theorem)指出:一个具有足够多隐藏单元的前馈神经网络可以以任意精度逼近任何连续函数。这为深度学习的表达能力提供了理论保证。但定理只保证存在性,不保证可以通过梯度下降找到最优解——这正是实际训练中面临的核心挑战。
神经网络基础
全连接网络
import torch
import torch.nn as nn
# 全连接网络(MLP)
class SimpleMLP(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super().__init__()
self.network = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(hidden_dim, output_dim)
)
def forward(self, x):
return self.network(x)
# 使用示例
model = SimpleMLP(input_dim=784, hidden_dim=256, output_dim=10)
print(f"参数量: {sum(p.numel() for p in model.parameters()):,}")激活函数详解
import torch
import torch.nn as nn
def compare_activations():
"""激活函数的作用和对比
激活函数引入非线性,使得神经网络可以拟合任意函数。
没有激活函数的多层网络等价于一个单层线性变换。
常见激活函数:
1. ReLU: max(0, x)
- 优点: 计算快,缓解梯度消失
- 缺点: "死亡 ReLU"问题(负半轴梯度为0)
2. LeakyReLU: max(0.01x, x)
- 缓解死亡 ReLU,负半轴保留小斜率
3. GELU: x * Phi(x),Phi 是标准正态 CDF
- 平滑的近似,Transformer 中常用
4. SiLU/Swish: x * sigmoid(x)
- 非单调,自门控,EfficientNet/ViT 中常用
5. Sigmoid: 1 / (1 + exp(-x))
- 输出 (0, 1),适合二分类输出层
- 隐藏层不推荐(梯度消失)
6. Tanh: (exp(x) - exp(-x)) / (exp(x) + exp(-x))
- 输出 (-1, 1),零中心化
- RNN 隐状态常用
"""
x = torch.linspace(-5, 5, 100)
activations = {
"ReLU": nn.ReLU(),
"LeakyReLU": nn.LeakyReLU(0.01),
"GELU": nn.GELU(),
"SiLU": nn.SiLU(),
"Sigmoid": nn.Sigmoid(),
"Tanh": nn.Tanh(),
}
print("激活函数值域对比:")
for name, act in activations.items():
y = act(x)
print(f" {name:15s}: min={y.min():.4f}, max={y.max():.4f}, "
f"x=0: {act(torch.tensor(0.0)).item():.4f}")
compare_activations()卷积神经网络(CNN)
# 图像分类 CNN
class ImageClassifier(nn.Module):
def __init__(self, num_classes=10):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), # 3通道 → 32通道
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2), # 尺寸减半
nn.Conv2d(32, 64, 3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.AdaptiveAvgPool2d(1) # 全局平均池化
)
self.classifier = nn.Linear(128, num_classes)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
return self.classifier(x)
model = ImageClassifier(num_classes=10)损失函数详解
import torch
import torch.nn as nn
def explain_loss_functions():
"""深度学习常用损失函数
分类任务:
1. CrossEntropyLoss: 多分类,内置 softmax + log
2. BCEWithLogitsLoss: 二分类/多标签,内置 sigmoid + log
回归任务:
3. MSELoss: 均方误差,回归基线
4. L1Loss: 平均绝对误差,对异常值更鲁棒
5. HuberLoss: MSE 和 L1 的平滑组合
生成任务:
6. KLDivLoss: KL 散度,知识蒸馏
7. CosineEmbeddingLoss: 余弦相似度
"""
# 分类损失
logits = torch.randn(4, 10)
targets = torch.randint(0, 10, (4,))
ce = nn.CrossEntropyLoss()(logits, targets)
print(f"CrossEntropy Loss: {ce.item():.4f}")
# 回归损失
pred = torch.randn(4, 1)
target = torch.randn(4, 1)
mse = nn.MSELoss()(pred, target)
l1 = nn.L1Loss()(pred, target)
huber = nn.HuberLoss()(pred, target)
print(f"MSE: {mse.item():.4f}, L1: {l1.item():.4f}, Huber: {huber.item():.4f}")
explain_loss_functions()优化器详解
import torch
import torch.nn as nn
def explain_optimizers():
"""深度学习常用优化器
1. SGD: 随机梯度下降
- 优点: 简单,内存少
- 缺点: 需要仔细调学习率,容易困在鞍点
- 适合: 大规模分类,配合动量和学习率调度
2. Adam: 自适应矩估计
- 优点: 对学习率不敏感,收敛快
- 缺点: 可能泛化不如 SGD
- 适合: NLP、生成模型、快速实验
3. AdamW: Adam + 解耦权重衰减
- 优点: 正则化效果更好
- 适合: Transformer、ViT 等现代模型
4. 学习率调度:
- StepLR: 每 N 个 epoch 衰减
- CosineAnnealing: 余弦退火
- OneCycleLR: 先升后降
- ReduceLROnPlateau: 验证损失不降则衰减
"""
model = nn.Linear(10, 2)
optimizers = {
"SGD (lr=0.01, momentum=0.9)": torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9),
"Adam (lr=1e-3)": torch.optim.Adam(model.parameters(), lr=1e-3),
"AdamW (lr=1e-3, weight_decay=0.01)": torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01),
}
for name, opt in optimizers.items():
print(f" {name}")
print("\n选择建议:")
print(" 快速实验: Adam / AdamW")
print(" 追求最佳泛化: SGD + Momentum + CosineAnnealing")
print(" Transformer: AdamW + CosineAnnealing")
explain_optimizers()训练循环
# 标准训练流程
def train_model(model, train_loader, val_loader, epochs=10, lr=0.001):
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1)
for epoch in range(epochs):
# 训练阶段
model.train()
train_loss = 0
correct = 0
total = 0
for batch_x, batch_y in train_loader:
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
optimizer.zero_grad()
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
loss.backward()
optimizer.step()
train_loss += loss.item()
_, predicted = outputs.max(1)
total += batch_y.size(0)
correct += predicted.eq(batch_y).sum().item()
# 验证阶段
model.eval()
val_loss = 0
val_correct = 0
val_total = 0
with torch.no_grad():
for batch_x, batch_y in val_loader:
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
val_loss += loss.item()
_, predicted = outputs.max(1)
val_total += batch_y.size(0)
val_correct += predicted.eq(batch_y).sum().item()
scheduler.step()
print(f"Epoch {epoch+1}/{epochs} | "
f"Train Loss: {train_loss/len(train_loader):.4f} Acc: {100*correct/total:.1f}% | "
f"Val Loss: {val_loss/len(val_loader):.4f} Acc: {100*val_correct/val_total:.1f}%")混合精度训练
def mixed_precision_training():
"""混合精度训练(AMP)详解
混合精度训练使用 FP16(半精度)进行大部分计算,同时保留 FP32 的主权重副本。
通过自动混合精度(AMP),PyTorch 自动决定哪些操作用 FP16,哪些用 FP32。
优势:
- 训练速度提升 1.5-3x
- 显存占用减少约 50%
- 精度几乎不受影响(配合损失缩放)
使用方式(PyTorch 原生):
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
with autocast():
output = model(input)
loss = criterion(output, target)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
"""
print("混合精度训练要点:")
print(" 1. 使用 torch.amp.autocast 和 GradScaler")
print(" 2. 训练速度提升 1.5-3x")
print(" 3. 显存减少约 50%")
print(" 4. 需要 NVIDIA GPU (Volta 或更新)")
mixed_precision_training()常见架构
残差连接
# ResNet 残差块
class ResidualBlock(nn.Module):
def __init__(self, channels):
super().__init__()
self.block = nn.Sequential(
nn.Conv2d(channels, channels, 3, padding=1),
nn.BatchNorm2d(channels),
nn.ReLU(),
nn.Conv2d(channels, channels, 3, padding=1),
nn.BatchNorm2d(channels)
)
def forward(self, x):
return torch.relu(x + self.block(x)) # 残差连接循环神经网络(RNN/LSTM)
# LSTM 序列模型
class LSTMModel(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_layers=2):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.lstm = nn.LSTM(embed_dim, hidden_dim, num_layers,
batch_first=True, dropout=0.3)
self.fc = nn.Linear(hidden_dim, vocab_size)
def forward(self, x, hidden=None):
embedded = self.embedding(x)
output, hidden = self.lstm(embedded, hidden)
return self.fc(output), hidden正则化技术总结
def regularization_summary():
"""深度学习正则化技术
1. Dropout: 随机丢弃神经元,防止过拟合
- 全连接层: 0.3-0.5
- CNN: 0.1-0.3
- Transformer: 0.1(注意力 dropout)
2. 权重衰减 (Weight Decay): L2 正则化
- 典型值: 1e-4 ~ 1e-2
- AdamW 使用解耦权重衰减
3. 批归一化 (BatchNorm): 标准化层输入
- 加速收敛
- 有轻微正则化效果
4. 早停 (Early Stopping):
- 验证损失不再下降时停止训练
5. 数据增强:
- 图像: 翻转、裁剪、颜色抖动
- NLP: 同义词替换、回译
6. Label Smoothing:
- 将硬标签 [0, 1] 改为 [0.05, 0.95]
- 防止模型过于自信
"""
print("正则化策略选择:")
print(" 小数据 + 大模型: 强正则化 (高 dropout + 权重衰减 + 数据增强)")
print(" 大数据 + 小模型: 弱正则化 (低 dropout + 小权重衰减)")
print(" Transformer: Dropout 0.1 + AdamW + Label Smoothing")
regularization_summary()网络架构对比
| 架构 | 适用领域 | 核心思想 | 代表模型 |
|---|---|---|---|
| CNN | 图像/视频 | 卷积提取局部特征 | ResNet, VGG |
| RNN/LSTM | 序列数据 | 时序记忆 | LSTM, GRU |
| Transformer | NLP/多模态 | 自注意力机制 | GPT, BERT |
| GAN | 生成任务 | 对抗训练 | StyleGAN |
| U-Net | 图像分割 | 编码器-解码器 | U-Net |
| ViT | 图像分类 | 图像分块+Transformer | ViT |
优点
缺点
总结
深度学习核心:多层神经网络自动学习特征。CNN 适合图像(卷积+池化),RNN/LSTM 适合序列数据,Transformer 用自注意力处理长序列。训练流程:前向传播 -> 计算损失 -> 反向传播 -> 更新权重。PyTorch 提供 nn.Module 定义网络、nn.Sequential 快速搭建、Adam 优化器收敛快。实际项目建议从预训练模型(迁移学习)入手,而非从零训练。
关键知识点
- 反向传播是深度学习的核心训练算法,通过链式法则高效计算梯度。
- 激活函数引入非线性,使多层网络具有强大的表达能力。
- 批归一化加速收敛并有一定的正则化效果。
- 残差连接是训练超深网络的关键技术。
- 混合精度训练可以显著加速训练并减少显存占用。
项目落地视角
- 优先使用预训练模型进行迁移学习,而非从头训练。
- 使用混合精度训练加速训练过程。
- 建立完善的训练监控(loss 曲线、学习率、梯度范数)。
常见误区
- 忘记 model.eval() 和 model.train() 的切换。
- 忽略数据预处理的一致性(训练和推理)。
- 过度拟合训练集而不使用正则化。
- 学习率设置不当导致训练不收敛。
进阶路线
- 深入学习 Transformer 和自注意力机制。
- 掌握知识蒸馏和模型压缩技术。
- 学习分布式训练和数据并行策略。
- 了解神经架构搜索(NAS)的基本原理。
适用场景
- 图像分类、目标检测、语义分割。
- 文本分类、机器翻译、文本生成。
- 语音识别、语音合成。
- 推荐系统、时间序列预测。
落地建议
- 使用 PyTorch Lightning 简化训练循环。
- 配合 Weights & Biases 或 MLflow 进行实验管理。
- 使用 ONNX 或 TensorRT 进行模型部署。
排错清单
- Loss 不下降:检查学习率、数据预处理、标签正确性。
- 过拟合:增加正则化、数据增强、减少模型容量。
- 欠拟合:增加模型容量、训练更长时间、减少正则化。
- NaN loss:检查梯度爆炸(使用梯度裁剪)、学习率过大。
复盘问题
- 是否使用了预训练模型?效果如何?
- 训练过程中 loss 曲线是否正常?
- 验证集表现是否与训练集差距过大?
Transformer 架构详解
Transformer 是当前深度学习最重要的架构之一,GPT、BERT、ViT 等模型都基于它。
import torch
import torch.nn as nn
import math
class MultiHeadAttention(nn.Module):
"""多头自注意力机制"""
def __init__(self, d_model=512, n_heads=8, dropout=0.1):
super().__init__()
self.d_model = d_model
self.n_heads = n_heads
self.d_k = d_model // n_heads
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, query, key, value, mask=None):
batch_size = query.size(0)
# 线性投影并分头
Q = self.W_q(query).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
K = self.W_k(key).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
V = self.W_v(value).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
# Scaled Dot-Product Attention
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn_weights = torch.softmax(scores, dim=-1)
attn_weights = self.dropout(attn_weights)
context = torch.matmul(attn_weights, V)
context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
return self.W_o(context)
class TransformerBlock(nn.Module):
"""Transformer 编码器块"""
def __init__(self, d_model=512, n_heads=8, d_ff=2048, dropout=0.1):
super().__init__()
self.attention = MultiHeadAttention(d_model, n_heads, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(),
nn.Dropout(dropout),
nn.Linear(d_ff, d_model),
nn.Dropout(dropout)
)
def forward(self, x, mask=None):
# Pre-Norm 变体(现代 Transformer 常用)
attended = self.attention(self.norm1(x), self.norm1(x), self.norm1(x), mask)
x = x + attended
x = x + self.ffn(self.norm2(x))
return x
class SimpleTransformer(nn.Module):
"""简单的 Transformer 分类模型"""
def __init__(self, vocab_size, d_model=256, n_heads=8, n_layers=4, num_classes=10):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = nn.Parameter(torch.randn(1, 512, d_model) * 0.02)
self.layers = nn.ModuleList([
TransformerBlock(d_model, n_heads) for _ in range(n_layers)
])
self.classifier = nn.Linear(d_model, num_classes)
def forward(self, x):
batch_size, seq_len = x.shape
x = self.embedding(x) + self.pos_encoding[:, :seq_len, :]
for layer in self.layers:
x = layer(x)
# 取 [CLS] token 或平均池化
x = x.mean(dim=1)
return self.classifier(x)
model = SimpleTransformer(vocab_size=30000, num_classes=10)
print(f"Transformer 参数量: {sum(p.numel() for p in model.parameters()):,}")学习率调度策略详解
学习率调度对训练效果影响巨大。以下展示常用调度策略的实现。
import torch
import math
class LearningRateScheduler:
"""常用学习率调度策略对比"""
@staticmethod
def cosine_annealing_lr(epoch, total_epochs, lr_max=1e-3, lr_min=1e-6):
"""余弦退火(Transformer 训练标配)"""
return lr_min + 0.5 * (lr_max - lr_min) * (1 + math.cos(math.pi * epoch / total_epochs))
@staticmethod
def warmup_cosine_lr(epoch, total_epochs, warmup_epochs=5, lr_max=1e-3, lr_min=1e-6):
"""Warmup + 余弦退火(推荐)"""
if epoch < warmup_epochs:
return lr_max * epoch / warmup_epochs
return LearningRateScheduler.cosine_annealing_lr(
epoch - warmup_epochs, total_epochs - warmup_epochs, lr_max, lr_min)
@staticmethod
def one_cycle_lr(epoch, total_epochs, lr_max=1e-3, pct_start=0.3):
"""One Cycle 策略(先升后降)"""
pct = epoch / total_epochs
if pct < pct_start:
return lr_max * pct / pct_start
else:
return lr_max * (1 - pct) / (1 - pct_start)
# PyTorch 内置调度器使用
model = nn.Linear(10, 2)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
# CosineAnnealingLR
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100, eta_min=1e-6)
# OneCycleLR(需要先知道总 step 数)
# scheduler = torch.optim.lr_scheduler.OneCycleLR(
# optimizer, max_lr=1e-3, total_steps=1000, pct_start=0.1)
# ReduceLROnPlateau(验证损失不降则衰减)
# scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
# optimizer, mode='min', factor=0.5, patience=5, min_lr=1e-6)
# 调度器选择建议:
# CNN 分类: StepLR 或 CosineAnnealingLR
# Transformer: WarmupCosine(线性预热 + 余弦退火)
# 快速实验: OneCycleLR
# 不确定时: ReduceLROnPlateau迁移学习实战
import torch
import torch.nn as nn
from torchvision import models
def transfer_learning_example():
"""迁移学习:使用预训练模型快速适配新任务"""
# 1. 加载预训练模型
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)
# 2. 冻结特征提取层(只训练分类头)
for param in model.parameters():
param.requires_grad = False
# 3. 替换分类头
num_features = model.fc.in_features
model.fc = nn.Sequential(
nn.Dropout(0.3),
nn.Linear(num_features, 256),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(256, 10) # 10 类目标
)
# 4. 只优化分类头参数
optimizer = torch.optim.AdamW(model.fc.parameters(), lr=1e-3, weight_decay=0.01)
# 5. 解冻策略:先训练分类头几个 epoch,再解冻部分层微调
def unfreeze_layers(model, num_layers_to_unfreeze=10):
"""解冻最后 N 层"""
layers = list(model.children())
for layer in layers[-num_layers_to_unfreeze:]:
for param in layer.parameters():
param.requires_grad = True
print(f"可训练参数: {sum(p.numel() for p in model.parameters() if p.requires_grad):,}")
print(f"总参数: {sum(p.numel() for p in model.parameters()):,}")
# 迁移学习策略总结:
# 小数据集 (<1000样本): 冻结全部 + 只训练分类头
# 中等数据集: 冻结前面层 + 解冻后面几层
# 大数据集: 全部解冻 + 小学习率微调
return model
transfer_learning_example()梯度裁剪与训练稳定性技巧
import torch
def training_stability_tips():
"""训练稳定性技巧汇总"""
# 1. 梯度裁剪(防止梯度爆炸)
model = nn.Linear(100, 10)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
# 方式 A: 按范数裁剪(推荐)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 方式 B: 按值裁剪
torch.nn.utils.clip_grad_value_(model.parameters(), clip_value=0.5)
# 2. 权重初始化(对训练稳定性至关重要)
def init_weights(module):
if isinstance(module, nn.Linear):
nn.init.xavier_uniform_(module.weight)
if module.bias is not None:
nn.init.zeros_(module.bias)
elif isinstance(module, nn.Conv2d):
nn.init.kaiming_normal_(module.weight, mode='fan_out', nonlinearity='relu')
model.apply(init_weights)
# 3. 梯度累积(显存不够时模拟大 batch)
accumulation_steps = 4
effective_batch_size = 32 * accumulation_steps # 等效 batch=128
optimizer.zero_grad()
for i, (data, target) in enumerate(train_loader):
output = model(data)
loss = criterion(output, target) / accumulation_steps
loss.backward()
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
# 4. EMA(指数移动平均)提升泛化
class EMA:
def __init__(self, model, decay=0.999):
self.decay = decay
self.shadow = {name: p.clone().detach()
for name, p in model.named_parameters()}
def update(self, model):
for name, p in model.named_parameters():
self.shadow[name].mul_(self.decay).add_(p.data, alpha=1 - self.decay)
training_stability_tips()