Blog

Entraîner un LLM sur un iGPU : nanochat (Karpathy) sur un simple GPU intégré

Pas de carte graphique, pas de CUDA : un iGPU Intel UHD 770 entraîne nanochat, le mini-ChatGPT de Karpathy, de A à Z en moins d'une heure avec PyTorch XPU. Chiffres mesurés, iGPU + CPU, script prêt à lancer.

Entraîner un LLM sur un iGPU : nanochat (Karpathy) sur un simple GPU intégré

nanochat est le projet d’Andrej Karpathy qui montre, en un seul dépôt lisible, toutes les étapes d’un « ChatGPT » : tokenizer, pré-entraînement, fine-tuning (SFT) et interface de chat. Il est pensé pour 8 GPU NVIDIA H100, mais il propose aussi une configuration réduite pour CPU.

Nous l’avons fait tourner entièrement sur un iGPU : l’Intel UHD 770, le GPU intégré au processeur (un Core i5 de bureau), sans aucune carte graphique dédiée et sans CUDA. Le tout avec PyTorch XPU, le support natif des GPU Intel dans PyTorch, puis avec l’iGPU et le CPU qui calculent ensemble.

Résultats en bref

  • Un simple iGPU suffit pour entraîner un LLM de A à Z : installation, données, tokenizer, pré-entraînement (33 min), SFT (environ 6 min) et premières réponses en moins d’une heure, sur le GPU intégré de la VM, sans carte graphique.
  • 1,33 s par pas de pré-entraînement, soit environ 6 150 tokens/s, pour un petit modèle de 4 couches. Sur le même travail, le GPU va environ 1,3 fois plus vite que les 6 vCPU.
  • iGPU et CPU ensemble : en confiant 4 lignes sur 16 de chaque lot au CPU, le pré-entraînement passe de 1,33 à 1,13 s par pas (−15 % de temps), pour une qualité presque identique (validation 1,55 contre 1,52). Donner plus de travail au CPU ralentit au contraire.
  • Le modèle obtenu joue l’assistant et parle anglais, mais reste incohérent : c’est la taille du modèle (37 millions de paramètres, surtout des tables d’embeddings, 39 min d’entraînement), pas la plateforme.
  • Il a fallu 4 adaptations pour le GPU Intel et 4 correctifs de nanochat pour une petite configuration. Tout est dans un script d’une commande, en bas de l’article.

Pourquoi un iGPU ?

Un iGPU (GPU intégré) est la partie graphique qui se trouve dans le processeur, sur la même puce que les cœurs CPU. On le réserve d’habitude à l’affichage ; ici, il sert au calcul.

  • Il partage la RAM du serveur au lieu d’avoir sa propre mémoire vidéo. Pas de limite de VRAM à 8 ou 12 Go, et pas de copie coûteuse entre CPU et GPU : c’est ce qui rend l’entraînement iGPU + CPU efficace plus bas. Notre modèle n’a utilisé que 1,5 Go.
  • PyTorch le gère nativement (build XPU), torch.compile compris : le même code qu’avec CUDA, à quelques lignes près.
  • Il coûte une fraction d’un GPU dédié : notre offre iGPU Pro est à 44,99 € HT par mois, quand un GPU dédié en cloud se loue souvent 300 à 500 € par mois.
  • Il est beaucoup moins puissant (moins de 1 TFLOPS) : il ne remplace pas un GPU dédié pour entraîner un gros modèle. Il suffit pour apprendre, expérimenter et faire tourner de petits modèles.

Conditions du test

ÉlémentValeur
Machine virtuelleoffre Pro : 6 vCPU, 24 Go de RAM, Debian 13, noyau 7.3
CPU / GPUIntel Core i5-13500, GPU intégré Intel UHD 770 (partagé avec d’autres VM)
Logicielnanochat (commit 92d63d4), PyTorch 2.9.1 build XPU, torch.compile avec Triton XPU
Modèled4 : 4 couches, largeur 256, contexte 512 tokens, vocabulaire de 32 768
Pré-entraînement1 500 pas de 8 192 tokens (12,3 millions de tokens)
SFT220 pas de 8 192 tokens, mélange de conversations, MMLU et GSM8K

