文章

什么是模型调优:从“先能用”到“更好用”的完整入门

从直觉理解到可落地实践,系统讲清模型调优的核心概念、常见方法与 Python 最小示例。

什么是模型调优:从“先能用”到“更好用”的完整入门

很多人第一次接触机器学习时,会把精力放在“选模型”上:逻辑回归、随机森林、XGBoost、神经网络……

但在真实项目里,同一个模型,调不调,效果可能差非常多

这篇文章就来讲清楚:

  1. 什么是模型调优(Model Tuning)
  2. 为什么调优会带来提升
  3. 常见调优方法有哪些
  4. 一个可以直接运行的 Python 最小示例
  5. 一个最简单的 LLM 调优 Python 示例
  6. 从入门到进阶的调优路线图

1. 什么是模型调优?

一句话:

模型调优就是在不改变任务目标的前提下,通过调整模型和训练过程中的关键参数,让模型在验证集/测试集上表现更好。

这里要先区分两个概念:

1.1 参数(Parameter)

参数是模型训练“学出来”的,比如线性回归里的权重 w、偏置 b

  • 你不用手动给它具体值
  • 训练算法会根据数据自动更新

1.2 超参数(Hyperparameter)

超参数是你在训练前设置的,比如:

  • 学习率 learning_rate
  • 树的深度 max_depth
  • 正则化强度 Clambda
  • batch size、epoch 数等

模型调优的核心对象通常是超参数


2. 为什么调优有用?先理解“欠拟合”和“过拟合”

可以把模型想象成“学生”:

  • 欠拟合:学得太浅,训练集都做不好(能力不足)
  • 过拟合:训练集做得很好,但新题(测试集)变差(记住了细节噪声)

调优本质上是在找一个平衡点:

  • 既不要太简单(避免欠拟合)
  • 也不要太复杂(降低过拟合)

例如:

  • 决策树太深可能过拟合
  • 正则化太强可能欠拟合
  • 学习率过大可能训练不稳定

3. 常见模型调优方法(由浅入深)

3.1 手动调参(Manual Tuning)

最基础的方法:改一个参数,看验证集指标变化。

优点:直观、能帮助你建立“参数-效果”的感觉。
缺点:慢、依赖经验。

提前给出候选参数集合,穷举组合后做交叉验证。

例如:

  • C in [0.1, 1, 10]
  • solver in ['liblinear', 'lbfgs']

优点:系统化。
缺点:组合爆炸,计算成本高。

在参数空间里随机采样若干组。

优点:在高维参数空间中往往比网格搜索更高效。
缺点:结果有随机性,需要足够采样次数。

3.4 贝叶斯优化(Bayesian Optimization)

利用历史试验结果来“预测哪里更可能好”,然后更聪明地选下一组参数。

优点:通常更省算力。
缺点:实现复杂度更高,适合进阶阶段。


4. Python 最小可运行示例:逻辑回归 + GridSearchCV

下面用 scikit-learn 做一个二分类例子,展示最简单的调优流程。

4.1 安装依赖

1
pip install scikit-learn pandas

4.2 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# 1) 准备数据
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 2) 建立流水线:标准化 + 逻辑回归
pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("model", LogisticRegression(max_iter=2000))
])

# 3) 定义待搜索的超参数空间
param_grid = {
    "model__C": [0.01, 0.1, 1, 10, 100],
    "model__penalty": ["l2"],
    "model__solver": ["lbfgs", "liblinear"]
}

# 4) 交叉验证 + 网格搜索
grid = GridSearchCV(
    estimator=pipe,
    param_grid=param_grid,
    cv=5,
    scoring="accuracy",
    n_jobs=-1
)

grid.fit(X_train, y_train)

print("最优参数:", grid.best_params_)
print("CV 最优分数:", round(grid.best_score_, 4))

# 5) 在测试集上评估
best_model = grid.best_estimator_
y_pred = best_model.predict(X_test)

print("测试集准确率:", round(accuracy_score(y_test, y_pred), 4))
print(classification_report(y_test, y_pred))

4.3 你会看到什么

运行后通常能看到:

  • 一组最优超参数(比如某个 C + solver 组合)
  • 交叉验证分数(CV score)
  • 测试集准确率

这就是一个完整的调优闭环:

定义搜索空间 → 交叉验证比较 → 选最佳参数 → 测试集确认泛化效果


5. 调优时最容易踩的坑

5.1 在测试集上反复调参

测试集应该只在最后做一次“最终验收”。

如果你不断看测试集结果再改参数,本质上就把测试集“泄漏”为验证集了。

5.2 指标选错

分类任务不一定只看准确率:

  • 类别不均衡时,更应关注 precision/recall/F1/AUC
  • 检索类任务可能更看重 recall

5.3 搜索空间不合理

  • 空间太小:找不到真正好的区域
  • 空间太大:计算成本爆炸

建议先粗调(大步试探),再细调(小步逼近)。

5.4 忽视基线模型

先有 baseline(基线)再调优,才能知道“提升是否真实”。


6. 有没有简单的 LLM 调优例子?有。

如果你说的“LLM 调优”是指让大语言模型更贴近你的任务,最常见做法是:

  • 不改全部参数(太贵)
  • 只训练一小部分新增参数(例如 LoRA)

下面给一个教学版最小示例,用很小的模型跑通流程。

6.1 安装依赖

1
pip install transformers datasets peft accelerate torch

6.2 最小 LoRA 微调示例(可直接改造成你的数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import torch
from datasets import Dataset
from transformers import (
    AutoTokenizer,
    AutoModelForCausalLM,
    DataCollatorForLanguageModeling,
    Trainer,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model

# 1) 用一个很小的演示模型,方便本地快速跑通
model_name = "sshleifer/tiny-gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token

base_model = AutoModelForCausalLM.from_pretrained(model_name)

# 2) 配置 LoRA:只训练少量低秩参数
lora_config = LoraConfig(
    r=8,
    lora_alpha=16,
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)
model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters()

# 3) 构造超小训练集(演示用)
texts = [
    "问题:什么是模型调优?\n回答:模型调优是调整超参数与训练策略,让模型泛化更好。",
    "问题:为什么要做 LoRA?\n回答:LoRA 可以用更低显存完成大模型任务适配。",
    "问题:过拟合是什么意思?\n回答:训练集表现很好,但测试集表现变差。",
]
dataset = Dataset.from_dict({"text": texts})

def tokenize_fn(example):
    out = tokenizer(
        example["text"],
        truncation=True,
        max_length=128,
        padding="max_length",
    )
    out["labels"] = out["input_ids"].copy()
    return out

tokenized = dataset.map(tokenize_fn)

# 4) 训练参数(演示:只跑很少步)
args = TrainingArguments(
    output_dir="./tiny-lora-out",
    per_device_train_batch_size=2,
    num_train_epochs=3,
    learning_rate=2e-4,
    logging_steps=1,
    save_strategy="no",
    report_to="none",
    fp16=torch.cuda.is_available(),
)

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=tokenized,
    data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)

trainer.train()
model.save_pretrained("./tiny-lora-adapter")
tokenizer.save_pretrained("./tiny-lora-adapter")

print("训练完成,LoRA 适配器已保存到 ./tiny-lora-adapter")

6.3 如何理解这个示例

这个例子核心目的是帮你理解 LLM 调优最小闭环:

  1. 选基座模型(base model)
  2. 选参数高效微调方法(LoRA)
  3. 准备指令数据
  4. 训练并保存 adapter

注意:

  • 这里的数据量极小,只用于教学,不代表真实效果。
  • 真正项目通常要更干净的数据、更严格的验证集评估。

7. 从入门到进阶的建议路线

如果你刚开始,可以按这个顺序:

  1. 先学会 train/validation/test 的正确拆分
  2. 学会 Pipeline + GridSearchCV
  3. 学会为不同任务选择合适指标
  4. 学会随机搜索,提升效率
  5. 再进入贝叶斯优化、Optuna 等进阶工具

对于深度学习任务,再逐步学习:

  • 学习率调度(scheduler)
  • 权重衰减(weight decay)
  • dropout / 数据增强
  • 早停(early stopping)

8. 一句话总结

模型调优,不是“玄学调参”,而是一个可重复、可验证的实验过程。

你只要坚持“数据划分正确 + 指标清晰 + 记录实验 + 渐进式搜索”,模型效果就会稳步提高。

本文由作者按照 CC BY 4.0 进行授权