Fix Florence2 training-loss double-shift (same pattern as Moonshine #…#46898
Conversation
…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.
| loss = self.loss_function( | ||
| logits=logits, labels=labels, vocab_size=self.config.text_config.vocab_size, **kwargs | ||
| ) | ||
| loss_fct = CrossEntropyLoss() |
There was a problem hiding this comment.
we can pass shift_labels=labels into loss-fn to not sift it twice
…as called (per reviewer)
| >>> 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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Simplified - removed the do_shift_labels flag entirely, now always passing shift_labels=labels when labels are present. Thanks for the feedback!
|
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. |
|
[For maintainers] Suggested jobs to run (before merge) run-slow: florence2 |
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.
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
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 viashift_tokens_right()to createdecoder_input_ids, then callsself.loss_function()which maps toForCausalLMLoss. That function shifts labels again internally (labels[..., 1:]), so the model trains againstlabels[..., 1:]instead oflabels.The fix replaces
self.loss_function()with plainCrossEntropyLoss(), matching the approach used in Whisper, Bart, and the now-fixed Moonshine.Both
modular_florence2.py(source of truth) andmodeling_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