glassllmDocumentação
DocumentaçãoReferência da biblioteca

Referência da biblioteca

Tokenizer: referência completa

BPE por caracteres, normalização, fusões, IDs, decodificação e persistência.

glassllm 0.1.04 min de leitura · estimativa

Construção e vocabulário

Importe Tokenizer da raiz; pre_tokenize, SPACE, SPECIALS e UNK_TEXT vêm de glassllm.tokenizer. Tokenizer(alphabet: list[str], merges: list[tuple[str,str]]) constrói um vocabulário com tokens especiais, alfabeto e resultados das fusões, nessa ordem. O construtor copia as listas; ele não aprende fusões nem valida todas as combinações possíveis de um vocabulário manual.

Atributo ou constante Conteúdo
SPECIALS ["<pad>", "<unk>", "<bos>", "<eos>"], IDs 0–3
SPACE "▁", representa um espaço ASCII
UNK_TEXT "⁇", texto usado ao decodificar <unk>
alphabet, merges Caracteres e pares aprendidos, em ordem
ranks Dicionário par → prioridade da fusão
vocab Lista completa de strings por ID
token_to_id, unk_id Dicionário inverso e ID do desconhecido, normalmente 1
vocab_size Propriedade inteira, len(vocab)

vocab_size é uma propriedade: use tok.vocab_size, sem parênteses. Para ler strings por ID, use tok.tokens(ids) ou tok.vocab[id]. Não existe método id_to_token.

Normalização e aprendizagem

pre_tokenize(text: str) -> list[str] normaliza Unicode para NFC, troca cada espaço ASCII por ▁ e separa chunks. Quebras de linha são chunks individuais; espaços anteriores à palavra ficam no mesmo chunk dela. Fusões não atravessam chunks. Outros tipos de espaço, como tabulação, não são todos convertidos para ▁. Um ▁ literal é interpretado como marcador, portanto não há reversibilidade irrestrita para qualquer string Unicode.

Tokenizer.train(text: str, vocab_size: int) -> Tokenizer conta chunks, começa pelo alfabeto observado e escolhe o par adjacente mais frequente. Empates são resolvidos pela ordem alfabética do par; cada fusão é aplicada sem sobreposição. O pedido deve comportar quatro especiais mais o alfabeto, ou ocorre ValueError. O tamanho pedido é um teto: corpora pequenos podem esgotar pares antes de alcançá-lo.

from glassllm import Tokenizer
from glassllm.tokenizer import pre_tokenize

assert pre_tokenize("Olá mundo\n") == ["Olá", "▁mundo", "\n"]
tok = Tokenizer.train("banana banana\n", vocab_size=32)
ids = tok.encode("banana banana\n")
assert tok.decode(ids) == "banana banana\n"
assert tok.vocab_size <= 32
assert len(tok.tokens(ids)) == len(ids)
assert tok.encode("🧪") == [tok.unk_id]
assert tok.decode([tok.unk_id]) == "⁇"

Codificar e explicar as fusões

encode(text: str) -> list[int] percorre cada chunk e aplica primeiro a fusão disponível de menor rank. Cada peça ausente do vocabulário vira unk_id. Não insere padding, BOS ou EOS e não limita o comprimento. Entrada vazia gera [], que não é um prompt válido para GlassLM.generate.

encode_verbose(text: str) -> list[dict] devolve uma entrada por chunk: {"chunk": str, "steps": list[list[str]]}. O primeiro estado contém os caracteres; os seguintes contêm as peças após cada fusão aplicada. Não são IDs nem probabilidades, e um chunk sem fusões ainda tem seu estado inicial. Esta chamada preserva os estados para explicação mesmo quando a codificação normal pode usar o cache interno.

from glassllm import Tokenizer

tok = Tokenizer.train("banana banana\n", 32)
detail = tok.encode_verbose("banana")
assert detail[0]["chunk"] == "banana"
assert detail[0]["steps"][0] == list("banana")
assert detail[0]["steps"][-1] == tok.tokens(tok.encode("banana"))

Tokens e texto

tokens(ids: list[int]) -> list[str] consulta vocab com indexação Python. IDs acima do limite produzem IndexError; índices negativos seguem a semântica da lista e não são rejeitados, portanto valide IDs externos. decode(ids: list[int]) -> str concatena peças, converte ▁ em espaços, transforma <unk> em ⁇ e omite os outros três especiais. Ele não reconstrói texto que foi perdido por normalização ou desconhecidos.

Salvar e carregar

save(path: str | Path) -> None escreve JSON UTF-8 com version: 1, alphabet e merges; sobrescreve o destino e não cria diretórios pais. Tokenizer.load(path: str | Path) -> Tokenizer lê essas listas e reconstrói ranks e vocabulário. O leitor atual não negocia versões nem valida um esquema completo: ausência de chaves gera KeyError, JSON inválido gera erro do leitor e problemas de arquivo geram OSError.

from pathlib import Path
from tempfile import TemporaryDirectory
from glassllm import Tokenizer

tok = Tokenizer.train("banana banana\n", 32)
with TemporaryDirectory() as directory:
    path = Path(directory) / "tokenizer.json"
    tok.save(path)
    restored = Tokenizer.load(path)
    assert restored.encode("banana") == tok.encode("banana")
    assert restored.vocab == tok.vocab

Relação com os artigos

O projeto usa a ideia de fusões BPE para subpalavras descrita por Sennrich, Haddow e Birch. A implementação começa por caracteres Unicode, não bytes, e não tem byte fallback. O marcador visual de espaços lembra SentencePiece, mas este é um tokenizer próprio: não carrega modelos SentencePiece nem implementa seu conjunto de algoritmos. Veja Tokens e BPE para acompanhar o cálculo.

Veja na interface

Texto, controles e tokens BPE: Editor, continuação e IDs dos tokens
Editor, continuação e IDs dos tokens

Frase inicial, Gerar, Um passo, Pausar, Limpar, saída e IDs.

Captura real da interface em português.
Abrir no tamanho original

Fontes no projeto

src/glassllm/tokenizer.py

Artigos relacionados

Fontes primárias dos conceitos usados no projeto. O ano identifica a primeira versão do preprint arXiv; a nota de publicação informa o evento ou periódico quando registrado na fonte.