feat(bindings): Python bindings rework, plugging PipelineTokenizer#2229
Draft
SBrandeis wants to merge 19 commits into
Draft
feat(bindings): Python bindings rework, plugging PipelineTokenizer#2229SBrandeis wants to merge 19 commits into
SBrandeis wants to merge 19 commits into
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
SBrandeis
force-pushed
the
feat/pipeline-python-api
branch
from
July 22, 2026 09:09
2d39468 to
df231fb
Compare
SBrandeis
force-pushed
the
feat/pipeline-python-api
branch
from
July 22, 2026 15:48
ed30269 to
711a49c
Compare
Co-authored-by: Simon Brandeis <33657802+SBrandeis@users.noreply.github.com>
SBrandeis
force-pushed
the
feat/pipeline-python-api
branch
from
July 23, 2026 13:27
711a49c to
4a17bff
Compare
* golden end-to-end tests through transformers v5 Same suite, two builds: `make golden-release` runs it on the tokenizers wheel transformers resolves (always green, defines the target behavior); `make golden` runs it on the in-tree build, where the failures enumerate what the 1.0 rewrite is still missing. Four layers: the tokenizers API driven directly, the transformers tokenizer API, inference (generate/ pipeline), and training (Trainer/collators). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * deepen golden tests with the transformers example recipes Scenarios lifted from the maintained examples/pytorch/ scripts at v5.14.1: run_qa's overflow/stride/sequence_ids/offsets span labeling, run_ner's word_ids label alignment, run_mlm's special_tokens_mask + masking collator, run_translation's text_target and seq2seq collator, plus token-classification pipeline spans, encoder-decoder generate, and the T5 Unigram+Metaspace archetype in the direct-API layer. 31 tests, all green on the release wheel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * golden production flows: chat serving, RAG, SFT Story-shaped tests mirroring how production stacks drive the tokenizer: chat serving (ChatML template + control tokens as added specials + history truncation to a token budget + left-padded batch generate + TextIteratorStreamer streaming == one-shot decode), RAG (token-budget chunking via offsets with exact source spans + mean-pooled embeddings + retrieval), and SFT (TRL-style completion-only masking, tokenizer pickled through datasets.map(num_proc=2), Trainer steps). 34 tests green on the release wheel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * golden conformance layer; rename the scenario suite to e2e tests/golden now holds true golden-master tests: goldens/*.jsonl record everything the released wheel (0.23.1) produces on the 8 bench-model tokenizers — ids, tokens, offsets, masks, word ids, decodes and pair encodings for fixture excerpts and edge-case strings, plus ids digests over the fixture corpora. generate.py regenerates them from .release/ (never hand-edited, guarded); test_golden.py replays the inputs on the current build, one test per output domain per model, so failures read as a conformance matrix. Opt-in via TOKENIZERS_GOLDEN (make golden) until the rewrite is green, then the gate should be dropped. The transformers scenario suite moves to tests/e2e (make e2e / e2e-release) — flows there, values here. CI: e2e-release and golden-freshness (regen must reproduce the committed goldens byte for byte) required; one informational in-tree job runs both. First catch, dev build vs release on llama-2: identical ids but tokens[0] renders as '▁<s>' instead of '<s>' — the Prepend normalizer leaks into the inserted special token's string. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * add huggingface_hub to the dev venv from_pretrained needs it (the wheel's optional hub extra), so the network-marked pretrained test failed in a fresh venv — it only worked after `make examples` pulled the dep in via datasets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * review pass: scope HF_TOKEN per step, unshadow offset loop var Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * iter Makefile * fix tk-encode doctest: fence PipelinePostProcessor example as text rustdoc compiles indented doc blocks as Rust doctests; the example is an illustration, not compilable code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix Python lint under ruff 0.16 defaults; pin ruff in CI ruff 0.16.0 widened the default rule set, breaking CI with no code change: import sorting (I001), loop vars captured by bench lambdas (B023), implicit string concat in lists (ISC004), open() without a context manager (SIM115), zip-for-pairwise (RUF007), and a blind pytest.raises(Exception) (B017). Pin the CI ruff so rule-set changes land deliberately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
TL;DR
Rewrite the Python bindings on
PipelineTokenizer(tokenizers v1.0)This is a big diff because it swaps one implementation for another: ~26k lines of the
old bindings go, ~6k come in.
Intent
What changed
multi-threaded, inputs are borrowed (not copied), and ids come back as
numpy.uint32with no copy.encode/encode_batch→Encoding/EncodingBatchfor compatibility with the ecosystem (with the transformers lib, notably). Misses a lot of features atmencode_ids/encode_batch_ids->numpy.ndarray: fast path when you just want the id array. Same encode work either way.BPE. Components (normalizer/pre-tokenizer/model) are plain values you assign.
word_ids,offsets,decode, and post-processing (special-token insertion)...TODO
attention_mask.[CLS]/[SEP]/<s>inserype_ids` and pair inputs.PipelineTokenizer benchmark
7 / 8 models supported — PipelineTokenizer vs
tokenizersv0.23.1 (latest release) · ~10 kB inputs · single thread + 1/2/4/8/max-thread sweepd546c7d52 · 2026-07-22 10:49 UTC· Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz · 48 coresvs base branch (
575582072) — per-model geomean ×speedup of this PR's PipelineTokenizer against the base branch's; regressions in red.bert-base-uncased — normalizer-heavy WordPiece · ×4.90 vs v0.23.1 · ×1.00 vs base
Memory (RSS MB, load+encode): v0.23.1 12+1 (peak 12) · Pipeline 8+0 (peak 17)
deepseek-v4 — deepseek 3-regex split-heavy byte-level BPE · ×4.02 vs v0.23.1 · ×1.03 vs base
Memory (RSS MB, load+encode): v0.23.1 62+0 (peak 67) · Pipeline 96+0 (peak 96)
Pre-tokenize:
classify + fsmvs regex engines — ns/byte, lower better. The fsm is the scalar jump-table in both pipe columns; SIMD / scalar is the classify pass (regex pre-tokenizers have no SIMD fsm).×vs= engine ÷ our pipeline (SIMD / scalar classify);onig&pcre2(JIT) are C,fancyis pure-Rust fancy-regex,logosis a compile-time DFA lexer (approximate grammar; n/a for deepseek).gpt2 — gpt2 ByteLevel regex · ×7.35 vs v0.23.1 · ×1.01 vs base
Memory (RSS MB, load+encode): v0.23.1 25+2 (peak 27) · Pipeline 30+0 (peak 30)
Pre-tokenize:
classify + fsmvs regex engines — ns/byte, lower better. The fsm is the scalar jump-table in both pipe columns; SIMD / scalar is the classify pass (regex pre-tokenizers have no SIMD fsm).×vs= engine ÷ our pipeline (SIMD / scalar classify);onig&pcre2(JIT) are C,fancyis pure-Rust fancy-regex,logosis a compile-time DFA lexer (approximate grammar; n/a for deepseek).gpt-oss — o200k-regex byte-level BPE (gpt-oss) · ×7.65 vs v0.23.1 · ×1.02 vs base
Memory (RSS MB, load+encode): v0.23.1 4+11 (peak 16) · Pipeline 7+0 (peak 7)
Pre-tokenize:
classify + fsmvs regex engines — ns/byte, lower better. The fsm is the scalar jump-table in both pipe columns; SIMD / scalar is the classify pass (regex pre-tokenizers have no SIMD fsm).×vs= engine ÷ our pipeline (SIMD / scalar classify);onig&pcre2(JIT) are C,fancyis pure-Rust fancy-regex,logosis a compile-time DFA lexer (approximate grammar; n/a for deepseek).glm-5.2 — cl100k-variant regex byte-level BPE (glm-5.2) · ×13.35 vs v0.23.1 · ×1.02 vs base
Memory (RSS MB, load+encode): v0.23.1 4+11 (peak 16) · Pipeline 6+0 (peak 6)
Pre-tokenize:
classify + fsmvs regex engines — ns/byte, lower better. The fsm is the scalar jump-table in both pipe columns; SIMD / scalar is the classify pass (regex pre-tokenizers have no SIMD fsm).×vs= engine ÷ our pipeline (SIMD / scalar classify);onig&pcre2(JIT) are C,fancyis pure-Rust fancy-regex,logosis a compile-time DFA lexer (approximate grammar; n/a for deepseek).llama-2 — model-bounded BPE, no pre-tokenizer · ×3.26 vs v0.23.1 · ×1.02 vs base
Memory (RSS MB, load+encode): v0.23.1 19+0 (peak 23) · Pipeline 22+0 (peak 21)
llama-3 — cl100k-regex byte-level BPE (llama-3), single regex · ×6.95 vs v0.23.1 · ×1.07 vs base
Memory (RSS MB, load+encode): v0.23.1 143+0 (peak 199) · Pipeline 144+0 (peak 199)
Pre-tokenize:
classify + fsmvs regex engines — ns/byte, lower better. The fsm is the scalar jump-table in both pipe columns; SIMD / scalar is the classify pass (regex pre-tokenizers have no SIMD fsm).×vs= engine ÷ our pipeline (SIMD / scalar classify);onig&pcre2(JIT) are C,fancyis pure-Rust fancy-regex,logosis a compile-time DFA lexer (approximate grammar; n/a for deepseek).Not yet supported:
t5-basenumbers (MB/s)