跳转至

LoRA Adapter

这个 recipe 展示真实的 Mint Recursive LoRA checkpoint 工作流程:

  1. 创建 LoRA TrainingClient。
  2. 用 forward_backward(..., loss_fn="cross_entropy") 跑一个或多个 SFT step。
  3. 用 save_state() 保存训练状态。
  4. 用 save_weights_for_sampler() 保存采样器权重。
  5. 用保存的采样器权重创建 SamplingClient,并从中采样。

它不会导出 PEFT 文件,也不会生成 vLLM 可用的本地权重。这个 recipe 里没有 export_lora_to_peft() API。

Use Case

  • Checkpoint 验证:确认训练好的 LoRA adapter 能保存和采样。
  • 短训练 demo:跑一个最小 SFT step,查看保存的 checkpoint 路径。
  • Mint Recursive 部署路径:通过 create_sampling_client() 使用 Mint Recursive 采样器权重。
  • API 自检:验证你的账号和模型能正常调用 save_state() 和 save_weights_for_sampler()。

核心训练步骤

recipe 构造一个很小的算术 SFT batch,用底层 TrainingClient API 训练:

training_client = service_client.create_lora_training_client(
    base_model="Qwen/Qwen3-0.6B",
    rank=16,
    train_mlp=True,
    train_attn=True,
    train_unembed=True,
)

tokenizer = training_client.get_tokenizer()
data = [process_sft_example(example, tokenizer) for example in generate_sft_examples()]

for step in range(1, SFT_STEPS + 1):
    fb_result = training_client.forward_backward(
        data,
        loss_fn="cross_entropy",
    ).result()
    loss = compute_cross_entropy(fb_result, data)
    training_client.optim_step(types.AdamParams(learning_rate=5e-5)).result()
    print(f"Step {step}: train_cross_entropy={loss:.6f}")

保存 Checkpoint

这里展示两个 save API:

state_checkpoint = training_client.save_state(
    name="lora-adapter-state"
).result()

sampler_checkpoint = training_client.save_weights_for_sampler(
    name="lora-adapter-sampler"
).result()

区别:

API 用途
save_state() 保存训练状态,用于恢复训练或检查。
save_weights_for_sampler() 保存能被 SamplingClient 使用的权重。

从保存的权重采样

sampling_client = service_client.create_sampling_client(
    model_path=sampler_checkpoint.path,
    base_model="Qwen/Qwen3-0.6B",
)

result = sampling_client.sample(
    prompt=types.ModelInput.from_ints(tokens=prompt_tokens),
    num_samples=1,
    sampling_params=types.SamplingParams(max_tokens=32, temperature=0.0),
).result()

response = tokenizer.decode(result.sequences[0].tokens).strip()

完整源码:https://github.com/MindLab-Research/mint-quickstart/blob/main/recipes/lora_adapter.py

Verified Run

已在 Mint Recursive 上验证:Qwen/Qwen3-0.6B,1 个 SFT step:

Step 1: train_cross_entropy=6.009224
State checkpoint:   tinker://1cbd1a15-dc76-4c63-8683-e8df2a46a45c_0/weights/lora-adapter-state
Sampler weights:    tinker://1cbd1a15-dc76-4c63-8683-e8df2a46a45c_0/sampler_weights/lora-adapter-sampler
Sampling from saved weights: success

采样示例:

Prompt:   Question: What is 4 + 5?
          Answer:
Response: 9

Note

这个 recipe 验证的是 Mint Recursive checkpoint 和 sampling API。如果你需要本地 PEFT/vLLM 导出,请等待单独文档化的权重导出路径;不要假设存在假的 export_lora_to_peft() API。

为什么这个结构成立

TrainingClient
  │ forward_backward(cross_entropy) + optim_step
  ▼
LoRA adapter state
  ├─ save_state() ───────────────▶ training/resume checkpoint
  └─ save_weights_for_sampler() ─▶ sampler checkpoint
                                      │
                                      ▼
                              create_sampling_client()
                                      │
                                      ▼
                                  sample()

这是 Mint Recursive LoRA adapter 最小可用的真实 checkpoint 生命周期。