超参数与模型参数的区别及常见超参数类型

很多人刚开始学调参时,会把模型参数和超参数混为一谈。我当年也犯过这个错——调了半天学习率,却忘了检查模型权重有没有初始化好。说白了,这是两个完全不同的东西。

模型参数是什么

模型参数是训练过程中自动学习到的。比如神经网络的权重和偏置,线性回归的系数。这些值随着梯度下降不断更新,最终存储在模型文件中。

# 看看 PyTorch 模型里有哪些参数
import torch
import torch.nn as nn

model = nn.Linear(10, 2)
for name, param in model.named_parameters():
    print(name, param.shape)

# 输出类似:
# weight torch.Size([2, 10])
# bias torch.Size([2])

你想想看,这些参数的数量是固定的。一个 10 输入 2 输出的线性层,权重就是 20 个,偏置 2 个。训练完就定死了。

超参数是什么

超参数是你在训练开始前就要定好的。它控制着训练过程怎么跑,模型长什么样。举个例子:学习率、批量大小、网络层数、正则化强度。这些东西不是模型自己学的,是你拍脑袋(或者调参)决定的。

关键区别一句话: 模型参数由训练数据决定,超参数由你决定。

对比表格

维度模型参数超参数
来源训练过程中自动学习训练前人工设定
更新方式梯度下降等优化算法手动调优或自动搜索
数量通常很大(百万级)通常很少(几十个)
示例权重 w、偏置 b学习率 lr、批量大小 batch_size
影响决定模型预测输出决定训练效率与模型性能
小技巧: 调参前先把模型参数可视化一下。我曾经遇到过梯度爆炸,就是靠看权重直方图发现的——那会儿学习率设太大了,参数直接飞了。

常见超参数分类

我习惯把超参数分成四大类。这样调参时思路清晰,不会东一榔头西一棒子。

1. 训练过程类

  • 学习率(learning rate):最敏感的超参数,没有之一。太大模型震荡不收敛,太小训练慢成蜗牛。我一般先试 0.01、0.001、0.0001 三个量级。
  • 批量大小(batch size):影响梯度稳定性和显存。小批量(16-64)泛化好点,大批量(128-512)训练快但容易过拟合。
  • 迭代次数(epochs):别死磕固定值。用早停法(early stopping)自动终止,省时间又防过拟合。

2. 优化器相关类

  • 优化器选择:SGD、Adam、RMSprop……我个人习惯 AdamW 起步,收敛快、省心。
  • 动量(momentum):SGD 加动量能加速,一般设 0.9。Adam 自带一阶矩,不用再设。
  • 权重衰减(weight decay):L2 正则化的另一种叫法。典型值 1e-4 或 1e-5。
# PyTorch AdamW 配置示例
optimizer = torch.optim.AdamW(
    model.parameters(),
    lr=0.001,
    weight_decay=1e-4
)

3. 网络结构类

  • 网络层数:深了能拟合更复杂函数,但容易梯度消失。残差连接可以救一部分。
  • 每层神经元数:太大算不动,太小欠拟合。经验法则:从输入到输出逐渐缩小或先增后减。
  • 激活函数选择:ReLU、GELU、SwiGLU……不同场景差异挺大。

4. 正则化类

  • Dropout 概率:一般 0.1-0.5,具体看模型容量。我做过一个 NLP 项目,dropout=0.3 效果最好。
  • 数据增强参数:随机翻转、旋转、色彩抖动——这些也算超参数,需要实验调。
  • 早停耐心值(patience):验证集 loss 连续多少轮不下降就停。通常 5-10。
注意: 正则化太强会欠拟合。我曾经在一个图像分类任务上,dropout 设到 0.7,结果模型直接摆烂,准确率一直 30%。后来降到 0.3 才恢复正常。

超参数与模型参数的关系图

为了让你更直观地理解两者的关系,我画了下面这张图。它展示了训练过程中超参数如何控制模型参数的更新。

超参数与模型参数关系图 超参数(训练前设定) 模型参数(训练中学习) 学习率 lr=0.001 批量大小 batch_size=64 网络层数 n_layers=6 Dropout 概率 p=0.3 权重衰减 wd=1e-4 权重矩阵 W 形状:[768, 3072] 偏置向量 b 形状:[3072] 嵌入层参数 形状:[vocab, 768] 超参数在训练开始前设定,控制模型参数的更新过程;模型参数则在训练中不断被优化。

超参数调优的通用步骤

了解了区别和分类,下一步就是动手调。我给个通用流程:

  1. 明确评估指标:准确率?F1?BLEU?先定好,不要调着调着改目标。
  2. 设置基线:用一组简单超参数快速跑通,比如 lr=0.01、batch_size=32、epochs=10。
  3. 单变量实验:每次只改一个超参数,看效果变化。我习惯先调学习率,再调批量大小。
  4. 组合调优:用网格搜索或贝叶斯优化,找最佳组合。注意——不要暴力遍历所有组合,时间不够的。
  5. 验证与复现:固定好随机种子,确认结果稳定。嗯,这一步很多人会漏掉。
# 一个简单的网格搜索框架
import itertools

lr_values = [0.1, 0.01, 0.001]
batch_sizes = [32, 64, 128]

best_score = 0
best_params = None

for lr, bs in itertools.product(lr_values, batch_sizes):
    score = train_and_evaluate(lr=lr, batch_size=bs)
    print(f"lr={lr}, bs={bs} -> score={score:.4f}")
    if score > best_score:
        best_score = score
        best_params = (lr, bs)

print(f"Best: lr={best_params[0]}, bs={best_params[1]}, score={best_score:.4f}")
实用建议: 如果训练时间很长,别傻等。先在小batch数据上粗调参数,再放大batch产线跑。我在一个BERT微调项目里就用这招,省了至少两天的调参时间。

好,超参数和模型参数的区别,以及常见超参数类型,就聊到这儿。记住一个核心:模型参数是训练的产物,超参数是调优的武器。搞清楚这个,后面几章学起来就顺了。