AIGC入门,#新手模型微调认知篇(六):模型评测原理与实践

新手模型微调认知篇(六):模型评测原理与实践
本文整理自实际微调教学过程中的问答,适合零基础入门者阅读。
Q1:微调完模型后,怎么知道模型变好了还是变差了?
A: 这是很多初学者容易忽略的问题。最常见(但也最不靠谱)的做法是:随便问几个问题,肉眼看回答是否"感觉"变好了。
问题在于:
- 样本太少:5 个问题 vs 训练集可能有 10 万条
- 没有量化:只能"感觉",无法比较
- 有随机性:
do_sample=True每次生成不同结果 - 不知道"好"在哪里:是更准确?更流畅?还是格式更好?
正确的做法是系统性评测:
┌─────────────────────────────────────────┐
│ 系统性评测 │
│ ├─ 客观题:自动打分(数学、翻译、推理) │
│ ├─ 主观题:人工或 LLM Judge 评估 │
│ ├─ 多任务分维度统计 │
│ └─ 输出量化对比表 │
└─────────────────────────────────────────┘
Q2:有哪些常用的评测指标?
A: 根据任务类型不同,评测指标也不同。
1. 精确匹配(Exact Match)
适用于有唯一正确答案的任务:数学题、推理题。
# 例子:数学题
问题:计算 37 × 48
参考答案:1776
模型回答:答案是 1776
评测:提取数字 → 1776 == 1776 → ✓ 正确
优点: 客观、无歧义
缺点: 只适用于有标准答案的任务
2. BLEU(Bilingual Evaluation Understudy)
适用于翻译任务。比较模型输出和参考答案的 n-gram 重合度。
# 例子:翻译题
问题:请将"知识就是力量"翻译成英文
参考答案:Knowledge is power
模型回答:Knowledge is power.
BLEU 计算(简化版):
- 1-gram 匹配:"Knowledge" ✓, "is" ✓, "power" ✓
- 4-gram 匹配:"Knowledge is power" ✓
- 分数:接近 1.0(完全匹配)
公式(简化理解):
BLEU = (匹配的 n-gram 数 / 总 n-gram 数) × 短句惩罚
优点: 自动化、可复现
缺点: 只比较字面,不理解语义(“Knowledge is power” 和 “Power comes from knowledge” 语义相同但 BLEU 很低)
3. ROUGE-L(Recall-Oriented Understudy for Gisting Evaluation)
适用于摘要、开放问答等生成任务。基于最长公共子序列(LCS)。
# 例子:开放问答
问题:如何缓解焦虑?
参考答案:缓解焦虑可以尝试运动、冥想、倾诉等方法
模型回答:焦虑可以通过运动、冥想和与他人交流来缓解
ROUGE-L 计算:
- 最长公共子序列:"运动" + "冥想" + "缓解"(顺序一致)
- 分数:约 0.6(部分重合)
优点: 对中文友好,考虑词序
缺点: 仍然是字面匹配,不理解语义
4. Perplexity(困惑度)
适用于语言模型整体质量评估。衡量模型对文本的"惊讶程度"。
Perplexity = 2^(-平均对数似然)
困惑度越低 → 模型对文本的预测越准确 → 模型质量越好
例子:
- GPT-2: Perplexity ≈ 20-30
- GPT-3: Perplexity ≈ 15-20
- 微调后模型: Perplexity 应该比原始模型低(在目标任务上)
优点: 不需要参考答案,只看模型对文本的预测能力
缺点: 不能反映生成质量(困惑度低的模型可能只是更保守)
Q3:业界主流的评测基准有哪些?
A: 评测基准(Benchmark)是标准化的测试集,方便不同模型之间横向对比。
1. MMLU(Massive Multitask Language Understanding)
用途: 通用知识评测
覆盖: 57 个学科(数学、物理、历史、医学、法律等)
题型: 四选一多选题
Question: Which of the following is NOT a characteristic of TCP?
A. Connection-oriented
B. Reliable delivery
C. Best-effort delivery
D. Flow control
Answer: C
评测方式: 比较模型对 A/B/C/D 四个选项的概率,取最高者。
优点: 不需要文本解析,直接看 token 概率
缺点: 只能评测知识记忆,不能评测推理和生成能力
2. GSM8K(Grade School Math 8K)
用途: 数学推理评测
覆盖: 8500 道小学到初中难度的数学应用题
题型: 开放问答,有唯一答案
Question: Janet's ducks lay 16 eggs per day. She eats 3 for breakfast
every morning and bakes muffins for her friends every day with 4 eggs.
She sells the remainder at the farmers' market daily for $2 per fresh
duck egg. How many dollars does she make per day at the farmers' market?
Answer: Let's think step by step.
Janet sells 16 - 3 - 4 = 9 duck eggs a day.
She makes 9 * 2 = $18 a day.
#### 18
评测方式: 提取 #### 后的数字,和标准答案比较。
优点: 可以评测多步推理能力
缺点: 需要约束输出格式(用 #### 标记答案)
3. HumanEval
用途: 代码生成评测
覆盖: 164 道编程题(主要是 Python)
题型: 给定函数签名和 docstring,生成实现代码
def has_close_elements(numbers: List[float], threshold: float) -> bool:
"""Check if in given list of numbers, are any two numbers closer to
each other than given threshold.
>>> has_close_elements([1.0, 2.0, 3.0], 0.5)
False
>>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)
True
"""
# 模型生成代码...
评测方式: 在沙箱中执行生成的代码,跑测试用例,看是否通过。
优点: 最客观——代码能跑通就是对的
缺点: 只适用于有测试用例的代码题
4. MT-Bench
用途: 对话能力评测
覆盖: 80 道开放式对话题(写作、角色扮演、推理等)
题型: 开放问答,无标准答案
评测方式: 用 GPT-4 作为 Judge,对比两个模型的回答,打分。
Judge Prompt:
请比较以下两个回答,从 helpfulness、harmlessness、honesty 三个维度打分。
问题:{question}
回答A:{answer_a}
回答B:{answer_b}
输出:{"winner": "A" or "B" or "tie", "reason": "..."}
优点: 能评测语义质量(不只是字面匹配)
缺点: 依赖 Judge 模型的质量,且 Judge 可能有偏见
5. OpenCompass
用途: 综合评测(国内最主流)
覆盖: 50+ 个评测集,包括 MMLU、GSM8K、HumanEval 等
特点: 支持一键评测多个模型,输出排行榜
# 使用 OpenCompass 评测
python run.py --models llama3-8b qwen-7b --datasets mmlu gsm8k humaneval
优点: 一站式评测,覆盖全面
缺点: 配置复杂,资源消耗大
Q4:如何提取模型输出中的答案?
A: 这是评测中最容易出问题的环节。
问题场景
模型输出:
这道题需要先分析。
首先,37 × 48 可以拆解为 (40-3) × 48 = 40×48 - 3×48
40 × 48 = 1920
3 × 48 = 144
所以 1920 - 144 = 1776
答案是 1776
如果直接取第一行 → 提取失败
如果取最后一行 → 成功提取 1776
行业做法:在 Prompt 中约束输出格式
# GSM8K 标准做法
prompt = f"""
{question}
请逐步推理,然后在最后一行用 #### 标记最终答案。
例如:#### 42
"""
# 提取答案
def extract_answer(text):
match = re.search(r"####\s*(\d+)", text)
if match:
return int(match.group(1))
# 兜底:取最后一个数字
numbers = re.findall(r"\d+", text)
return int(numbers[-1]) if numbers else None
多种兜底策略
def robust_extract(text, task_type):
"""多策略提取答案"""
# 策略1:优先匹配显式标记
if "####" in text:
match = re.search(r"####\s*([^\n]+)", text)
if match:
return match.group(1).strip()
if "The answer is" in text:
match = re.search(r"The answer is\s*([^\n.]+)", text)
if match:
return match.group(1).strip()
# 策略2:取最后一行的数字
lines = text.strip().split("\n")
for line in reversed(lines):
numbers = re.findall(r"-?\d+\.?\d*", line)
if numbers:
return float(numbers[-1])
# 策略3:全文最后一个数字
numbers = re.findall(r"-?\d+\.?\d*", text)
return float(numbers[-1]) if numbers else None
Q5:评测时有哪些常见坑?
A: 评测看似简单,但细节很多。
1. 必须关闭采样(do_sample=False)
# ✗ 错误:每次生成不同结果
outputs = model.generate(..., do_sample=True, temperature=0.7)
# ✓ 正确:贪婪解码,结果可复现
outputs = model.generate(..., do_sample=False)
原因: do_sample=True 每次生成不同文本,评测分数会波动,无法对比。
2. 测试集不能出现在训练集中
# ✗ 错误:训练集和测试集有重复
train_data = load_data("all.json")
test_data = load_data("all.json") # 测试集和训练集相同!
# ✓ 正确:严格划分
train_data = load_data("train.json") # 98%
val_data = load_data("val.json") # 1%
test_data = load_data("test.json") # 1%
检查方法: 对比训练集和测试集的哈希值,确保无重复。
3. 要同时评估"退化"情况
微调可能让模型在目标任务上变好,但在其他能力上变差(灾难性遗忘)。
评测设计:
目标任务(数学、翻译等):应该提升
通用能力(常识、推理等):不应该严重退化
方法: 加入一组"通用能力"测试题(模型没训练过的领域),确认没有严重退化。
4. 不要只看平均分
平均分可能掩盖问题:
模型A:数学 80%,翻译 60%,推理 70% → 平均 70%
模型B:数学 95%,翻译 20%,推理 95% → 平均 70%
两个模型平均分相同,但能力分布完全不同。
方法: 分任务类型统计,看能力分布。
5. 注意评测数据的分布偏差
如果测试集 80% 是加法题,20% 是乘法题:
- 模型只学会了加法 → 准确率 80%
- 但乘法题准确率可能只有 0%
平均分看起来不错,但实际能力有严重偏差。
方法: 确保测试集覆盖所有题型,且分布均匀。
Q6:如何提升评测的可靠性?
A: 从低成本到高成本,有几种方法。
Level 1:约束输出格式(零成本)
# 在 Prompt 中明确要求输出格式
prompt = f"""
{instruction}
请逐步推理,然后在最后一行用「答案:X」的格式给出最终答案。
"""
# 提取时直接匹配
match = re.search(r"答案:\s*(.+)", text)
answer = match.group(1).strip() if match else None
优点: 零成本,提取准确率高
缺点: 需要修改 Prompt,可能影响模型表现
Level 2:多种兜底策略(低成本)
def extract_with_fallback(text):
# 策略1:显式标记
match = re.search(r"答案:\s*(.+)", text)
if match:
return match.group(1).strip()
# 策略2:最后一行数字
last_line = text.strip().split("\n")[-1]
numbers = re.findall(r"-?\d+\.?\d*", last_line)
if numbers:
return float(numbers[-1])
# 策略3:全文最后一个数字
all_numbers = re.findall(r"-?\d+\.?\d*", text)
return float(all_numbers[-1]) if all_numbers else None
优点: 鲁棒性高
缺点: 兜底策略可能不准确
Level 3:LLM Judge(中等成本)
def eval_with_judge(predicted, reference, instruction):
"""用强模型评判弱模型的回答"""
judge_prompt = f"""
请判断以下回答的质量,评分 1-5 分。
问题:{instruction}
参考答案:{reference}
模型回答:{predicted}
评分标准:
5分:答案正确且完整
4分:答案基本正确,有小瑕疵
3分:部分正确
2分:大部分错误
1分:完全错误
输出 JSON:{{"score": N, "reason": "..."}}
"""
# 调用 GPT-4 / Claude API
response = call_llm_api(judge_prompt)
return json.loads(response)
优点: 能评测语义质量,不只是字面匹配
缺点: 需要调用 API,有成本;Judge 模型可能有偏见
Level 4:人工评估(高成本)
招募标注员,按维度打分:
- 准确性:回答是否正确
- 完整性:是否涵盖关键信息
- 流畅性:表达是否自然
- 相关性:是否回答了用户的问题
优点:最可靠
缺点:成本高、速度慢
适用场景: 最终版本上线前的质量把关
Q7:评测脚本应该输出什么样的报告?
A: 一份好的评测报告应该包含:
1. 分任务类型的对比表
═══════════════════════════════════════════════════════
微调模型评估报告(Llama-3.2-1B + LoRA)
═══════════════════════════════════════════════════════
任务类型 │ 原始模型 │ 微调模型 │ 提升幅度
─────────────┼───────────┼───────────┼──────────
数学准确率 │ 45.2% │ 82.3% │ +37.1% ✓
翻译 BLEU │ 0.31 │ 0.58 │ +0.27 ✓
代码可执行率 │ 62.0% │ 78.5% │ +16.5% ✓
推理准确率 │ 38.7% │ 71.2% │ +32.5% ✓
知识 QA (LLM)│ 3.2/5 │ 4.1/5 │ +0.9 ✓
创意写作(LLM)│ 3.5/5 │ 3.8/5 │ +0.3 ~
生活建议(LLM)│ 3.8/5 │ 4.0/5 │ +0.2 ~
─────────────┴───────────┴───────────┴──────────
加权总分 │ 52.1 │ 78.4 │ +26.3
═══════════════════════════════════════════════════════
2. 每个维度的详细统计
数学题详细统计:
总题数:120
原始模型正确:54 (45.2%)
微调模型正确:99 (82.3%)
平均耗时:原始 1.2s,微调 1.3s
错误类型分析:
- 计算错误:原始 35%,微调 8%
- 理解错误:原始 20%,微调 10%
3. 退化检测
通用能力评测(模型未训练过的领域):
常识推理:原始 72%,微调 68% → 退化 4%(可接受)
历史知识:原始 65%,微调 63% → 退化 2%(可接受)
结论:微调在目标任务上显著提升,通用能力轻微退化但在可接受范围内。
Q8:有没有现成的评测框架可以直接用?
A: 有,但需要权衡。
1. lm-evaluation-harness(EleutherAI)
# 安装
pip install lm-eval
# 评测 Llama-3 在 MMLU 和 GSM8K 上的表现
lm_eval --model hf \
--model_args pretrained=meta-llama/Llama-3-8B \
--tasks mmlu,gsm8k \
--device cuda:0 \
--batch_size 8
优点: 覆盖 600+ 个 benchmark,社区活跃
缺点: 配置复杂,需要 GPU 资源
2. OpenCompass(上海 AI Lab)
# 安装
git clone https://github.com/open-compass/opencompass
cd opencompass
pip install -e .
# 评测
python run.py --models llama3-8b --datasets mmlu gsm8k
优点: 国内最主流,中文 benchmark 丰富
缺点: 配置复杂,文档不够友好
3. DeepEval(Confident AI)
# 安装
pip install deepeval
# 类似 pytest 的评测体验
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric
def test_model_answer():
test_case = LLMTestCase(
input="什么是机器学习?",
actual_output=model.generate("什么是机器学习?"),
expected_output="机器学习是人工智能的一个分支..."
)
metric = AnswerRelevancyMetric(threshold=0.7)
assert_test(test_case, [metric])
优点: 类似 pytest,易上手
缺点: 商业产品,部分功能收费
4. 自己写(推荐初学者)
# 优点:
# - 完全控制评测逻辑
# - 可以针对自己的数据定制
# - 学习评测原理
# 缺点:
# - 需要自己实现指标
# - 容易踩坑(如答案提取、采样设置)
建议: 先自己写一个简单的评测脚本(如本文档配套的 04_eval.py),理解原理后再用成熟框架。
Q9:评测结果应该怎么看?
A: 评测结果需要结合多个维度解读。
1. 看相对提升,不要只看绝对值
场景1:
原始模型:数学 45%,翻译 30%
微调模型:数学 82%,翻译 58%
→ 数学提升 37%,翻译提升 28% → 微调效果显著 ✓
场景2:
原始模型:数学 85%,翻译 80%
微调模型:数学 88%,翻译 82%
→ 提升很小 → 可能微调数据不够好,或者原始模型已经很强
2. 看能力分布,不要只看平均分
模型A:数学 95%,翻译 20%,推理 95% → 平均 70%
模型B:数学 70%,翻译 70%,推理 70% → 平均 70%
两个模型平均分相同,但:
- 模型A 是"偏科生",数学和推理强,翻译弱
- 模型B 是"均衡生",各维度差不多
选择哪个模型取决于你的应用场景。
3. 看退化情况
如果微调后:
目标任务:+30% → 很好
通用能力:-20% → 灾难性遗忘严重
需要权衡:
- 如果只用于目标任务 → 可以接受退化
- 如果需要通用能力 → 需要调整微调策略(如混合通用数据)
4. 看统计显著性
如果只评测了 10 道题:
原始模型:7/10 (70%)
微调模型:8/10 (80%)
→ 提升 10%,但样本太少,可能只是随机波动
建议至少评测 100+ 道题,且做多次实验取平均。
Q10:评测的下一步是什么?
A: 评测不是终点,而是迭代的起点。
1. 分析错误案例
# 找出模型答错的题目
wrong_cases = []
for item in test_data:
predicted = model.generate(item["instruction"])
if not is_correct(predicted, item["output"]):
wrong_cases.append({
"instruction": item["instruction"],
"expected": item["output"],
"actual": predicted
})
# 分析错误模式
for case in wrong_cases:
print(case)
# 可能的发现:
# - 模型在多位数乘法上总是错
# - 模型对"如果...那么..."句型理解不好
# - 模型对中文成语翻译不准确
2. 针对性改进
发现:模型在多位数乘法上准确率低
改进:
- 在训练数据中增加多位数乘法的样本
- 或者在 Prompt 中加入 CoT(Chain-of-Thought)引导
发现:模型对开放题回答过于简短
改进:
- 在训练数据中增加更详细的回答
- 或者在 Prompt 中要求"请详细回答"
3. 持续评测
每次微调后都跑一遍评测,记录历史:
版本 │ 数学 │ 翻译 │ 推理 │ 通用
────────┼───────┼───────┼───────┼──────
v1.0 │ 45% │ 30% │ 38% │ 70%
v1.1 │ 82% │ 58% │ 71% │ 68% ← 第一次微调
v1.2 │ 85% │ 62% │ 73% │ 65% ← 增加数据后
v1.3 │ 88% │ 65% │ 75% │ 60% ← 继续微调(通用能力退化)
结论: v1.3 在目标任务上最好,但通用能力退化严重,可能 v1.2 是更好的平衡点。
总结
模型评测是微调流程中不可或缺的一环:
- 为什么评测: 量化微调效果,避免"感觉"判断
- 用什么指标: 精确匹配(数学)、BLEU(翻译)、ROUGE(摘要)、Perplexity(整体)
- 主流基准: MMLU(知识)、GSM8K(数学)、HumanEval(代码)、MT-Bench(对话)
- 常见坑: 忘记关闭采样、测试集泄漏、只看平均分
- 提升可靠性: 约束输出格式、多种兜底策略、LLM Judge
- 怎么看结果: 看相对提升、能力分布、退化情况、统计显著性
评测不是终点,而是迭代的起点——分析错误、针对性改进、持续评测,才能让模型越来越好。
更多推荐
所有评论(0)