Repository navigation
Is eval_loss computed after response-only masking? (train_on_completions=true, alpaca template) #15404
|
Environment: Unsloth Studio 2026.10.8 (bundled unsloth 2026.10.7), Qwen3.5-2B, QLoRA 4-bit, While training, the log prints: Reading studio/backend/core/training/*, apply_completion_masking -> train_on_responses_only is a
We are not reporting a crash -- training itself runs fine (we have a separate, unrelated resume/UI |
Replies: 6 comments 2 replies
|
your reading agrees with the published on that path, for a non-streaming eval dataset, rows with every label set to i couldn't find an independent eval-only convention switch in that studio release's training settings. i'd evaluate the saved checkpoint separately for a full-sequence baseline how losses are averaged depends on the installed versions. for your thesis, could you share the |
|
Thanks, this is exactly the kind of answer we needed. Recording it so the thread is complete:
To answer your question directly - the versions come from the environments themselves, not from the
What we observe, on comparable runs (same dataset, same recipe):
Two orders of magnitude lower, or close to it, and the starting point is already near zero. We are
One more, unrelated to the above: on the old stack (2026.7.x) a 2B run went NaN around step 30k |
|
We did the scored-token check, and it confirms your expectation rather than overturning it. Method: for 5 rows of the eval split (shortest two, median, longest two) we rebuilt the exact training text (alpaca markers), tokenized it with the run's own tokenizer, and located the span
Decoded, the scored span equals the answer on all five rows, and it starts right after On the version question we asked earlier, we can now answer it from the wheels:
Two points we are taking from your reply:
Correction - the paragraph that used to sit here is wrong. I argued from the token counts (12-55 prompt vs 35-450 answer) that the two metrics could only differ by ~1.1-1.4x and that supervising the prompt should push the loss down. Both were wrong: measured on one checkpoint, the prompt segment is harder than the answer, and the ratio between the two metrics is ~36x at step 500 and ~66x at step 1000. The conclusion survives (the two runs are not comparable, the near-zero curve is only a direction check) but for the measured reason, not the estimated one. If you would like the runtime labels rather than a reconstruction, we can dump one collated eval batch with your snippet the next time we start that environment. |
|
A correction, the measurements behind it, and where we still are. In my previous comment I argued that the masking change could not explain the size of the difference, because the prompt is only 12-55 tokens against 35-450 answer tokens. That argument was wrong. I would rather correct it with numbers than leave it standing. How we measured it Take a checkpoint, load its base weights, apply the adapter's LoRA delta, and push the same fixed batch of eval rows through it twice. The text is built exactly the way the trainer builds it for the alpaca template, and the two runs differ in one thing only - the labels:
For each row we compute per-token cross-entropy, sum it, and divide by the number of labelled tokens. The prompt segment is obtained by subtracting the two runs, so it is measured, not estimated. We repeated this on the base model and on two checkpoints of the same run, over 400 rows sampled evenly from the eval split. Results
Two checks. Our answer-only numbers land within 8% of the What it says
What this means for the two runs The 2026.7.x run and the 2026.10.x run differ in two ways, and both come from the same switch: what is scored (full sequence vs answer only), and what is optimised (in 7.5 the alpaca branch skips masking entirely, so the prompt is trained; in 10.x only the answer is trained). Because of the second, the old run's prompt segment fell during training, which is why its full-sequence number came down; with masking on, the prompt segment here rises instead. These are not the same quantity, and we will keep them in separate tables and say why. What we now consider resolved
What we are still unsure about
Thanks again for the pointers - "check the scored tokens first" is exactly what led us to the text mismatch and to the correction above. |
|
A correction, and the whole picture in one place. I owe you an apology for something in my earlier comments. Our environment descriptions were written before we had gone through all of the old notebooks, and part of what I said about the 2026.7.x environment was simply wrong - I claimed those versions were no longer recoverable and gave a bound instead of the real numbers. That was our mistake, not a limitation of the software. I have corrected the earlier comments in place; since nobody should have to scroll back through several edits, everything is restated in full below. First, thank you. The masking code is well documented, and your suggestion to check the scored text before trusting the near-zero curve is exactly what led us to the real problem - which turned out to be our own text reconstruction, not the trainer. How our two environments were actually built Both came from the same base image, and the operations we applied only ever changed two packages:
One caveat found while digging: that Studio build can also pin a per-model How we measured We take a checkpoint, load its base weights, apply the adapter's LoRA delta, and push the same fixed batch of eval rows through it twice. The text is built exactly the way the trainer builds it for the alpaca template, and the two runs differ in one thing only - the labels: answer-only labels everything after the response marker (EOS included) and masks the rest; full-sequence labels every token. For each row we sum per-token cross-entropy and divide by the number of labelled tokens. The prompt segment is obtained by subtracting the two runs, so it is measured, not estimated.
Two checks: our answer-only numbers land within 8% of the What we now consider resolved
What we are still unsure about
Thanks again for the patience and for the pointers - and sorry for the noise the earlier version of that environment description caused. |
|
Quick background, since the numbers below only make sense with it: we're building a small Chinese-language task parser. Input is one sentence of Chinese describing a to-do ("remind me to hand in the lab report at 3pm tomorrow"); output is a single JSON object — an intent (create / update / query / mark-done) plus a fixed schema of about a dozen fields (title, due time, priority, subtasks, a completion flag, a list name, and so on). We fine-tune a 2B model for this; it's a student project, not a benchmark submission. Following your suggestion, we stopped ranking checkpoints by loss and instead scored the generated answers. Setup. Qwen3.5-2B, QLoRA (4-bit base + LoRA) trained in Studio; 7 intermediate checkpoints from 500 to 14,000 steps, evaluated by us. 500 rows sampled uniformly from a 5,000-row validation split (not the official test set), the same rows for every checkpoint. Greedy decoding, batch 8, max_new 1024, stop as soon as the JSON braces balance. Base weights in fp16 with the LoRA merged manually — PEFT silently no-ops in this environment, so we verified the merge numerically. The scoring code was copied verbatim from our scorer, which we cross-checked bit-for-bit against the official script on 5,000 previously generated answers.
Paired McNemar on the same rows: 5,000 is significantly better than every other checkpoint (smallest margin is against 10,000: −4.60 points, 95% paired half-width ±4.02). After 5,000 it doesn't decline monotonically — it drops into a 53–72 band and oscillates inside it (8,000 and 14,000 are statistically indistinguishable, +0.20 ±4.91; so are 3,000 and 10,000, +1.00 ±3.66). We read that as instability rather than a clean over-fitting curve. On the loss side — same rows, same checkpoints — both scoring modes point the wrong way. Answer-only eval loss (the number What actually goes wrong when the answers degrade: the intent is still right ~99% of the time and the JSON always closes, so it isn't a formatting failure. The field values collapse — the completion flag gets filled with a time string, a list field that should be empty gets a default bucket, every relative-time answer becomes the same phrase. Loss cannot see that by construction. Three things we haven't resolved, and they're the reason I'm posting rather than just reporting a score:
What we're doing next, and why the numbers above are deliberately provisional: the winning checkpoint (5,000 steps) still has to be run on our actual test set — one full pass over its 5,000 rows, roughly 9–10 GPU hours on a single T4. Everything in this thread is a 500-row subset of the validation split, so we're not putting an absolute number next to anyone else's results yet. The only figure we'd treat as comparable is that full test-set run; we'll post it when it's done, including whether the post-5k oscillation reproduces there. If it does, that's the more interesting finding than the peak itself. Caveats: 500-row validation subset (so these numbers are not comparable to anyone's test-set results), one training run, and the paired half-widths are only valid within this batch. One question, since this is a Studio UX matter as much as a training one: would it make sense for Studio to surface a generation-based metric after eval, or at least label eval loss as answer-only? Right now that number silently changed meaning between versions, and it's easy for people to compare across that boundary. |
your reading agrees with the published
unslothandunsloth_zoo2026.10.7/2026.10.8wheels. the studio masking call processes both splitson that path,
eval_lossuses response labels, including any retained eosfor a non-streaming eval dataset, rows with every label set to
-100are filtered out. if the whole eval split is masked, that code raises rather than averaging an empty split. a row with an unmasked eos label stays ini couldn't find an independent eval-only convention switch in that studio release's training settings. i'd evaluate the saved checkpoint separately for a full-sequence baseline
how losses are averaged depends on the installed versions. for your thesis, could you share …