C’est la configuration « CPU » de nanochat, réduite pour tenir en moins d’une heure. Le vrai nanochat (speedrun.sh, modèle de 20 couches) demande environ 4 h sur 8 H100 : c’est trois ordres de grandeur de calcul en plus, hors de portée d’un GPU intégré.

1. Les chiffres

Calcul brut

Produit de matrices 2048×2048TFLOPS
fp320,71
bf160,73

Le GPU est partagé : quand une autre VM l’occupe, nous avons mesuré jusqu’à 0,27 TFLOPS. Ce GPU n’a pas d’unités matricielles dédiées, donc le bf16 ne va pas plus vite que le fp32, mais il prend deux fois moins de mémoire.

Entraînement et chat

ÉtapeDuréeDétail
Installation (paquets, nanochat, PyTorch XPU)~1 min
Données (8 fichiers) + tokenizer50 ssur le CPU
1ʳᵉ itération du pré-entraînement83 scompilation des kernels GPU, une seule fois
Pré-entraînement, 1 500 pas33 min1,33 s/pas, ~6 150 tokens/s, 1,5 Go de mémoire GPU
SFT, 220 pas~6 min~1,5 s/pas
1ʳᵉ réponse du chat3 mincompilation
Réponses suivantes13 à 15 sréponses longues, jusqu’à la limite de tokens

GPU contre CPU, même travail

SFT, pas de 16 384 tokenss/pastokens/s
GPU Intel UHD 7702,646 200
6 vCPU (i5-13500)3,0 à 3,54 630

La courbe d’apprentissage

DébutFin
Pré-entraînement, bits par octet en validation3,201,52
SFT, bits par octet en validation1,351,10

Plus c’est bas, mieux le modèle prédit le texte. Les deux courbes descendent régulièrement, sans accident.

2. iGPU et CPU ensemble

Le GPU calcule pendant que les 6 vCPU attendent. Nous avons donc fait travailler les deux en même temps (correctif nanochat_hybrid_patch.py) :

  1. Chaque lot de 16 lignes est coupé en deux : une partie part sur le GPU, l’autre sur une copie du modèle en mémoire CPU. Les deux calculent en parallèle.
  2. Les gradients des deux parties sont additionnés, au prorata du nombre de lignes. C’est mathématiquement le même calcul qu’un lot entier sur un seul processeur.
  3. L’optimiseur met à jour le modèle sur le GPU, puis les poids sont recopiés vers la copie CPU. Sur un GPU intégré, GPU et CPU partagent la même mémoire : cette copie coûte environ 0,1 s par pas.

Tout tourne en fp32 : le CPU de ce serveur n’a pas d’instructions bf16 rapides, et sur ce GPU le fp32 va aussi vite que le bf16.

Combien de travail donner au CPU ?

Lignes GPU + CPU (threads CPU)s/pasPar rapport au GPU seul en fp32 (1,40 s)
16 + 0 (GPU seul)1,40référence
12 + 4 (3 ou 4 threads)1,16−17 %
10 + 6 (5 threads)1,32−6 %
10 + 6 (4 threads)1,41aucun gain
8 + 8 (4 threads)1,43plus lent

Contre-intuitif : donner plus de lignes au CPU ralentit tout. Nos mesures montrent que le CPU finit toujours avant le GPU, mais que la partie GPU devient plus lente quand le CPU calcule : les cœurs qui calculent ne sont plus disponibles pour piloter le GPU (lancer ses kernels, gérer la différentiation automatique). Le meilleur réglage laisse donc de la marge : 4 lignes sur 16 et 3 threads de calcul sur 6 vCPU.

Le run complet, GPU seul contre GPU + CPU

Pré-entraînement, 1 500 pasGPU seul (bf16)GPU + CPU (fp32)
Temps par pas1,33 s1,13 s
Tokens par seconde~6 150~7 200
Durée totale33 min28 min
Validation finale (bits par octet)1,521,55
SFT puis chatidentiqueidentique

La validation finale est un peu moins bonne en hybride (1,55 contre 1,52). Nous n’avons pas encore isolé la cause : le passage en fp32, ou un effet de la répartition entre GPU et CPU.

Deux limites à connaître : le gain dépend du nombre de vCPU (avec 2 vCPU, il n’y a rien à partager), et nous n’avons appliqué cette méthode qu’au pré-entraînement, l’étape la plus longue. Le SFT tourne sur le GPU seul.

3. Ce que répond le modèle

What is the capital of France? The city of France has a fundamental concept in Japan, which is a city of France’s Italian history and country. […] a fundamental concept in Paris and the way to showcase the world’s most fundamental and modern aspects of the history…

Hi! Who are you? I’m glad you’ve got a few minutes of time. We’re passionate about the concept of “A”…

Le modèle a appris la forme d’une réponse d’assistant et des associations de mots (France, Paris), mais pas à raisonner : avec 4 couches et 39 minutes de calcul, c’est le résultat attendu. Le modèle de base, avant le SFT, se contentait de prolonger le texte sans répondre.

4. Ce qu’il a fallu changer

Pour le GPU Intel (PyTorch XPU)

  1. Reconnaître le GPU : nanochat ne connaît que cuda, mps et cpu. Nous ajoutons xpu (détection, synchronisation, mémoire).
  2. Pas de calcul en double précision (fp64) sur ce GPU : une ligne du calcul des embeddings rotatifs passait par du fp64 et plantait (UR error: 45). Nous la réécrivons en fp32.
  3. En-têtes Level Zero : torch.compile compile ses kernels GPU avec Triton XPU, qui a besoin du paquet libze-dev.
  4. Limite de 512 work-items par groupe : le tri des 32 768 tokens du vocabulaire (topk) dépasse cette limite. Nous le faisons sur le CPU, le coût est négligeable.

Pour nanochat en petite configuration

Ces quatre problèmes apparaissent aussi sur CPU : ils viennent de la configuration réduite (contexte de 512 tokens), pas du GPU.

  1. Le chargeur du SFT se bloque : il ne prend que les conversations qui tiennent entières dans 513 tokens. Les plus longues restent dans sa file d’attente jusqu’à la remplir, puis il ne produit plus que du remplissage : le modèle n’apprend plus rien, dérive et finit en nan. Nous tronquons les conversations à 513 tokens.
  2. Une loss nan quand un lot ne contient aucun token de réponse (division 0/0). Nous divisons par au moins 1.
  3. Un learning rate trop fort pour un si petit modèle : nous utilisons 20 % de la valeur par défaut pour le SFT, et nous nous arrêtons à 220 pas (au-delà, le modèle s’effondrait d’un coup, toujours au même pas).
  4. Le chat chargeait un ancien modèle : chat_cli prend le checkpoint au plus grand numéro de pas, pas le plus récent. Nous lui passons -s 219.

5. Le faire vous-même

Sur une VM avec un GPU Intel (Debian 13, noyau récent), une seule commande lance tout et chronomètre chaque étape :

curl -fsSLO https://linuxgpu.eu/blog/files/nanochat-xpu/run.sh
sudo bash run.sh                      # GPU seul
sudo HYBRID_CPU_ROWS=4 bash run.sh    # GPU + CPU

Le script installe les paquets, nanochat et PyTorch XPU, applique les correctifs (nanochat_xpu_patch.py et nanochat_hybrid_patch.py), puis enchaîne données, tokenizer, pré-entraînement, SFT et une première question. Les durées de chaque étape sont dans ~/nanochat-logs/timeline.txt. Pour discuter ensuite :

cd ~/nanochat && .venv/bin/python -m scripts.chat_cli --device-type=xpu -s 219

Ce qu’il faut en retenir

  • Un iGPU entraîne vraiment un petit modèle de langage, sans carte graphique dédiée : PyTorch natif, torch.compile, pas de CUDA, et le CPU peut l’épauler (−15 % de temps).
  • C’est le bon terrain pour apprendre comment fonctionne un LLM de bout en bout, modifier le code et voir l’effet en quelques minutes, pas pour entraîner un modèle utile en production.
  • Pour servir un modèle déjà entraîné, voir plutôt nos guides sur les modèles Hugging Face sur iGPU et l’inférence avec OpenVINO.

Essayer

Toutes nos VM ont un iGPU Intel UHD 770 utilisable par PyTorch XPU, OpenCL et Vulkan dès l’installation, à partir de 14,99 € HT par mois. Ce test a tourné sur l’offre iGPU Pro (6 vCPU, 24 Go de RAM, 240 Go de SSD, la plus grosse part de l’iGPU), à 44,99 € HT par mois : le bon choix pour entraîner, grâce aux vCPU qui épaulent l’iGPU. Voir les offres iGPU.