# Personalizando tokenizers

Os tokenizers são desacoplados de seus vocabulários aprendidos. Isso permite que você inicialize um tokenizer vazio para treinamento ou crie um diretamente com seu próprio vocabulário. O pipeline de tokenização subjacente permanece o mesmo (normalizador, pré-tokenizador, algoritmo de tokenização), então você não precisa recriá-lo do zero.

Este guia mostra como treinar e criar um tokenizador personalizado.

## Treinando um tokenizador

Um tokenizer treinável vazio substitui o vocabulário por um novo vocabulário de destino. Isso é útil para se adaptar a um novo domínio, como finanças, um idioma com poucos recursos ou código.

Crie um tokenizador vazio e carregue um conjunto de dados.

```py
from datasets import load_dataset
from transformers import GemmaTokenizer

tokenizer = GemmaTokenizer()
dataset = load_dataset("Josephgflowers/Finance-Instruct-500k", split="train")
```

Use o método [TokenizersBackend.train_new_from_iterator()](/docs/transformers/main/pt/main_classes/tokenizer#transformers.TokenizersBackend.train_new_from_iterator) para treinar o tokenizador. Este método aceita uma função geradora para retornar blocos de texto do conjunto de dados, em vez de carregar tudo na memória de uma só vez. O argumento `vocab_size` define o tamanho do vocabulário dos tokenizadores.

```py
def batch_iterator(batch_size=1000):
    for i in range(0, len(dataset), batch_size):
        yield dataset[i : i + batch_size]["assistant"]

trained_tokenizer = tokenizer.train_new_from_iterator(
    batch_iterator(),
    vocab_size=32000,
)
encoded = trained_tokenizer("The stock market rallied today.")
print(encoded["input_ids"])
[5866, 11503, 98, 5885, 8617, 13381, 30]
```

Adicione novos tokens especiais com o argumento `new_special_tokens` ou use `special_tokens_map` para renomear os tokens especiais antigos para os novos tokens especiais.

Salve o novo tokenizer de finanças com [save_pretrained()](/docs/transformers/main/pt/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.save_pretrained) ou salve e envie para o Hub com [push_to_hub()](/docs/transformers/main/pt/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). Isso cria um arquivo `tokenizer.json` que captura o vocabulário recém-treinado, as regras de mesclagem e a configuração completa do pipeline.

```py
trained_tokenizer.save_pretrained("./finance-gemma-tokenizer")
trained_tokenizer.push_to_hub("finance-gemma-tokenizer")
```

## Vocabulário personalizado

Um tokenizer vazio suporta vocabulário personalizado com os argumentos `vocab` e `merges`.

- `vocab` é o conjunto completo de tokens que um tokenizer conhece e cada entrada mapeia um token para seu id de entrada.
- `merges` define como o algoritmo BPE deve combinar tokens adjacentes.

```py
from transformers import GemmaTokenizer

vocab={
    "<pad>": 0,
    "</s>": 1,
    "<s>": 2,
    "<unk>": 3,
    "<mask>": 4,
    "▁the": 5,
    "▁stock": 6,
    "▁market": 7,
    "▁": 8,
    "r": 9,
    "a": 10,
    "l": 11,
    "i": 12,
    "e": 13,
    "d": 14,
    "ra": 15,
    "li": 16,
    "lie": 17,
    "lied": 18,
    "ral": 19,
    "ralli": 20,
    "rallie": 21,
    "rallied": 22,
}
merges=[
    ("r", "a"),       # r + a → ra
    ("l", "i"),       # l + i → li
    ("li", "e"),      # li + e → lie
    ("lie", "d"),     # lie + d → lied
    ("ra", "l"),      # ra + l → ral
    ("ral", "li"),    # ral + li → ralli
    ("ralli", "e"),   # ralli + e → rallie
    ("rallie", "d"),  # rallie + d → rallied
]

tokenizer = GemmaTokenizer(vocab=vocab, merges=merges)
encoded = tokenizer("the stock market rallied")
print(encoded["input_ids"])
```

## Subclassing de TokenizersBackend

O Tokenizers suporta quatro [backends](./fast_tokenizers#backends) diferentes. Em geral, você deve usar o [TokenizersBackend](/docs/transformers/main/pt/main_classes/tokenizer#transformers.TokenizersBackend) para definir um novo tokenizer, pois ele é mais rápido.

> [!TIP]
> O [PythonBackend](/docs/transformers/main/pt/main_classes/tokenizer#transformers.PythonBackend) é um tokenizador em Python puro que não depende de backends como Rust, SentencePiece ou mistral-common. Você deve usar o [PythonBackend](/docs/transformers/main/pt/main_classes/tokenizer#transformers.PythonBackend) apenas se estiver construindo um tokenizador muito especializado que não pode ser expresso pelo backend Rust.

1. Subclasse o [TokenizersBackend](/docs/transformers/main/pt/main_classes/tokenizer#transformers.TokenizersBackend) com atributos de classe, como o lado do padding e o algoritmo de tokenização a ser usado.
2. Defina o pipeline de tokenização no `__init__`. Isso inclui o algoritmo de tokenização a ser usado, como dividir o texto bruto antes do algoritmo e como decodificar os tokens de volta para texto.

```py
from tokenizers import Tokenizer, decoders, pre_tokenizers
from tokenizers.models import BPE
from transformers import TokenizersBackend

class NewTokenizer(TokenizersBackend):
    padding_side = "left"
    model = BPE

    def __init__(
        self,
        vocab=None,
        merges=None,
        unk_token="<unk>",
        bos_token="<s>",
        eos_token="</s>",
        pad_token="<pad>",
    ):
        self._vocab = vocab or {
            str(unk_token): 0,
            str(bos_token): 1,
            str(eos_token): 2,
            str(pad_token): 3,
        }
        self._merges = merges or []

        self._tokenizer = Tokenizer(
            BPE(vocab=self._vocab, merges=self._merges, fuse_unk=True)
        )
        self._tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
        self._tokenizer.decoder = decoders.ByteLevel()

        super().__init__(
            unk_token=unk_token,
            bos_token=bos_token,
            eos_token=eos_token,
            pad_token=pad_token,
        )
```

Treine ou salve o novo tokenizer vazio.

```py
tokenizer = NewTokenizer()

# train on new corpus
corpus = ["The stock market rallied today.", "Bond yields fell sharply."]
trained_tokenizer = tokenizer.train_new_from_iterator(corpus, vocab_size=32000)
# save tokenizer
trained_tokenizer.save_pretrained("./new-tokenizer")
```

