fix: adapt Whisper models to use self.loss_function with num_items_in_batch support - #46068
Closed
Ashutosh-177 wants to merge 4 commits into
Closed
fix: adapt Whisper models to use self.loss_function with num_items_in_batch support#46068Ashutosh-177 wants to merge 4 commits into
Ashutosh-177 wants to merge 4 commits into
Conversation
Fixes gradient accumulation for Whisper by replacing the manual CrossEntropyLoss instantiation with self.loss_function, which supports the num_items_in_batch parameter introduced in PR huggingface#34191. Key changes: - loss_utils.py: ForConditionalGeneration now maps to ForMaskedLMLoss instead of ForCausalLMLoss. Encoder-decoder models have labels already aligned with logits (no token shift needed), matching the masked-LM loss pattern. - modeling_whisper.py: WhisperForConditionalGeneration and WhisperForCausalLM both gain an explicit num_items_in_batch parameter and delegate loss computation to self.loss_function. Closes huggingface#36119
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates Whisper’s forward() implementations to use the unified self.loss_function(...) interface (including num_items_in_batch support) to fix gradient-accumulation loss scaling, and adjusts the global loss dispatch for ForConditionalGeneration.
Changes:
- Add
num_items_in_batchtoWhisperForConditionalGeneration.forward()andWhisperForCausalLM.forward()and route loss computation throughself.loss_function(...). - Update
LOSS_MAPPING["ForConditionalGeneration"]to point toForMaskedLMLossinstead ofForCausalLMLoss.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/transformers/models/whisper/modeling_whisper.py |
Switch Whisper LM losses to self.loss_function(...) and accept num_items_in_batch for correct GA normalization. |
src/transformers/loss/loss_utils.py |
Changes the default loss implementation used for classes matching ForConditionalGeneration. |
Comments suppressed due to low confidence (1)
src/transformers/models/whisper/modeling_whisper.py:1224
WhisperForCausalLMpreviously computed loss directly againstlabels(no shifting). Switching toself.loss_functionwill useForCausalLMLossby default, which shifts labels internally; this is a behavior change and contradicts the PR description claim of “no behavior change when num_items_in_batch is None”. If Whisper’s decoder labels are intended to be already aligned with logits (as in many encoder-decoder decoders), consider settingself.loss_type = "ForMaskedLM"for this class or passing an explicitshift_labelsto preserve current semantics.
logits = self.proj_out(outputs[0])
loss = None
if labels is not None:
loss = self.loss_function(
logits=logits, labels=labels, vocab_size=self.config.vocab_size, num_items_in_batch=num_items_in_batch
)
Revert the LOSS_MAPPING["ForConditionalGeneration"] change — it was too broad and would break decoder-only models that match the same key (LlavaForConditionalGeneration, PaliGemmaForConditionalGeneration, etc.) which rely on ForCausalLMLoss label-shifting behavior. Instead, set self.loss_type = "ForMaskedLM" explicitly in both WhisperForConditionalGeneration.__init__ and WhisperForCausalLM.__init__. This overrides the per-instance loss resolution in PreTrainedModel without touching the global mapping, ensuring: - All other *ForConditionalGeneration models remain unaffected - WhisperForConditionalGeneration and WhisperForCausalLM both use ForMaskedLMLoss (no label shift), matching the original CrossEntropyLoss behavior and preserving correctness
Ashutosh-177
force-pushed
the
fix/whisper-loss-function-36119
branch
from
May 19, 2026 07:04
1e377ce to
08d7337
Compare
Both WhisperForConditionalGeneration.forward() and WhisperForCausalLM.forward() were missing docstring entries for the new num_items_in_batch parameter, causing check_docstrings to fail.
Contributor
|
[For maintainers] Suggested jobs to run (before merge) run-slow: whisper |
Author
|
Opened PR #46068 that fixes this. All CI checks are passing — would appreciate a review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CrossEntropyLossinstantiation withself.loss_function, which supports thenum_items_in_batchparameter introduced in Fix Gradient Accumulation issue #34191.num_items_in_batchparameter to bothWhisperForConditionalGeneration.forward()andWhisperForCausalLM.forward().self.loss_type = "ForMaskedLM"in both Whisper class__init__methods so the correct (no-shift) loss is used without touching the globalLOSS_MAPPING.Changes
src/transformers/models/whisper/modeling_whisper.pyWhisperForConditionalGeneration.__init__: setsself.loss_type = "ForMaskedLM". Encoder-decoder models receive labels already aligned with decoder logits — no token shifting is needed.WhisperForConditionalGeneration.forward(): addsnum_items_in_batchparameter; replaces manualCrossEntropyLossblock withself.loss_function(...).WhisperForCausalLM.__init__: sameself.loss_type = "ForMaskedLM"override, preserving the original no-shift behavior.WhisperForCausalLM.forward(): same treatment.src/transformers/loss/loss_utils.pyLOSS_MAPPING["ForConditionalGeneration"]remainsForCausalLMLossto avoid affecting decoder-only models likeLlavaForConditionalGenerationandPaliGemmaForConditionalGenerationthat rely on label shifting.Behavior
num_items_in_batch=None(default): loss is identical to the previousCrossEntropyLoss(reduction="mean")call — no behavior change.num_items_in_batchis provided by the Trainer: loss is normalized correctly across gradient accumulation steps, fixing the GA bug.Test plan
num_items_in_batch=Nonenum_items_in_batchis suppliedpytest tests/models/whisper/ -xCloses #36119