fix: un-blocklist deepseek_v3 in transformers tokenizer class set - #3116
Merged
Conversation
ZhiyuLi-Nvidia
force-pushed
the
fix/moonlight-tokenizer-offline-2764
branch
2 times, most recently
from
July 8, 2026 17:52
1b10a01 to
02e7e91
Compare
Contributor
Author
|
/ok to test 02e7e91 |
Contributor
Author
|
/ok to c82d9a0 |
yuki-97
reviewed
Jul 9, 2026
yuki-97
left a comment
Contributor
There was a problem hiding this comment.
@ZhiyuLi-Nvidia thanks for the fix! left some minor comments.
Fixes #2764. transformers 5.4-5.11 lists "deepseek_v3" in two internal registries -- MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS (a set) and TOKENIZER_MAPPING_NAMES (a dict pinning it to "TokenizersBackend"). Together they force the fast tokenizer backend and suppress trust_remote_code, so AutoTokenizer can only load via a local tokenizer.json. Models like Moonlight-16B-A3B ship no tokenizer.json (only tiktoken.model + a remote-code TikTokenTokenizer), so offline loading fails with "Couldn't instantiate the backend tokenizer". Two coordinated patches: 1. nemo_rl/__init__.py: discard "deepseek_v3" from both registries at nemo_rl import time. Adds a version assertion that fires if transformers is bumped past 5.12 (upstream fix), noting Megatron-Bridge is the current blocker for that bump. 2. nemo_rl/models/megatron/setup.py: set megatron_cfg.tokenizer.trust_remote_code attribute directly. The pre-existing hf_tokenizer_kwargs["trust_remote_code"] dict mutation was dead code because Megatron-Bridge's TokenizerConfig snapshots hf_tokenizer_kwargs into plain attributes at __post_init__ and never re-reads the dict afterwards. Both patches are held together by the same MBridge-caps-transformers-below-5.12 dependency chain and can be dropped together once that pin is relaxed. Verified end-to-end: llm_grpo_moonlight_16b_automodel_1n8g_ep8 trains 10+ steps offline; llm_grpo_moonlight_16ba3b_4n8g_megatron trains 17+ steps offline with KL 0.0003 stable, no NaN, zero backend-tokenizer errors on driver or 32 workers. Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
ZhiyuLi-Nvidia
force-pushed
the
fix/moonlight-tokenizer-offline-2764
branch
from
July 9, 2026 08:57
f421f4b to
a74e966
Compare
…sert String comparison "5.5.0" < "5.12.0" is False in Python (lexicographic '5' > '1' at the minor position), so the assertion would fire and raise AssertionError on every import for every currently-pinned transformers version (>=5.5.0,<5.9.0). Switch to packaging.version.Version. Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
…op packaging dep) Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
…y canonical pattern Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
Contributor
Author
|
/ok to test ca6a042 |
The lint CI's editable install pipeline (uv sync + setuptools) imports nemo_rl to statically read __version__ before deps are guaranteed to be present. Without a guard, 'import transformers' at nemo_rl load time crashes the build with 'nemo_rl has no attribute __version__'. Wrap the top-level 'import transformers' in try/except so the patch becomes a no-op under build isolation. Runtime venv always has the package, so the assertion + discards still fire in real use. Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
…ead of try/except Same rationale as the existing _check_container_fingerprint guard on line 99: setuptools' uv-based build isolation imports nemo_rl to read __version__, but transformers isn't in the isolated build env. Match the existing pattern -- skip the patch at the call site under build isolation, keep the function body clean (no exception handling for control flow). Runtime venv is never a build isolation, so the patch still fires in real use. Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
…emo_rl.models.policy.__init__ The patch is only needed by policy code paths that eventually call AutoTokenizer.from_pretrained -- driver's get_tokenizer(), Megatron worker's build_tokenizer, DTensor worker's tokenizer reconstruction. All three share nemo_rl.models.policy as an import ancestor. Placing it in nemo_rl.models.policy.__init__.py fires exactly once per process when policy code is first imported. Non-policy consumers (tests, utilities, environments) no longer mutate the global transformers registries as a side effect of importing nemo_rl. Bonus: setuptools build isolation reads nemo_rl.__version__ from nemo_rl.__init__.py but never cascades into models/policy, so the _is_build_isolation() guard is no longer needed at the call site. Verified locally with 'from nemo_rl.models.policy import PolicyConfig': deepseek_v3 removed from MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS and TOKENIZER_MAPPING_NAMES as expected. Signed-off-by: Zhiyu Li <zhiyul@NVIDIA.com>
Contributor
Author
|
/ok to test 0405109 |
yuki-97
approved these changes
Jul 9, 2026
yuki-97
left a comment
Contributor
There was a problem hiding this comment.
LGTM, thanks @ZhiyuLi-Nvidia @ahmadki
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.
Summary
#2764
Two coordinated fixes so Moonlight-16B-A3B (and any future
deepseek_v3model) can load its tokenizer offline.Bug 1 — transformers blocks the tokenizer
transformers 5.4–5.11 lists
"deepseek_v3"in two internal registries that together force the fast tokenizer backend and suppresstrust_remote_code:MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS(set)tokenizer_class/auto_mapTOKENIZER_MAPPING_NAMES(dict)deepseek_v3toTokenizersBackend(fast)Under
HF_HUB_OFFLINE=1the fast backend can't enumerate the repo to findtiktoken.modeland fails. Moonlight ships notokenizer.json, only a slowTikTokenTokenizerreachable viaauto_map— so the online fallback also can't help.Fix:
nemo_rl/__init__.pyremoves both entries at import time.discard/pop-with-defaultare no-ops if the entries are absent, so the patch is safe on any transformers version.Bug 2 — dead code in Megatron tokenizer setup
nemo_rl/models/megatron/setup.py:setup_model_and_optimizerused to mutatehf_tokenizer_kwargs["trust_remote_code"] = Trueon the MegatronTokenizerConfig. This was dead code:__post_init__(empty dict)trust_remote_codedict.get("trust_remote_code", False)= Falsetokenizer_hf_no_use_fastnot dict.get("use_fast", True)= False (i.e.use_fast=True)use_fast=Truevia defaultuse_fast=TrueRoot cause of the deadness:
TokenizerConfig.__post_init__(seeMegatron-Bridge/src/megatron/bridge/training/tokenizers/config.py) snapshotshf_tokenizer_kwargsinto plain attributes once at construction time; from then onbuild_tokenizerreads the attribute, not the dict.Fix: assign the attribute directly —
megatron_cfg.tokenizer.trust_remote_code = True. This is the API Megatron-Bridge's own deprecation notice recommends.Blast radius of the
trust_remote_code=TrueflipHistorically every model on this Megatron path ran with
trust_remote_code=False(the dead-code effect above). Making it actuallyTrue:auto_map/tokenizer_classpointing at remote code.Test plan
llm_grpo_moonlight_16b_automodel_1n8g_ep8(1n8g automodel) — 10+ training steps offline, KL 0.0003, no NaN, no backend-tokenizer errors on driver + 8 workers.llm_grpo_moonlight_16ba3b_4n8g_megatron(4n8g Megatron) — 17+ training steps offline, KL 0.0003 stable across steps, zero tokenizer errors on driver + 32 workers.import nemo_rl; "deepseek_v3" not in MODELS_WITH_INCORRECT_HUB_TOKENIZER_CLASS and "deepseek_v3" not in TOKENIZER_MAPPING_NAMES→ True.AutoTokenizer.from_pretrained("moonshotai/Moonlight-16B-A3B-Instruct", trust_remote_code=True)returnsTikTokenTokenizerwith byte-identicalinput_idsto the worker-sideNeMoAutoTokenizerWithBosEosEnforcedunderadd_special_tokens=False.llm_grpo_moonlight_16ba3b_4n8g_megatron_tq_simpleand_fp8_e2e— variants of the base 4n8g recipe; expected to pass since the fix is at tokenizer construction (pre-quantization).