Skip to content

Fix how we compute the final non-padding token for ForSequenceClassification models#35911

Merged
Rocketknight1 merged 12 commits into
mainfrom
fix_sequence_classification_padding_side
Feb 5, 2025
Merged

Fix how we compute the final non-padding token for ForSequenceClassification models#35911
Rocketknight1 merged 12 commits into
mainfrom
fix_sequence_classification_padding_side

Conversation

@Rocketknight1

@Rocketknight1 Rocketknight1 commented Jan 27, 2025

Copy link
Copy Markdown
Member

We have a lot of CLM models with ForSequenceClassification heads. These models are supposed to use the hidden state at the final non-padding token as the input to the classification head. However, the way they compute it is a bit weird - they get the index of the leftmost token that is equal to pad_token_id and subtract 1 from it. This has a few issues:

  • It breaks on left-padding
  • It creates index arithmetic issues when pad_token_id is absent, that need workarounds
  • It depends on implementation details of argmax(), specifically that when multiple indices have the same maximum value, it always returns the smallest one

This PR replaces that logic with simpler logic that actually searches for what we want, the rightmost non-padding token, not the token next to the leftmost padding token. This means the same logic works with left-padding, right-padding, no-padding, or even padding on both sides (I don't think any models do that, but we're ready if they do!)

Fixes #30004
Fixes #35352
Fixes #35909

@Rocketknight1
Rocketknight1 force-pushed the fix_sequence_classification_padding_side branch from 4620592 to 8ccde63 Compare January 27, 2025 19:14
@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.

@Rocketknight1

Copy link
Copy Markdown
Member Author

cc @ArthurZucker for core maintainer review - but if you have too much to do, let me know and I'll find another reviewer!

@Rocketknight1

Copy link
Copy Markdown
Member Author

cc @Cyrilvallez actually, as core-maintainer-in-training

@Cyrilvallez Cyrilvallez 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.

Hey! Nicely done, indeed much simpler than before! Just added some small comments! Let me know what you think!

Comment thread src/transformers/models/bloom/modeling_bloom.py
Comment thread src/transformers/models/bloom/modeling_bloom.py Outdated
Comment thread src/transformers/models/bloom/modeling_bloom.py Outdated
Comment thread src/transformers/models/ctrl/modeling_tf_ctrl.py
Comment on lines +959 to +963
last_non_pad_token = -1
logger.warning_once(
f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
"unexpected if using padding tokens in conjunction with `inputs_embeds.`"
)

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.

Instead of adding the warning everywhere, maybe we should do it the other way around and actually remove it from the few classes where it is present? It is a fairly niche case, and people using it should be aware of the caveat IMO. It's nice to have less warnings in general, WDYT? (It would allow to simplify branching as well)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm - I think a lot of classes actually support inputs_embeds as well as input_ids, so we still need this on most classes I think! It just only fires when users actually pass inputs_embeds and not input_ids.

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.

Be aware that it breaks torch.compile as well, would anyone want to use it! But once again, it is quite a niche case, and it's already here for some models, so I'll let you judge -- we can keep it if you think that removing it would bring confusion/error for users 🤗

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it's better to leave the warning, because the results will generally be wrong in that case. In future, we might consider raising an error and asking users to supply an attention_mask in that case!

@Cyrilvallez Cyrilvallez 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.

All right, LGTM! Thank you very much!

@Rocketknight1
Rocketknight1 merged commit 694aaa7 into main Feb 5, 2025
@Rocketknight1
Rocketknight1 deleted the fix_sequence_classification_padding_side branch February 5, 2025 16:23
MekkCyber pushed a commit that referenced this pull request Feb 7, 2025
…ication models (#35911)

* Fix how we compute the final non-padding token for Gemma (and probably other models)

* .size() -> .shape[]

* Propagating changes to other models

* Propagating changes to other models

* Change it for all ForSequenceClassification models

* Fix batch dim

* More TF fixes

* Copy the TF fix around as well

* Correct layer name for TFCTRL

* Cleaner .to()

* Clean up the nested if-else

* Use argmax() instead of .max().values
elvircrn pushed a commit to elvircrn/transformers that referenced this pull request Feb 13, 2025
…ication models (huggingface#35911)

* Fix how we compute the final non-padding token for Gemma (and probably other models)

* .size() -> .shape[]

* Propagating changes to other models

* Propagating changes to other models

* Change it for all ForSequenceClassification models

* Fix batch dim

* More TF fixes

* Copy the TF fix around as well

* Correct layer name for TFCTRL

* Cleaner .to()

* Clean up the nested if-else

* Use argmax() instead of .max().values
sbucaille pushed a commit to sbucaille/transformers that referenced this pull request Feb 16, 2025
…ication models (huggingface#35911)

* Fix how we compute the final non-padding token for Gemma (and probably other models)

* .size() -> .shape[]

* Propagating changes to other models

* Propagating changes to other models

* Change it for all ForSequenceClassification models

* Fix batch dim

* More TF fixes

* Copy the TF fix around as well

* Correct layer name for TFCTRL

* Cleaner .to()

* Clean up the nested if-else

* Use argmax() instead of .max().values
Sunt-ing added a commit to Sunt-ing/transformers that referenced this pull request Jun 19, 2026
BioGptForSequenceClassification was the last decoder classification head
still using the legacy pooling index (input_ids != pad).sum(-1) - 1, which
is the last real token only under right padding. With left padding the real
tokens are shifted to the end, so the head pooled an earlier token and
returned silently wrong logits and loss. Use the same left/right-padding
safe selection as the other decoders (from huggingface#35911).

Signed-off-by: Ting Sun <[email protected]>
pull Bot pushed a commit to tianhm/transformers that referenced this pull request Jun 22, 2026
…huggingface#46782)

Fix left-padding token selection in BioGptForSequenceClassification

BioGptForSequenceClassification was the last decoder classification head
still using the legacy pooling index (input_ids != pad).sum(-1) - 1, which
is the last real token only under right padding. With left padding the real
tokens are shifted to the end, so the head pooled an earlier token and
returned silently wrong logits and loss. Use the same left/right-padding
safe selection as the other decoders (from huggingface#35911).

Signed-off-by: Ting Sun <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants