Documentation
Retour
  • IA générative
    • Introduction
    • 1. IA générative et LLM
    • 2. Tokens
      • Un token n’est pas forcément un mot
      • Suivons un exemple précis, du texte aux identifiants
      • Un identifiant n’est pas le sens d’un token
      • Pourquoi découper le texte de cette façon ?
      • Les espaces, la casse et la langue changent le découpage
      • Pourquoi cela compte dans votre utilisation d’un LLM
      • Vérifier votre compréhension
      • Des unités d’entrée aux unités de réponse
    • 3. Générer une réponse
    • 4. Dans le modèle
    • 5. Entraîner un assistant
    • 6. Contexte et mémoire
    • 7. Variation des réponses
    • 8. Raisonnement
    • 9. Erreurs et hallucinations
    • 10. Documents et outils
    • 11. Formuler et évaluer

2. Comment le texte devient-il des tokens ?

Suivre le passage d’une phrase à des tokens, puis à des identifiants numériques, et comprendre pourquoi ce découpage compte.

Reprenons une phrase à propos de notre association fictive :

Passerelle organise six ateliers gratuits.

Vous y reconnaissez cinq mots et un point. Vous pouvez aussi la regarder comme une suite de lettres et d’espaces. Un modèle de langage ne travaille pas nécessairement selon l’un de ces deux découpages. Avant de lui transmettre le texte, un programme le transforme en une suite de tokens.

Cette étape est discrète dans une conversation, mais elle explique plusieurs choses : pourquoi une limite de tokens n’est pas une limite de mots, pourquoi la ponctuation et les espaces comptent, et pourquoi manipuler des lettres n’est pas toujours aussi simple pour un modèle que pour un lecteur.

Nous allons suivre le passage du texte aux tokens, puis aux nombres qui les identifient. Nous verrons ensuite comment ces unités sont choisies. Il n’est pas nécessaire de programmer pour comprendre ce mécanisme.

Un token n’est pas forcément un mot

Un token est une unité dans la représentation utilisée par le modèle. Pour du texte, il peut correspondre à un mot entier, à un fragment de mot, à un signe de ponctuation ou à un espace. Il peut aussi réunir un espace et le début du mot qui suit.

Le programme qui effectue cette transformation est appelé tokeniseur, ou tokenizer en anglais. Il applique un vocabulaire et des règles de découpage définis à l’avance. Le vocabulaire désigne ici l’ensemble des unités que ce tokeniseur peut utiliser, pas un dictionnaire de mots avec leurs définitions.

Dans la phrase de Passerelle, rien ne permet donc de conclure que cinq mots et un point produiront six tokens. Le nom de l’association pourrait être découpé en plusieurs fragments. Certains espaces pourraient être associés au mot suivant. Il faut connaître le tokeniseur et lui soumettre le texte exact pour obtenir le résultat.

Cette distinction entre mots et tokens est également expliquée dans la section Tokens de Microsoft. Retenez surtout qu’un token n’est pas une unité grammaticale : son contour ne suit pas nécessairement celui d’un mot, d’une syllabe ou d’une idée.

Suivons un exemple précis, du texte aux identifiants

Prenons hello world, avec des minuscules et un seul espace. Nous utilisons ici cet exemple anglais parce que son découpage est montré explicitement par Karpathy avec le tokeniseur cl100k_base. Il ne s’agit pas d’un résultat supposé valable pour tous les modèles.

Position dans le texte tokeniséTexte représenté par le tokenIdentifiant dans cl100k_base
1hello15339
2␠world1917

Le signe ␠ rend l’espace visible dans ce tableau. Il ne fait pas partie du texte saisi. Le deuxième token représente bien un espace suivi de world.

Le passage peut donc se lire ainsi :

hello world → deux tokens → [15339, 1917]

La phrase comporte onze caractères, espace compris, deux mots et deux tokens avec ce tokeniseur. Ces nombres décrivent trois façons différentes de compter le même texte. Ici, le nombre de mots et le nombre de tokens coïncident ; ce n’est pas une règle générale.

