Views
No views yet
.spm)tokenizer.model converted, id for id, into a plain-text
format that a human can read, diff and audit — and that a tokenizer can load
without a protobuf dependency.NOTICE file. Use is subject to the Gemma Terms of Use,
including the Section 3.2 use restrictions — see Licence.tokenizer.model is a protocol buffer. That makes it opaque:
you cannot diff two of them, grep one, or see in a pull request what a change
did. It also means anything that wants to read one needs a protobuf parser and
the SentencePiece schema..tiktoken format, base64(token) rank per line
— is lossy for SentencePiece, in three separate ways:<0x41>; storing the raw byte forces a reader to reconstruct that
spelling by scanning for a run of 256 consecutive ids.USER_DEFINED pieces
verbatim, before merging; they are never merge candidates. CONTROL pieces
are never matched from text at all. Both score 0.0 and both are spelled
<...>, so neither the score nor the spelling tells them apart.USER_DEFINED pieces —
HTML markers such as <blockquote> and <table>. Drop the type and
<blockquote> is re-merged from < + blockquote + >, which measurably
mistokenized 5.6% of real documents in testing. Gemma 3, which declares
6,410 of them (it adds the whitespace and newline runs), was worse.<base64 of the piece, UTF-8 encoded> <score> <type>PHBhZD4= 0.0 3 # <pad> score 0.0 CONTROL
PGVvcz4= 0.0 3 # <eos> score 0.0 CONTROL
PGJvcz4= 0.0 3 # <bos> score 0.0 CONTROLid_to_piece(i), so <0x41> keeps its real
byte-fallback spelling and ▁ word-boundary runs keep theirs. Base64 because
a piece may contain spaces, newlines or invalid-looking bytes.get_score(i), written as the shortest decimal that round-trips
the IEEE-754 value.ModelProto.SentencePiece.Type enum:
1 NORMAL, 2 UNKNOWN, 3 CONTROL, 4 USER_DEFINED, 6 BYTE.| pieces | 256,000 |
| NORMAL | 255,495 |
| USER_DEFINED | 245 |
| BYTE | 256 |
| CONTROL | 3 (<pad>, <eos>, <bos>) |
| UNKNOWN | 1 (<unk>) |
add_dummy_prefix is false. Gemma does not prepend a word-boundary
marker to the input, unlike Llama and Mistral. Prepending one anyway shifts
the first piece of every input to a different token.byte_fallback is true, and the 256 <0xNN> pieces are how it is
reached.f32 to confirm it survives a
single-precision parse. To repeat that yourself against your own copy of
Google's tokenizer.model:python extract_spm_vocab.py --model tokenizer.model --output gemma2.spm --verifyscripts/extract_spm_vocab.py in
splintr. Any SentencePiece implementation
will do the same job; the format is simple enough to re-derive in a few lines.1import base64
2
3pieces, scores, types = [], [], []
4for line in open("gemma2.spm"):
5 b64, score, kind = line.split()
6 pieces.append(base64.b64decode(b64).decode("utf-8"))
7 scores.append(float(score))
8 types.append(int(kind))
9
10# USER_DEFINED (4) pieces are matched verbatim, never merged.
11user_defined = {p for p, t in zip(pieces, types) if t == 4}tokenizer.model, MD5
f9e2445870ec741aa6346bbd75531bb4.NOTICE:gemma2.spm is a modified form of Google's Gemma 2 tokenizer.model — it
is not the original file. The protocol-buffer model was converted, id by id,
into the plain-text format described above. Nothing was added, removed,
reordered or rounded: all 256,000 pieces keep their ids, scores and piece
types, and no vocabulary entry differs from Google's file in any way.LICENSE file in this repository.NOTICE file.