Map prepended text to a zero-width span to avoid overlapping offsets (#1775)#2149
Open
v-code01 wants to merge 1 commit into
Open
Map prepended text to a zero-width span to avoid overlapping offsets (#1775)#2149v-code01 wants to merge 1 commit into
v-code01 wants to merge 1 commit into
Conversation
NormalizedString::prepend borrowed the first original character's offsets for the prepended text (which has no counterpart in the original input). Once a tokenizer split the prepended marker into its own token -- e.g. CJK text under the Metaspace pre-tokenizer, where "中文" becomes tokens ["▁", "中文"] -- the marker token and the following token both claimed the first character's bytes, producing overlapping offsets and making char_to_token point at the wrong token (huggingface#1775). Prepend now inserts the text as new characters at an empty range, mapping it to a zero-width span at the start while leaving the existing characters' offsets untouched. ByteLevel's byte-level remap is updated to transform over the full normalized range (rather than the original range) so the now-zero-width prefix byte -- e.g. the prefix space from add_prefix_space -- is still covered. Adds a multi-byte prepend regression test and updates the prepend alignment expectations to the corrected zero-width behaviour.
Author
|
cc @ArthurZucker @McPatate — this fixes #1775 (overlapping offsets → |
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.
Problem
char_to_token()can point to the wrong token for tokenizers that use a Metaspace-style prefix (e.g.DebertaV2TokenizerFast,XLMRobertaTokenizerFast), because token offsets overlap on multi-byte scripts. Reported in #1775.Root cause is in
NormalizedString::prepend. It mapped the prepended text — which has no counterpart in the original input — onto the first original character's byte range. That is invisible while the prefix stays glued to the following text, but once the model splits the prepended marker into its own token it surfaces. For"中文"under Metaspace (xlm-roberta), the tokens are["▁", "中文"]and the offsets were:so
char_to_token(0)resolves to▁instead of中文. Reproduces on Chinese and Japanese samples; Latin/Cyrillic/Korean don't split the▁wordunit, so they never exposed it.Fix
Prepended text has no source in the original string, so it should map to a zero-width span at the start.
prependnow inserts the text as new characters at an empty range, leaving the existing characters' offsets untouched:ByteLevel's byte-level remap is updated to transform over the full normalized range instead of the original range, so the now-zero-width prefix byte (e.g. the prefix space fromadd_prefix_space) is still covered — otherwise it would be excluded and desync the transformation offsets.Tests
prepend_multibyte_no_overlapregression test (the exact CJK +▁case).prependandPrepend-normalizer alignment expectations to the corrected zero-width behaviour.cargo test, withmake testdata), including allbyte_level,added_tokens, andnormalizertests.cargo fmt/cargo clippyclean.Every prepend caller in the tree (Metaspace, ByteLevel's leading space, the
Prependnormalizer) prepends synthetic text, so zero-width alignment is correct for all of them.