基础篇 / 神经网络是什么

神经网络是什么

从"函数拟合器"的角度理解,比从"模拟大脑"理解更准确。

一句话定义:神经网络是一类可微分的参数化函数,由大量简单的"神经元"按层堆叠而成, 通过梯度下降在数据中自动调整参数,从而学会从输入到输出的映射。

三个视角

① 生物视角(启发来源)

神经元接收树突信号 → 胞体加权求和 → 超过阈值则沿轴突发放脉冲。人工神经元保留了"加权求和 + 非线性激发"这一骨架。

② 数学视角(本质)

一个复合函数 y = fL(...f2(f1(x)))。每层做一次线性变换加一次非线性,层数越深表达能力越强。

③ 工程视角(怎么用)

定义结构 → 定义损失 → 反向传播求梯度 → 优化器更新参数 → 重复直到验证集指标不再提升。

④ 几何视角(直觉)

每一层把输入空间做一次扭曲与折叠,最终让不同类别的样本在高维空间里变得线性可分。

为什么"深"比"宽"更有效

  • 理论上单隐层网络已能逼近任意连续函数(万能逼近定理),但可能需要指数级宽的神经元。
  • 深层网络通过逐层复用特征(边缘 → 纹理 → 部件 → 物体)实现指数级的表达效率。
  • 代价:梯度消失/爆炸、训练不稳定 —— 这正是残差连接、归一化、精细初始化要解决的问题。

和其他模型的关系

模型特征处理方式适用场景
线性/逻辑回归人工设计特征 + 线性组合可解释性优先、小数据
树模型(XGBoost)人工特征 + 自动切分表格数据、中小规模
神经网络端到端自动学习特征图像 / 语音 / 文本 / 高维感知
选型经验表格类数据优先树模型;当输入是"原始信号"(像素、波形、token 序列)且数据量充足时,神经网络几乎总是更优。
基础篇 / 神经元与感知机

神经元与感知机

M-P 模型、单层感知机,以及它为什么搞不定 XOR。

人工神经元(M-P 模型)

z = Σi wi·xi + b  →  a = σ(z) 加权求和(线性) + 偏置 + 非线性激活,缺一不可
  • w(权重):每个输入的重要程度,模型真正要学的参数。
  • b(偏置):让决策边界可以平移,否则超平面必须过原点。
  • σ(激活):引入非线性,否则多层网络等价于一层。

单层感知机

激活函数取符号函数 sign(z),输出 ±1。学习规则非常简单:

w ← w + η·(y − ŷ)·x  ,  b ← b + η·(y − ŷ) 预测错了就朝着正确类别的方向推一把
致命缺陷:XOR 问题 单层感知机只能表示线性可分的二分问题。XOR(异或)在二维平面上无论如何画一条直线都分不开, 1969 年 Minsky 正是用这一点指出了感知机的局限,直接导致第一次神经网络寒冬。

解决方法:加一层

两层感知机(含一个隐层)即可表示任意形状的凸区域划分,从而解决 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,多层直接塌缩成一层,网络再深也只是线性回归。 非线性的每一次"折叠"才是深度的来源。
基础篇 / 激活函数大全

激活函数大全

选错了不会报错,只会训不动 —— 这是最隐蔽的坑之一。

函数公式输出范围优点缺点 / 注意
Sigmoid1/(1+e-z)(0,1)可当概率用两端饱和梯度≈0;输出非零中心
Tanh(ez−e-z)/(ez+e-z)(−1,1)零中心,收敛更快仍会饱和导致梯度消失
ReLUmax(0, z)[0,+∞)计算极快,不饱和死亡 ReLU(负半轴永久为 0)
Leaky ReLUmax(0.01z, z)(−∞,+∞)缓解死亡问题斜率 α 需调,效果不稳定
GELUz·Φ(z)≈(−0.17,+∞)平滑;Transformer 标配计算稍贵
SiLU/Swishz·σ(z)≈(−0.28,+∞)平滑非单调,常略优于 ReLU同上
Softmaxezᵢ/Σezⱼ(0,1) 且和为 1多分类概率分布只能用在输出层

直观对比

1 -1 z Sigmoid Tanh ReLU Leaky

怎么选

  • 隐藏层默认 ReLU(CNN、MLP);追求精度可试 GELU / SiLU。
  • Transformer / BERT 类:用 GELU。
  • RNN 门控:必须用 Sigmoid(需要 0~1 的"开关")和 Tanh(需要 −1~1 的"信息")。
  • 输出层:二分类 Sigmoid,多分类 Softmax,回归任务不激活。
死亡 ReLU 排查 如果训练中大量神经元的输出恒为 0(可用直方图统计激活值),尝试:降低学习率、改用 Leaky ReLU / GELU、 检查初始化方差是否过大、或先加 BatchNorm 再激活。
基础篇 / 网络结构与参数量

网络结构与参数量

看懂模型大小、显存占用从会算参数开始。

层级术语

  • 输入层:原始特征,不算参数。
  • 隐藏层:做特征提取的部分,深度 = 隐藏层数。
  • 输出层:映射到任务目标(类别数 / 回归维度)。
  • 全连接层(FC / Dense / Linear):每个输出与所有输入相连。

全连接层参数量

params = (in × out) + out 权重矩阵 W ∈ Rout×in,加上 out 个偏置

例:784 → 128 → 10 的 MLP,参数量 = (784×128+128) + (128×10+10) = 101,770。

卷积层参数量

params = (Kh × Kw × Cin + 1) × Cout 与输入分辨率无关 —— 这就是卷积的权值共享优势

例: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]输出通道 × 输入通道 × 核高 × 核宽
显存粗算 FP32 下每参数 4 字节。训练时总显存 ≈ 参数(1x) + 梯度(1x) + Adam 状态(2x) + 激活值。 所以 1 亿参数的模型,光权重+梯度+优化器就要约 1.6 GB,这还没算 batch 的激活。
训练篇 / 前向传播

前向传播

输入从第一层流到最后一层,得到预测值并计算损失。

流程

  1. 取一个 batch 数据 x;
  2. 逐层计算 a(l) = σ(W(l)a(l-1) + b(l)),并缓存中间激活;
  3. 输出层得到 ŷ;
  4. 用损失函数算 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
关键:为什么必须缓存中间值 反向传播求梯度时需要用到前向的激活值(例如 ReLU 的梯度取决于 z 的符号、Softmax 的梯度取决于输出概率)。 这也是深度学习显存开销的大头 —— batch 越大、层数越深,缓存的激活越多。

推理模式

  • model.eval() + torch.no_grad():关闭 Dropout、冻结 BatchNorm 统计量、不建计算图。
  • 忘了切 eval 是"验证集指标莫名其妙很差"的经典原因。
训练篇 / 损失函数

损失函数

损失函数定义了"什么叫好",选错它,训练就是在认真地优化一个错误目标。

任务损失函数公式
回归MSE / L2mean((y − ŷ)²)
回归(抗离群)MAE / L1mean(|y − ŷ|)
回归(兼顾)Huber / SmoothL1小误差平方,大误差线性
二分类BCE−[y·log ŷ + (1−y)·log(1−ŷ)]
多分类交叉熵 CE−Σ yc·log ŷc
多标签分类BCEWithLogits对每个标签独立做二分类

为什么分类用交叉熵而不是 MSE

  • MSE 配合 Sigmoid 输出时,梯度含 σ'(z) 因子,在预测严重错误(饱和区)时梯度反而趋近 0,学不动。
  • 交叉熵 + Softmax 的梯度简洁漂亮:∂L/∂z = ŷ − y,误差越大梯度越大,修正越快。
数值稳定性 永远优先用框架内置的融合实现(如 PyTorch 的 CrossEntropyLoss、BCEWithLogitsLoss), 它们内部做了 LogSumExp 稳定化。自己先 Softmax 再取 log 极易得到 log(0) = -inf。

