Unbundle tokenizer.json from the wheel — load from converted-checkpoint dir - #129
Open
Andrewxu313 wants to merge 8 commits into
Open
Unbundle tokenizer.json from the wheel — load from converted-checkpoint dir#129Andrewxu313 wants to merge 8 commits into
Andrewxu313 wants to merge 8 commits into
Conversation
…heckpoint dir (queue #45)
lausannel
marked this pull request as ready for review
April 20, 2026 17:48
Collaborator
|
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.
Unbundle tokenizer.json from the wheel — load from converted-checkpoint dir
Goal
Stop shipping per-model
tokenizer.jsonfiles inside the BatchGen wheel. Instead, have the checkpoint converter copytokenizer.json(andtokenizer_config.jsonif present) from the source Hugging-Face checkpoint into the converted-checkpoint output directory at conversion time, and make the runtime tokenizer abstraction load those files from the converted-checkpoint directory instead of the bundled package path.Background
BatchGen currently bundles per-model tokenizer assets as package data:
batchgen/models/openai/gpt_oss_120b/tokenizer.jsonbatchgen/models/glm/glm5/tokenizer.jsonbatchgen/models/minimax/minimax_m25/tokenizer.jsonbatchgen/models/deepseek/deepseekv3/tokenizer.jsonPlus four
tokenizer_config.jsonfiles (~8 KB each). Total: ~64 MB — roughly 14% of the wheel size.They end up in the wheel because of three cooperating declarations:
setup.py:160—package_data={"batchgen": ["**/*.json"]}MANIFEST.in:4—recursive-include batchgen *.jsonpyproject.toml:176—include_package_data=TrueAt runtime, each model's tokenizer class resolves its path via
Path(__file__).parentand loadstokenizer.jsonfrom the package directory. See e.g.:batchgen/models/minimax/minimax_m25/tokenizer.py:67—super().__init__(str(TOKENIZER_DIR))batchgen/models/openai/gpt_oss_120b/tokenizer.py:50—TOKENIZER_DIR = Path(__file__).parentbatchgen/config/fast_tokenizer.py:73—tokenizer_file = self.tokenizer_path / "tokenizer.json"The converted-checkpoint path is already a first-class concept in the server — PR #94 added
--converted-ckpt-dir. The server/worker already knows where the converted checkpoint lives at tokenizer-load time.Design
Two coordinated changes:
tokenizer.jsonandtokenizer_config.jsonfrom the source checkpoint dir to the converted-checkpoint output dir.Converter changes
File:
batchgen/ckpt_converter/ckpt_converter.pyconvert(ckpt_path, output_dir, marlin=False)(currently around line 114), after the weights are written, locatetokenizer.jsonandtokenizer_config.jsonin the source directory (ckpt_path). If found, copy them verbatim intooutput_dir.tokenizer.jsonis missing from the source, print a clear warning naming the missing file and the source path, but do not fail the conversion — some users may convert weights separately from tokenizer setup.File:
batchgen/tools/convert_checkpoint.pyTokenizer abstraction changes
File:
batchgen/config/fast_tokenizer.pyFastTokenizer.__init__(tokenizer_path)already takes a path — good. Confirm it still works unchanged.File:
batchgen/config/tokenizer_registry.pyload_tokenizer(model_identifier)→load_tokenizer(model_identifier, converted_ckpt_dir). The new argument is the directory containing the converted checkpoint (i.e. where we just copiedtokenizer.json).Files: each
batchgen/models/**/tokenizer.pythat currently hard-codesTOKENIZER_DIR = Path(__file__).parent:batchgen/models/openai/gpt_oss_120b/tokenizer.pybatchgen/models/glm/glm5/tokenizer.pybatchgen/models/deepseek/deepseekv3/tokenizer.pybatchgen/models/minimax/minimax_m25/tokenizer.pybatchgen/models/*/tokenizer.py)Change each constructor to accept the tokenizer directory as a parameter and forward it to
FastTokenizer.__init__. Remove theTOKENIZER_DIRmodule-level constant.File:
batchgen/batchgen_worker.pyself.tokenizer = load_tokenizer(self.huggingface_ckpt_name)→ pass the converted-checkpoint directory as well. The worker already knows this path from the--converted-ckpt-dirplumbing added in PR fix: add --converted-ckpt-dir server flag and fix JIT linker paths for conda environments #94; reuse that attribute, don't re-derive it.File:
batchgen/server/batch_scheduler.pytokenizer = load_tokenizer(model)— same update. Pass the converted-checkpoint dir from the existing server/config plumbing.Packaging changes
File:
setup.pypackage_dataJSON glob so it no longer capturestokenizer.json/tokenizer_config.jsonanywhere underbatchgen/models/. Keep any other*.jsonthat are genuinely package data (config schemas, model metadata BatchGen itself authors).File:
MANIFEST.inrecursive-include ... *.jsonline in tandem withsetup.py. Add exclusions for the tokenizer files underbatchgen/models/.File:
pyproject.tomlinclude_package_data=True). No change expected ifsetup.py/MANIFEST.inexclusions are correct.Delete the bundled tokenizer files from the repo
Remove from the tree (a
git rm, not an ignore):batchgen/models/openai/gpt_oss_120b/tokenizer.jsonbatchgen/models/glm/glm5/tokenizer.jsonbatchgen/models/deepseek/deepseekv3/tokenizer.jsonbatchgen/models/minimax/minimax_m25/tokenizer.jsontokenizer_config.jsonfiles in the same dirsAcceptance criteria
python -m buildproduces a wheel at least 50 MB smaller than fromorigin/main. Include the measurement in the PR description.python -m batchgen.tools.convert_checkpoint --input <hf-checkpoint-dir> --output <out>on a Hugging-Face checkpoint that containstokenizer.jsonresults in an<out>/tokenizer.jsonbyte-identical to the source (diff -qpasses).tokenizer.jsonsucceeds (exit 0) and prints a clear warning naming the missing file.load_tokenizer(model_identifier, converted_ckpt_dir)returns a working tokenizer for each of the four bundled models (GPT-OSS-120B, GLM-5, DeepSeek-V3, MiniMax-M25) when pointed at a converted-checkpoint dir with the copiedtokenizer.json.tests/unit/test_tokenizer_loading.py(new file) that, for at least one model, creates a temp dir, copies a small fixturetokenizer.json, callsload_tokenizer, and verifiesencode("hello world")returns a non-empty list.tests/e2e/gpt_oss_mmlu_pro_test/simple_completion_test.py,tests/e2e/r1_mmlu_pro_test/r1_mmlu_pro_test.py) are updated to point at a converted-checkpoint dir and still pass locally. If you can't run them, say so in the PR and tag the maintainer to verify.Path(__file__).parent-based tokenizer path resolution remains anywhere underbatchgen/models/*/tokenizer.py.git grep -n tokenizer.json batchgen/shows no results pointing at a bundled asset (only code references).tokenizer.json— verify withunzip -l dist/*.whl | grep tokenizer.json→ empty.Files expected to change
batchgen/ckpt_converter/ckpt_converter.pybatchgen/config/tokenizer_registry.pybatchgen/models/openai/gpt_oss_120b/tokenizer.pybatchgen/models/glm/glm5/tokenizer.pybatchgen/models/deepseek/deepseekv3/tokenizer.pybatchgen/models/minimax/minimax_m25/tokenizer.pybatchgen/models/*/tokenizer.pynot listed above)batchgen/batchgen_worker.pybatchgen/server/batch_scheduler.pysetup.pyMANIFEST.intests/unit/test_tokenizer_loading.py(new)tests/e2e/gpt_oss_mmlu_pro_test/simple_completion_test.py(if tokenizer loading touched)tests/e2e/r1_mmlu_pro_test/r1_mmlu_pro_test.py(if tokenizer loading touched)tokenizer.json+tokenizer_config.jsonfiles underbatchgen/models/How to test
Out of scope
tokenizer.jsonremoval (e.g., other bundled assets).--converted-ckpt-dirserver flag semantics — reuse it as-is.Reference PRs
--converted-ckpt-dirserver flag and checkpoint handling. Closest analog to the server-side plumbing you'll be reusing.batchgen_kernelsversioning. Example of packaging/setup.pychanges.Notes
convert()function must be resilient to the case where the user points it at a directory with just.safetensorsand notokenizer.json. Don't hard-fail; warn and continue.