章节导航 第 9 章 / 共 20 章
课程化与退火策略
课程学习(Curriculum Learning)原理(从易到难)、退火(Annealing)策略设计(LR线性衰减/高质量精选)、退火数据组成、工业级实践案例、训练阶段切换时序
预训练的最后 5% 数据,决定了模型 20% 的最终能力。
退火是预训练的”压轴戏”——低学习率 + 高质量精选 = 模型能力的最后跃升。
9.1 课程学习原理
9.1.1 什么是课程学习
课程学习(Curriculum Learning, Bengio et al., 2009)的核心思想:模型像人一样,应该从易到难学习。
直觉上:
- 学数学先学加减,再学乘除,最后学代数
- 学语言先学日常对话,再学复杂论证
- 训练大模型也应该先学简单模式,再学复杂推理
9.1.2 为什么课程学习有效
- 梯度方向更稳定:早期数据简单,模型梯度方向稳定,收敛快
- 避免被难数据”震飞”:如果一开始就喂复杂数学,模型容易陷入局部最优
- 逐步建立抽象:简单模式是复杂模式的基础,先建立基础再上层建筑
9.1.3 难度评估
如何判断数据的”难度”?三种主流方法:
class DifficultyEstimator:
"""数据难度评估"""
def __init__(self):
# 用一个 reference 模型计算 PPL
self.ref_model = load_reference_model()
def estimate_by_ppl(self, text):
"""
方法1: 用参考模型计算 PPL
PPL 高 = 难,PPL 低 = 易
"""
ppl = compute_perplexity(self.ref_model, text)
# 归一化到 1-5 分
if ppl < 3.0:
return 1
elif ppl < 4.0:
return 2
elif ppl < 5.0:
return 3
elif ppl < 6.0:
return 4
else:
return 5
def estimate_by_features(self, text):
"""
方法2: 基于文本特征
- 句子长度
- 词汇复杂度(长词比例)
- 数学公式数量
- 代码行数
"""
sentences = text.split('.')
avg_sentence_len = np.mean([len(s.split()) for s in sentences])
words = text.split()
long_words = sum(1 for w in words if len(w) > 8)
long_word_ratio = long_words / max(len(words), 1)
formula_count = text.count('$')
code_lines = text.count('```')
# 综合评分
score = 0
if avg_sentence_len > 25: score += 1
if long_word_ratio > 0.15: score += 1
if formula_count > 10: score += 1
if code_lines > 3: score += 1
if len(text) > 5000: score += 1
return min(score + 1, 5)
def estimate_by_fineWeb_edu(self, text):
"""
方法3: 用 FineWeb-Edu 教育价值评分
教育价值 1-2 = 容易(基础内容)
教育价值 3 = 中等
教育价值 4-5 = 难(高密度知识)
"""
return fineweb_edu_classify(text)
EACL 2026 发现的最有效难度信号(Zhang et al., 2026, EACL 2026 Main):系统研究 200+ 模型在 100B tokens 上的课程学习效果,识别出三种比 FineWeb-Edu 更有效的难度信号:
- 压缩比(Compression Ratio):文本经 gzip 压缩后的比率,压缩比越低=冗余度越高=越容易
- 词汇多样性 MTLD(Measure of Textual Lexical Diversity):衡量文本词汇丰富度,MTLD 越高=词汇越多样=越难
- 可读性 Flesch Reading Ease:基于句子长度和音节数计算,得分越低=文本越难
EACL 2026 还发现课程学习可加速收敛 18-45%,作为 warmup 后切换随机采样可获得持续 +3.5% 提升——暗示”课程学习 + 随机混合”的组合策略可能优于纯课程学习。
难度信号的”偏好侧”扩展(PDPC):上述难度信号(PPL/文本特征/FineWeb-Edu)都来自”文本侧”,Preference Curriculum(PDPC, arXiv:2501.13126) 提出用偏好数据中的”预测难度(prediction difficulty, PD)“作为课程难度信号,配合 S 形(sigmoid)调度,在 3B 规模平均提升 +4.1%。这把”难度信号来源”从文本统计扩展到偏好信号。
课程学习的组合协调(CGLS, ICML 2026):课程学习通常与其它训练加速策略(如渐进层堆叠 progressive layer stacking)各自独立使用,CGLS(arXiv:2506.11389)将二者在同一训练流程中联合调度,探索”课程 × 层堆叠”的协调范式——这代表课程学习从”单点策略”走向”组合策略”的延伸方向。
9.1.4 课程学习的实验对比
Lee et al. (2024) 的实验(1B 模型):
| 训练策略 | 数据顺序 | MMLU |
|---|---|---|
| 随机 | 全程随机混合 | 24.5 |
| 从难到易 | 5→4→3→2→1 | 22.1(崩塌) |
| 从易到难 | 1→2→3→4→5 | 26.8 |
从难到易反而比随机差——印证了”先易后难”的合理性。
9.2 退火(Annealing)策略设计
9.2.1 什么是退火
退火源自金属学——缓慢冷却使晶体结构更稳定。在大模型训练中:
Pretrain 主训练: LR=3e-4, 数据=混合, tokens=10T
↓
退火阶段: LR=3e-5→0, 数据=精选, tokens=200B
9.2.2 退火的核心要素
# 退火的核心配置
ANNEALING_CONFIG = {
# 学习率配置
'lr_start': 3e-5, # 起始学习率(比主训练低10倍)
'lr_end': 1e-7, # ⚠️ 传统推荐=接近0,但 ICLR 2026 发现这会浪费高质量数据→见 §9.2.3 策略4 CMA
'schedule': 'linear_decay', # 或 'cosine_decay'
'warmup_steps': 100, # 短warmup
# 数据配置
'data_quality': 'high', # 高质量精选
'data_size': 200_000_000_000,# 200B tokens
'mix': {
'fineweb_edu_4plus': 0.50,
'arxiv_math': 0.20,
'github_clean': 0.15,
'stackexchange_top': 0.10,
'synthetic_reasoning': 0.05,
},
# 训练配置
'batch_size': 'same_as_pretrain', # 保持batch size
'gradient_accumulation': 'same',
'weight_decay': 0.1, # 略微提高正则化
}
9.2.3 四种退火策略
⚠️ LR 衰减的隐患(ICLR 2026, Luo et al., arXiv:2511.18903):课程学习在恒定 LR 下显著优于随机打乱,但在标准 LR 衰减(WSD/Cosine)下优势几乎消失。原因是 LR 衰减到低值时模型更新步长过小,无法充分学习最后阶段的高质量数据——“LR 衰减浪费了最好的数据”。解决方案见下文策略 4(CMA)和 CDMA。
策略1:纯线性衰减
def linear_decay_lr(step, total_steps, lr_start, lr_end):
"""线性衰减"""
return lr_start - (lr_start - lr_end) * (step / total_steps)
最简单,效果中等。适合算力紧张。
策略2:余弦衰减
import math
def cosine_decay_lr(step, total_steps, lr_start, lr_end):
"""余弦衰减"""
progress = step / total_steps
cosine_factor = 0.5 * (1 + math.cos(math.pi * progress))
return lr_end + (lr_start - lr_end) * cosine_factor
更平滑,效果略好于线性。
策略3:阶梯式衰减
def step_decay_lr(step, total_steps, stages):
"""
阶梯式衰减
stages: [(end_step1, lr1), (end_step2, lr2), ...]
"""
for end_step, lr in stages:
if step < end_step:
return lr
return stages[-1][1] # 最后一个stage的lr
# 示例
stages = [
(50_000_000_000, 3e-5), # 前50B: 3e-5
(120_000_000_000, 1e-5), # 50-120B: 1e-5
(170_000_000_000, 3e-6), # 120-170B: 3e-6
(200_000_000_000, 1e-6), # 170-200B: 1e-6
]
最复杂但效果最好。Llama3 用的是这种。
策略4:CMA(Controlled Moderate Annealing)
def cma_lr(step, total_steps, lr_peak, final_ratio=0.2):
"""
CMA (Controlled Moderate Annealing)
最终 LR 保持在峰值 LR 的 1/5~1/3,而非衰减到 0
"""
lr_end = lr_peak * final_ratio
progress = step / total_steps
# Cosine 衰减到 final_ratio * lr_peak,而非 0
cosine_factor = 0.5 * (1 + math.cos(math.pi * progress))
return lr_end + (lr_peak - lr_end) * cosine_factor
# 示例
# lr_peak=3e-5, final_ratio=0.2 → lr_end=6e-6
# 而非传统的 lr_end=1e-7(几乎为 0)
关键思想:将”步长控制”与”噪声降低”解耦。CMA 保持中等 LR 以确保高质量数据阶段有足够的学习步长,噪声降低则通过 CDMA(Checkpoint-Decoupled Model Averaging) 实现——对最后 N 个 checkpoint 做加权平均(如 EMA),在不牺牲步长的情况下降低噪声。
ICLR 2026 在 1.5B/30B tokens 实验上,CMA+CDMA 组合比传统 LR 衰减到 0 的方案提升 1.64%。这挑战了章节之前推荐的
lr_end=1e-7策略——“LR 逼近 0”的衰减恰恰浪费了退火阶段精心准备的高质量数据。
9.3 退火数据组成
退火数据是预训练的”压轴戏”,每条 token 都要”值得”。
9.3.1 推荐组成
# 退火阶段数据组成(500B tokens 为例)
annealing_data:
# 主力1: 高质量教育内容(50%)
fineweb_edu_4plus:
weight: 0.50
tokens: 250B
source: 'FineWeb-Edu ≥4 分精选'
description: '高中-大学级深度内容,结构化、信息密集'
# 主力2: 学术论文与数学(20%)
arxiv_math:
weight: 0.15
tokens: 75B
source: 'arXiv 数学/物理/CS 论文'
description: 'LaTeX 源码,公式完整还原'
openwebmath:
weight: 0.05
tokens: 25B
source: 'OpenWebMath'
description: '数学网页精选'
# 主力3: 代码(15%)
github_clean:
weight: 0.10
tokens: 50B
source: '高 star GitHub 仓库'
description: '至少 10 star,过滤测试和文档'
the_stack:
weight: 0.05
tokens: 25B
source: 'The Stack v2'
description: 'BigCode 项目代码精选'
# 主力4: 高质量问答(10%)
stackexchange_top:
weight: 0.07
tokens: 35B
source: 'StackExchange 高赞回答'
description: '投票 ≥10 的高质量问答'
# 主力5: 合成推理链(5%)
synthetic_reasoning:
weight: 0.03
tokens: 15B
source: 'GSM8K/MATH 合成推理链'
description: '用 GPT-4 生成的 step-by-step 推理'
orca_reasoning:
weight: 0.02
tokens: 10B
source: 'Orca 风格推理数据'
description: '复杂推理任务+解释'
# 主力6: 少量 SFT 风味(5%)
sft_like_data:
weight: 0.03
tokens: 15B
source: '指令风格数据'
description: '为后训练"破冰",让模型熟悉指令格式'
9.3.2 为什么需要 SFT 风味
退火阶段加少量 SFT 风味数据(5%)的原因:
- 为后训练破冰:让模型提前”感受”指令格式,减少 SFT 时的分布偏移
- 提升指令遵循能力:少量指令数据让模型学会”听指挥”
- 不破坏生成能力:5% 比例足够小,不会让模型只学会指令跟随
# SFT 风味数据示例
SFT_LIKE_TEMPLATES = [
# 数学推理
{
'prompt': 'What is 15 * 24? Think step by step.',
'response': 'Let me calculate 15 * 24 step by step.\n15 * 20 = 300\n15 * 4 = 60\n300 + 60 = 360\nSo 15 * 24 = 360.'
},
# 知识问答
{
'prompt': 'Explain how photosynthesis works.',
'response': 'Photosynthesis is the process by which plants convert light energy into chemical energy...'
},
# 代码解释
{
'prompt': 'What does this code do?\n```python\ndef fib(n): return n if n<2 else fib(n-1)+fib(n-2)```',
'response': 'This is a recursive implementation of the Fibonacci sequence...'
}
]
9.3.3 合成推理链
退火阶段推荐加 5% 合成推理链,特别提升数学/推理能力:
# 合成推理链示例(用 GPT-4 生成)
SYNTHETIC_REASONING_EXAMPLES = [
{
'task': 'Solve: A train travels 60 km/h for 2 hours, then 80 km/h for 1 hour. Total distance?',
'reasoning': '''
Step 1: Calculate distance for first part
60 km/h × 2 hours = 120 km
Step 2: Calculate distance for second part
80 km/h × 1 hour = 80 km
Step 3: Add distances
120 + 80 = 200 km
Answer: 200 km
''',
'answer': '200 km'
}
]
生成流程:
def generate_synthetic_reasoning(num_samples=10000):
"""用 GPT-4 生成合成推理链"""
from openai import OpenAI
client = OpenAI()
examples = []
# 用 GSM8K 题目作为种子
gsm8k_problems = load_gsm8k_train()
for problem in gsm8k_problems[:num_samples]:
response = client.chat.completions.create(
model='gpt-4',
messages=[
{'role': 'system', 'content': 'You are a math tutor. Solve the problem step by step with clear reasoning.'},
{'role': 'user', 'content': problem['question']}
],
temperature=0.7 # 适度多样性
)
examples.append({
'question': problem['question'],
'reasoning': response.choices[0].message.content,
'answer': problem['answer']
})
return examples
9.4 工业级实践案例
9.4.1 Llama3 退火实践
Llama3(Meta, 2024)的退火实践:
| 阶段 | tokens | LR | 数据 |
|---|---|---|---|
| Pretrain 主训练 | 15T | 3e-4 → 3e-5 | 混合 |
| 退火阶段 | 200B | 3e-5 → 0 | 精选(同主训练但质量更高) |
Llama3 的关键发现:退火数据用”主训练数据中质量最高的子集”,而不是全新数据。这避免了分布偏移。
9.4.2 DeepSeek-V3 退火实践
DeepSeek-V3 的退火更激进:
| 阶段 | tokens | LR | 数据 |
|---|---|---|---|
| Pretrain 主训练 | 14T | 3e-4 → 3e-5 | 数学/代码占比高 |
| 退火阶段 | 500B | 3e-5 → 1e-6 | 数学 30%+代码 30%+推理 20% |
| 长文训练 | 100B | 1e-5 | 长文档拼接 |
DeepSeek-V3 的关键发现:退火阶段数学/代码配比拉满,效果显著——MATH 从 35 跃升到 61.6。
9.4.3 Qwen2.5 退火实践
Qwen2.5(阿里, 2024)的退火策略:
# Qwen2.5 退火配方
qwen25_annealing:
total_tokens: 300B
# 学习率:用阶梯式衰减
lr_schedule:
- {tokens: 100B, lr: 3e-5}
- {tokens: 100B, lr: 1e-5}
- {tokens: 70B, lr: 3e-6}
- {tokens: 30B, lr: 1e-6}
# 数据:精选+合成
mix:
fineweb_edu_4plus: 0.40
arxiv_math: 0.20
synthetic_reasoning: 0.15 # 比例较高
github_clean: 0.15
wiki: 0.05
sft_like: 0.05
9.4.4 YuLan-Mini:小规模开源模型的完整课程+退火配方
上述三个案例都是大厂大模型,YuLan-Mini(人大高瓴,arXiv:2412.17743)则提供了一个小规模开源模型的完整落地配方,作为”课程 + 退火”在小体量模型上的对照样本:
- 27 阶段课程学习:将预训练切分为 27 个难度递进的课程阶段(远多于前述大厂的 3-8 阶段),在较小算力下精细调度数据难度
- 80B tokens 退火:退火阶段规模与模型体量匹配,而非简单套用大厂的 200-500B
- RoPE 基频提升:在课程后期配合 RoPE 基频调整,扩展长程位置建模能力
YuLan-Mini 的价值在于说明”课程 + 退火”并非大厂专属——小体量模型同样可以用更细粒度的课程切分 + 匹配体量的退火规模 + 位置编码调整,拼出完整的能力曲线。
9.4.5 三家对比
| 维度 | Llama3 | DeepSeek-V3 | Qwen2.5 |
|---|---|---|---|
| 退火 tokens | 200B | 500B | 300B |
| 学习率衰减 | 阶梯 | 线性 | 阶梯 |
| 数学配比 | 5% | 30% | 20% |
| 合成推理 | 0% | 5% | 15% |
| SFT 风味 | 0% | 0% | 5% |
核心规律:
- 退火 tokens 占总训练的 1-5%
- 学习率降到主训练的 1/10 到 0
- 数据全部用高质量精选
- 数学/代码配比拉满(推理能力提升关键)
9.5 训练阶段切换时序
9.5.1 完整预训练时序
时间轴 →
Pretrain 主训练 (10T tokens, 3-6 个月)
↓
Midtrain 二阶段 (1-3T tokens, 2-4 周)
↓
退火阶段 (200-500B tokens, 3-7 天)
↓
长文训练 (50-200B tokens, 2-5 天)
↓
进入后训练 (SFT/DPO/RL)
9.5.2 阶段切换的”平滑过渡”
class PhaseTransitionScheduler:
"""阶段切换调度器"""
def __init__(self):
self.transitions = []
def add_transition(self, from_phase, to_phase, transition_tokens=10_000_000_000):
"""
添加一个阶段切换
transition_tokens: 过渡期 token 数(默认 10B)
"""
self.transitions.append({
'from': from_phase,
'to': to_phase,
'transition_tokens': transition_tokens
})
def get_lr_during_transition(self, step, transition_steps):
"""
过渡期学习率:线性插值
"""
from_lr = self.transitions[0]['from']['lr']
to_lr = self.transitions[0]['to']['lr']
# 线性插值
progress = step / transition_steps
return from_lr + (to_lr - from_lr) * progress
def get_mix_during_transition(self, step, transition_steps):
"""
过渡期数据混合:渐进切换
"""
from_mix = self.transitions[0]['from']['mix']
to_mix = self.transitions[0]['to']['mix']
progress = step / transition_steps
# 渐进切换:从 from_mix 渐变到 to_mix
blended_mix = {}
for key in set(from_mix.keys()) | set(to_mix.keys()):
from_w = from_mix.get(key, 0)
to_w = to_mix.get(key, 0)
blended_mix[key] = from_w * (1 - progress) + to_w * progress
# 归一化
total = sum(blended_mix.values())
return {k: v/total for k, v in blended_mix.items()}
9.5.3 切换的踩坑
坑1:学习率突然降10倍
某团队从 Pretrain(LR=3e-4)切到退火(LR=3e-5)时直接切换,loss 突然跳变 0.3,模型陷入次优解。
解决:用 10B tokens 做线性插值过渡。
坑2:数据突然切换
某团队从混合数据切到精选数据时直接切换,模型在切换后出现”知识遗忘”——之前学的能力丢失了。
解决:渐进切换混合比例(保留 20% 主训练数据 + 80% 退火数据)。
坑3:阶段切换太频繁
某团队设计了 8 个阶段(每 200B tokens 切换一次),结果每次切换都损失一些能力,最终效果不如 3 阶段。
解决:阶段数控制在 3-5 个,每个阶段至少 200B tokens。
9.6 课程化的工业实现
9.6.1 难度排序的数据准备
def prepare_curriculum_data(documents):
"""
准备课程化数据
1. 给每条数据打难度标签
2. 按难度分桶
3. 准备不同阶段的数据混合
"""
# Step 1: 难度评估
for doc in documents:
doc['difficulty'] = estimate_difficulty(doc['text'])
# Step 2: 按难度分桶
buckets = {1: [], 2: [], 3: [], 4: [], 5: []}
for doc in documents:
buckets[doc['difficulty']].append(doc)
# Step 3: 准备各阶段混合
curriculum = {
'phase1_easy': {
1: 0.50, 2: 0.30, 3: 0.15, 4: 0.04, 5: 0.01
},
'phase2_medium': {
1: 0.20, 2: 0.30, 3: 0.30, 4: 0.15, 5: 0.05
},
'phase3_hard': {
1: 0.05, 2: 0.15, 3: 0.30, 4: 0.30, 5: 0.20
},
'phase4_annealing': {
1: 0.00, 2: 0.05, 3: 0.20, 4: 0.40, 5: 0.35
}
}
return buckets, curriculum
9.6.2 课程调度器
class CurriculumScheduler:
"""课程学习调度器"""
def __init__(self, curriculum, total_tokens):
self.curriculum = curriculum
self.total_tokens = total_tokens
self.current_phase = 'phase1_easy'
self.phase_progress = 0
def get_phase_for_step(self, step):
"""根据当前训练步数确定阶段"""
# 假设4个阶段,每阶段占 25%/35%/30%/10% 的训练量
phase_allocations = [
('phase1_easy', 0.25),
('phase2_medium', 0.35),
('phase3_hard', 0.30),
('phase4_annealing', 0.10)
]
cumulative = 0
for phase, alloc in phase_allocations:
cumulative += alloc
if step < cumulative * self.total_tokens:
return phase
return 'phase4_annealing'
def sample_batch(self, buckets, batch_size):
"""按当前阶段的配比采样一个 batch"""
mix = self.curriculum[self.current_phase]
batch = []
for difficulty, weight in mix.items():
n_samples = int(batch_size * weight)
samples = random.sample(buckets[difficulty], min(n_samples, len(buckets[difficulty])))
batch.extend(samples)
return batch[:batch_size]
9.7 退火效果监控
9.7.1 关键指标
class AnnealingMonitor:
"""退火效果监控"""
def __init__(self):
self.metrics_history = []
def log_metrics(self, step, model, eval_loader):
"""记录退火过程中的关键指标"""
metrics = {
'step': step,
'train_loss': self._compute_train_loss(model),
'eval_loss': self._compute_eval_loss(model, eval_loader),
'mmlu': eval_mmlu(model), # 通用能力
'gsm8k': eval_gsm8k(model), # 数学能力
'human_eval': eval_human_eval(model), # 代码能力
'mt_bench': eval_mt_bench(model), # 对话能力
}
self.metrics_history.append(metrics)
# 检查异常
self._check_regression(metrics)
return metrics
def _check_regression(self, current):
"""检查能力倒退"""
if len(self.metrics_history) < 2:
return
prev = self.metrics_history[-1]
# 如果任何能力下降超过 2 分,告警
for metric in ['mmlu', 'gsm8k', 'human_eval', 'mt_bench']:
if prev[metric] - current[metric] > 2:
print(f'⚠️ {metric} regression: {prev[metric]} → {current[metric]}')
9.7.2 退火效果实证
某 7B 模型的退火前后对比:
| 指标 | 退火前 | 退火后 | 提升 |
|---|---|---|---|
| MMLU | 48.2 | 52.8 | +4.6 |
| GSM8K | 12.3 | 22.1 | +9.8 |
| HumanEval | 28.5 | 35.2 | +6.7 |
| MT-Bench | 5.8 | 6.2 | +0.4 |
退火对推理类任务(GSM8K)提升最大,对闲聊类(MT-Bench)提升最小。
9.8 退火的踩坑经验
坑1:退火数据与主训练重复
某团队退火用的是主训练数据的子集,结果退火几乎无效果。退火数据必须独立精选,质量比主训练高一个级别。
坑2:退火 tokens 过多
某团队退火用了 2T tokens(占总训练 20%),结果模型出现过拟合,泛化能力下降。退火 tokens 应该占总训练的 1-5%。
坑3:退火学习率太高
某团队退火学习率 = 主训练的 1/3,结果退火过程中 loss 波动剧烈。退火学习率应为主训练的 1/10 到 1/100。
坑4:未做能力倒退监控
某团队退火后发现数学能力提升,但代码能力下降 5 分。退火过程中必须监控所有能力维度,及时调整配比。
坑5:合成推理数据质量差
某团队用 GPT-3.5 生成合成推理链,结果推理链有错误,模型学到了错误推理。合成数据必须用 GPT-4/Claude 等顶级模型生成,且要做质量验证。
9.9 推荐退火配方模板
9.9.1 通用模型退火
# 通用模型退火(适合 Llama/Qwen 类)
general_annealing:
total_tokens: 200B # 主训练的 2%
lr_schedule: linear_decay
lr_start: 3e-5
lr_end: 1e-7
mix:
fineweb_edu_4plus: 0.50 # 100B
arxiv_math: 0.20 # 40B
github_clean: 0.15 # 30B
stackexchange_top: 0.10 # 20B
synthetic_reasoning: 0.05 # 10B
9.9.2 数学模型退火
# 数学模型退火(适合 DeepSeek-Math 类)
math_annealing:
total_tokens: 100B
mix:
arxiv_math: 0.40 # 数学论文 40B
openwebmath: 0.20 # 数学网页 20B
synthetic_reasoning: 0.25 # 合成推理 25B(高比例)
fineweb_edu_4plus: 0.10
gsm8k_augmented: 0.05 # GSM8K 增强
9.9.3 代码模型退火
# 代码模型退火(适合 Code Llama 类)
code_annealing:
total_tokens: 100B
mix:
github_clean: 0.50 # 高 star 代码 50B
the_stack_v2: 0.20 # BigCode 数据 20B
stackexchange: 0.15 # 编程问答 15B
fineweb_edu_4plus: 0.10
synthetic_code: 0.05 # 合成代码(如 LeetCode 题解)
9.10 本课总结
- 课程学习:从易到难训练,比随机混合提升 2-3 分
- 退火:低学习率 + 高质量精选,最后 1-5% 数据带来 20% 能力提升
- 退火数据组成:FineWeb-Edu≥4分50% + 数学20% + 代码15% + 问答10% + 合成5%
- 三种退火策略:线性衰减(简单)/ 余弦(平滑)/ 阶梯式(最佳)
- 阶段切换:用 10B tokens 做平滑过渡,避免学习率/数据突变
- 工业实践:Llama3/DeepSeek-V3/Qwen2.5 都用退火,tokens 占总训练 1-5%
课后练习
- 实现一个难度评估器,给你的数据集打 1-5 分难度
- 设计一个 4 阶段课程学习方案,并配置各阶段的配比
- 实现退火学习率调度器(线性 + 余弦 + 阶梯三种)
- 思考:你的模型最需要补强的能力是什么?退火数据配比应该怎么调?
下一章我们将进入评估、归因与闭环——用数据探针、消融实验、训练数据归因(TDA)和 Scaling Law 拟合,建立数据工程的反馈闭环。