Fix CohereAsr training-loss double-shift (train against labels, not labels[..., 1:])#47090
Fix CohereAsr training-loss double-shift (train against labels, not labels[..., 1:])#47090eliaghazal wants to merge 5 commits into
Conversation
…abels[..., 1:]) CohereAsrForConditionalGeneration right-shifts labels into decoder_input_ids, then computes the loss via ForCausalLMLoss, which shifts again, so the model trains against labels[..., 1:]. Use a plain CrossEntropyLoss instead, matching Whisper/Bart and the Moonshine fix in huggingface#46784 (CohereAsr overrides forward, so that fix did not propagate). Adds the same regression test (with and without -100 padding). Fixes huggingface#46894
There was a problem hiding this comment.
Nice catch! See the comment (84e2058) I added to make this explicit, but the issue here is that we were mixing two different conventions:
- whisper/ legacy encoder-decoder convention: we pass labels, and forward builds decoder_input_ids from them by right-shifting:
[the, black, cat]→[bos, the, black, cat] - llama-like / causal LM convention:
labels == input_ids.input_idsandlabelsare[bos, the, black, cat]andForCausalLMLossshifts labels into[the, black, cat], ie we do[bos, the, black, cat]→[the, black, cat]
Ideally we would modernize Whisper and similar models to follow the causal LM convention, but that would require too much BC handling, so this fix LGTM 👌
| if labels is not None: | ||
| loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size) | ||
| loss_fct = CrossEntropyLoss() | ||
| loss = loss_fct(logits.reshape(-1, self.config.vocab_size), labels.reshape(-1)) |
There was a problem hiding this comment.
My only concern with this is that we don't really support proper gradient accumulation with this anymore which is the reason behind the whole loss function tbh --> gradient accumulation sums and divides only at the end (before it divided on each step)
There was a problem hiding this comment.
Fixed in 4629fa3 — kept self.loss_function and passed the already-aligned labels as shift_labels, so the internal shift is skipped but the num_items_in_batch reduction still applies (same pattern as Florence2 after #46898). Also extended the regression test with an assertion for the num_items_in_batch path.
|
Can we add closes #... for the other PRs so we focus on only this one? |
|
@vasqu good catch on the gradient accumulation — dropping On fixing collectively — from a sweep of models mixing the whisper-style label shift with
I'd keep this PR scoped to CohereAsr and do the Moonshine/PPFormulaNet pass in a follow-up, unless you'd prefer it all in one. Also added the closes-references for the earlier duplicate PRs (#46895, #46958) to the description. |
|
Fair point 😅 — reading through #46895, the review there converged on this same Whichever one you pick, two bits from here may be worth carrying over: the regression test also asserts the Either way I'll follow up on the Moonshine/PPFormulaNet sweep discussed above once this settles. |
|
Yep, not on you. Imo it's just about coordination now and imo probably best to sweep all affected models at once |
|
Happy to do the sweep in this PR then. I'd extend it to move Moonshine off the plain CrossEntropyLoss (it has the same num_items_in_batch gap) and check/fix PPFormulaNet, each with the same regression test including the grad accumulation reduction path. If you'd rather do it in #46895 with @sharmax-vikas driving that's fine too, just say the word and I'll share what I have. |
Moonshine's huggingface#46784 fix used a plain CrossEntropyLoss, dropping num_items_in_batch handling; PPFormulaNet overrides Florence2's forward and missed the huggingface#46898 fix, double-shifting labels. Both now pass labels as shift_labels through self.loss_function, keeping gradient accumulation reduction. Regression tests use a global token count that differs from the per-step count so the summed path is distinguishable.
|
Then maybe we can merge this #46895 and @eliaghazal, if you are willing, maybe you can propagate this change to other models so that the have the same behavior across all models that have this isssue ? |
|
@SunMarc done — this PR now carries the propagation:
Coordination so we don't trip over each other: if #46895 lands first I'll rebase and drop the CohereASR commits here; and #46903 (@OmkumarSolanki) also covers PPFormulaNet with a config-gated common test — happy to drop my PPFormulaNet half in deference, whichever way you prefer to slice it. |
modular_moonshine_streaming.py inherits MoonshineForConditionalGeneration, so the generated modeling file must be regenerated after the Moonshine change (repo-consistency CI failure). Extend its regression test with the same num_items_in_batch grad-accumulation check.
|
[For maintainers] Suggested jobs to run (before merge) run-slow: cohere_asr, moonshine, moonshine_streaming, pp_formulanet |
CI recapDashboard: View test results in Grafana |
What does this PR do?
CohereAsrForConditionalGeneration.forwardright-shiftslabelsintodecoder_input_idsviashift_tokens_right, then computes the loss withself.loss_function(ForCausalLMLoss), which shifts the labels a second time internally. The model therefore trains againstlabels[..., 1:]instead oflabels.Verified on main (
b70d02fc72) with a tiny random-init model:This is the same bug fixed for Moonshine in #46784. CohereAsr inherits from Moonshine but overrides
forward, so that fix didn't propagate.The fix keeps
self.loss_functionand passes the (already aligned) labels asshift_labels, soForCausalLMLossskips its internal shift while preserving thenum_items_in_batchhandling needed for correct loss reduction under gradient accumulation — same pattern as Florence2 after #46898. Changed inmodular_cohere_asr.pyand regeneratedmodeling_cohere_asr.pywith the modular converter.Also adds the same regression test as Moonshine's (
test_training_loss_no_double_shift, with and without-100padding), extended with an assertion for thenum_items_in_batch(summed) reduction path. It fails on current main and passes with this fix; the fulltests/models/cohere_asrfile passes (124 passed, 138 skipped).Fixes #46894
Closes #46895, closes #46958 (earlier PRs for the same issue)
Before submitting
Who can review?
@eustlb @vasqu