Views
No views yet
1 expert response c
2 |
3 v
4conversation x ----> teacher prompt: x + c ----> frozen base model
5 | |
6 | v
7 +---------> student prompt: x ----------> teacher logits over y
8 |
9 v
10 trainable student
11 |
12 v
13 sampled response y
14 |
15 v
16 reverse KL(student logits || teacher logits)11. Sample y from the current student:
2 y ~ pi_theta(. | conversation)
3
42. Score each sampled token with two distributions:
5 student: pi_theta(. | conversation, y_<t)
6 teacher: pi_0(. | conversation, expert_reference, y_<t)
7
83. Train the student toward the teacher on the sampled trajectory:
9 loss = KL(pi_theta || pi_0) over the rollout tokens
1SFT:
2 conversation x + expert tokens y*
3 |
4 v
5 cross entropy: -log pi_theta(y* | x)
6 |
7 v
8 off-policy learning on fixed demonstrations1SDFT:
2 conversation x ---> current model samples y
3 | |
4 | v
5 +---- expert c ---> teacher scores y
6 |
7 v
8 on-policy distillation on the student's own rolloutlambda_on_policy = 1.0, so all training examples are
on-policy. There is no plain next-token cross-entropy SFT objective in this
run.unsloth/Qwen3.5-9Barmand0e/claude-fable-5-claude-code<expert_reference> block. The student does not see that block when it samples
its response.| Setting | Value |
|---|---|
| Base checkpoint | unsloth/Qwen3.5-9B |
| Max sequence length | 65536 |
| Max teacher prompt tokens | 57344 |
| Max rollout tokens | 8192 |
| Optimizer steps | 600 |
| Batch size | 1 |
| Learning rate | 1.0e-5 |
| Warmup steps | 20 |
| Weight decay | 0.0 |
| LoRA rank | 64 |
| LoRA alpha | 128 |
| LoRA dropout | 0.0 |
| Distillation loss | reverse KL |
| KL temperature | 1.0 |
| Rollout temperature | 0.8 |
| Rollout top-p | 0.95 |
1q_proj, k_proj, v_proj, o_proj,
2gate_proj, up_proj, down_proj,
3in_proj_qkv, in_proj_z, out_proj1import torch
2from transformers import AutoTokenizer
3
4try:
5 from transformers import AutoModelForMultimodalLM as AutoModel
6except ImportError:
7 from transformers import AutoModelForCausalLM as AutoModel
8
9model_id = "your-name/qwen35-9b-64k-sdft"
10
11tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
12model = AutoModel.from_pretrained(
13 model_id,
14 torch_dtype=torch.bfloat16,
15 device_map="auto",
16 trust_remote_code=True,
17)
18
19messages = [
20 {"role": "user", "content": "Write a small Python function that validates an email address."}
21]
22
23prompt = tokenizer.apply_chat_template(
24 messages,
25 tokenize=False,
26 add_generation_prompt=True,
27 enable_thinking=False,
28)
29inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
30
31with torch.no_grad():
32 output = model.generate(
33 **inputs,
34 max_new_tokens=512,
35 temperature=0.7,
36 top_p=0.95,
37 do_sample=True,
38 )
39
40print(tokenizer.decode(output[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True))1@misc{shenfeld2026selfdistillationenablescontinuallearning,
2 title = {Self-Distillation Enables Continual Learning},
3 author = {Shenfeld, Idan and Damani, Mehul and Hubotter, Jonas and Agrawal, Pulkit},
4 year = {2026},
5 eprint = {2601.19897},
6 archivePrefix = {arXiv},
7 primaryClass = {cs.LG},
8 url = {https://arxiv.org/abs/2601.19897}
9}