Add HuggingFace pretrained vocab provider and refactor bench data ite… - #382
Open
crutcher wants to merge 7 commits into
Open
Add HuggingFace pretrained vocab provider and refactor bench data ite…#382crutcher wants to merge 7 commits into
crutcher wants to merge 7 commits into
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Member
Author
further progress; I have a dirty loader; but no tests. |
…ration
- Add `huggingface` feature and `HFVocabProvider` for loading tokenizers from HuggingFace Hub
- Refactor bench data methods to use `.values()` instead of `.iter()` for cleaner iteration
- Fix clippy warning by allowing explicit counter loop in datagym vocab.
This is broken still:
```
crutcher@HeatLamp:~/git/wordchipper$ echo 'hello world' | cargo run -p wordchipper-cli -- cat --model 'hf:Xenova/gpt2' --encode
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
Running `target/debug/wordchipper-cli cat --model 'hf:Xenova/gpt2' --encode`
Error: External("No pre-tokenizer")
```
- Add support for ByteLevel and Sequence pre-tokenizers in addition to Split
- Implement proper byte-to-unicode mapping for byte-level BPE vocabularies
- Filter out special tokens when building span maps
- Extract and validate split patterns from pre-tokenizer configurations
- Add `bytes_char()` function implementing GPT-2 style byte-to-unicode conversion
- Use GPT2_PATTERN as default for bare ByteLevel pre-tokenizers
- Improve error messages with detailed context about unsupported configurations
```terminaloutput
crutcher@HeatLamp:~/git/wordchipper$ echo 'hello world' | cargo run -p wordchipper-cli -- cat --model 'cl100k_base' --encode
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/wordchipper-cli cat --model cl100k_base --encode`
15339 1917 198
crutcher@HeatLamp:~/git/wordchipper$ echo 'hello world' | cargo run -p wordchipper-cli -- cat --model 'hf:Xenova/text-embedding-ada-002' --encode
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
Running `target/debug/wordchipper-cli cat --model 'hf:Xenova/text-embedding-ada-002' --encode`
15339 1917 198
crutcher@HeatLamp:~/git/wordchipper$ echo 'hello world' | cargo run -p wordchipper-cli -- cat --model 'openai:gpt2' --encode
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
Running `target/debug/wordchipper-cli cat --model 'openai:gpt2' --encode`
31373 995 198
crutcher@HeatLamp:~/git/wordchipper$ echo 'hello world' | cargo run -p wordchipper-cli -- cat --model 'hf:Xenova/gpt2' --encode
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
Running `target/debug/wordchipper-cli cat --model 'hf:Xenova/gpt2' --encode`
31373 995 198
```
Will now search hf for pretrained models if there is no schema.
- Add `VocabQuery::to_context()` to build cache context from schema, path, and name - Make `VocabDescription::new()` generic over context and description string types - Extract `vocab_from_hf_tokenizer()` as reusable conversion function - Add special token handling to span_config instead of filtering them out - Fix ByteLevel pre-tokenizer to require `use_regex=true` and use OA_GPT2_PATTERN - Update HF vocab description context to use `to_context()` helper - Add tests for `to_context()` with various query formats
This is broken; the vocab seems to have aggregate tokens with no prior piecewise merges that are not special tokens. Which wordchipper enforces is never the case.
I need to investigate if this is true for this dataset; and explore what needs to change about wordchipper to handle this.
It may be that we need to support a situation where there multi-byte strings in the span map that are not in the byte map, but also *products* in the merge map (so they can only be produced by exact-match lookup, never by merges); but can still be members of merge pairs.
```terminaloutput
echo 'hello world' | RUST_BACKTRACE=1 cargo run -p wordchipper-cli -- cat --model Qwen/Qwen3.5-9B --encode
Blocking waiting for file lock on artifact directory
Compiling wordchipper v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper)
Compiling wordchipper-training v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-training)
Compiling wordchipper-cli-util v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-cli-util)
Compiling wordchipper-cli v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-cli)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 15.19s
Running `target/debug/wordchipper-cli cat --model Qwen/Qwen3.5-9B --encode`
Debug: Some(("ĠаÑįÑĢо", 157513))
Debug: {
248067: AddedToken {
content: "</tool_response>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248064: AddedToken {
content: "<|repo_name|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248046: AddedToken {
content: "<|im_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248059: AddedToken {
content: "</tool_call>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248054: AddedToken {
content: "<|vision_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248044: AddedToken {
content: "<|endoftext|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248058: AddedToken {
content: "<tool_call>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248049: AddedToken {
content: "<|box_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248057: AddedToken {
content: "<|video_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248056: AddedToken {
content: "<|image_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248062: AddedToken {
content: "<|fim_suffix|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248050: AddedToken {
content: "<|box_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248055: AddedToken {
content: "<|vision_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248048: AddedToken {
content: "<|object_ref_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248045: AddedToken {
content: "<|im_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248066: AddedToken {
content: "<tool_response>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248068: AddedToken {
content: "<think>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248069: AddedToken {
content: "</think>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248052: AddedToken {
content: "<|quad_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248053: AddedToken {
content: "<|vision_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248060: AddedToken {
content: "<|fim_prefix|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248047: AddedToken {
content: "<|object_ref_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248051: AddedToken {
content: "<|quad_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248061: AddedToken {
content: "<|fim_middle|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248063: AddedToken {
content: "<|fim_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248065: AddedToken {
content: "<|file_sep|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
}
thread 'main' (852780) panicked at crates/wordchipper/src/vocab/span_vocab.rs:247:51:
called `Result::unwrap()` on an `Err` value: VocabConflict("Pair (157513, 157853) -> 229601 parent 157513 is not defined")
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/std/src/panicking.rs:689:5
1: core::panicking::panic_fmt
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/panicking.rs:80:14
2: core::result::unwrap_failed
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/result.rs:1867:5
3: core::result::Result<T,E>::unwrap
at /home/crutcher/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1233:23
4: wordchipper::vocab::span_vocab::SpanMapVocab<T>::to_pair_vocab
at ./crates/wordchipper/src/vocab/span_vocab.rs:247:51
5: wordchipper::vocab::unified_vocab::UnifiedTokenVocab<T>::from_span_vocab
at ./crates/wordchipper/src/vocab/unified_vocab.rs:85:37
6: wordchipper::pretrained::huggingface::hf_factory::vocab_from_hf_tokenizer
at ./crates/wordchipper/src/pretrained/huggingface/hf_factory.rs:199:18
7: <wordchipper::pretrained::huggingface::hf_factory::HFVocabProvider as wordchipper::pretrained::factory::vocab_provider::VocabProvider>::load_vocab
at ./crates/wordchipper/src/pretrained/huggingface/hf_factory.rs:245:29
8: wordchipper::pretrained::factory::vocab_factory::VocabFactory::load_vocab
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:229:28
9: wordchipper::pretrained::factory::vocab_factory::load_vocab::{{closure}}
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:99:55
10: wordchipper::pretrained::factory::vocab_factory::with_vocab_factory
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:76:5
11: wordchipper::pretrained::factory::vocab_factory::load_vocab
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:99:5
12: wordchipper_cli_util::model_selector::ModelSelectorArgs::load_vocab
at ./crates/wordchipper-cli-util/src/model_selector.rs:29:21
13: wordchipper_cli_util::model_selector::ModelSelectorArgs::load_tokenizer
at ./crates/wordchipper-cli-util/src/model_selector.rs:41:26
14: wordchipper_cli::commands::cat_cmd::CatArgs::run
at ./crates/wordchipper-cli/src/commands/cat_cmd.rs:51:45
15: wordchipper_cli::Commands::run
at ./crates/wordchipper-cli/src/main.rs:44:39
16: wordchipper_cli::main
at ./crates/wordchipper-cli/src/main.rs:18:18
17: core::ops::function::FnOnce::call_once
at /home/crutcher/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```terminaloutput
$ echo 'hello world' | RUST_BACKTRACE=1 cargo run -p wordchipper-cli -- cat --model Qwen/Qwen3.5-9B --encode
Blocking waiting for file lock on artifact directory
Compiling wordchipper v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper)
Compiling wordchipper-training v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-training)
Compiling wordchipper-cli-util v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-cli-util)
Compiling wordchipper-cli v0.9.1 (/home/crutcher/git/wordchipper/crates/wordchipper-cli)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 15.19s
Running `target/debug/wordchipper-cli cat --model Qwen/Qwen3.5-9B --encode`
Debug: Some(("ĠаÑįÑĢо", 157513))
Debug: {
248067: AddedToken {
content: "</tool_response>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248064: AddedToken {
content: "<|repo_name|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248046: AddedToken {
content: "<|im_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248059: AddedToken {
content: "</tool_call>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248054: AddedToken {
content: "<|vision_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248044: AddedToken {
content: "<|endoftext|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248058: AddedToken {
content: "<tool_call>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248049: AddedToken {
content: "<|box_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248057: AddedToken {
content: "<|video_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248056: AddedToken {
content: "<|image_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248062: AddedToken {
content: "<|fim_suffix|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248050: AddedToken {
content: "<|box_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248055: AddedToken {
content: "<|vision_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248048: AddedToken {
content: "<|object_ref_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248045: AddedToken {
content: "<|im_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248066: AddedToken {
content: "<tool_response>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248068: AddedToken {
content: "<think>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248069: AddedToken {
content: "</think>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248052: AddedToken {
content: "<|quad_end|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248053: AddedToken {
content: "<|vision_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248060: AddedToken {
content: "<|fim_prefix|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248047: AddedToken {
content: "<|object_ref_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248051: AddedToken {
content: "<|quad_start|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: true,
},
248061: AddedToken {
content: "<|fim_middle|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248063: AddedToken {
content: "<|fim_pad|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
248065: AddedToken {
content: "<|file_sep|>",
single_word: false,
lstrip: false,
rstrip: false,
normalized: false,
special: false,
},
}
thread 'main' (852780) panicked at crates/wordchipper/src/vocab/span_vocab.rs:247:51:
called `Result::unwrap()` on an `Err` value: VocabConflict("Pair (157513, 157853) -> 229601 parent 157513 is not defined")
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/std/src/panicking.rs:689:5
1: core::panicking::panic_fmt
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/panicking.rs:80:14
2: core::result::unwrap_failed
at /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/result.rs:1867:5
3: core::result::Result<T,E>::unwrap
at /home/crutcher/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1233:23
4: wordchipper::vocab::span_vocab::SpanMapVocab<T>::to_pair_vocab
at ./crates/wordchipper/src/vocab/span_vocab.rs:247:51
5: wordchipper::vocab::unified_vocab::UnifiedTokenVocab<T>::from_span_vocab
at ./crates/wordchipper/src/vocab/unified_vocab.rs:85:37
6: wordchipper::pretrained::huggingface::hf_factory::vocab_from_hf_tokenizer
at ./crates/wordchipper/src/pretrained/huggingface/hf_factory.rs:199:18
7: <wordchipper::pretrained::huggingface::hf_factory::HFVocabProvider as wordchipper::pretrained::factory::vocab_provider::VocabProvider>::load_vocab
at ./crates/wordchipper/src/pretrained/huggingface/hf_factory.rs:245:29
8: wordchipper::pretrained::factory::vocab_factory::VocabFactory::load_vocab
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:229:28
9: wordchipper::pretrained::factory::vocab_factory::load_vocab::{{closure}}
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:99:55
10: wordchipper::pretrained::factory::vocab_factory::with_vocab_factory
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:76:5
11: wordchipper::pretrained::factory::vocab_factory::load_vocab
at ./crates/wordchipper/src/pretrained/factory/vocab_factory.rs:99:5
12: wordchipper_cli_util::model_selector::ModelSelectorArgs::load_vocab
at ./crates/wordchipper-cli-util/src/model_selector.rs:29:21
13: wordchipper_cli_util::model_selector::ModelSelectorArgs::load_tokenizer
at ./crates/wordchipper-cli-util/src/model_selector.rs:41:26
14: wordchipper_cli::commands::cat_cmd::CatArgs::run
at ./crates/wordchipper-cli/src/commands/cat_cmd.rs:51:45
15: wordchipper_cli::Commands::run
at ./crates/wordchipper-cli/src/main.rs:44:39
16: wordchipper_cli::main
at ./crates/wordchipper-cli/src/main.rs:18:18
17: core::ops::function::FnOnce::call_once
at /home/crutcher/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```
Member
Author
|
Issue opened to track the orphan tokens bug/feature: #386 Note, this issue is listed in an error message in the PR. |
crutcher
marked this pull request as ready for review
May 11, 2026 06:13
crutcher
enabled auto-merge (squash)
May 11, 2026 06:15
|
Trying some related stuff branched off of this on #387 let me know if it's interesting, feel free to pick into PRs or into your branch as you see fit. |
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.
…ration
huggingfacefeature andHFVocabProviderfor loading tokenizers from HuggingFace Hub.values()instead of.iter()for cleaner iterationThis is broken still: