Skip to main content

GgufSpmTokenizer

Struct GgufSpmTokenizer 

Source
pub struct GgufSpmTokenizer { /* private fields */ }
Expand description

A real SentencePiece-BPE tokenizer, built from a GGUF file’s tokenizer.ggml.tokens + tokenizer.ggml.scores metadata (tokenizer.ggml.model == "llama" in GGUF’s convention – this is SentencePiece’s BPE model type, not its Unigram model type, despite both living under the umbrella term “SentencePiece”; the distinction matters because the encode algorithms are different).

§How this differs from GgufBpeTokenizer

GgufBpeTokenizer implements GPT2-style BPE: a fixed merge-rank table applied greedily left-to-right after GPT2’s own byte-to-unicode remap and regex pre-tokenization. SentencePiece-BPE vocabularies (used by the original LLaMA, and generally any model whose GGUF reports tokenizer.ggml.model = "llama") don’t ship a merge-rank table at all – instead every vocabulary entry carries a score, and encoding works by repeatedly merging whichever currently adjacent pair of symbols forms the highest-scoring known vocabulary piece, using a priority queue over merge candidates (this is the llm_tokenizer_spm algorithm from llama.cpp, reimplemented here independently against the public GGUF metadata, not from llama.cpp source). Preprocessing replaces spaces with (U+2581) and adds a leading , matching SentencePiece’s own convention, rather than GPT2’s byte-to-unicode remap.

§A real bug found and fixed while building this

The first implementation of this algorithm checked merge-candidate validity by adjacency alone (is this pair still directly next to each other in the linked list?). That’s necessary but not sufficient: a symbol’s content can change between when a candidate merge is queued and when it’s popped, if that symbol was itself the survivor of a different merge in the meantime, while staying adjacency-valid at the same list position. The fix is to also store the exact left/right text expected at queue time and re-check it at pop time, discarding (not re-queuing) any candidate whose content has since changed. This was caught immediately by testing against real reference data (see below) rather than by code review – the bug produced plausible-looking but wrong output (“Hello world” tokenized as 6 pieces instead of the correct 2) which would have been easy to miss without a real ground truth to check against.

§Verification

Tested against tests/fixtures/llama-spm-vocab.gguf (downloaded directly from ggml-org/llama.cpp’s own repository, the real LLaMA-1/2 tokenizer vocabulary) and its accompanying .gguf.inp/.gguf.out files – llama.cpp’s own CI test corpus of 45 input strings and their exact expected token ID sequences, covering ASCII, whitespace runs, control characters, CJK/Khmer/ Vietnamese text, emoji, and byte-fallback. All 45 match exactly.

Implementations§

Source§

impl GgufSpmTokenizer

Source

pub fn from_gguf(file: &impl TensorSource) -> Result<Self, TokenizerLoadError>

Source

pub fn vocab_size(&self) -> usize

Source

pub fn encode(&self, text: &str) -> Vec<u32>

Encodes text using SentencePiece’s space-replacement convention (' ' -> , plus a leading ) and the score-prioritized pairwise-merge algorithm described in this struct’s doc comment. Characters with no direct vocabulary entry are expanded to UTF-8 byte-fallback tokens (<0xXX>, which every real SentencePiece-BPE vocabulary includes for exactly this purpose) before merging begins.

Control/user-defined tokens (chat-template markers like <|user|>) are first carved out as atomic substrings via split_on_special_tokens, matching real llama.cpp’s tokenizer_st_partition behavior, so they’re never shattered into byte-fallback pieces; each remaining raw-text run between them is merged independently. A leading dummy is applied to a run only when Self::add_space_prefix is true (llama.cpp add_space_prefix && is_prev_special for each fragment).

Source

pub fn decode(&self, ids: &[u32]) -> String

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.