La séquence numérique conserve aussi l’ordre. [15339, 1917] ne signifie pas « deux nombres à additionner ». Elle indique : d’abord le token numéro 15339, ensuite le token numéro 1917.

Dans l’autre sens, le décodage permet de retrouver le texte correspondant à la séquence. Pour cet exemple, les deux identifiants redonnent exactement hello world, espace compris. Encoder n’est donc ni résumer la phrase ni la traduire dans une autre langue : c’est la représenter autrement.

Les identifiants du tableau proviennent de la démonstration de Karpathy, à 12 min 40 s. Ils sont liés à cl100k_base ; il ne faut pas les réutiliser comme s’ils désignaient les mêmes fragments dans n’importe quel tokeniseur.

Vérifions le découpage de notre phrase française

Reprenons exactement Passerelle organise six ateliers gratuits., sans guillemets ni retour à la ligne, avec un seul espace entre les mots. Voici le résultat calculé avec la bibliothèque tiktoken 0.12.0 et le même encodage cl100k_base. Chaque ligne correspond à un token effectivement obtenu, pas à un découpage inventé pour expliquer le principe.

PositionTexte représenté par le tokenIdentifiant dans cl100k_base
1Pass12465
2er261
3elle6853
4␠organise71040
5␠six4848
6␠at520
7el301
8iers4918
9␠gratuits76623
10.13

Les cinq mots et le point donnent donc dix tokens, pour 42 caractères, espaces et ponctuation compris. Passerelle occupe trois tokens ; ateliers aussi, avec l’espace qui le précède dans le premier fragment. À l’inverse, ␠gratuits forme un seul token. Le signe ␠ sert toujours à montrer un espace, pas à en ajouter un au texte.

Le décodage de ces dix identifiants restitue exactement la phrase initiale. Ce résultat concerne ce texte et cet encodage, pas tous les modèles ni toutes les variantes de la phrase. Il ne compte pas les instructions ou marqueurs qu’une application de conversation pourrait ajouter autour du texte.

Pour reproduire le calcul avec Python et tiktoken 0.12.0 — étape facultative pour comprendre le cours —, les opérations sont celles de la bibliothèque officielle tiktoken :

import tiktoken

enc = tiktoken.get_encoding("cl100k_base")
texte = "Passerelle organise six ateliers gratuits."
tokens = enc.encode(texte)
print(tokens)
print(len(tokens))  # 10
assert enc.decode(tokens) == texte

Un identifiant n’est pas le sens d’un token

Pourquoi transmettre des nombres ? Parce que le modèle réalise des calculs sur des représentations numériques. L’identifiant lui permet d’accéder à la représentation associée à une unité de son vocabulaire.

Mais le nombre lui-même n’est pas cette représentation. Dans notre exemple, 15339 ne signifie pas que hello serait plus important, plus long ou plus « positif » que world. Deux identifiants proches ne désignent pas nécessairement des mots de sens voisin.

On peut comparer un identifiant au numéro d’une entrée dans un répertoire : le numéro permet de la retrouver, mais ne décrit pas ce qu’elle signifie. L’analogie s’arrête là. Un modèle ne consulte pas simplement une définition écrite sous cette entrée.

À l’intérieur du modèle, chaque identifiant donne accès à une liste de valeurs numériques apprise pendant l’entraînement. Cette représentation, appelée embedding, est ensuite transformée en tenant compte des autres tokens. Nous expliquerons ces calculs dans le chapitre consacré à l’intérieur du modèle. Pour l’instant, il suffit de distinguer l’étiquette — l’identifiant — de la représentation sur laquelle le modèle travaille.

Pourquoi découper le texte de cette façon ?

Ni un dictionnaire de tous les mots, ni une lettre à la fois

Imaginons un vocabulaire contenant un token pour chaque mot entier. Ce choix paraît naturel, mais quels mots faudrait-il y mettre ? Ceux de quelles langues ? Faudrait-il une entrée pour chaque conjugaison, chaque nom de personne, chaque faute de frappe et chaque mot nouveau ? Une liste de mots connue à l’avance ne peut pas couvrir toutes les formes que les utilisateurs écriront.

