plumbing: full pipeline#2130
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. |
| impl PipelinePatternMatcher for AddedVocabulary { | ||
| fn get_next_special_token( | ||
| &self, | ||
| input: &str, | ||
| normalized: bool, | ||
| ) -> Option<((usize, usize), u32)> { | ||
| if input.is_empty() { | ||
| return None; | ||
| } | ||
| let trie = if normalized { | ||
| self.split_normalized_trie.as_ref() | ||
| } else { | ||
| self.split_trie.as_ref() | ||
| }?; | ||
| let matched = trie.leftmost_find_iter(input).next()?; | ||
| let start = matched.start(); | ||
| let end = matched.end(); | ||
| let token_id = matched.value(); | ||
|
|
||
| Some(((start, end), token_id)) | ||
| } | ||
| } |
There was a problem hiding this comment.
cc @ArthurZucker this is where to plug the new added_vocab matching logic
There was a problem hiding this comment.
I need an offset on the string to be able to do lstrip / rstrip and single word falgs
| impl PreTokenizer for PipelinePreTokenizer { | ||
| fn pre_tokenize(&self, text: &str, out: &mut Vec<Split>) -> Result<()> { | ||
| match self { | ||
| Self::None => Ok(()), | ||
| Self::Bert(pretok) => pretok.pre_tokenize(text, out), | ||
| Self::Whitespace(pretok) => pretok.pre_tokenize(text, out), | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
cc @McPatate we just add an entry to the enum per pre-tokenizer we implement
| { | ||
| type Item = Segment<'a>; | ||
|
|
||
| fn next(&mut self) -> Option<Self::Item> { |
There was a problem hiding this comment.
can we document what we are ddoing?
Like why dod we store the special for example
| impl PipelinePatternMatcher for AddedVocabulary { | ||
| fn get_next_special_token( | ||
| &self, | ||
| input: &str, | ||
| normalized: bool, | ||
| ) -> Option<((usize, usize), u32)> { | ||
| if input.is_empty() { | ||
| return None; | ||
| } | ||
| let trie = if normalized { | ||
| self.split_normalized_trie.as_ref() | ||
| } else { | ||
| self.split_trie.as_ref() | ||
| }?; | ||
| let matched = trie.leftmost_find_iter(input).next()?; | ||
| let start = matched.start(); | ||
| let end = matched.end(); | ||
| let token_id = matched.value(); | ||
|
|
||
| Some(((start, end), token_id)) | ||
| } | ||
| } |
There was a problem hiding this comment.
I need an offset on the string to be able to do lstrip / rstrip and single word falgs
6af5ebf to
1954de7
Compare
Rebased onto feat/train_encode_split, which parked the #2129 fast path (BucketVocabStore / Buckets / bucket_added_vocabulary) and restored the legacy Tokenizer as the A/B baseline. This collapses the three stale fixup commits ("rebase", "attempt to fix", "apply normalizer in legacy tokenizer") from the previous rebase — they targeted the pre-park base — into one coherent step: - bucket_added_vocabulary.rs: the final fast AddedVocabulary (Buckets-backed, extract_next / extract_and_normalize, impl PipelinePatternMatcher). - PipelineTokenizer uses the bucket AddedVocabulary; the base Tokenizer stays legacy. TryFrom<&Tokenizer> rebuilds the bucket AV from the tokenizer's added tokens in id order, so ids are preserved (model-present tokens reuse their model id) and the pipeline emits the same ids as the reference tokenizer. pipeline_oracle passes: identical ids on big.txt (English) and wagahai (Japanese) at 1kB/10kB chunks. Full tk-encode/tk-train suites green; fmt + clippy -D warnings clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The PipelineTokenizer drives special-token matching through `extract_next` (`PipelinePatternMatcher`) + `SpecialSegmentIterator`, so the bucket AV's `extract_and_normalize` / `split_on_matches` pair is dead code (only its own test used it). Drop them and the now-unused `Range`/`PreTokenizedString`/`Token` imports. The shared helpers (`is_ws`, `is_single_word`, `skip_whitespace_*`) stay — `extract_next` uses them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the test-only `extract_segments` / `extract_two_pass` / `owned` helpers and the 7 extraction tests built on them. `extract_two_pass` reimplemented `PipelineTokenizer::encode`'s two-pass loop inside the test module (a drift-prone duplicate); `extract_next`'s matching behavior is exercised end-to-end by pipeline_oracle. Kept the AV-level unit tests that don't go through the harness: can_add_tokens, can_add_special_tokens, normalized_tokens_are_stored_by_normalized_form. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6371e9c to
89a1d19
Compare
Restore the extract_next coverage dropped with the extract_two_pass harness, but drive the real `SpecialSegmentIterator` instead of a parallel reimplementation. Five single-pass tests over a bucket `AddedVocabulary`: raw added-token carving, single_word, lstrip/rstrip span absorption, the encode_special_tokens toggle, and raw-vs-normalized matcher selection. `SpecialSegmentIterator::new` is now pub(crate) so the AV tests can construct it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| if self.encode_special_tokens && metadata.special { | ||
| search = match_end; | ||
| continue; | ||
| } |
| struct FixedMatcher(Vec<((usize, usize), u32)>); | ||
| impl PipelinePatternMatcher for FixedMatcher { | ||
| fn extract_next( | ||
| &self, | ||
| _bytes: &[u8], | ||
| search_offset: usize, | ||
| _normalized: bool, | ||
| ) -> Option<((usize, usize), u32)> { | ||
| self.0 | ||
| .iter() | ||
| .find(|((start, _), _)| *start >= search_offset) | ||
| .copied() | ||
| } | ||
| } |
There was a problem hiding this comment.
Fixed is naive? we could / should use daachorse as replacement
There was a problem hiding this comment.
Just a test fixture even
TL;DR
Implement a new encode loop using the optimized blocks from other PRs