Text preprocessing and tokenization

First lesson of the Natural Language Processing (NLP) and LLMs course, free to read: about 15 minutes, 3 exercises and 3 quiz questions. This is the catalogue's base lesson; in the student space, it is rewritten for your profile.

Objectives

  • Normalize a text (case, accents, whitespace) while knowing the trade-offs
  • Split a text into tokens by word and then by subword
  • Understand the principle of the BPE algorithm used by LLMs

Text normalizationTokenizationByte Pair Encoding (BPE)

A language model does not read sentences: it handles numbers. The first step of any NLP project is therefore to turn text into a sequence of token identifiers drawn from a fixed vocabulary.

Normalizing text

Normalization makes different spellings of the same word comparable:

import re
import unicodedata

def normaliser(texte):
    texte = texte.lower()                                   # case
    texte = unicodedata.normalize("NFD", texte)             # separates letters and accents
    texte = "".join(c for c in texte if unicodedata.category(c) != "Mn")
    texte = re.sub(r"\s+", " ", texte).strip()             # multiple spaces
    return texte

print(normaliser("  L'Été   est LÀ ! "))   # "l'ete est la !"

Every choice has a cost: removing accents confuses « pêche » (peach) and « pèche » (sins), lowercasing erases the difference between « Apple » and « apple ». For a TF-IDF classifier, strong normalization often helps; for a pre-trained Transformer model, you barely normalize: its tokenizer was designed for raw text. Essential rule: the same preprocessing must be applied in training and in production.

Tokenizing into words

The simplest approach splits on alphanumeric characters:

def tokeniser(texte):
    return re.findall(r"\w+", normaliser(texte))

print(tokeniser("Le colis n'est pas arrivé."))
# ['le', 'colis', 'n', 'est', 'pas', 'arrive']

Libraries such as spaCy handle elisions, numbers or dates finely, and add lemmatization (« arrivées » → « arriver »). The drawback of word tokens: the vocabulary explodes and any word absent from training (typo, proper noun, neologism) becomes unknown.

Subwords and BPE

Modern models split into subwords: frequent words stay whole, rare words are broken down (« anticonstitutionnellement » → « anti », « constitution », « nellement »). There is no unknown word anymore.

The BPE (Byte Pair Encoding) algorithm learns this vocabulary:

  1. start with each word split into characters (or bytes, to cover all of Unicode);
  2. count the adjacent pairs of symbols in the corpus, weighted by word frequency;
  3. merge the most frequent pair into a new symbol;
  4. repeat until the desired vocabulary size (often 32,000 to 200,000 tokens).
from collections import Counter

corpus = {("b", "a", "s"): 5, ("b", "a", "l"): 3, ("v", "a", "s"): 2}
paires = Counter()
for mot, freq in corpus.items():
    for a, b in zip(mot, mot[1:]):
        paires[(a, b)] += freq
print(paires.most_common(1))   # [(('a', 's'), 7)] -> we merge "a" + "s"

WordPiece (BERT) and Unigram (SentencePiece) follow the same idea with other merge criteria.

Model tokenizers

With Hugging Face, each model provides its tokenizer:

from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained("camembert-base")
enc = tok("Le colis n'est pas arrivé.")
print(enc["input_ids"])                                   # identifiers
print(tok.convert_ids_to_tokens(enc["input_ids"]))        # word pieces

The number of tokens matters: it determines a model’s context limit and the cost of LLM APIs, which are billed per token. French generally produces slightly more tokens than English for the same content.

Key takeaways

Consistent normalization, tokenization suited to the model, and awareness of the number of tokens: these foundations condition everything else, from TF-IDF to LLMs.

Exercises

Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.

  1. CodeDifficulty 1Python in the browser2 hints

    Normalize and tokenize

    Write normaliser(texte) (lowercase, accent removal via unicodedata, multiple spaces collapsed and edges stripped) and tokeniser(texte) that returns the list of words (re.findall(r"\w+", ...)) of the normalized text.

    import re
    import unicodedata
    
    def normaliser(texte):
        # TODO
        pass
    
    def tokeniser(texte):
        # TODO
        pass
  2. CodeDifficulty 3Python in the browser2 hints

    One BPE step

    The corpus is a dictionary {tuple_of_symbols: frequency}. Write compter_paires(corpus) that returns a Counter of adjacent pairs weighted by frequency, and fusionner(paire, corpus) that returns a new corpus where each adjacent occurrence of the pair is replaced by the concatenation of the two symbols.

    from collections import Counter
    
    def compter_paires(corpus):
        # TODO
        pass
    
    def fusionner(paire, corpus):
        # TODO
        pass
  3. Multiple choiceDifficulty 11 hint

    Why subwords?

    What is the main advantage of subword tokenization (BPE) over word tokenization?

    • It removes punctuation
    • It avoids unknown words by breaking rare words into known pieces, with a vocabulary of controlled size
    • It always produces fewer tokens
    • It automatically translates the text

End-of-lesson quiz

  1. Why avoid removing accents before a pre-trained Transformer model?

    • Because it is too slow
    • Because its tokenizer and weights were learned on raw text: modifying the text degrades the representations
    • Because accents are special tokens
    • Because it increases the cost
  2. In BPE, which pair is merged at each step?

    • The first pair in the corpus
    • The most frequent adjacent pair
    • The rarest pair
    • A randomly drawn pair
  3. Why count the tokens of a prompt before calling an LLM?

    • To correct spelling
    • Because cost and context limit are expressed in tokens
    • Because the model only reads the first 100 words
    • To choose the temperature

The rest of the course

  1. Bag of words, TF-IDF and text classification18 min
  2. Embeddings and semantic search18 min
  3. Transformers, attention and large language models20 min
  4. RAG: retrieval-augmented generation20 min
  5. Adapting a model: lightweight fine-tuning (LoRA) and evaluation20 min

Natural Language Processing (NLP) and LLMs · Advanced · 4 h 21 min