Caveat: this is a very short run
100k tokens is 14 optimizer steps. With 3% warmup and a cosine decay, most of the
schedule is spent warming up and annealing, so the adapter is lightly trained and its final
loss (1.547) sits well above the ~1M-token arms (0.88-0.93), which ran 86-98 steps. Treat it
as a small-data datapoint rather than a converged model.
What is supervised
Everything outside an assistant turn is -100. A supervised span starts immediately after
the <|im_start|>assistant\n header and ends after the closing <|im_end|>, which the model
must emit in order to stop. Verified: zero user or system tokens inside any supervised span.
TRL's own assistant_only_loss cannot do this on Qwen3.6 — its chat template has no
{% generation %} markers. Spans are derived from the rendered text via the fast
tokenizer's offset mapping instead, and TRL receives finished labels.
loss_type: nll is set because TRL's default chunked-CE path patches the LM head and reads
forward.__func__, which fails on this checkpoint's functools.partial forward. The loss is
mathematically the same.
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-100k-tulu-numina-norobots")
model = model.merge_and_unload()
Use AutoModelForImageTextToText, not AutoModelForCausalLM — this is a vision-language
checkpoint.