神经网络是什么
从"函数拟合器"的角度理解,比从"模拟大脑"理解更准确。
三个视角
① 生物视角(启发来源)
神经元接收树突信号 → 胞体加权求和 → 超过阈值则沿轴突发放脉冲。人工神经元保留了"加权求和 + 非线性激发"这一骨架。
② 数学视角(本质)
一个复合函数 y = fL(...f2(f1(x)))。每层做一次线性变换加一次非线性,层数越深表达能力越强。
③ 工程视角(怎么用)
定义结构 → 定义损失 → 反向传播求梯度 → 优化器更新参数 → 重复直到验证集指标不再提升。
④ 几何视角(直觉)
每一层把输入空间做一次扭曲与折叠,最终让不同类别的样本在高维空间里变得线性可分。
为什么"深"比"宽"更有效
- 理论上单隐层网络已能逼近任意连续函数(万能逼近定理),但可能需要指数级宽的神经元。
- 深层网络通过逐层复用特征(边缘 → 纹理 → 部件 → 物体)实现指数级的表达效率。
- 代价:梯度消失/爆炸、训练不稳定 —— 这正是残差连接、归一化、精细初始化要解决的问题。
和其他模型的关系
| 模型 | 特征处理方式 | 适用场景 |
|---|---|---|
| 线性/逻辑回归 | 人工设计特征 + 线性组合 | 可解释性优先、小数据 |
| 树模型(XGBoost) | 人工特征 + 自动切分 | 表格数据、中小规模 |
| 神经网络 | 端到端自动学习特征 | 图像 / 语音 / 文本 / 高维感知 |
神经元与感知机
M-P 模型、单层感知机,以及它为什么搞不定 XOR。
人工神经元(M-P 模型)
- w(权重):每个输入的重要程度,模型真正要学的参数。
- b(偏置):让决策边界可以平移,否则超平面必须过原点。
- σ(激活):引入非线性,否则多层网络等价于一层。
单层感知机
激活函数取符号函数 sign(z),输出 ±1。学习规则非常简单:
解决方法:加一层
两层感知机(含一个隐层)即可表示任意形状的凸区域划分,从而解决 XOR。这也说明了非线性激活 + 多层堆叠是必要的:
# XOR 的手工解(ReLU 激活)
h1 = relu( x1 + x2 - 0.5 ) # 两个都为 1
h2 = relu( x1 + x2 - 1.5 ) # 抑制重复计数
y = h1 - h2 # 输出 0/1
W₂(W₁x) = (W₂W₁)x,多层直接塌缩成一层,网络再深也只是线性回归。
非线性的每一次"折叠"才是深度的来源。激活函数大全
选错了不会报错,只会训不动 —— 这是最隐蔽的坑之一。
| 函数 | 公式 | 输出范围 | 优点 | 缺点 / 注意 |
|---|---|---|---|---|
| Sigmoid | 1/(1+e-z) | (0,1) | 可当概率用 | 两端饱和梯度≈0;输出非零中心 |
| Tanh | (ez−e-z)/(ez+e-z) | (−1,1) | 零中心,收敛更快 | 仍会饱和导致梯度消失 |
| ReLU | max(0, z) | [0,+∞) | 计算极快,不饱和 | 死亡 ReLU(负半轴永久为 0) |
| Leaky ReLU | max(0.01z, z) | (−∞,+∞) | 缓解死亡问题 | 斜率 α 需调,效果不稳定 |
| GELU | z·Φ(z) | ≈(−0.17,+∞) | 平滑;Transformer 标配 | 计算稍贵 |
| SiLU/Swish | z·σ(z) | ≈(−0.28,+∞) | 平滑非单调,常略优于 ReLU | 同上 |
| Softmax | ezᵢ/Σezⱼ | (0,1) 且和为 1 | 多分类概率分布 | 只能用在输出层 |
直观对比
怎么选
- 隐藏层默认 ReLU(CNN、MLP);追求精度可试 GELU / SiLU。
- Transformer / BERT 类:用 GELU。
- RNN 门控:必须用 Sigmoid(需要 0~1 的"开关")和 Tanh(需要 −1~1 的"信息")。
- 输出层:二分类 Sigmoid,多分类 Softmax,回归任务不激活。
网络结构与参数量
看懂模型大小、显存占用从会算参数开始。
层级术语
- 输入层:原始特征,不算参数。
- 隐藏层:做特征提取的部分,深度 = 隐藏层数。
- 输出层:映射到任务目标(类别数 / 回归维度)。
- 全连接层(FC / Dense / Linear):每个输出与所有输入相连。
全连接层参数量
例:784 → 128 → 10 的 MLP,参数量 = (784×128+128) + (128×10+10) = 101,770。
卷积层参数量
例:3×3 卷积,输入 64 通道、输出 128 通道 → (3×3×64+1)×128 = 73,856。 对比同等全连接(假设输入 64×32×32)会是数千万级。
张量形状记忆法
| 数据 | PyTorch 形状 | 含义 |
|---|---|---|
| 图像 | [N, C, H, W] | 批 × 通道 × 高 × 宽 |
| 文本 | [N, L, d] | 批 × 序列长 × 特征维 |
| 卷积核 | [Cout, Cin, K, K] | 输出通道 × 输入通道 × 核高 × 核宽 |
前向传播
输入从第一层流到最后一层,得到预测值并计算损失。
流程
- 取一个 batch 数据
x; - 逐层计算
a(l) = σ(W(l)a(l-1) + b(l)),并缓存中间激活; - 输出层得到
ŷ; - 用损失函数算
L(ŷ, y)。
def forward(x, params):
cache = []
a = x
for W, b, act in params:
z = a @ W + b # 线性变换
a = act(z) # 非线性激活
cache.append((z, a)) # 反向传播要用!
return a, cache
推理模式
model.eval()+torch.no_grad():关闭 Dropout、冻结 BatchNorm 统计量、不建计算图。- 忘了切 eval 是"验证集指标莫名其妙很差"的经典原因。
损失函数
损失函数定义了"什么叫好",选错它,训练就是在认真地优化一个错误目标。
| 任务 | 损失函数 | 公式 |
|---|---|---|
| 回归 | MSE / L2 | mean((y − ŷ)²) |
| 回归(抗离群) | MAE / L1 | mean(|y − ŷ|) |
| 回归(兼顾) | Huber / SmoothL1 | 小误差平方,大误差线性 |
| 二分类 | BCE | −[y·log ŷ + (1−y)·log(1−ŷ)] |
| 多分类 | 交叉熵 CE | −Σ yc·log ŷc |
| 多标签分类 | BCEWithLogits | 对每个标签独立做二分类 |
为什么分类用交叉熵而不是 MSE
- MSE 配合 Sigmoid 输出时,梯度含
σ'(z)因子,在预测严重错误(饱和区)时梯度反而趋近 0,学不动。 - 交叉熵 + Softmax 的梯度简洁漂亮:
∂L/∂z = ŷ − y,误差越大梯度越大,修正越快。
CrossEntropyLoss、BCEWithLogitsLoss),
它们内部做了 LogSumExp 稳定化。自己先 Softmax 再取 log 极易得到 log(0) = -inf。损失不下降时怎么想
- 先在一个极小数据集(如 20 个样本)上过拟合:如果连这个都做不到,说明是代码 bug 或结构问题,不是调参问题。
- 能过拟合小数据但泛化差 → 过拟合,加正则化 / 增数据。
- 小数据都过拟合不了 → 学习率太大 / 初始化有问题 / 数据标签错 / 梯度断掉。
反向传播
链式法则 + 动态规划。整个深度学习的引擎。
核心思想
要算损失对每一个参数的梯度,直接对每个参数单独求导是 O(N²) 的灾难。 反向传播利用链式法则,从输出层往输入层倒着走一遍,每层复用上一层的梯度,复杂度降到 O(N)。
四步记忆法
- 算输出层误差:
δL = ŷ − y(配合 Softmax+CE)。 - 第 l 层权重梯度:
∂L/∂W = δ(l) a(l-1)T。 - 第 l 层偏置梯度:
∂L/∂b = δ(l)(在一个 batch 上求和)。 - 把误差往前传:
δ(l-1) = W(l)Tδ(l) ⊙ σ′(z(l-1))。
def backward(x, y, params, cache):
grads = [None] * len(params)
m = x.shape[0]
delta = (cache[-1][1] - y) / m # 输出层误差
for l in reversed(range(len(params))):
a_prev = x if l == 0 else cache[l-1][1]
grads[l] = (a_prev.T @ delta, delta.sum(0))
if l > 0:
delta = (delta @ params[l][0].T) * relu_grad(cache[l-1][0])
return grads
梯度消失与爆炸
δ 往前传时要不断乘 WT 和 σ′:
- 若
|W| < 1且 σ′ ≤ 1(Sigmoid 最大才 0.25),连乘后梯度指数级衰减 → 浅层几乎学不到东西。 - 若
|W| > 1,梯度指数级放大 → 数值溢出、训练发散。
解决手段:
ReLU 类激活残差连接 ResNetBatchNorm / LayerNorm 合理初始化梯度裁剪LSTM 门控∂L/∂θ ≈ [L(θ+ε) − L(θ−ε)] / 2ε,与解析梯度相对误差应小于 1e-5。
只在小维度、不开 Dropout 的情况下做,慢但能救命。优化器
梯度告诉我们往哪走,优化器决定怎么走、走多快。
| 优化器 | 更新规则要点 | 特点 |
|---|---|---|
| SGD | θ ← θ − η·g | 最基础,泛化常最好,但慢、易卡鞍点 |
| SGD + Momentum | 累积速度 v = μv + g | 惯性加速,减少震荡 |
| AdaGrad | 按历史梯度平方缩放 | 适合稀疏特征;学习率单调衰减到 0 |
| RMSProp | 梯度平方的滑动平均 | 修复 AdaGrad 过早停止 |
| Adam | 动量 + 自适应缩放 + 偏置校正 | 默认首选,收敛快,对学习率不敏感 |
| AdamW | Adam + 解耦权重衰减 | Transformer / 现代训练的事实标准 |
Adam 的更新式
θt = θt−1 − η · m̂t / (√v̂t + ε) 默认 β₁=0.9, β₂=0.999, ε=1e-8
学习率调度
- Warmup:前几百/几千步从小学习率线性升到峰值 —— 训练 Transformer 几乎必需,否则初期直接崩。
- Cosine Decay:余弦衰减到 0,目前最常用的衰减曲线。
- Step Decay:每 N 个 epoch 乘 0.1,简单可靠,适合 CV。
- ReduceLROnPlateau:验证集指标不涨了就降学习率。
权重初始化
全零初始化为什么不行?因为对称性问题。
核心原则:保持方差
让信号在前向传播时激活值方差稳定、反向传播时梯度方差稳定,避免指数级放大或衰减。
| 方法 | 分布 | 适用激活 |
|---|---|---|
| Xavier / Glorot | U(−√(6/(fin+fout)), +√(...)) | Sigmoid、Tanh、线性 |
| He / Kaiming | N(0, √(2/fin)) | ReLU 及其变体(默认选择) |
| Orthogonal | 正交矩阵 | RNN,缓解梯度爆炸 |
| Fixup / T-Fixup | 残差缩放 | 无归一化的深层 Transformer |
# PyTorch 中正确初始化一个 ReLU 网络
for m in model.modules():
if isinstance(m, nn.Linear) or isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.zeros_(m.bias)
正则化与归一化
让模型从"背答案"变成"学规律"的一整套工具。
过拟合与欠拟合
| 训练误差 | 验证误差 | 对策 | |
|---|---|---|---|
| 欠拟合 | 高 | 高 | 加大模型、加特征、训更久、调大学习率 |
| 过拟合 | 很低 | 高 | 加数据/增强、正则化、减容量、早停 |
常用正则化手段
L2 权重衰减
损失加 λ‖w‖²,惩罚大权重,让模型更平滑。AdamW 中通过 weight_decay 实现(注意:与 L2 正则在 Adam 下不等价)。
L1 稀疏
损失加 λ‖w‖₁,会把不重要的权重压到精确 0,可做特征选择。
Dropout
训练时以概率 p 随机置零部分神经元,等价于训练大量子网络的集成。推理时关闭并按 1/(1−p) 缩放(PyTorch 的 nn.Dropout 在训练时已做反向缩放,推理直接恒等)。常用 p=0.1~0.5。
数据增强
最有效且"免费"的正则化。图像:翻转/裁剪/色彩抖动/MixUp/CutMix;文本:回译/同义替换。
早停 Early Stopping
验证指标连续 N 轮不提升就停止,回滚到最优 checkpoint。实现简单、效果好。
标签平滑
把硬标签 1 改成 0.9、0 改成 0.05,防止模型过度自信,提升校准性。
归一化层对比
| 方法 | 归一化维度 | 典型应用 |
|---|---|---|
| BatchNorm | 跨 batch 的每一通道 | CNN 标配;依赖 batch size,训练和推理行为不同 |
| LayerNorm | 每个样本的所有特征 | Transformer / NLP 标配,与 batch 无关 |
| InstanceNorm | 每样本每通道 | 风格迁移 |
| GroupNorm | 通道分组 | 小 batch 的目标检测 / 分割 |
| RMSNorm | 去掉均值只用 RMS | LLaMA 等现代大模型,更快更稳 |
卷积神经网络 CNN
为图像而生的归纳偏置:局部性 + 权值共享 + 平移等变性。
卷积在做什么
用一个小窗口(卷积核)在输入上滑动,每步做一次点乘求和,得到一个特征图(feature map)。 不同的核检测不同的模式:边缘、角点、纹理……
三个核心超参
- 核大小 K:3×3 是黄金选择。两个 3×3 堆叠的感受野等于一个 5×5,但参数更少、非线性更多。
- 步幅 stride:滑动步长。stride=2 直接把分辨率减半,常用于替代池化下采样。
- 填充 padding:
same保持尺寸,valid不填充。K=3 时 pad=1 保持尺寸。
输出尺寸公式
感受野
输出层一个像素能"看到"的输入区域大小。堆叠层数越深,感受野越大,语义层级越高:
浅层:边缘/颜色中层:纹理/部件深层:物体/语义
典型组件
| 组件 | 作用 |
|---|---|
| Conv + BN + ReLU | 现代卷积的标准三件套(早期是 Conv+ReLU+Pool) |
| MaxPool | 下采样、保留最显著响应、带来一定平移不变性 |
| Global Avg Pool | 替代全连接收尾,参数量为 0,防止过拟合 |
| 1×1 卷积 | 跨通道信息融合 + 升降维(ResNet bottleneck 的关键) |
| Depthwise Separable | 深度可分离卷积,MobileNet 的提速核心 |
| 空洞卷积 Dilated | 不降分辨率扩大感受野,用于分割(DeepLab) |
一个极简 CNN
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(),
nn.MaxPool2d(2), # 32x32 -> 16x16
nn.Conv2d(32, 64, 3, padding=1), nn.BatchNorm2d(64), nn.ReLU(),
nn.MaxPool2d(2), # 16x16 -> 8x8
)
self.head = nn.Sequential(nn.AdaptiveAvgPool2d(1), nn.Flatten(),
nn.Linear(64, num_classes))
def forward(self, x):
return self.head(self.features(x))
循环网络 RNN / LSTM / GRU
处理序列:把"上一步的记忆"传给下一步。
基本 RNN
沿时间展开后就是一个很深的、每层参数相同的网络 —— 所以梯度消失问题格外严重, 基本 RNN 实际只能记住十几步以内的信息。
LSTM:用"门"保护记忆
核心是引入一条细胞状态 C(信息高速公路),用三个门控制读写:
| 门 | 公式 | 作用 |
|---|---|---|
| 遗忘门 f | σ(Wf·[ht−1, xt]) | 决定旧记忆保留多少 |
| 输入门 i | σ(Wi·[ht−1, xt]) | 决定新信息写入多少 |
| 候选 C̃ | tanh(WC·[ht−1, xt]) | 待写入的新内容 |
| 输出门 o | σ(Wo·[ht−1, xt]) | 决定输出多少记忆 |
GRU:精简版 LSTM
把遗忘门和输入门合并成一个更新门 z,去掉独立的细胞状态,参数减少约 1/3, 多数任务上与 LSTM 效果相当、训练更快。
改进方向
- 双向 Bi-RNN:同时从头到尾、从尾到头读一遍,拼接两个方向的隐状态(理解任务常用)。
- 多层堆叠:把下层隐状态作为上层输入。
- Encoder-Decoder + Attention:解决定长向量的信息瓶颈,直接演化出 Transformer。
注意力机制与 Transformer
"让模型自己决定该看哪里" —— 当代 AI 的地基。
Scaled Dot-Product Attention
- Q(Query):我在找什么;K(Key):我能提供什么;V(Value):我实际的内容。
- 本质是"按相似度做加权平均查表",复杂度 O(n²·d)。
多头注意力
把 d 维切成 h 个头并行做注意力,每个头可以关注不同的关系模式(句法、指代、位置……),最后拼接再线性变换。
Transformer Block 结构
x → LayerNorm → MultiHeadAttention → 残差加 → x
→ LayerNorm → FFN(升维4倍→GELU→降维) → 残差加 → out
- 残差连接是深层 Transformer 能训起来的关键(Pre-LN 比 Post-LN 更稳,现代模型普遍用 Pre-LN + RMSNorm)。
- 位置编码:注意力本身对顺序无感。绝对正弦编码 / 可学习编码 / RoPE 旋转位置编码(LLaMA 系)。
- 因果掩码:解码器里屏蔽未来位置,保证自回归。
三条演化路线
| 类型 | 代表 | 预训练任务 | 擅长 |
|---|---|---|---|
| Encoder-only | BERT、RoBERTa | 掩码语言模型 MLM | 理解:分类、抽取、检索 |
| Decoder-only | GPT、LLaMA、Qwen | 下一个 token 预测 | 生成、对话、通用推理 |
| Encoder-Decoder | T5、BART | 去噪 / 文本到文本 | 翻译、摘要等 seq2seq |
复杂度与优化
标准注意力的时间和显存都是 O(n²),这是长上下文的根本瓶颈。常见优化:
FlashAttention(IO 感知,精确)KV Cache(推理加速) MQA / GQA(共享 KV 头)稀疏 / 线性注意力 RoPE 外推 / YaRN经典架构速查
一张表记住视觉到语言的主干脉络。
| 年份 | 架构 | 核心贡献 | 今天还用吗 |
|---|---|---|---|
| 1998 | LeNet-5 | 卷积+池化的开山之作,用于手写数字 | 教学 |
| 2012 | AlexNet | ReLU + Dropout + GPU 训练,引爆深度学习 | 教学 |
| 2014 | VGG | 统一用 3×3 小卷积堆叠,结构规整 | 特征提取骨干仍有使用 |
| 2014 | GoogLeNet | Inception 多分支 + 1×1 卷积降维 | 思想被继承 |
| 2015 | ResNet | 残差连接,让上百层网络可训练 | 仍是首选骨干 |
| 2016 | DenseNet | 每层与后续所有层相连,特征复用 | 小数据/医学影像 |
| 2015 | U-Net | 编码器-解码器 + 跳跃连接 | 分割任务标配 |
| 2016 | YOLO / SSD | 单阶段实时检测 | 检测主流(YOLO 系列) |
| 2014 | GAN | 生成器与判别器对抗训练 | 图像生成、风格迁移 |
| 2017 | Transformer | 纯注意力,彻底并行化 | 一切的基础 |
| 2018 | BERT / GPT | 预训练 + 微调范式 | 范式仍主导 |
| 2020 | ViT / DETR | 把 Transformer 搬进视觉 | 大数据场景优 |
| 2022 | Diffusion / DiT | 扩散去噪生成,质量超越 GAN | 图像/视频生成主流 |
迁移学习:几乎总是正确选择
- 用 ImageNet / 大规模语料预训练的权重初始化;
- 替换最后的分类头为新任务的输出维度;
- 先冻结骨干只训分类头(几个 epoch);
- 再解冻全部用很小学习率(如 1e-5)微调;
- 数据极少时,也可只做线性探测(Linear Probe)。
训练流程与调参清单
一份可以直接照着做的 checklist。
标准训练循环
for epoch in range(epochs):
model.train()
for x, y in train_loader:
x, y = x.to(device), y.to(device)
optimizer.zero_grad() # 1. 清梯度
logits = model(x) # 2. 前向
loss = criterion(logits, y) # 3. 算损失
loss.backward() # 4. 反向
nn.utils.clip_grad_norm_(model.parameters(), 1.0) # 5. 可选裁剪
optimizer.step() # 6. 更新
scheduler.step() # 7. 学习率调度
model.eval() # 8. 验证(务必切 eval)
with torch.no_grad():
...
调参优先级(从高到低)
- 学习率 —— 影响最大,先做 LR Range Test 找一个数量级。
- 数据与增强 —— 加高质量数据往往胜过任何调参。
- 模型容量 —— 欠拟合就加深加宽,过拟合就加正则。
- Batch size —— 在显存允许范围内尽量大,配合相应学习率。
- 优化器与调度 —— AdamW + cosine + warmup 是稳妥默认。
- 正则强度 —— weight decay、dropout 最后微调。
超参速查表
| 超参 | 常用默认 | 备注 |
|---|---|---|
| 学习率(Adam) | 3e-4 | 微调预训练 1e-5 ~ 5e-5 |
| 学习率(SGD) | 0.1 | momentum 0.9,常配 step decay |
| Batch size | 32 / 64 / 128 | 受显存限制,可用梯度累积模拟大 batch |
| Weight decay | 1e-4 ~ 1e-2 | AdamW 下 0.05 常见 |
| Dropout | 0.1 ~ 0.5 | Transformer 常用 0.1 |
| Warmup | 总步数 1%~5% | 大模型必开 |
| 梯度裁剪 | 1.0 | RNN 必备,Transformer 也建议开 |
| 随机种子 | 固定 seed | 否则无法复现实验结果 |
torch.manual_seed、np.random.seed、random.seed;
若需完全确定性,还要设置 cudnn.deterministic=True(会牺牲部分速度)。NumPy 手写一个小网络
约 60 行,跑通 MNIST 级别任务。理解原理最好的方式就是写一遍。
import numpy as np
def relu(z): return np.maximum(0, z)
def relu_g(z): return (z > 0).astype(np.float32)
def softmax(z):
e = np.exp(z - z.max(1, keepdims=True)) # 防溢出
return e / e.sum(1, keepdims=True)
class MLP:
def __init__(self, dims, seed=0):
rng = np.random.default_rng(seed)
self.W, self.b = [], []
for din, dout in zip(dims[:-1], dims[1:]):
# He 初始化:保持方差
self.W.append(rng.normal(0, np.sqrt(2./din), (din, dout)))
self.b.append(np.zeros(dout))
def forward(self, x):
self.a = [x]
for W, b in zip(self.W[:-1], self.b[:-1]):
self.a.append(relu(self.a[-1] @ W + b))
self.logits = self.a[-1] @ self.W[-1] + self.b[-1]
return softmax(self.logits)
def backward(self, y):
n = y.shape[0]
p = softmax(self.logits)
p[np.arange(n), y] -= 1
delta = p / n # CE + softmax 的优雅梯度
for l in reversed(range(len(self.W))):
self.dW = getattr(self, "dW", [])
gW = self.a[l].T @ delta
gb = delta.sum(0)
if l > 0:
delta = (delta @ self.W[l].T) * relu_g(self.a[l])
self.dW.insert(0, (gW, gb))
return self.dW
def step(self, lr):
for (W, b), (gW, gb) in zip(zip(self.W, self.b), self.dW):
W -= lr * gW
b -= lr * gb
self.dW = []
# ---- 训练 ----
net = MLP([784, 256, 128, 10])
for epoch in range(10):
for xb, yb in batches(X, y, size=64):
net.forward(xb)
net.backward(yb)
net.step(lr=0.1)
acc = (net.forward(X_test).argmax(1) == y_test).mean()
print(f"epoch {epoch}: test acc = {acc:.4f}")
常见坑与调试技巧
这些错误 90% 的人都会踩一遍。
| 症状 | 可能原因 | 排查方法 |
|---|---|---|
| 损失是 NaN | 学习率过大;出现 log(0) 或除零;数据含 NaN/Inf | 逐步降 lr;打印每层输出的 min/max;检查输入 |
| 损失完全不动 | 梯度被 detach/截断;最后一层忘加激活;标签与输出错位 | 打印各层 grad 的范数;检查 requires_grad |
| 训练好、验证差 | 过拟合;数据泄漏;忘切 eval | 加增强/正则;检查 train/val 是否有重复样本 |
| 验证集比训练集还好 | 训练时开了 Dropout/增强,验证时没有 —— 这是正常的 | 无需处理 |
| 显存 OOM | batch 太大;激活缓存;忘了 no_grad 做验证 | 梯度累积;混合精度;del + empty_cache() |
| 准确率卡在随机 | 学习率太小或太大;标签错位;数据顺序未打乱 | 先在小数据上过拟合;检查 DataLoader shuffle |
| 类别不平衡 | 模型全预测多数类 | 加权损失 / 重采样 / Focal Loss |
调试工具箱
- 打印张量统计:每层的 mean / std / min / max,是发现梯度消失最快的方式。
- 梯度范数监控:
torch.nn.utils.clip_grad_norm_返回值就是裁剪前的范数。 - TensorBoard / WandB:把损失、准确率、学习率、梯度直方图全部记下来。
- 可视化中间特征:CNN 看特征图,Transformer 看注意力权重。
- 单元测试式验证:用形状已知的小张量过一遍网络,确认维度变化符合预期。
名词速查表
看到缩写不认识时来这里。
| 缩写 | 全称 / 含义 | 一句话解释 |
|---|---|---|
| epoch | — | 把整个训练集过一遍 |
| batch / mini-batch | — | 一次前向反向所用的样本子集 |
| iteration / step | — | 处理一个 batch 并完成一次参数更新 |
| FC / Dense / Linear | Fully Connected | 全连接层 |
| GAP | Global Average Pooling | 全局平均池化,替代 Flatten+FC |
| BN / LN / GN | Batch / Layer / Group Norm | 归一化层 |
| BPTT | Backprop Through Time | 沿时间展开的反向传播 |
| CE | Cross Entropy | 交叉熵损失 |
| MSE / MAE | 均方 / 平均绝对误差 | 回归损失 |
| mAP / IoU | 平均精度 / 交并比 | 检测与分割指标 |
| EMA | Exponential Moving Average | 权重滑动平均,常提升泛化 |
| AMP | Automatic Mixed Precision | 混合精度训练,省显存提速 |
| GQA / MQA | Grouped / Multi-Query Attention | KV 头共享,推理加速 |
| PEFT / LoRA | 参数高效微调 | 只训少量低秩适配参数 |
| RLHF | 人类反馈强化学习 | 对齐大模型与人类偏好 |
| KD | Knowledge Distillation | 大模型教小模型 |
| SGD / AdamW | 优化器 | 参数更新的具体算法 |
| ICLR / NeurIPS | 顶会 | 深度学习主要发表 venue |