Skip to content

fix(tokenizer): do not strip a BOS token the tokenizer does not have - #1629

Merged
jlarson4 merged 1 commit into
TransformerLensOrg:dev-4.xfrom
sohv:fix/tokenizer-bos-removal
Aug 10, 2026
Merged

fix(tokenizer): do not strip a BOS token the tokenizer does not have#1629
jlarson4 merged 1 commit into
TransformerLensOrg:dev-4.xfrom
sohv:fix/tokenizer-bos-removal

Conversation

@sohv

@sohv sohv commented Aug 8, 2026

Copy link
Copy Markdown

get_tokens_with_bos_removed assumed the tokenizer has a bos_token_id. When cfg.tokenizer_prepends_bos goes stale the helper is reached anyway, and it then does damage in two directions.

Under right padding, which is the default, it drops the first token unconditionally. For a BERT tokenizer that silently removes [CLS] and returns a plausible looking wrong result. Under left padding it evaluates (tokens == None).int(), which is a Python bool rather than a tensor, and raises AttributeError: 'bool' object has no attribute 'int'.

What I changed

With no bos_token_id there is nothing to remove, so the helper returns the tokens unchanged. This is correct however the config got out of sync, it fixes both symptoms, and it leaves the boot_transformers path untouched.

What I did not change and why

The root cause is the reassignment test at bridge_core.py:113. I left it alone, and not only because it alters build and attach semantics. Correcting the flag would route to_tokens(prepend_bos=True) into the manual prepend branch at transformer_bridge.py:716, which calls get_input_with_manually_prepended_bos(tokenizer.bos_token, ...) and raises TypeError: unsupported operand type(s) for +: 'NoneType' and 'str' when there is no BOS token. The stale flag is currently masking that, so the root cause fix needs the prepend path hardened first. Happy to take that on as a follow up if you want it.

Verification

Six unit tests, four of which are red on dev-4.x. The two that pass either way are controls confirming a real BOS is still removed for distilgpt2 on both padding sides.

Reproduced with two off the shelf tokenizers, google-bert/bert-base-cased and google-t5/t5-small, both of which have bos_token_id set to None.

get_tokens_with_bos_removed assumed a bos_token_id exists. Callers gate it on
cfg.tokenizer_prepends_bos, which detect_tokenizer_bos_eos only sets when the
tokenizer has one, but the flag goes stale on a bridge built via
build_bridge_from_module(tokenizer=None) and given a tokenizer afterwards: the
setter re-runs configure_tokenizer only on reassignment, so the config default
of True survives.

Trusting it then does damage in both directions. Under right padding, the
default, the helper drops the first token unconditionally, silently removing
[CLS] from a BERT tokenizer's output and returning a plausible-looking wrong
result. Under left padding it evaluates (tokens == None).int() and raises
AttributeError: 'bool' object has no attribute 'int', which names neither the
tokenizer nor the flag.

Return the tokens unchanged when there is no bos_token_id: with no BOS there is
nothing to remove, which is correct however the config got out of sync.

Reproduced with two off-the-shelf tokenizers, bert-base-cased and t5-small,
both of which have bos_token_id None. The normal boot_transformers path is
unaffected, since detection runs there.

The root cause is the reassignment test in bridge_core.py, left alone
deliberately. Correcting the flag would route to_tokens(prepend_bos=True) into
the manual-prepend branch at transformer_bridge.py:716, which calls
get_input_with_manually_prepended_bos(tokenizer.bos_token, ...) and raises
TypeError on a None bos_token. The stale flag currently masks that, so the
root-cause fix needs the prepend path hardened first.

Fixes TransformerLensOrg#1628

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jlarson4

Copy link
Copy Markdown
Collaborator

Looks good @sohv, thanks for filing and tackling this issue. Feel free to file the follow-up and work on that at your convenience.

@jlarson4
jlarson4 merged commit 4574892 into TransformerLensOrg:dev-4.x Aug 10, 2026
25 checks passed
@jlarson4

Copy link
Copy Markdown
Collaborator

@sohv It looks like @Chinmayrawat15 has already addressed that follow up in #1634.

@sohv

sohv commented Aug 10, 2026

Copy link
Copy Markdown
Author

@jlarson4 Great and thanks for the merge! Please also take a look at #1627 and let me know if you have any issues.

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.

2 participants