Mixture
Sized by example count, not by token budget.
Table with columns: Source, Examples, Tokens, % examples, % tokens| Source | Examples | Tokens | % examples | % tokens |
|---|
| difficult_advice (synthdoc_v2, traits t1/t2/t3) | 250 | 422,588 | 25.0% | 51.0% |
| NuminaMath-CoT | 750 | 406,169 | 75.0% | 49.0% |
| total | 1,000 | 828,757 | | |
Difficult-advice rows average 1,690 tokens against NuminaMath's 542, so the 25/75 split by
examples is roughly 51/49 by training signal. This arm is therefore not directly
comparable to the token-budgeted 10/90 and 20/80 arms.
Trait balance in the difficult-advice half: t1=84, t2=83, t3=83 (drawn from pools of 98/84/91).
Think blocks
Every difficult-advice row carries a real <think> trace from stage 6 of the
synthdoc_v2 six-stage pipeline.
NuminaMath rows carry no think block. No row carries an empty <think></think> —
training a model to emit one is the documented reasoning-collapse pattern.
What is supervised
Everything outside an assistant turn is -100; 81.7% of tokens carry loss. Verified at
token-ID level before launch: 0 rows leaked a user/system token into the loss, and 0
difficult-advice rows lost their trace.
TRL's own assistant_only_loss cannot do this on Qwen3.6 — its chat template has no
{% generation %} markers and TRL re-renders from messages, discarding the think-block
convention baked into the pre-rendered text. Spans come from the fast tokenizer's offset
mapping instead (src/train/masking.py).
Training
bf16 LoRA (not QLoRA — bitsandbytes does not reliably cover this model's hybrid
linear-attention/SSM layers). 1xH100 80GB, 45 min.
Table | |
|---|
| r / alpha / dropout | 32 / 64 / 0.05 |
| target modules | regex scoped to model.language_model.* |
| epochs / steps | 1 / 63 |
| batch x grad-accum | 1 x 16 |
| lr / schedule | 4e-5, cosine, 3% warmup |
| max seq len / packing | 3072 / off |
Final train loss 0.7751, mean token accuracy
0.7947, 828,757 tokens seen.
Table with columns: step, loss, token acc| step | loss | token acc |
|---|
| 5 | 1.5865 | 0.6367 |
| 10 | 0.8564 | 0.7759 |
| 15 | 0.6939 | 0.8070 |
| 20 | 0.7732 | 0.7853 |
| 25 | 0.6928 | 0.8002 |
| 30 | 0.7421 | 0.7890 |
Status
Not yet evaluated on ODCV-Bench or agentic-misalignment.
Usage
from peft import PeftModel
from transformers import AutoModelForImageTextToText
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen3.6-27B", dtype="bfloat16")
model = PeftModel.from_pretrained(model, "LASR-Callum/qwen3.6-27b-lora-1000ex-da250-t1t3-numina750")
model = model.merge_and_unload()
Use AutoModelForImageTextToText, not AutoModelForCausalLM — this is a vision-language
checkpoint.