Comment créer un modèle de langage : comprendre le parcours et en entraîner un petit
Ce qu’apprend un LLM, quand choisir RAG ou fine-tuning et ce qu’implique un entraînement de zéro. Entraîner, mesurer et sauvegarder un petit modèle original.

Que signifie « créer mon LLM » ?
Vous souhaitez une IA utile pour votre produit, votre code ou les connaissances de votre entreprise. Plusieurs démarches très différentes sont possibles. Appeler un modèle existant avec des instructions crée une application autour du modèle. Le RAG apporte des documents au moment de la question. Le fine-tuning modifie tout ou partie des poids d’un modèle existant. L’entraînement de zéro apprend des poids en partant d’une initialisation aléatoire. Les problèmes résolus et les coûts sont différents.
Ce guide explique ces choix, puis vous fait réellement entraîner un petit réseau de langage sur votre ordinateur. Il prédit des caractères, sauvegarde des poids et génère du texte. C’est un MLP pédagogique, pas un grand Transformer ni un assistant de conversation utilisable. Le but est de rendre l’apprentissage concret : données, prédiction, erreur, mise à jour et résultat mesurable, sans confondre appel d’API et modèle entraîné.
1. Choisir le bon projet selon le besoin
Pour répondre à partir de manuels qui changent, commencez par évaluer un RAG. Pour obtenir un format constant ou un comportement spécialisé grâce à de bons exemples, prompts ou fine-tuning peuvent aider. Aucun ne garantit l’exactitude. Pour apprendre le fonctionnement, ce petit entraînement de zéro est adapté. Un LLM généraliste de production est un projet de recherche et d’infrastructure beaucoup plus vaste.
Un assistant événementiel a besoin de procédures actuelles et de sources : le RAG est un point de comparaison pertinent. Un classificateur de billets en JSON peut commencer avec prompt et validation, puis comparer un ajustement si nécessaire. Recréer un raisonnement multilingue général depuis des poids aléatoires dépasse cet exercice. Écrivez une tâche mesurable avant de choisir un modèle ou un GPU.
2. Comprendre les mots essentiels
Le tokenizer convertit le texte en identifiants ; ici chaque caractère reçoit un identifiant. L’embedding convertit chaque identifiant en nombres appris. Les paramètres sont les nombres modifiés par l’entraînement. Le contexte est l’historique visible pour une prédiction. Le réseau produit des logits ; softmax les transforme en probabilités ; la perte pénalise une faible probabilité pour le vrai caractère suivant. Les gradients indiquent comment ajuster les paramètres pour réduire l’erreur.
Un batch contient plusieurs exemples. Un pas d’entraînement applique une mise à jour ; une époque correspond à un passage sur les données. Ici les lots sont tirés aléatoirement : 400 pas ne signifient pas 400 époques. Un checkpoint conserve les poids. L’inférence les utilise sans les modifier. Température et échantillonnage changent la variété du texte, pas les connaissances.
3. Voir le parcours complet d’un entraînement
Pour un vrai projet : définir tâche et évaluation ; collecter des données avec les droits nécessaires ; retirer informations sensibles et doublons ; séparer entraînement, validation et test sans chevauchement. Choisir tokenizer et architecture, estimer mémoire et calcul, surveiller la perte, sauvegarder des checkpoints versionnés, puis évaluer sur des tâches réservées avant le déploiement. Versionnez données, code, configuration et modèle.
Un assistant utile peut demander aussi entraînement aux instructions, alignement et évaluations de sécurité. Le service nécessite authentification, limites de requêtes, gestion du contexte, surveillance et mises à jour. Le budget n’est pas universel : architecture, volume de tokens, états d’optimiseur, précision, longueur des séquences et matériel comptent. Ce guide ne promet pas un LLM de production pour un prix fixe ou quelques lignes.
4. Ce que contient vraiment le modèle téléchargeable
Notre modèle original possède huit caractères de contexte, des embeddings de dimension 12, une couche cachée tanh de 48 unités et une distribution sur le vocabulaire fourni. Avec ce corpus : 6 303 paramètres. Il utilise NumPy sur CPU et montre explicitement les mises à jour de gradients. Il n’implémente ni attention ni Transformer.
Le corpus contient quelques phrases originales et fictives sur les événements et l’apprentissage. Il est volontairement trop petit pour une compétence linguistique générale. Les tests vérifient la baisse de perte sur l’entraînement, des probabilités finies de somme un, l’erreur claire sur un caractère inconnu et des prédictions identiques après sauvegarde/rechargement. Ils ne mesurent pas les connaissances générales.
5. Installer, entraîner et sauvegarder
Décompressez dans un nouveau dossier. Python 3.9+ et NumPy suffisent ; l’installation accède au registre de paquets, mais l’entraînement n’a besoin ni de téléchargement de modèle, ni de compte, clé API ou GPU. Les dépendances autorisent NumPy 2.x ; les chiffres exacts peuvent varier selon la plateforme.
Lancez les tests, puis model.py. Il affiche paramètres, perte avant/après et exemple, et écrit tiny-model.npz dans le dossier courant. Gardez d’abord le corpus fourni. Si vous le remplacez, conservez un espace dans le vocabulaire pour le remplissage et vérifiez les droits. N’utilisez pas de secrets ou de conversations privées comme données d’essai.
# Python 3.9+; create an isolated environment in the extracted folder.
python3 -m venv .venv
# macOS/Linux (Windows: .venv\Scripts\activate)
. .venv/bin/activate
python -m pip install -r requirements.txt
python -m unittest discover -p 'test_*.py'
python model.py --steps 400
# Output checkpoint: tiny-model.npz6. Interpréter le résultat mesuré
Lors de notre exécution locale, la perte est passée d’environ 3,3004 à 0,9185 après 400 pas. Le réseau prédit donc mieux les caractères de son corpus d’apprentissage. L’extrait généré reste incohérent : c’est une conséquence attendue de l’échelle de cet exercice.
La perte affichée est mesurée sur l’entraînement ; nous ne revendiquons aucune généralisation sur des données réservées. Un réseau peut mémoriser et échouer ailleurs. Plus de pas peut améliorer la perte d’entraînement tout en aggravant le surapprentissage. Pour la suite, créez une validation pertinente sans chevauchement, comparez les deux pertes et gardez les mêmes débuts de phrases pour inspecter les sorties. Un nombre plus faible ne prouve ni utilité ni vérité.
Measured local run, seed 7, supplied corpus, 400 training steps:
parameters: 6303
training_loss_before: 3.3004
training_loss_after: 0.9185
sample begins: seatimin whean sert tes s vitg ...
Interpretation: the model learned local character patterns.
It still produces nonsense and has not demonstrated general knowledge.
These are training-set measurements, not held-out quality scores.7. Recharger et générer : l’inférence
Le code recharge les poids appris et tire des caractères successifs, sans mise à jour. La fenêtre de huit caractères avance avec le texte. Un caractère absent du vocabulaire provoque une erreur explicite. Le checkpoint est une archive NumPy chargée sans pickle ; cela ne dispense pas de vérifier la provenance des fichiers de modèle.
# The training objective: predict the NEXT character.
# Input: "seating "
# Target: the following character in the training text.
# In the supplied model, each input contains exactly 8 characters.
# Generation uses the last 8 characters to predict a distribution,
# samples one character, appends it, then repeats.
from model import load
model = load("tiny-model.npz")
print(model.generate("seat", count=120, seed=42))7 bis. Utiliser le modèle entraîné dans une application locale
Vous avez des poids entraînés ; comment une autre application s’en sert-elle ? Lancez le serveur Python fourni après que model.py a créé tiny-model.npz. Il charge ces poids et expose un seul endpoint local POST /generate. Envoyez prefix="seat" et count=40 : il renvoie generated_text et educational=true. Le texte reste pédagogique et ne constitue pas une réponse fiable.
L’entraînement reste en Python/NumPy. Les quatre onglets ci-dessous appellent le MÊME modèle : ils ne prétendent pas entraîner ce réseau en PHP ou dans le navigateur. Ce petit serveur sert à apprendre sur localhost. Il limite les entrées et n’écoute pas publiquement. Pour un vrai service, il faudrait un framework adapté, authentification et contrôles d’exploitation.
# First train the model with the instructions above.
# Keep your Python virtual environment active.
python server.py
# Keep this terminal open. The API listens only on 127.0.0.1:8765.
# Browser demo: open http://127.0.0.1:8765/
# In ANOTHER terminal, from this same project folder:
# Choose your client (Python needs the same environment).
python client.py
# OR: Node.js 22+
node client.mjs
# OR: PHP 8.1+ with HTTP URL wrappers enabled
php client.php7 ter. Choisir Python, Node.js, JavaScript ou PHP
Choisissez un onglet, copiez le code et lancez le fichier correspondant. Python, Node.js et PHP utilisent l’adresse localhost complète. Le JavaScript navigateur s’exécute sur la page http://127.0.0.1:8765/ fournie par le serveur ; /generate reste volontairement sur la même origine. Ne collez pas ce code sur un autre site. Ouvrez la démo et cliquez sur Generate 40 characters.
Tous les clients envoient le même JSON et reçoivent le même échantillon déterministe. educational=true identifie l’expérience, sans prouver une compréhension du langage. En cas de connexion impossible, vérifiez entraînement, serveur et port 8765. Un caractère inconnu ou count hors de 1..200 provoque une erreur lisible.
import json
from urllib.request import Request,urlopen
request=Request('http://127.0.0.1:8765/generate',
data=json.dumps({'prefix':'seat','count':40}).encode(),
headers={'Content-Type':'application/json'},method='POST')
with urlopen(request,timeout=10) as response:
result=json.load(response)
print(json.dumps(result,indent=2))// Node.js 22+. First run the Python model and local server.
const response = await fetch('http://127.0.0.1:8765/generate', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({prefix: 'seat', count: 40}),
signal: AbortSignal.timeout(10_000),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error || 'Generation failed');
console.log(JSON.stringify(result, null, 2));// Run on http://127.0.0.1:8765/ served by this local project.
// That page already contains <button id="generate"> and <pre id="result">.
document.querySelector('#generate').addEventListener('click', async () => {
const output = document.querySelector('#result');
try {
const response = await fetch('/generate', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({prefix: 'seat', count: 40}),
signal: AbortSignal.timeout(10_000),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error || 'Generation failed');
output.textContent = JSON.stringify(result, null, 2);
} catch (error) {
output.textContent = error.message;
}
});<?php
// PHP 8.1+ with HTTP URL wrappers enabled; run the Python server first.
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['prefix' => 'seat', 'count' => 40]),
'timeout' => 10,
'ignore_errors' => true,
'follow_location' => 0,
]]);
$raw = file_get_contents('http://127.0.0.1:8765/generate', false, $context);
if ($raw === false) throw new RuntimeException('Local server unavailable');
$result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if (isset($result['error'])) throw new RuntimeException($result['error']);
echo json_encode($result, JSON_PRETTY_PRINT).PHP_EOL;{
"model": "tiny-character-mlp",
"educational": true,
"generated_text": "seatimin whean sert tes s vitg bemovge peans"
}8. Le lien avec un vrai LLM Transformer
Les Transformers autorégressifs prédisent aussi le prochain token, avec des architectures profondes et beaucoup plus de données. L’attention combine l’information des positions autorisées. Un masque causal empêche de lire les tokens futurs pendant la prédiction. Informations de position, blocs feed-forward, connexions résiduelles et normalisation complètent l’architecture. Notre MLP à fenêtre fixe n’en est pas une implémentation réduite complète.
Pour apprendre davantage, réalisez un petit Transformer causal séparé avec tests des tenseurs et du masque, ou suivez le cours Stanford indiqué. Pour un produit utile, comparez d’abord un modèle préentraîné dont la licence convient. LoRA adapte certains poids avec de petites mises à jour de faible rang ; il ne crée pas un modèle fondateur à partir de rien. Vérifiez licence, droits et résultats avant de publier un adaptateur.
9. Utiliser l’IA comme professeur et relecteur
Le premier prompt demande d’expliquer le code réel puis de lancer l’expérience. Attendez paramètres, commandes, perte mesurée, extrait et limites. « Votre ChatGPT personnel est prêt » serait trompeur ici. Le deuxième prompt encadre un projet réel d’adaptation et évite qu’un entraînement coûteux devienne une suite implicite.
Act as a patient machine-learning teacher. Inspect this tiny NumPy character
language model and explain its data flow before modifying anything.
Identify the vocabulary, eight-character context, embeddings, hidden layer,
softmax probabilities, next-character targets, loss and gradient update.
Run the local tests, train with 400 steps, save the checkpoint and reload it.
Report actual parameter count, training loss before/after and a generated sample.
Explain why reduced training loss is not evidence of held-out quality or truth.
Do not describe this 6,303-parameter educational MLP as a large Transformer,
a chat assistant or a production LLM. Do not download a model or private dataset.
Propose one next learning experiment with a measurable success criterion.10. Résultat final et prochaine expérience
Vous avez entraîné des poids de zéro, mesuré un apprentissage, sauvegardé puis rechargé un modèle et généré du texte. Vous distinguez modèle, application, RAG et fine-tuning. Prochaine étape : une expérience contrôlée sur le contexte ou les données autorisées, avec évaluation réservée et comparaison au point de départ. Pour un assistant métier, repartez du besoin utilisateur et comparez modèles existants et RAG avant de choisir l’entraînement.
Before proposing a REAL model adaptation, ask for the task, licensed base model,
data rights, deployment language, evaluation set, hardware and budget.
Compare RAG, prompting, LoRA fine-tuning and training from scratch for that task.
If fine-tuning is justified, propose an isolated reproducible experiment:
base-model revision, tokenizer, non-overlapping train/validation/test splits,
training configuration, checkpoint policy, metrics and comparison with baseline.
Include privacy leakage, memorization and unsupported-answer evaluations.
State estimates and untested assumptions explicitly. Do not start an expensive
training job, publish weights or use private data without the agreed scope.Références officielles et pour aller plus loin
- Stanford CS336 · Language Modeling from Scratch
- Vaswani et al. · Attention Is All You Need
- Hugging Face PEFT · LoRA
- NumPy · Random generator
- Python · Local teaching HTTP server
- Node.js · fetch
- PHP · HTTP context options
Passez à votre projet
Récupérez les fichiers, gardez le guide ou donnez un brief prêt à utiliser à votre assistant.
Préparer avec l’IA
Copiez ce prompt anglais dans votre assistant. Il inclut l’article, les fichiers disponibles et les étapes de préparation.
Voir le prompt de préparation
Read this tutorial as reference material:
https://nethanelfitoussi.com/article/create-language-model-explained?lang=en
Goal: apply the documented workflow to my development project.
Read the existing project instructions, inspect the relevant files and explain the smallest useful setup.
Available starter files:
https://nethanelfitoussi.com/api/media/08d5b33c-5d92-4495-ae4a-729eb570d94d.zip
Download and inspect these files in a temporary folder before using them. Do not overwrite existing project instructions.
If I have not supplied a project folder, ask which development project to use. Do not invent a repository URL.
Additional project setup instructions:
Extract the supplied ZIP into a NEW folder. Read README.md before installing or running code.
Act as a patient machine-learning teacher. Inspect this tiny NumPy character
language model and explain its data flow before modifying anything.
Identify the vocabulary, eight-character context, embeddings, hidden layer,
softmax probabilities, next-character targets, loss and gradient update.
Run the local tests, train with 400 steps, save the checkpoint and reload it.
Report actual parameter count, training loss before/after and a generated sample.
Explain why reduced training loss is not evidence of held-out quality or truth.
Do not describe this 6,303-parameter educational MLP as a large Transformer,
a chat assistant or a production LLM. Do not download a model or private dataset.
Propose one next learning experiment with a measurable success criterion.
Before proposing a REAL model adaptation, ask for the task, licensed base model,
data rights, deployment language, evaluation set, hardware and budget.
Compare RAG, prompting, LoRA fine-tuning and training from scratch for that task.
If fine-tuning is justified, propose an isolated reproducible experiment:
base-model revision, tokenizer, non-overlapping train/validation/test splits,
training configuration, checkpoint policy, metrics and comparison with baseline.
Include privacy leakage, memorization and unsupported-answer evaluations.
State estimates and untested assumptions explicitly. Do not start an expensive
training job, publish weights or use private data without the agreed scope.
Adapt example paths, commands and acceptance criteria to this repository rather than assuming they match.
Give me a short plan, then make the agreed local changes and run the relevant checks. Report actual results and anything not verified. Stop before credentials, paid services, production changes, push, merge or deployment.

