SFT Hyperparameters
这个 recipe 会在 MinT 上跑真实的 supervised fine-tuning sweep。它用同一个小的 arithmetic chat 数据集训练多组超参数,然后比较最终 training loss。
关键点:这个 recipe 不再手写 Datum。它使用 recipe.supervised.conversation_to_datum() 和高层的 recipe.supervised.train.main(config) 训练循环。
Use Case
- Instruction tuning:训练 model 按任务指令工作。
- Domain adaptation:在领域内 Q&A 或 chat 样本上微调。
- 小规模 grid search:在大训练前先比较 learning rate 和 LoRA rank。
- Recipe debugging:确认 MinT API key、renderer、tokenizer、SFT 训练循环可以一起跑通。
Sweep 什么
默认情况下,recipes/sft_hyperparameters.py 会跑:
learning_rate: [1e-5, 5e-5]
lora_rank: [8, 16]
max_steps: 每组配置 2 step
configs: 2 x 2 = 4可以用环境变量覆盖:
MINT_SFT_STEPS=1 \
MINT_SFT_LRS=1e-5,5e-5 \
MINT_LORA_RANKS=8,16 \
python recipes/sft_hyperparameters.py核心模式
recipe 先创建一个内存里的 supervised dataset:
class ArithmeticSFTDataset(recipe.supervised.types.SupervisedDataset):
def __init__(self, conversations, model_name, renderer_name, batch_size, max_length):
tokenizer = get_tokenizer(model_name)
renderer = recipe.renderers.get_renderer(renderer_name, tokenizer)
self.datums = [
recipe.supervised.conversation_to_datum(
conversation,
renderer,
max_length=max_length,
)
for conversation in conversations
]
self.batch_size = batch_size
def __len__(self):
return max(1, (len(self.datums) + self.batch_size - 1) // self.batch_size)
def get_batch(self, index):
start = (index * self.batch_size) % len(self.datums)
return self.datums[start : start + self.batch_size]然后每个 grid item 调用标准 SFT trainer:
config = recipe.supervised.train.Config(
log_path="/tmp/mint-sft-sweep-lr1e-5-rank8",
model_name="Qwen/Qwen3-0.6B",
renderer_name="qwen3",
dataset_builder=ArithmeticSFTDatasetBuilder(...),
learning_rate=1e-5,
lora_rank=8,
max_steps=2,
save_every=999,
eval_every=999,
infrequent_eval_every=999,
ttl_seconds=3600,
)
await recipe.supervised.train.main(config=config)完整源码:https://github.com/MindLab-Research/mint-quickstart/blob/main/recipes/sft_hyperparameters.py
运行
export MINT_API_KEY=sk-your-api-key
python recipes/sft_hyperparameters.py输出最后会有类似这样的表:
=== Grid Search Summary ===
LR Rank Steps Final train NLL Log path
------------------------------------------------------------------------------------------
1e-05 8 2 10.4975 /tmp/mint-sft-sweep-...-1em05-rank8
1e-05 16 2 10.4919 /tmp/mint-sft-sweep-...-1em05-rank16
5e-05 8 2 10.1574 /tmp/mint-sft-sweep-...-5em05-rank8
5e-05 16 2 9.4928 /tmp/mint-sft-sweep-...-5em05-rank16Verified Run
已在 MinT 上验证:Qwen/Qwen3-0.6B,8 条生成的 arithmetic conversations,每组配置 2 steps:
| Learning rate | LoRA rank | Steps | Final train NLL |
|---|---|---|---|
1e-5 | 8 | 2 | 10.4975 |
1e-5 | 16 | 2 | 10.4919 |
5e-5 | 8 | 2 | 10.1574 |
5e-5 | 16 | 2 | 9.4928 |
这些数字来自很小的 smoke dataset。它们用于验证 API 和代码形状,不代表模型质量。真正调参时,请使用你的真实数据集、更多训练 steps,并比较 validation metrics。
为什么这个形状有效
chat messages
│
▼
conversation_to_datum()
│ 应用 renderer + assistant-token loss mask
▼
SupervisedDataset.get_batch()
│
▼
recipe.supervised.train.main(config)
│ 创建 LoRA TrainingClient,执行 forward/backward + optimizer steps
▼
metrics.jsonl + final checkpoint这样 tokenization 和 loss masking 会和 MinT 使用的 renderer 对齐。它也使用了更大的 supervised recipes 使用的同一个高层训练循环,所以这个 sweep 验证的是用户会复制的真实路径。