À l’inverse, représenter chaque caractère séparément permet de construire beaucoup de textes avec de petites unités. Mais les séquences deviennent plus longues : un mot de dix lettres exige alors dix unités, avant même de compter l’espace ou la ponctuation.

Les tokeniseurs en sous-mots offrent un compromis. Ils peuvent représenter certaines suites fréquentes par une seule unité et composer les autres avec des fragments plus courts. Le modèle peut ainsi recevoir un nom inconnu sans qu’une entrée correspondant à ce nom entier ait été prévue.

Cela ne veut pas dire qu’il connaît la personne ou l’organisation ainsi nommée. Pouvoir représenter un texte et disposer d’informations fiables sur ce texte sont deux choses différentes.

Comment des fragments entrent dans le vocabulaire

Une méthode répandue s’appelle BPE, pour Byte Pair Encoding. Son idée centrale consiste à construire progressivement des unités à partir de paires fréquentes dans un ensemble de textes.

Supposons, pour illustrer le principe, que deux unités voisines a et b apparaissent souvent ensemble. La méthode peut créer l’unité ab. Les occurrences concernées sont alors représentées par une unité plutôt que deux. Une étape suivante peut regrouper cette nouvelle unité avec une autre. Répété sur de nombreux textes, ce procédé fait apparaître des fragments de différentes longueurs.

Cet exemple est volontairement schématique : il explique une fusion, pas le découpage réel d’un modèle particulier. En pratique, le résultat dépend des textes utilisés, des règles de préparation et de la taille de vocabulaire choisie. Les fragments fréquents dans ces textes auront davantage de chances d’être représentés de façon compacte. Ce n’est pas une analyse de leur sens.

Il faut surtout séparer deux moments. Lors de la construction du tokeniseur, on détermine le vocabulaire et les règles de fusion. Lors de son utilisation, on applique les règles déjà obtenues au texte reçu. Le tokeniseur ne reconstruit pas son vocabulaire à chaque question.

Construire ce vocabulaire est aussi distinct d’entraîner le modèle à prévoir la suite d’un texte. Le premier travail définit les unités ; le second apprend des régularités entre ces unités. Le cours de Hugging Face sur BPE détaille cette séparation et montre les fusions sur un petit exemple.

Et les caractères inhabituels ?

Certains tokeniseurs BPE partent des octets du texte plutôt que d’une liste limitée de caractères. Un octet est une petite unité de représentation informatique pouvant prendre 256 valeurs. Dans un encodage de texte comme UTF-8, un caractère peut occuper un ou plusieurs octets.

Cette base permet de représenter un caractère rare ou un symbole nouveau avec des unités plus petites, même s’il ne correspond pas à un token unique. Un token peut ne représenter qu’une partie des octets d’un caractère. Il faut alors décoder l’ensemble de la séquence pour retrouver correctement le texte.

La bibliothèque tiktoken décrit cette tokenisation réversible fondée sur BPE. Il existe d’autres méthodes de tokenisation : les propriétés d’un tokeniseur précis ne doivent pas être attribuées automatiquement à tous les LLM.

Les espaces, la casse et la langue changent le découpage

Revenez au deuxième token de l’exemple hello world : il contient l’espace devant world. Cet espace n’a pas été jeté comme un détail inutile. Il fait partie de la représentation.

Une majuscule, un espace supplémentaire, un accent ou un signe de ponctuation peuvent modifier les tokens obtenus. Un même mot peut aussi être représenté différemment selon qu’il commence le texte ou qu’il est précédé d’un espace. Et deux textes peuvent contenir le même nombre de tokens sans avoir les mêmes identifiants.

La langue compte également. Un vocabulaire construit à partir de certains textes ne représente pas toutes les langues avec la même compacité. Un mot courant dans une langue peut correspondre à une seule unité, alors qu’un mot d’une longueur comparable dans une autre langue peut en demander plusieurs.

Il n’existe donc pas de conversion exacte et universelle entre mots, caractères et tokens. Une estimation fondée sur des textes anglais n’est pas un compteur fiable pour un document français, du code ou une suite de nombres.

