Skip to content

Fix Florence2 training-loss double-shift (same pattern as Moonshine #…#46898

Merged
zucchini-nlp merged 11 commits into
huggingface:mainfrom
sharmax-vikas:fix/florence2-double-shift-loss
Jun 29, 2026
Merged

Fix Florence2 training-loss double-shift (same pattern as Moonshine #…#46898
zucchini-nlp merged 11 commits into
huggingface:mainfrom
sharmax-vikas:fix/florence2-double-shift-loss

Conversation

@sharmax-vikas

@sharmax-vikas sharmax-vikas commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

CI

What does this PR do?

Fixes #46897

Fix double-shift training-loss bug in Florence2ForConditionalGeneration - the exact same pattern fixed in Moonshine (#46784) and CohereASR (#46894).

Florence2ForConditionalGeneration.forward() shifts labels right via shift_tokens_right() to create decoder_input_ids, then calls self.loss_function() which maps to ForCausalLMLoss. That function shifts labels again internally (labels[..., 1:]), so the model trains against labels[..., 1:] instead of labels.

The fix replaces self.loss_function() with plain CrossEntropyLoss(), matching the approach used in Whisper, Bart, and the now-fixed Moonshine.

Both modular_florence2.py (source of truth) and modeling_florence2.py (auto-generated) are updated.

Who can review?

@zucchini-nlp @yonigozlan (multimodal/vision-language models)


CI recap

Dashboard: View test results in Grafana
Latest run: 28365382183:2
Result: success | Jobs: 2 | Tests: 19 | Failures: 0 | Duration: 2m 2s

…uggingface#46784)

Florence2ForConditionalGeneration shifts labels right via shift_tokens_right()
to create decoder_input_ids, then calls self.loss_function() which maps to
ForCausalLMLoss — that function shifts labels again internally. This causes
the model to train against labels[..., 1:] instead of labels.

Replace self.loss_function() with plain CrossEntropyLoss, matching the fix
applied to Moonshine in huggingface#46784 and CohereASR.
Comment on lines +905 to +906
loss = self.loss_function(
logits=logits, labels=labels, vocab_size=self.config.text_config.vocab_size, **kwargs
)
loss_fct = CrossEntropyLoss()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can pass shift_labels=labels into loss-fn to not sift it twice

>>> processor.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
"A green car parked in front of a yellow building."
```"""
do_shift_labels = False

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do_shift_labels is always True imo since users prepare labels by copying input ids, and shift decoder-input-ids when created by a collator. CMIIW, I can't remember a train use-case with non-shifted inputs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified - removed the do_shift_labels flag entirely, now always passing shift_labels=labels when labels are present. Thanks for the feedback!

@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@github-actions

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: florence2

@zucchini-nlp zucchini-nlp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, merging

@zucchini-nlp
zucchini-nlp enabled auto-merge June 29, 2026 10:36
@zucchini-nlp
zucchini-nlp added this pull request to the merge queue Jun 29, 2026
Merged via the queue into huggingface:main with commit 2370ba6 Jun 29, 2026
34 checks passed
eliaghazal added a commit to eliaghazal/transformers that referenced this pull request Jul 17, 2026
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.
ShamSaleem added a commit to ShamSaleem/transformers that referenced this pull request Jul 23, 2026
PPFormulaNetForConditionalGeneration.forward() computes its loss via
self.loss_function() (ForCausalLMLoss), which left-shifts labels by one
(labels[..., 1:]). PPFormulaNet is an encoder-decoder model whose logits are
already aligned with labels, so this extra shift drops the last target token
and trains the model against misaligned labels.

Pass shift_labels=labels so ForCausalLMLoss skips its internal shift and keeps
labels aligned with logits. This is the same fix already merged for Florence2
in huggingface#46898; PPFormulaNet inherits from Florence2 but overrides forward(), so the
fix did not propagate.

Fixes huggingface#47317
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Florence2 training-loss double-shift bug (same pattern as Moonshine #46784)

3 participants