损失不下降时怎么想

  1. 先在一个极小数据集(如 20 个样本)上过拟合:如果连这个都做不到,说明是代码 bug 或结构问题,不是调参问题。
  2. 能过拟合小数据但泛化差 → 过拟合,加正则化 / 增数据。
  3. 小数据都过拟合不了 → 学习率太大 / 初始化有问题 / 数据标签错 / 梯度断掉。
训练篇 / 反向传播

反向传播

链式法则 + 动态规划。整个深度学习的引擎。

核心思想

要算损失对每一个参数的梯度,直接对每个参数单独求导是 O(N²) 的灾难。 反向传播利用链式法则,从输出层往输入层倒着走一遍,每层复用上一层的梯度,复杂度降到 O(N)。

∂L/∂W(l) = δ(l) · (a(l-1))T ,  δ(l) = (W(l+1))T δ(l+1) ⊙ σ′(z(l)) δ 是"误差信号",从后往前一层层传;⊙ 表示逐元素乘

四步记忆法

  1. 算输出层误差:δL = ŷ − y(配合 Softmax+CE)。
  2. 第 l 层权重梯度:∂L/∂W = δ(l) a(l-1)T。
  3. 第 l 层偏置梯度:∂L/∂b = δ(l)(在一个 batch 上求和)。
  4. 把误差往前传:δ(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 门控
梯度检查(Gradient Check) 自己写反向传播时,用数值梯度验证: ∂L/∂θ ≈ [L(θ+ε) − L(θ−ε)] / 2ε,与解析梯度相对误差应小于 1e-5。 只在小维度、不开 Dropout 的情况下做,慢但能救命。
训练篇 / 优化器

优化器

梯度告诉我们往哪走,优化器决定怎么走、走多快。

优化器更新规则要点特点
SGDθ ← θ − η·g最基础,泛化常最好,但慢、易卡鞍点
SGD + Momentum累积速度 v = μv + g惯性加速,减少震荡
AdaGrad按历史梯度平方缩放适合稀疏特征;学习率单调衰减到 0
RMSProp梯度平方的滑动平均修复 AdaGrad 过早停止
Adam动量 + 自适应缩放 + 偏置校正默认首选,收敛快,对学习率不敏感
AdamWAdam + 解耦权重衰减Transformer / 现代训练的事实标准

Adam 的更新式

mt = β₁mt−1 + (1−β₁)gt , vt = β₂vt−1 + (1−β₂)gt²
θ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:验证集指标不涨了就降学习率。
经验值 初始学习率:Adam 系 3e-4(Transformer 常用 1e-4~5e-5);SGD 系 0.1(配合 Momentum 0.9)。 batch size 放大 k 倍时,学习率可按线性缩放 √k~k 倍。
训练篇 / 权重初始化

权重初始化

全零初始化为什么不行?因为对称性问题。

禁止全零初始化 若同一层所有权重相同,则它们梯度相同、更新也相同,整层的神经元永远"步调一致",等价于只有 1 个神经元。 必须随机打破对称性。偏置可以初始化为 0。

核心原则:保持方差

让信号在前向传播时激活值方差稳定、反向传播时梯度方差稳定,避免指数级放大或衰减。

方法分布适用激活
Xavier / GlorotU(−√(6/(fin+fout)), +√(...))Sigmoid、Tanh、线性
He / KaimingN(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)
现代框架的默认初始化一般已经够好 PyTorch / TensorFlow 的 Linear 与 Conv 层默认就用了合理的均匀分布。 只有在自己手写参数、或用了非常深/非常规结构时,才需要专门调整。
训练篇 / 正则化与归一化

正则化与归一化

让模型从"背答案"变成"学规律"的一整套工具。

过拟合与欠拟合

训练误差验证误差对策
欠拟合高高加大模型、加特征、训更久、调大学习率
过拟合很低高加数据/增强、正则化、减容量、早停

常用正则化手段

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去掉均值只用 RMSLLaMA 等现代大模型,更快更稳
x̂ = (x − μ) / √(σ² + ε) → y = γ·x̂ + β 标准化后再做可学习的仿射变换 γ、β —— 关键,否则会破坏已学到的表示能力
BatchNorm 为什么有效(仍有争议) 主流解释是它让损失曲面更平滑(Internal Covariate Shift 的说法已被部分证伪), 使大学习率可用、对初始化不敏感,同时带来轻微的集成正则效果。
架构篇 / 卷积神经网络 CNN

卷积神经网络 CNN

为图像而生的归纳偏置:局部性 + 权值共享 + 平移等变性。

卷积在做什么

用一个小窗口(卷积核)在输入上滑动,每步做一次点乘求和,得到一个特征图(feature map)。 不同的核检测不同的模式:边缘、角点、纹理……

out[i, j] = Σm,n input[i+m, j+n] · kernel[m, n] 互相关运算(深度学习中常说的"卷积"实际不翻转核)

三个核心超参

  • 核大小 K:3×3 是黄金选择。两个 3×3 堆叠的感受野等于一个 5×5,但参数更少、非线性更多。
  • 步幅 stride:滑动步长。stride=2 直接把分辨率减半,常用于替代池化下采样。
  • 填充 padding:same 保持尺寸,valid 不填充。K=3 时 pad=1 保持尺寸。

输出尺寸公式

Hout = ⌊(Hin + 2·pad − K) / stride⌋ + 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

循环网络 RNN / LSTM / GRU

处理序列:把"上一步的记忆"传给下一步。

基本 RNN

ht = tanh(Wxhxt + Whhht−1 + b) , yt = Whyht 所有时间步共享同一套参数(权值共享的时间版本)

沿时间展开后就是一个很深的、每层参数相同的网络 —— 所以梯度消失问题格外严重, 基本 RNN 实际只能记住十几步以内的信息。

LSTM:用"门"保护记忆

核心是引入一条细胞状态 C(信息高速公路),用三个门控制读写:

门公式作用
遗忘门 fσ(Wf·[ht−1, xt])决定旧记忆保留多少
输入门 iσ(Wi·[ht−1, xt])决定新信息写入多少
候选 C̃tanh(WC·[ht−1, xt])待写入的新内容
输出门 oσ(Wo·[ht−1, xt])决定输出多少记忆
Ct = ft ⊙ Ct−1 + it ⊙ C̃t , ht = ot ⊙ tanh(Ct) 关键:C 的更新是加法,梯度可以沿 C 近乎无损地回溯很长距离

GRU:精简版 LSTM

把遗忘门和输入门合并成一个更新门 z,去掉独立的细胞状态,参数减少约 1/3, 多数任务上与 LSTM 效果相当、训练更快。

改进方向

  • 双向 Bi-RNN:同时从头到尾、从尾到头读一遍,拼接两个方向的隐状态(理解任务常用)。
  • 多层堆叠:把下层隐状态作为上层输入。
  • Encoder-Decoder + Attention:解决定长向量的信息瓶颈,直接演化出 Transformer。
现实建议 今天做序列建模,除非序列很短或资源极其受限,优先用 Transformer。 RNN 的串行计算无法并行、长程依赖仍弱于注意力机制。但在实时流式、超低延迟场景,RNN/GRU 依然实用。
架构篇 / 注意力与 Transformer

注意力机制与 Transformer

"让模型自己决定该看哪里" —— 当代 AI 的地基。

Scaled Dot-Product Attention

Attention(Q, K, V) = softmax( QKT / √dk ) · V 除以 √dk 是为了防止点积过大把 softmax 推入饱和区(梯度消失)
  • Q(Query):我在找什么;K(Key):我能提供什么;V(Value):我实际的内容。
  • 本质是"按相似度做加权平均查表",复杂度 O(n²·d)。

多头注意力

把 d 维切成 h 个头并行做注意力,每个头可以关注不同的关系模式(句法、指代、位置……),最后拼接再线性变换。

MultiHead = Concat(head1, ..., headh) WO , headi = Attention(QWiQ, KWiK, VWiV)

Transformer Block 结构

x → LayerNorm → MultiHeadAttention → 残差加 → x
  → LayerNorm → FFN(升维4倍→GELU→降维) → 残差加 → out
  • 残差连接是深层 Transformer 能训起来的关键(Pre-LN 比 Post-LN 更稳,现代模型普遍用 Pre-LN + RMSNorm)。
  • 位置编码:注意力本身对顺序无感。绝对正弦编码 / 可学习编码 / RoPE 旋转位置编码(LLaMA 系)。
  • 因果掩码:解码器里屏蔽未来位置,保证自回归。

三条演化路线

类型代表预训练任务擅长
Encoder-onlyBERT、RoBERTa掩码语言模型 MLM理解:分类、抽取、检索
Decoder-onlyGPT、LLaMA、Qwen下一个 token 预测生成、对话、通用推理
Encoder-DecoderT5、BART去噪 / 文本到文本翻译、摘要等 seq2seq

复杂度与优化

标准注意力的时间和显存都是 O(n²),这是长上下文的根本瓶颈。常见优化:

FlashAttention(IO 感知,精确)KV Cache(推理加速) MQA / GQA(共享 KV 头)稀疏 / 线性注意力 RoPE 外推 / YaRN
架构篇 / 经典架构速查

经典架构速查

一张表记住视觉到语言的主干脉络。

年份架构核心贡献今天还用吗
1998LeNet-5卷积+池化的开山之作,用于手写数字教学
2012AlexNetReLU + Dropout + GPU 训练,引爆深度学习教学
2014VGG统一用 3×3 小卷积堆叠,结构规整特征提取骨干仍有使用
2014GoogLeNetInception 多分支 + 1×1 卷积降维思想被继承
2015ResNet残差连接,让上百层网络可训练仍是首选骨干
2016DenseNet每层与后续所有层相连,特征复用小数据/医学影像
2015U-Net编码器-解码器 + 跳跃连接分割任务标配
2016YOLO / SSD单阶段实时检测检测主流(YOLO 系列)
2014GAN生成器与判别器对抗训练图像生成、风格迁移
2017Transformer纯注意力,彻底并行化一切的基础
2018BERT / GPT预训练 + 微调范式范式仍主导
2020ViT / DETR把 Transformer 搬进视觉大数据场景优
2022Diffusion / DiT扩散去噪生成,质量超越 GAN图像/视频生成主流

迁移学习:几乎总是正确选择

  1. 用 ImageNet / 大规模语料预训练的权重初始化;
  2. 替换最后的分类头为新任务的输出维度;
  3. 先冻结骨干只训分类头(几个 epoch);
  4. 再解冻全部用很小学习率(如 1e-5)微调;
  5. 数据极少时,也可只做线性探测(Linear Probe)。
经验法则数据集小于 1 万张图时,从头训 CNN 通常不如微调预训练模型; 领域差异很大(如医学影像、遥感)时,可用领域数据做一次自监督预训练再迁移。
实战篇 / 训练流程与调参清单

训练流程与调参清单

一份可以直接照着做的 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():
        ...

调参优先级(从高到低)

  1. 学习率 —— 影响最大,先做 LR Range Test 找一个数量级。
  2. 数据与增强 —— 加高质量数据往往胜过任何调参。
  3. 模型容量 —— 欠拟合就加深加宽,过拟合就加正则。
  4. Batch size —— 在显存允许范围内尽量大,配合相应学习率。
  5. 优化器与调度 —— AdamW + cosine + warmup 是稳妥默认。
  6. 正则强度 —— weight decay、dropout 最后微调。

超参速查表

超参常用默认备注
学习率(Adam)3e-4微调预训练 1e-5 ~ 5e-5
学习率(SGD)0.1momentum 0.9,常配 step decay
Batch size32 / 64 / 128受显存限制,可用梯度累积模拟大 batch
Weight decay1e-4 ~ 1e-2AdamW 下 0.05 常见
Dropout0.1 ~ 0.5Transformer 常用 0.1
Warmup总步数 1%~5%大模型必开
梯度裁剪1.0RNN 必备,Transformer 也建议开
随机种子固定 seed否则无法复现实验结果
可复现性 固定 torch.manual_seed、np.random.seed、random.seed; 若需完全确定性,还要设置 cudnn.deterministic=True(会牺牲部分速度)。
实战篇 / NumPy 手写小网络

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}")
写完对照检查 ① 先在小数据上过拟合到 100%;② 用数值梯度做梯度检查;③ 打印每层激活的均值/方差, 若某层方差趋近 0 说明网络"死掉了"。
实战篇 / 常见坑与调试