Pour un tokeniseur BPE fixé comme celui de notre exemple, encoder le même texte exact avec les mêmes réglages donne la même séquence. La variation entre deux réponses à une question n’est pas, à elle seule, la preuve d’un découpage aléatoire. Nous étudierons les choix de génération plus loin : ils interviennent après cette étape.

Pourquoi cela compte dans votre utilisation d’un LLM

La place occupée par une demande se mesure en tokens

Les modèles disposent d’une capacité limitée pour traiter les informations d’une demande. Cette capacité est généralement exprimée en tokens. Nous l’étudierons sous le nom de fenêtre de contexte.

Le texte que vous venez de taper n’est pas nécessairement la seule entrée. L’application peut lui joindre des instructions, des échanges précédents ou des extraits de documents. Ces éléments occupent eux aussi de la place. Le format qui délimite les messages peut également utiliser des tokens particuliers, que vous ne voyez pas comme des mots dans l’interface.

Compter les tokens de votre dernière question ne suffit donc pas à connaître la taille de la demande complète. La réponse générée est elle aussi composée de tokens ; la façon dont les limites d’entrée, de sortie et de contexte s’articulent dépend du modèle et du service.

Cette mesure intervient aussi dans la facturation de nombreuses API. Mais un abonnement à une application n’est pas nécessairement facturé à l’utilisateur selon le même calcul. Retenons la conséquence pratique, sans entrer ici dans les tarifs : un document de dix pages n’a pas un nombre de tokens prévisible à partir de ses seules dimensions.

Une tâche simple pour un lecteur peut demander un autre travail au modèle

Dans hello world, vous pouvez compter les lettres en parcourant les caractères. La représentation tokenisée contient, elle, deux unités. Elle ne donne pas directement au modèle onze positions correspondant chacune à un caractère.

Cette différence aide à comprendre pourquoi les tâches portant sur des lettres — compter, inverser ou extraire un caractère sur deux — ne se réduisent pas à parcourir les tokens. Le modèle doit accomplir un travail supplémentaire pour les réussir, ou l’application peut lui fournir un outil adapté.

Ce n’est pas une preuve qu’un LLM serait incapable d’épeler ou de compter des caractères. Ses capacités dépendent aussi de l’entraînement, de la tâche et des outils disponibles. Karpathy illustre certaines difficultés dans sa séquence sur la tokenisation et l’orthographe ; ces observations ne constituent pas une liste d’échecs garantis pour tous les modèles.

Vérifier votre compréhension

Reprenez le tableau de hello world, sans utiliser de service d’IA :

  1. Dans l’exemple hello world, pourquoi retirer l’espace du deuxième token changerait-il le texte reconstruit ?
  2. Peut-on déduire le sens d’un token de la grandeur de son identifiant ? Que faudrait-il consulter pour savoir quel texte représente cet identifiant ?
  3. Un nouveau nom d’association se découpe en quatre tokens. Cela signifie-t-il que le modèle connaît quatre informations à son sujet ?
  4. Une application indique que votre demande contient davantage de tokens que votre question seule. Quels autres éléments pourraient expliquer cet écart ?

Vous devriez pouvoir justifier vos réponses en distinguant le contenu du texte, sa représentation et ce que l’application transmet réellement au modèle. Aucun identifiant n’est à mémoriser.

Des unités d’entrée aux unités de réponse

Nous avons suivi une transformation : un texte devient une séquence de tokens, chacun identifié par un nombre. Le vocabulaire et les règles du tokeniseur déterminent ce découpage ; ils ne suffisent pas à expliquer le sens du texte ni à construire une réponse pertinente.

La prochaine question est donc différente : à partir des tokens déjà disponibles, comment le modèle estime-t-il ce qui pourrait suivre ? Et comment passe-t-on de plusieurs continuations possibles à une réponse précise ? Ce sera l’objet du prochain chapitre.

Chapitre suivant : Comment le modèle construit-il une réponse ?

Chapitre précédent : Qu’est-ce que l’IA générative ?

Revenir au sommaire de la formation