Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/megatron/bridge/inference/_tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ def __init__(
) -> None:
self._tokenizer = tokenizer
self._force_skip_special_tokens = force_skip_special_tokens
# MCore's incremental detokenizer treats ``_tokenizer`` as its Hugging Face wrapper.
if not hasattr(tokenizer, "tokenizer"):
tokenizer.tokenizer = tokenizer
if not hasattr(tokenizer, "include_special_tokens"):
tokenizer.include_special_tokens = force_skip_special_tokens is False
Comment on lines +49 to +53

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These attributes are set on tokenizer (the wrapped HF tokenizer, stored as self._tokenizer), but the object handed to HuggingFaceFastIncrementalDetokenizer in the new test is the adapter itself (self), not the wrapped tokenizer:

adapter = HFTokenizerAdapter(tokenizer)
detokenizer = HuggingFaceFastIncrementalDetokenizer(adapter, [])

If MCore's detokenizer reads .tokenizer / .include_special_tokens off the argument it's constructed with, it will look at adapter.tokenizer / adapter.include_special_tokens — which are never set here (the adapter has no __getattr__ forwarding). It would only "work" via a getattr(..., default) fallback in MCore, in which case this whole block is dead code w.r.t. the adapter path.

Can you confirm MCore reads these off the wrapped HF tokenizer and not off the adapter? If it reads off the adapter, these should be self.tokenizer = tokenizer and self.include_special_tokens = ....

if set_pad_token and tokenizer.pad_token is None and tokenizer.eos_token is not None:
tokenizer.pad_token = tokenizer.eos_token
self.eod = tokenizer.eos_token_id
Expand Down
17 changes: 17 additions & 0 deletions tests/unit_tests/inference/test_tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

from __future__ import annotations

from megatron.core.inference.text_generation_server.dynamic_text_gen_server.incremental_detokenizer import (
HuggingFaceFastIncrementalDetokenizer,
)
from tokenizers import Tokenizer, models
from transformers import PreTrainedTokenizerFast

from megatron.bridge.inference._tokenizer import HFTokenizerAdapter


Expand Down Expand Up @@ -119,3 +125,14 @@ def test_openai_server_preserves_hf_chat_template_contract():
},
)
]


def test_openai_streaming_accepts_hf_fast_tokenizer_adapter():
backend = Tokenizer(models.WordLevel(vocab={"[UNK]": 0, "hello": 1}, unk_token="[UNK]"))
tokenizer = PreTrainedTokenizerFast(tokenizer_object=backend, unk_token="[UNK]", eos_token="[UNK]")
adapter = HFTokenizerAdapter(tokenizer)

detokenizer = HuggingFaceFastIncrementalDetokenizer(adapter, [])

assert detokenizer.text == ""
assert detokenizer.update([tokenizer.eos_token_id]) == ""
Loading