常见坑与调试技巧

这些错误 90% 的人都会踩一遍。

症状可能原因排查方法
损失是 NaN学习率过大;出现 log(0) 或除零;数据含 NaN/Inf逐步降 lr;打印每层输出的 min/max;检查输入
损失完全不动梯度被 detach/截断;最后一层忘加激活;标签与输出错位打印各层 grad 的范数;检查 requires_grad
训练好、验证差过拟合;数据泄漏;忘切 eval加增强/正则;检查 train/val 是否有重复样本
验证集比训练集还好训练时开了 Dropout/增强,验证时没有 —— 这是正常的无需处理
显存 OOMbatch 太大;激活缓存;忘了 no_grad 做验证梯度累积;混合精度;del + empty_cache()
准确率卡在随机学习率太小或太大;标签错位;数据顺序未打乱先在小数据上过拟合;检查 DataLoader shuffle
类别不平衡模型全预测多数类加权损失 / 重采样 / Focal Loss

调试工具箱

  • 打印张量统计:每层的 mean / std / min / max,是发现梯度消失最快的方式。
  • 梯度范数监控:torch.nn.utils.clip_grad_norm_ 返回值就是裁剪前的范数。
  • TensorBoard / WandB:把损失、准确率、学习率、梯度直方图全部记下来。
  • 可视化中间特征:CNN 看特征图,Transformer 看注意力权重。
  • 单元测试式验证:用形状已知的小张量过一遍网络,确认维度变化符合预期。
数据比模型重要 花在清洗数据、检查标注、平衡类别上的时间,回报通常远高于调模型结构。 训练前务必人工抽查 50~100 个样本,很多"玄学问题"其实只是标签错了。
实战篇 / 名词速查表

名词速查表

看到缩写不认识时来这里。

缩写全称 / 含义一句话解释
epoch—把整个训练集过一遍
batch / mini-batch—一次前向反向所用的样本子集
iteration / step—处理一个 batch 并完成一次参数更新
FC / Dense / LinearFully Connected全连接层
GAPGlobal Average Pooling全局平均池化,替代 Flatten+FC
BN / LN / GNBatch / Layer / Group Norm归一化层
BPTTBackprop Through Time沿时间展开的反向传播
CECross Entropy交叉熵损失
MSE / MAE均方 / 平均绝对误差回归损失
mAP / IoU平均精度 / 交并比检测与分割指标
EMAExponential Moving Average权重滑动平均,常提升泛化
AMPAutomatic Mixed Precision混合精度训练,省显存提速
GQA / MQAGrouped / Multi-Query AttentionKV 头共享,推理加速
PEFT / LoRA参数高效微调只训少量低秩适配参数
RLHF人类反馈强化学习对齐大模型与人类偏好
KDKnowledge Distillation大模型教小模型
SGD / AdamW优化器参数更新的具体算法
ICLR / NeurIPS顶会深度学习主要发表 venue
推荐学习路径 先跑通一个 MNIST 分类 → 自己用 NumPy 写反向传播 → 读 ResNet 与 Transformer 原始论文 → 复现一篇经典工作 → 做一个自己的小项目。动手远比看视频有效。