<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Local AI on kenji.blog</title><link>http://kenji.blog/fr/tags/local-ai/</link><description>Recent content in Local AI on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/local-ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Comment affiner TinyLLaMA le plus rapidement possible dans un environnement sur site</title><link>http://kenji.blog/fr/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/tinyllama-on-premises-fast-tuning-guide/</guid><description>&lt;img src="http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/img/eyecatch.jpg" alt="Featured image of post Comment affiner TinyLLaMA le plus rapidement possible dans un environnement sur site" />&lt;h2 id="1-introduction--pourquoi-tinyllama-et-le-sur-site-aujourdhui-">1. Introduction : Pourquoi TinyLLaMA et le sur site aujourd&amp;rsquo;hui ?
&lt;/h2>&lt;p>L&amp;rsquo;évolution des grands modèles de langage (LLM) progresse à une vitesse fulgurante, et avec elle, le nombre de paramètres des modèles continue de s&amp;rsquo;étendre pour atteindre des centaines de milliards. Si des modèles gigantesques comme GPT-4 et Claude 3 offrent des performances inégalées, les coûts de calcul pour l&amp;rsquo;inférence et l&amp;rsquo;apprentissage, ainsi que les problèmes de sécurité et de confidentialité des données lors de l&amp;rsquo;utilisation d&amp;rsquo;API externes, constituent des obstacles majeurs pour les entreprises. En particulier pour les tâches impliquant des données internes hautement confidentielles ou des informations personnelles, l&amp;rsquo;envoi de données à des API LLM publiques dans le cloud est souvent inacceptable du point de vue de la conformité (RGPD, APPI, etc.).&lt;/p>
&lt;p>C&amp;rsquo;est là que les &lt;strong>petits modèles de langage (SLM : Small Language Models)&lt;/strong> et le &lt;strong>déploiement local dans des environnements sur site&lt;/strong> (on-premises) entrent en jeu. Parmi eux, &amp;ldquo;&lt;strong>TinyLLaMA&lt;/strong>&amp;rdquo; se distingue. Avec une taille compacte de seulement 1,1B (1,1 milliard) de paramètres, il a été pré-entraîné sur un ensemble de données massif d&amp;rsquo;environ 3 billions de jetons (tokens), offrant des performances exceptionnelles par rapport aux modèles de la même catégorie.&lt;/p>
&lt;p>Cet article fournit un guide complet pour affiner (fine-tuning) TinyLLaMA de manière &amp;ldquo;ultra-rapide et très efficace&amp;rdquo; pour vos tâches spécifiques dans un environnement sur site (serveur local ou station de travail). Nous couvrirons tout de manière exhaustive, des fondements mathématiques aux dernières techniques d&amp;rsquo;optimisation, en passant par le code d&amp;rsquo;implémentation concret en PyTorch.&lt;/p>
&lt;hr>
&lt;h2 id="2-architecture-et-caractéristiques-de-tinyllama">2. Architecture et caractéristiques de TinyLLaMA
&lt;/h2>&lt;p>TinyLLaMA suit l&amp;rsquo;architecture LLaMA (Large Language Model Meta AI) développée par Meta. Tout en maintenant le nombre de paramètres à 1,1B, il utilise la même pile technologique que LLaMA 2, ce qui rend son écosystème hautement compatible.&lt;/p>
&lt;h3 id="principaux-composants-de-larchitecture">Principaux composants de l&amp;rsquo;architecture
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization) :&lt;/strong>
Une méthode de normalisation qui améliore l&amp;rsquo;efficacité des calculs en omettant la soustraction de la moyenne des calculs LayerNorm traditionnels. Elle augmente le débit tout en maintenant la stabilité de l&amp;rsquo;apprentissage.&lt;/li>
&lt;li>&lt;strong>Fonction d&amp;rsquo;activation SwiGLU :&lt;/strong>
Dans le Feed Forward Network (FFN), SwiGLU est utilisé à la place des classiques ReLU ou GELU. Mathématiquement, cela s&amp;rsquo;exprime comme suit :
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
Ici, $\otimes$ représente le produit élément par élément (produit de Hadamard), et la fonction Swish est $\text{Swish}(z) = z \cdot \sigma(\beta z)$. Cela améliore considérablement la puissance de représentation.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding) :&lt;/strong>
Une méthode qui combine les avantages de l&amp;rsquo;encodage de position absolu et relatif. Elle présente de fortes performances de généralisation même lorsque la longueur de la séquence est étendue.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA) :&lt;/strong>
Une approche intermédiaire entre la Multi-Head Attention (MHA) et la Multi-Query Attention (MQA), qui permet d&amp;rsquo;économiser la bande passante mémoire et d&amp;rsquo;améliorer considérablement la vitesse d&amp;rsquo;inférence en regroupant les têtes de clé (key) et de valeur (value).&lt;/li>
&lt;/ol>
&lt;p>Le diagramme Mermaid ci-dessous illustre le flux de données global de TinyLLaMA et la structure du bloc Transformer.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texte d'entrée"] --> B["Tokeniseur (BPE)"]
B --> C["Couche d'intégration (Embedding)"]
C --> D["Blocs Transformer (x22 Couches pour TinyLLaMA)"]
D --> E["RMSNorm (Final)"]
E --> F["Projection Linéaire (Taille du vocabulaire)"]
F --> G["Probabilités de sortie (Softmax)"]
subgraph "Anatomie du bloc Transformer"
D1["État caché d'entrée"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Ajout Résiduel"]
D4 --> D5["RMSNorm"]
D5 --> D6["FFN SwiGLU"]
D6 --> D7["Ajout Résiduel"]
D7 --> D8["Sortie vers la couche suivante"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-la-révolution-du-fine-tuning--lora-et-qlora">3. La révolution du Fine-Tuning : LoRA et QLoRA
&lt;/h2>&lt;p>Pour effectuer un fine-tuning avec tous les paramètres dans un environnement sur site, même avec un modèle de 1,1B, il faut consommer des dizaines de gigaoctets de VRAM (mémoire vidéo) pour stocker les états de l&amp;rsquo;optimiseur et les gradients. Les méthodes &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong> telles que &amp;ldquo;&lt;strong>LoRA&lt;/strong>&amp;rdquo; et son extension quantifiée &amp;ldquo;&lt;strong>QLoRA&lt;/strong>&amp;rdquo; sont essentielles pour un apprentissage efficace avec des ressources limitées.&lt;/p>
&lt;h3 id="31-contexte-mathématique-de-lora-low-rank-adaptation">3.1 Contexte mathématique de LoRA (Low-Rank Adaptation)
&lt;/h3>&lt;p>LoRA est une méthode qui fixe (gèle) la matrice de poids pré-entraînée et approxime la quantité de mise à jour de ce poids ($\Delta W$) par le produit de deux petites matrices de rang inférieur.&lt;/p>
&lt;p>Soit $W_0 \in \mathbb{R}^{d \times k}$ le poids pré-entraîné. Dans un fine-tuning complet, $W_0$ lui-même est mis à jour en $W_0 + \Delta W$. Cependant, avec LoRA, la matrice de mise à jour $\Delta W$ est décomposée comme suit :&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>Ici, $B \in \mathbb{R}^{d \times r}$ et $A \in \mathbb{R}^{r \times k}$, et $r$ est un hyperparamètre appelé rang (Rank), qui est une très petite valeur (généralement 8, 16, 32, etc.) satisfaisant $r \ll \min(d, k)$.&lt;/p>
&lt;p>Le calcul de la passe avant (forward pass) est le suivant :&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>À l&amp;rsquo;état initial, la matrice $A$ est initialisée de manière aléatoire avec une distribution normale (distribution gaussienne), et la matrice $B$ est initialisée avec une matrice nulle. Ainsi, $\Delta W$ au début de l&amp;rsquo;apprentissage est zéro, ce qui permet de commencer l&amp;rsquo;apprentissage tout en conservant parfaitement la sortie du modèle de base.&lt;/p>
&lt;div class="mermaid">graph LR
X["Vecteur d'entrée x"] --> W0["Poids pré-entraîné gelé (W_0)"]
X --> A["Matrice LoRA entraînable A (r x k)"]
A --> B["Matrice LoRA entraînable B (d x r)"]
W0 --> Add["Addition vectorielle"]
B --> Add
Add --> Y["Vecteur de sortie h"]&lt;/div>
&lt;h3 id="32-linnovation-de-qlora-quantized-lora">3.2 L&amp;rsquo;innovation de QLoRA (Quantized LoRA)
&lt;/h3>&lt;p>QLoRA pousse l&amp;rsquo;approche LoRA encore plus loin en quantifiant le modèle de base $W_0$ avec une précision de 4 bits (NormalFloat 4, NF4) et en le chargeant en mémoire. Cela réduit considérablement la consommation de VRAM.&lt;/p>
&lt;p>QLoRA intègre trois technologies importantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Quantification 4-bit NormalFloat (NF4) :&lt;/strong> Un type de données théoriquement optimal pour les poids suivant une distribution normale.&lt;/li>
&lt;li>&lt;strong>Double Quantification (Double Quantization) :&lt;/strong> Économise encore plus de mémoire en quantifiant également la constante de quantification (facteur d&amp;rsquo;échelle) elle-même.&lt;/li>
&lt;li>&lt;strong>Paged Optimizers :&lt;/strong> Utilise la fonction de mémoire unifiée de NVIDIA pour évacuer temporairement le statut de l&amp;rsquo;optimiseur vers la RAM du processeur lorsque la VRAM est insuffisante.&lt;/li>
&lt;/ol>
&lt;p>Grâce à cela, un fine-tuning qui nécessite normalement 16 à 24 Go de VRAM peut être exécuté confortablement même sur des GPU grand public (comme la RTX 3060 12 Go ou la RTX 4070).&lt;/p>
&lt;hr>
&lt;h2 id="4-exigences-matérielles-et-configuration-dans-un-environnement-sur-site">4. Exigences matérielles et configuration dans un environnement sur site
&lt;/h2>&lt;p>Les exigences matérielles pour affiner TinyLLaMA (1,1B) avec QLoRA sont extrêmement faibles.&lt;/p>
&lt;h3 id="spécifications-matérielles-recommandées">Spécifications matérielles recommandées
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU :&lt;/strong> NVIDIA RTX 3060 (12 Go), RTX 3090/4090 (24 Go), ou NVIDIA A10G/A100, etc. Un minimum de 8 Go de VRAM est nécessaire pour fonctionner, mais 12 Go ou plus sont recommandés pour augmenter la taille du lot (batch size).&lt;/li>
&lt;li>&lt;strong>CPU :&lt;/strong> Processeur moderne à 8 cœurs ou plus (Intel Core i7/i9, AMD Ryzen 7/9)&lt;/li>
&lt;li>&lt;strong>RAM :&lt;/strong> 32 Go ou plus (Important comme destination d&amp;rsquo;évacuation depuis la VRAM lors de l&amp;rsquo;utilisation de Paged Optimizers)&lt;/li>
&lt;li>&lt;strong>Stockage :&lt;/strong> SSD NVMe (Pour accélérer le chargement des ensembles de données et la sauvegarde du modèle)&lt;/li>
&lt;/ul>
&lt;h3 id="configuration-de-lenvironnement-logiciel">Configuration de l&amp;rsquo;environnement logiciel
&lt;/h3>&lt;p>Voici les étapes d&amp;rsquo;installation prévues pour un environnement Ubuntu 22.04 LTS. Nous utiliserons Python 3.10 ou une version ultérieure.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Création et activation de l&amp;#39;environnement virtuel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 -m venv tinyllama_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> tinyllama_env/bin/activate
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installation de PyTorch (pour CUDA 12.1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installation des bibliothèques liées aux Transformers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install transformers datasets peft trl accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="5-techniques-doptimisation-pour-le-fine-tuning-le-plus-rapide">5. Techniques d&amp;rsquo;optimisation pour le fine-tuning le plus rapide
&lt;/h2>&lt;p>Pour terminer le fine-tuning &amp;ldquo;le plus rapidement possible&amp;rdquo; plutôt que de simplement exécuter un script, il est nécessaire de combiner les techniques d&amp;rsquo;optimisation suivantes.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>Le mécanisme d&amp;rsquo;Attention standard a une complexité temporelle et spatiale de $O(N^2)$ pour une longueur de séquence $N$. Flash Attention 2 optimise l&amp;rsquo;accès mémoire entre la SRAM du GPU et la HBM (High Bandwidth Memory), éliminant ainsi les goulots d&amp;rsquo;étranglement d&amp;rsquo;E/S sans réduire la quantité de calcul, augmentant la vitesse d&amp;rsquo;apprentissage de plusieurs fois et réduisant considérablement la consommation de mémoire.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-point-de-contrôle-du-gradient">5.2 Gradient Checkpointing (Point de contrôle du gradient)
&lt;/h3>&lt;p>Une technique dans laquelle, au lieu de sauvegarder toutes les activations intermédiaires calculées lors de la passe avant dans la VRAM, seule une partie est sauvegardée, et elles sont recalculées lorsqu&amp;rsquo;elles sont nécessaires lors de la passe arrière. Le temps de calcul augmente d&amp;rsquo;environ 20 %, mais la consommation de mémoire peut être considérablement réduite, ce qui permet de définir une taille de lot plus importante et d&amp;rsquo;améliorer le débit global.&lt;/p>
&lt;h3 id="53-mixed-precision-training-apprentissage-en-précision-mixte-et-bfloat16">5.3 Mixed Precision Training (Apprentissage en précision mixte) et Bfloat16
&lt;/h3>&lt;p>Pour maximiser l&amp;rsquo;utilisation des Tensor Cores du GPU, les calculs pendant l&amp;rsquo;apprentissage sont effectués en &lt;code>bfloat16&lt;/code> (Brain Floating Point). Par rapport à &lt;code>float16&lt;/code>, la longueur en bits de l&amp;rsquo;exposant est la même que celle de &lt;code>float32&lt;/code>, de sorte que le risque de dépassement de capacité (overflow) ou de sous-dépassement (underflow) est extrêmement faible, ce qui stabilise l&amp;rsquo;apprentissage.&lt;/p>
&lt;hr>
&lt;h2 id="6-pratique--code-de-fine-tuning-qlora-pour-tinyllama">6. Pratique : Code de fine-tuning QLoRA pour TinyLLaMA
&lt;/h2>&lt;p>Nous allons maintenant expliquer le script PyTorch pour le fine-tuning le plus rapide intégrant toutes les optimisations ci-dessus. Nous utiliserons ici &lt;code>SFTTrainer&lt;/code> de la bibliothèque &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) de Hugging Face.&lt;/p>
&lt;h3 id="61-préparation-de-lensemble-de-données-et-chargement-du-modèle">6.1 Préparation de l&amp;rsquo;ensemble de données et chargement du modèle
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datasets&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dataset&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TrainingArguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">trl&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Spécification du modèle et du tokeniseur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;TinyLlama/TinyLlama-1.1B-Chat-v1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Paramètres de quantification 4-bit pour QLoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bnb_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_in_4bit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_use_double_quant&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_quant_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;nf4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_compute_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span> &lt;span class="c1"># Les calculs sont effectués en bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Chargement du modèle (Activation de Flash Attention 2)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement du modèle...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantization_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bnb_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_flash_attention_2&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span> &lt;span class="c1"># La clé de l&amp;#39;accélération&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Chargement du tokeniseur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">trust_remote_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pad_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">eos_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">padding_side&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;right&amp;#34;&lt;/span> &lt;span class="c1"># Défini sur right pour éviter un bug lors de l&amp;#39;entraînement fp16/bf16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-application-de-ladaptateur-lora-et-formatage-des-données">6.2 Application de l&amp;rsquo;adaptateur LoRA et formatage des données
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. Préparation de l&amp;#39;apprentissage k-bit et activation du gradient checkpointing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gradient_checkpointing_enable&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 6. Configuration de LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">peft_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Rang&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Facteur d&amp;#39;échelle&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_dropout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.05&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bias&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;none&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;CAUSAL_LM&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_modules&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;q_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;k_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;o_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;gate_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;up_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;down_proj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># Cibler toutes les couches Linear améliore les performances&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">peft_config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">print_trainable_parameters&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple de sortie : trainable params: 14,286,848 || all params: 1,114,335,232 || trainable%: 1.282%&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 7. Chargement de l&amp;#39;ensemble de données (ici, un ensemble de données d&amp;#39;instructions en japonais est utilisé comme exemple)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># En réalité, vous chargerez un fichier JSONL privé sur site, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_dataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kunishou/databricks-dolly-15k-ja&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">split&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;train&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">format_instruction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Formate la chaîne pour correspondre au format ChatML ou au modèle de prompt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_start|&amp;gt;user&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;instruction&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;input&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_end|&amp;gt;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;|im_start|&amp;gt;assistant&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;output&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataset&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">format_instruction&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="63-exécution-de-lentraînement">6.3 Exécution de l&amp;rsquo;entraînement
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 8. Configuration des arguments d&amp;#39;entraînement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">training_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TrainingArguments&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-output&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">per_device_train_batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Augmenter s&amp;#39;il y a assez de VRAM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gradient_accumulation_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Taille de lot effective = 8 * 2 = 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">optim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;paged_adamw_32bit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Économie de VRAM avec Paged Optimizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">learning_rate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2e-4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fp16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bf16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Apprentissage en précision mixte (bfloat16)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_grad_norm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 500 étapes pour les tests. En production, spécifier par nombre d&amp;#39;époques&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warmup_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.03&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">group_by_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lr_scheduler_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 9. Démarrage de l&amp;#39;apprentissage avec SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">train_dataset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">peft_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">peft_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dataset_text_field&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_seq_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Ajuster selon la longueur d&amp;#39;entrée prévue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">training_args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Démarrage de l&amp;#39;entraînement...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 10. Sauvegarde de l&amp;#39;adaptateur LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Entraînement terminé et modèle sauvegardé.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-évaluation-des-performances-et-dépannage">7. Évaluation des performances et dépannage
&lt;/h2>&lt;p>Voici les problèmes courants rencontrés lors de l&amp;rsquo;exécution de l&amp;rsquo;apprentissage dans un environnement sur site et leurs solutions.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OOM (Out Of Memory) se produit :&lt;/strong>
&lt;ul>
&lt;li>Réduisez &lt;code>per_device_train_batch_size&lt;/code> à &lt;code>1&lt;/code>.&lt;/li>
&lt;li>Augmentez &lt;code>gradient_accumulation_steps&lt;/code> pour maintenir la taille de lot effective.&lt;/li>
&lt;li>Raccourcissez &lt;code>max_seq_length&lt;/code> de &lt;code>2048&lt;/code> à &lt;code>1024&lt;/code> ou &lt;code>512&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>La perte (Loss) ne diminue pas / diverge :&lt;/strong>
&lt;ul>
&lt;li>Le taux d&amp;rsquo;apprentissage (&lt;code>learning_rate&lt;/code>) peut être trop élevé. Essayez de le réduire de &lt;code>2e-4&lt;/code> à environ &lt;code>5e-5&lt;/code>.&lt;/li>
&lt;li>Si vous utilisez Float16 au lieu de Bfloat16, un sous-dépassement de gradient peut se produire. Vérifiez &lt;code>bf16=True&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Des chaînes de caractères mystérieuses sont générées lors de l&amp;rsquo;inférence :&lt;/strong>
&lt;ul>
&lt;li>Assurez-vous que &lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> est correctement défini. Il est également nécessaire de vérifier si le format du jeu de données (les tokens spéciaux comme &lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code>) est cohérent avec celui de la phase de pré-entraînement du modèle de base.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-déploiement-du-modèle-après-le-fine-tuning">8. Déploiement du modèle après le fine-tuning
&lt;/h2>&lt;p>Une fois le fine-tuning terminé, ce qui est sauvegardé n&amp;rsquo;est pas &amp;ldquo;l&amp;rsquo;ensemble du modèle de base&amp;rdquo;, mais seulement &amp;ldquo;l&amp;rsquo;&lt;strong>adaptateur LoRA (poids différentiels)&lt;/strong>&amp;rdquo; de quelques mégaoctets à quelques dizaines de mégaoctets. Pour effectuer une inférence à grande vitesse, ce poids LoRA doit être fusionné (intégré) dans le modèle de base d&amp;rsquo;origine et exporté en tant que modèle unique.&lt;/p>
&lt;h3 id="script-de-fusion-de-modèle">Script de fusion de modèle
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Charger le modèle et l&amp;#39;adaptateur en FP16/BF16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output_dir&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Fusionner les poids et sauvegarder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge_and_unload&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">safe_serialization&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Modèle fusionné et sauvegardé avec succès !&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="lancement-dun-serveur-dinférence-ultra-rapide-avec-vllm">Lancement d&amp;rsquo;un serveur d&amp;rsquo;inférence ultra-rapide avec vLLM
&lt;/h3>&lt;p>Pour un déploiement dans un environnement sur site, afin de maximiser la vitesse d&amp;rsquo;inférence (Jetons par seconde), il est fortement recommandé d&amp;rsquo;utiliser &lt;strong>vLLM&lt;/strong> ou &lt;strong>TGI (Text Generation Inference)&lt;/strong> au lieu du &lt;code>pipeline&lt;/code> standard de Hugging Face. vLLM utilise la technologie PagedAttention pour éviter la fragmentation de la mémoire GPU, améliorant considérablement la capacité de traitement des requêtes simultanées.&lt;/p>
&lt;p>Le diagramme Mermaid ci-dessous montre le pipeline allant de l&amp;rsquo;apprentissage au déploiement du serveur d&amp;rsquo;inférence.&lt;/p>
&lt;div class="mermaid">graph TD
A["Données privées brutes"] --> B["Prétraitement et formatage (JSONL)"]
B --> C["Fine-Tuning QLoRA (SFTTrainer)"]
C --> D["Poids de l'adaptateur LoRA (.safetensors)"]
D --> E["Fusion avec le TinyLLaMA 1.1B de base"]
E --> F["Modèle fusionné"]
F --> G["Déploiement via le serveur vLLM"]
G --> H["Point de terminaison API / UI (par ex. Chatbot)"]&lt;/div>
&lt;p>Le démarrage du serveur d&amp;rsquo;API avec vLLM s&amp;rsquo;effectue avec la commande suivante.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">python -m vllm.entrypoints.openai.api_server &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model ./tinyllama-merged &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --host 0.0.0.0 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --port &lt;span class="m">8000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-model-len &lt;span class="m">2048&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dtype bfloat16
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec cela, un point de terminaison compatible avec l&amp;rsquo;API OpenAI est construit dans l&amp;rsquo;environnement sur site, vous permettant d&amp;rsquo;utiliser l&amp;rsquo;IA locale de manière sécurisée et à haute vitesse.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion">9. Conclusion
&lt;/h2>&lt;p>Dans cet article, nous avons expliqué la méthode de fine-tuning de &amp;ldquo;TinyLLaMA&amp;rdquo;, qui offre des performances élevées malgré son poids léger de 1,1B de paramètres, de manière très rapide et économe en mémoire dans un environnement sur site.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LoRA / QLoRA&lt;/strong> permet un véritable fine-tuning de LLM même sur des GPU grand public.&lt;/li>
&lt;li>En exploitant &lt;strong>Flash Attention 2&lt;/strong> et &lt;strong>Gradient Checkpointing&lt;/strong>, le temps d&amp;rsquo;apprentissage et la consommation de VRAM sont optimisés à l&amp;rsquo;extrême.&lt;/li>
&lt;li>Le déploiement utilisant &lt;strong>vLLM&lt;/strong> permet d&amp;rsquo;atteindre un débit élevé même dans des environnements de production.&lt;/li>
&lt;/ul>
&lt;p>L&amp;rsquo;exploitation locale de LLM sur site protège non seulement la confidentialité des données, mais constitue également l&amp;rsquo;arme ultime pour construire à faible coût une IA spécialisée pour un domaine spécifique (juridique, médical, réglementations internes, etc.). N&amp;rsquo;hésitez pas à utiliser ce guide comme référence pour développer votre propre TinyLLaMA.&lt;/p></description></item><item><title>Procédure de développement de petits modèles d'IA (TinyLLaMA, etc.) avec C++</title><link>http://kenji.blog/fr/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cpp-small-ai-model-tinyllama-dev-guide/</guid><description>&lt;img src="http://kenji.blog/p/cpp-small-ai-model-tinyllama-dev-guide/img/eyecatch.jpg" alt="Featured image of post Procédure de développement de petits modèles d'IA (TinyLLaMA, etc.) avec C++" />&lt;h1 id="procédure-de-développement-de-petits-modèles-dia-tinyllama-etc-avec-c">Procédure de développement de petits modèles d&amp;rsquo;IA (TinyLLaMA, etc.) avec C++
&lt;/h1>&lt;p>Ces dernières années, l&amp;rsquo;intérêt pour l&amp;rsquo;exécution locale de grands modèles de langage (LLM) a augmenté rapidement. En particulier, les petits modèles tels que TinyLLaMA (1,1B paramètres) peuvent effectuer des inférences à une vitesse pratique même sur des appareils périphériques aux ressources limitées ou des PC portables standards (y compris les environnements Windows). Bien que le développement utilisant Python et PyTorch soit courant, lorsqu&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;atteindre des performances et une efficacité mémoire ultimes, la combinaison du C++ et de « ggml », une bibliothèque de tenseurs basée sur le langage C, est devenue la norme de facto.&lt;/p>
&lt;p>Cet article explique en détail la procédure de développement pour construire un moteur d&amp;rsquo;inférence à partir de zéro (ou comprendre en profondeur l&amp;rsquo;architecture interne du llama.cpp existant) afin de charger TinyLLaMA et de générer du texte en utilisant C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-pourquoi-c-et-ggml-">1. Pourquoi C++ et ggml ?
&lt;/h2>&lt;p>Dans la phase d&amp;rsquo;apprentissage de l&amp;rsquo;IA, Python, avec sa flexibilité et son écosystème riche, a un avantage écrasant. Cependant, dans les phases de déploiement ou d&amp;rsquo;« inférence (Inference) », C++ devient un choix puissant pour les raisons suivantes.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Réduction des surcoûts&lt;/strong> : Le Global Interpreter Lock (GIL) de Python et les surcoûts d&amp;rsquo;exécution peuvent être complètement éliminés.&lt;/li>
&lt;li>&lt;strong>Efficacité de la mémoire et allocation d&amp;rsquo;arène&lt;/strong> : L&amp;rsquo;allocation et la libération de la mémoire pouvant être contrôlées manuellement, les pics imprévisibles causés par le ramasse-miettes (garbage collection) sont évités.&lt;/li>
&lt;li>&lt;strong>Accès direct au matériel&lt;/strong> : Il est possible d&amp;rsquo;appeler directement des fonctions intrinsèques SIMD (Intrinsics) telles que AVX-512, AVX2 et ARM NEON, exploitant ainsi la puissance de calcul du processeur à son maximum.&lt;/li>
&lt;li>&lt;strong>Élimination des dépendances&lt;/strong> : ggml est une bibliothèque C/C++ sans aucune dépendance (Zero dependencies), et peut être facilement compilée même dans un environnement MSVC sous Windows tant qu&amp;rsquo;il y a un compilateur.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-vue-densemble-de-larchitecture">2. Vue d&amp;rsquo;ensemble de l&amp;rsquo;architecture
&lt;/h2>&lt;p>Le diagramme Mermaid ci-dessous montre le flux complet du pipeline d&amp;rsquo;inférence. Il s&amp;rsquo;agit d&amp;rsquo;une série de processus commençant par le texte d&amp;rsquo;entrée de l&amp;rsquo;utilisateur et se terminant par la génération du jeton suivant.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texte d'entrée utilisateur"] --> B["Tokeniseur BPE"]
B --> C["Tableau d'ID de jetons"]
C --> D["Recherche de couche d'intégration"]
D --> E["Blocs Transformer"]
E --> F["RMSNorm"]
F --> G["Couche LM Head"]
G --> H["Tableau des logits"]
H --> I["Module échantillonneur"]
I --> J["ID du jeton suivant"]
J --> K["Détokeniseur"]
K --> L["Morceau de texte de sortie"]
J -.-> |"Ajouter au contexte"| C&lt;/div>
&lt;p>Puisqu&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;un modèle autorégressif, le jeton produit est à nouveau ajouté au contexte et circule en tant qu&amp;rsquo;entrée pour la prédiction du jeton suivant (la partie en pointillé du diagramme).&lt;/p>
&lt;hr>
&lt;h2 id="3-format-de-modèle-et-mappage-en-mémoire-mmap">3. Format de modèle et mappage en mémoire (mmap)
&lt;/h2>&lt;p>Le principal obstacle à la gestion des poids des grands réseaux de neurones est l&amp;rsquo;I/O disque et la consommation de mémoire. Dans l&amp;rsquo;implémentation C++ , cela est résolu par le &lt;strong>mappage en mémoire (mmap)&lt;/strong>.&lt;/p>
&lt;h3 id="31-mécanisme-du-mappage-en-mémoire-et-implémentation-sous-windows">3.1 Mécanisme du mappage en mémoire et implémentation sous Windows
&lt;/h3>&lt;p>L&amp;rsquo;utilisation de mmap permet de mapper le contenu d&amp;rsquo;un fichier directement dans l&amp;rsquo;espace mémoire virtuel du processus.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zéro copie (Zero-copy)&lt;/strong> : Les données sont lues directement depuis le disque vers le cache de pages du noyau, évitant ainsi des copies supplémentaires vers l&amp;rsquo;espace utilisateur.&lt;/li>
&lt;li>&lt;strong>Chargement à la demande (Page Fault)&lt;/strong> : Au moment précis où le processeur accède à cette adresse mémoire, un défaut de page (page fault) se produit, et seul le morceau (chunk) requis (généralement 4 Ko) est chargé dans la mémoire physique.&lt;/li>
&lt;/ul>
&lt;p>Dans l&amp;rsquo;environnement Windows, au lieu du &lt;code>mmap&lt;/code> de POSIX, on utilise les API Win32 &lt;code>CreateFileMapping&lt;/code> et &lt;code>MapViewOfFile&lt;/code>.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["Système d'exploitation Windows"]
participant RAM["Mémoire physique"]
participant App["Application C++"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Pointeur d'adresse de mémoire virtuelle"
App->>App: "Lire les données du tenseur au pointeur"
OS->>RAM: "Défaut de page / Charger la page depuis le disque"
RAM-->>App: "Données prêtes pour le calcul SIMD"&lt;/div>
&lt;h3 id="32-structure-binaire-du-format-gguf">3.2 Structure binaire du format GGUF
&lt;/h3>&lt;p>Converti à partir de formats tels que &lt;code>.safetensors&lt;/code> de Hugging Face, le &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> est le format ultime pour l&amp;rsquo;inférence. Il possède la disposition binaire stricte suivante.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Octets magiques (Magic Bytes)&lt;/strong> : &lt;code>0x46554747&lt;/code> (GGUF).&lt;/li>
&lt;li>&lt;strong>Version&lt;/strong> : Numéro de version du format.&lt;/li>
&lt;li>&lt;strong>Nombre de tenseurs et de métadonnées&lt;/strong> : Nombre de tenseurs et de paires clé-valeur de métadonnées.&lt;/li>
&lt;li>&lt;strong>Métadonnées (Paires Clé-Valeur)&lt;/strong> : Clés avec préfixe de longueur de chaîne, et valeurs typées.&lt;/li>
&lt;li>&lt;strong>Infos sur le tenseur&lt;/strong> : Nom de chaque tenseur, nombre de dimensions, type de données (FP16, Q4_K, etc.), et position de décalage (offset) dans le fichier.&lt;/li>
&lt;li>&lt;strong>Remplissage (Padding)&lt;/strong> : Remplissage inséré de sorte que les données du tenseur soient alignées sur une limite spécifique (généralement 32 octets ou 64 octets). Indispensable pour un accès rapide à la mémoire avec les instructions SIMD (en particulier AVX).&lt;/li>
&lt;li>&lt;strong>Données du tenseur&lt;/strong> : Tableau des données de poids réelles alignées.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-fondements-mathématiques-de-tinyllama-et-algorithmes-c">4. Fondements mathématiques de TinyLLaMA et algorithmes C++
&lt;/h2>&lt;p>TinyLLaMA intègre plusieurs améliorations architecturales avancées pour l&amp;rsquo;efficacité. Nous expliquons ici les expressions mathématiques pour les implémenter correctement en C++.&lt;/p>
&lt;h3 id="41-rmsnorm-root-mean-square-normalization">4.1 RMSNorm (Root Mean Square Normalization)
&lt;/h3>&lt;p>Il omet le centrage de la moyenne du LayerNorm et n&amp;rsquo;effectue que la mise à l&amp;rsquo;échelle de la variance, ce qui réduit les coûts de calcul.&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>$d$ est le nombre de dimensions, $\gamma$ est le tenseur de mise à l&amp;rsquo;échelle appris.
Lors de l&amp;rsquo;implémentation en C++, on optimise d&amp;rsquo;abord en calculant rapidement la somme des carrés du tableau avec &lt;code>_mm256_fmadd_ps&lt;/code> d&amp;rsquo;AVX2, etc., et en la multipliant par la racine carrée inverse (par ex., avec l&amp;rsquo;instruction &lt;code>_mm256_rsqrt_ps&lt;/code>).&lt;/p>
&lt;h3 id="42-rope-rotary-position-embedding">4.2 RoPE (Rotary Position Embedding)
&lt;/h3>&lt;p>C&amp;rsquo;est une technique qui applique l&amp;rsquo;information de position du jeton sous forme de rotation (Rotate) dans l&amp;rsquo;espace tensoriel. Elle peut être considérée comme une rotation sur un plan complexe, appliquant la rotation suivante à la paire de dimensions adjacentes $(x_1, x_2)$ du vecteur $x$.&lt;/p>
$$ \text{RoPE}(x, m) = \begin{pmatrix} x_{1} \cos(m\theta) - x_{2} \sin(m\theta) \\ x_{1} \sin(m\theta) + x_{2} \cos(m\theta) \end{pmatrix} $$
&lt;p>Ici, $m$ est l&amp;rsquo;index de position absolu du jeton, $\theta$ est la fréquence fondamentale précalculée. Dans ggml, elle s&amp;rsquo;exécute en parallèle simplement en ajoutant l&amp;rsquo;opérateur &lt;code>ggml_rope&lt;/code> pendant la construction du graphe d&amp;rsquo;inférence.&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>Dans le Multi-Head Attention (MHA) standard, on a le même nombre de têtes (heads) pour Query, Key et Value. Cependant, TinyLLaMA utilise le &lt;strong>Grouped-Query Attention (GQA)&lt;/strong> pour réduire drastiquement la bande passante mémoire et la consommation du cache KV.&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>Dans le GQA, plusieurs têtes Query partagent une seule tête Key/Value. L&amp;rsquo;implémentation C++ nécessite une opération de diffusion (broadcast) du tenseur KV pour correspondre au nombre de Query avant d&amp;rsquo;exécuter la multiplication matricielle &lt;code>ggml_mul_mat&lt;/code>.&lt;/p>
&lt;h3 id="44-fonction-dactivation-swiglu">4.4 Fonction d&amp;rsquo;activation SwiGLU
&lt;/h3>&lt;p>Dans la couche de réseau à propagation avant (Feed-Forward Network, FFN), SwiGLU est utilisé à la place de GELU.&lt;/p>
$$ \text{SwiGLU}(x) = \text{Swish}(x W_{\text{gate}}) \otimes (x W_{\text{up}}) $$
$$ \text{Swish}(z) = z \cdot \sigma(z) = z \cdot \frac{1}{1 + e^{-z}} $$
&lt;p>Dans le graphe de calcul, ceci est exprimé en combinant les opérateurs &lt;code>ggml_silu&lt;/code> et &lt;code>ggml_mul&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-construction-du-graphe-de-calcul-avec-ggml-et-gestion-de-la-mémoire">5. Construction du graphe de calcul avec ggml et gestion de la mémoire
&lt;/h2>&lt;p>ggml adopte une approche « Define-and-Run », construisant un graphe de calcul statique pour l&amp;rsquo;inférence et l&amp;rsquo;évaluant (evaluate) par la suite.&lt;/p>
&lt;h3 id="51-ggml_context-et-allocateur-darène">5.1 ggml_context et allocateur d&amp;rsquo;arène
&lt;/h3>&lt;p>Le point le plus unique de ggml est l&amp;rsquo;« allocation d&amp;rsquo;arène » qui n&amp;rsquo;effectue aucune allocation de mémoire dynamique (&lt;code>malloc&lt;/code> ou &lt;code>new&lt;/code>) à l&amp;rsquo;intérieur de la boucle d&amp;rsquo;inférence.
Lors de l&amp;rsquo;initialisation, une énorme zone mémoire contiguë (arène) est allouée, et chaque fois que &lt;code>ggml_new_tensor&lt;/code> etc. est appelé, le pointeur de cette zone est incrémenté. Une fois qu&amp;rsquo;une étape d&amp;rsquo;inférence est terminée, il suffit de réinitialiser le pointeur d&amp;rsquo;allocation à sa position initiale pour terminer instantanément l&amp;rsquo;allocation de mémoire pour l&amp;rsquo;étape d&amp;rsquo;inférence suivante.&lt;/p>
&lt;h3 id="52-exemple-concret-de-construction-de-graphe">5.2 Exemple concret de construction de graphe
&lt;/h3>&lt;p>À chaque étape d&amp;rsquo;inférence, le graphe de calcul suivant est assemblé en mémoire.&lt;/p>
&lt;div class="mermaid">graph TD
A["ID d'entrée des jetons"] --> B["Recherche d'intégration"]
B --> C["ggml_rms_norm"]
C --> D["Projections Q / K / V"]
D --> E["ggml_rope Positionnel"]
E --> F["Stockage du cache KV"]
E --> G["Chargement du cache KV"]
G --> H["Auto-Attention"]
H --> I["Échelle &amp; Softmax"]
I --> J["Sortie de l'Attention"]
J --> K["Projection de Sortie"]
K --> L["Ajout Résiduel"]&lt;/div>
&lt;hr>
&lt;h2 id="6-quantification-quantization-et-optimisation-windows--simd">6. Quantification (Quantization) et optimisation Windows / SIMD
&lt;/h2>&lt;p>Traiter TinyLLaMA (1.1B) en FP16 nécessite environ 2,2 Go de mémoire, mais cela peut être considérablement réduit à environ 600 Mo grâce à la quantification 4 bits (comme Q4_K).&lt;/p>
&lt;h3 id="61-architecture-de-quantification-par-blocs">6.1 Architecture de quantification par blocs
&lt;/h3>&lt;p>ggml ne quantifie pas l&amp;rsquo;intégralité du tenseur uniformément, mais le fait par unités de « blocs ».
Dans le format &lt;code>Q4_0&lt;/code>, 32 valeurs FP16 sont regroupées en un seul bloc.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Facteur d&amp;rsquo;échelle (Scale factor)&lt;/strong> : 1 valeur FP16 (2 octets)&lt;/li>
&lt;li>&lt;strong>Données quantifiées&lt;/strong> : 32 valeurs 4 bits (16 octets)
Cela minimise l&amp;rsquo;impact des valeurs aberrantes locales.&lt;/li>
&lt;/ul>
&lt;h3 id="62-accélération-du-produit-scalaire-avec-avx2">6.2 Accélération du produit scalaire avec AVX2
&lt;/h3>&lt;p>Lors de la compilation pour les derniers processeurs x86 dans un environnement Windows, en utilisant des indicateurs de compilation (flags) tels que &lt;code>/arch:AVX2&lt;/code>, le traitement SIMD est effectué via le flux suivant.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Chargement (Load)&lt;/strong> : Charge les données quantifiées 4 bits depuis la mémoire dans un registre AVX de 256 bits.&lt;/li>
&lt;li>&lt;strong>Expansion et déballage (Unpack)&lt;/strong> : Développe les valeurs 4 bits en Int8 ou Int16 avec un masque de bits et des opérations de décalage.&lt;/li>
&lt;li>&lt;strong>Déqualification (Dequantize)&lt;/strong> : Multiplie par le facteur d&amp;rsquo;échelle pour convertir en virgule flottante.&lt;/li>
&lt;li>&lt;strong>Opération FMA&lt;/strong> : Exécute en parallèle les opérations de multiplication-addition avec les valeurs d&amp;rsquo;activation en utilisant &lt;code>_mm256_fmadd_ps&lt;/code> (Fused Multiply-Add).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-détails-dimplémentation-du-cache-kv">7. Détails d&amp;rsquo;implémentation du cache KV
&lt;/h2>&lt;p>Dans la génération autorégressive, le « cache KV » est une fonctionnalité indispensable pour omettre le calcul des Key et Value des jetons passés.&lt;/p>
&lt;p>Les points clés lors de l&amp;rsquo;implémentation en C++ sont les suivants.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pré-allocation du tenseur&lt;/strong> : Initialiser un énorme tenseur pour le cache KV correspondant à la longueur de contexte maximale (ex. : 2048 jetons) (FP16 recommandé).&lt;/li>
&lt;li>&lt;strong>Copie avec décalage (Offset copy)&lt;/strong> : Lorsque le calcul pour la position du jeton $N$ est effectué, les vecteurs K et V obtenus à cette étape sont stockés à la $N$-ième ligne du tenseur de cache KV en utilisant &lt;code>ggml_cpy&lt;/code> etc.&lt;/li>
&lt;li>&lt;strong>Création de la vue (view) lors de l&amp;rsquo;Attention&lt;/strong> : Lors du calcul de l&amp;rsquo;Attention, créer une « vue » pointant uniquement sur la partie des jetons de 0 à $N$, et la transmettre à la multiplication matricielle.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-tokeniseur-bpe-et-décodage">8. Tokeniseur BPE et décodage
&lt;/h2>&lt;p>Traite la chaîne d&amp;rsquo;entrée sous forme d&amp;rsquo;une séquence d&amp;rsquo;octets UTF-8 et la compare à un vocabulaire prédéfini. En C++, pour accélérer la recherche dans le vocabulaire, on implémente un algorithme utilisant un &lt;strong>Trie (arbre de préfixes)&lt;/strong> ou une file de priorité.&lt;/p>
&lt;p>À partir des logits sortis du LM Head, les probabilités sont mises à l&amp;rsquo;échelle en utilisant le paramètre de température (Temperature), les candidats sont réduits par des méthodes d&amp;rsquo;extraction Top-K ou Top-P (Nucleus Sampling), et le jeton suivant final est déterminé à l&amp;rsquo;aide de nombres aléatoires.&lt;/p>
&lt;hr>
&lt;h2 id="9-lancement-dun-projet-c-environnement-windows--powershell">9. Lancement d&amp;rsquo;un projet C++ (Environnement Windows / PowerShell)
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.14&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">TinyLLaMACpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">17&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Optimisation pour Windows (MSVC) et configuration du flag AVX2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MSVC&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/O2&lt;/span> &lt;span class="s">/arch:AVX2&lt;/span> &lt;span class="s">/fp:fast&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/STACK:8388608&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">else&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">-O3&lt;/span> &lt;span class="s">-march=native&lt;/span> &lt;span class="s">-ffast-math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">OBJECT&lt;/span> &lt;span class="s">ggml/ggml.c&lt;/span> &lt;span class="s">ggml/ggml-alloc.c&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">GGML_USE_AVX2&lt;/span> &lt;span class="s">GGML_USE_F16C&lt;/span> &lt;span class="s">GGML_USE_FMA&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">ggml&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Exemple de commande de build dans PowerShell :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-G&lt;/span> &lt;span class="s2">&amp;#34;Visual Studio 17 2022&amp;#34;&lt;/span> &lt;span class="n">-A&lt;/span> &lt;span class="n">x64&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="10-conclusion">10. Conclusion
&lt;/h2>&lt;p>Implémenter à partir de zéro un moteur d&amp;rsquo;inférence pour un petit modèle d&amp;rsquo;IA comme TinyLLaMA en utilisant C++ et ggml est une excellente occasion de révéler la boîte noire de l&amp;rsquo;apprentissage profond et d&amp;rsquo;apprendre la beauté du contrôle matériel de bas niveau. Tout en profitant pleinement de l&amp;rsquo;essence de la programmation système, telle que le chargement zéro copie à l&amp;rsquo;aide du mappage mémoire, l&amp;rsquo;optimisation SIMD et la construction du cache KV, ouvrons la voie à l&amp;rsquo;avenir de l&amp;rsquo;IA périphérique (Edge AI).&lt;/p></description></item><item><title>【Introduction à l'implémentation de RAG】 Comment faire lire vos propres documents à une 'IA locale'</title><link>http://kenji.blog/fr/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【Introduction à l'implémentation de RAG】 Comment faire lire vos propres documents à une 'IA locale'" />&lt;h1 id="introduction">Introduction
&lt;/h1>&lt;p>Ces dernières années, l&amp;rsquo;évolution des grands modèles de langage (LLM) a été remarquable, et de nombreuses IA telles que ChatGPT et Claude ont imprégné nos vies et nos entreprises. Cependant, les LLM généraux présentent une faiblesse évidente. Ils ne connaissent que les « informations publiques au moment de leur entraînement ». Naturellement, ils ne peuvent pas répondre aux questions concernant des « documents privés » tels que les règlements internes d&amp;rsquo;une entreprise, les notes personnelles ou les documents de projets non publiés. Si vous essayez de les forcer à répondre, le risque qu&amp;rsquo;ils génèrent des mensonges plausibles qui ne correspondent pas aux faits (hallucinations) augmente considérablement.&lt;/p>
&lt;p>C&amp;rsquo;est pourquoi l&amp;rsquo;architecture technologique appelée &lt;strong>RAG (Retrieval-Augmented Generation : Génération Augmentée par la Recherche)&lt;/strong> connaît actuellement une diffusion explosive dans le monde entier. L&amp;rsquo;utilisation du RAG permet de fournir dynamiquement des connaissances propres au LLM à partir d&amp;rsquo;une base de données externe, ce qui lui permet de générer des réponses précises et fondées.&lt;/p>
&lt;p>De plus, lors du traitement d&amp;rsquo;informations confidentielles d&amp;rsquo;entreprise ou personnelles, l&amp;rsquo;envoi de données à des API basées sur le cloud telles qu&amp;rsquo;OpenAI est souvent inacceptable du point de vue de la politique de sécurité. C&amp;rsquo;est là qu&amp;rsquo;intervient la construction d&amp;rsquo;un « RAG local » combiné à une &lt;strong>IA locale&lt;/strong> (un LLM qui fonctionne entièrement sur votre propre PC ou serveur sur site).&lt;/p>
&lt;p>Dans cet article, nous expliquerons en détail la théorie de base du RAG, les méthodes concrètes d&amp;rsquo;implémentation d&amp;rsquo;un RAG local avec Python, le contexte mathématique (le fonctionnement de la recherche vectorielle) et les techniques avancées pour faire fonctionner le système en production.&lt;/p>
&lt;hr>
&lt;h1 id="1-architecture-globale-du-rag">1. Architecture globale du RAG
&lt;/h1>&lt;p>Le RAG n&amp;rsquo;est pas un modèle d&amp;rsquo;IA unique, mais une architecture système dans laquelle plusieurs composants collaborent. Il se compose principalement de deux phases : la « phase d&amp;rsquo;ingestion (importation des données) » et la « phase de recherche et de génération (Retrieval &amp;amp; Generation) ».&lt;/p>
&lt;p>Le diagramme Mermaid ci-dessous montre la vue d&amp;rsquo;ensemble du système RAG.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Phase d'ingestion (Préparation)"
Doc["Documents propres (PDF, TXT, etc.)"] --> Loader["Chargeur de documents"]
Loader --> Splitter["Division du texte (Chunking)"]
Splitter --> EmbedModel1["Modèle de plongement (Embedding)"]
EmbedModel1 --> VectorDB["Base de données vectorielle"]
end
subgraph "Phase d'inférence (Lors de la requête de l'utilisateur)"
User["Question de l'utilisateur (Requête)"] --> EmbedModel2["Modèle de plongement (Embedding)"]
EmbedModel2 --> QueryVector["Vecteur de requête"]
QueryVector --> Search["Recherche de similarité (Recherche vectorielle)"]
VectorDB --> Search
Search --> Context["Extraction des morceaux pertinents (Contexte)"]
User --> PromptBuilder["Construction du prompt"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["LLM local"]
LocalLLM --> Answer["Génération de la réponse finale"]
end&lt;/div>
&lt;h2 id="phase-dingestion-préparation">Phase d&amp;rsquo;ingestion (Préparation)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Chargement des documents&lt;/strong> : Chargez des données non structurées telles que des PDF, des documents Word, des fichiers texte, etc.&lt;/li>
&lt;li>&lt;strong>Chunking (Division du texte)&lt;/strong> : Divisez les textes longs en blocs significatifs (chunks) pour les adapter à la limite d&amp;rsquo;entrée (fenêtre de contexte) du LLM et pour améliorer la précision de la recherche.&lt;/li>
&lt;li>&lt;strong>Embedding (Vectorisation)&lt;/strong> : Entrez les chunks divisés dans un modèle de plongement (Embedding Model) et convertissez-les en un tableau de nombres (vecteur) de plusieurs centaines à plusieurs milliers de dimensions.&lt;/li>
&lt;li>&lt;strong>Enregistrement dans la base de données&lt;/strong> : Enregistrez les vecteurs convertis et les données textuelles d&amp;rsquo;origine associées dans une base de données vectorielle (Vector DB).&lt;/li>
&lt;/ol>
&lt;h2 id="phase-dinférence-lors-de-lexécution">Phase d&amp;rsquo;inférence (Lors de l&amp;rsquo;exécution)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Vectorisation de la requête&lt;/strong> : Vectorisez la question de l&amp;rsquo;utilisateur en utilisant le même modèle de plongement que celui de la préparation.&lt;/li>
&lt;li>&lt;strong>Recherche de similarité&lt;/strong> : Calculez la similarité entre le vecteur de la requête et les vecteurs des documents dans la base de données, et récupérez les chunks de texte les plus proches sémantiquement (les plus pertinents).&lt;/li>
&lt;li>&lt;strong>Construction du prompt&lt;/strong> : Combinez les textes pertinents obtenus comme « contexte (connaissances de base) » avec la question de l&amp;rsquo;utilisateur pour créer le prompt d&amp;rsquo;entrée pour le LLM.&lt;/li>
&lt;li>&lt;strong>Génération de la réponse&lt;/strong> : Le LLM reçoit le prompt augmenté et génère une réponse basée sur les informations de contexte fournies.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-compréhension-approfondie-de-la-recherche-vectorielle-et-des-plongements-embeddings">2. Compréhension approfondie de la recherche vectorielle et des plongements (Embeddings)
&lt;/h1>&lt;p>Le cœur du RAG est la « recherche vectorielle (recherche sémantique) ». Alors que la recherche par mots-clés traditionnelle (comme BM25) est basée sur la correspondance exacte et la fréquence des mots, la recherche vectorielle est basée sur la « similarité de sens ». Par exemple, même des mots différents comme « chien » et « chiot », ou « PC » et « ordinateur » seront trouvés si leur sens est proche.&lt;/p>
&lt;h2 id="quest-ce-quun-modèle-de-plongement-embedding-model-">Qu&amp;rsquo;est-ce qu&amp;rsquo;un modèle de plongement (Embedding Model) ?
&lt;/h2>&lt;p>Un modèle de plongement est un réseau de neurones qui prend un texte en langage naturel en entrée et génère un vecteur dense de longueur fixe (Dense Vector). Les modèles courants (par exemple, &lt;code>text-embedding-3-small&lt;/code> ou l&amp;rsquo;open source &lt;code>multilingual-e5-large&lt;/code>) associent le texte à un vecteur de nombres réels de 384 ou 1024 dimensions.&lt;/p>
&lt;p>Dans cet espace multidimensionnel (espace latent), l&amp;rsquo;apprentissage est fait de manière à ce que les textes ayant des significations similaires soient plus proches en termes de distance dans l&amp;rsquo;espace des coordonnées.&lt;/p>
&lt;h2 id="contexte-mathématique-du-calcul-de-similarité--similarité-cosinus">Contexte mathématique du calcul de similarité : Similarité cosinus
&lt;/h2>&lt;p>Lorsque la base de données vectorielle recherche des documents pertinents, la mesure de distance la plus couramment utilisée est la &lt;strong>similarité cosinus (Cosine Similarity)&lt;/strong>. Contrairement à la distance euclidienne (distance spatiale absolue), la similarité cosinus se concentre sur « l&amp;rsquo;angle entre deux vecteurs ». Étant donné qu&amp;rsquo;elle est peu affectée par la longueur du texte (la norme du vecteur), elle est très adaptée au calcul de similarité de textes.&lt;/p>
&lt;p>Exprimée mathématiquement, la similarité cosinus des vecteurs $\mathbf{A}$ et $\mathbf{B}$ est la suivante :&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ représente le produit scalaire (Dot Product).&lt;/li>
&lt;li>$\|\mathbf{A}\|$ représente la norme L2 (longueur) du vecteur $\mathbf{A}$.&lt;/li>
&lt;li>$n$ est le nombre de dimensions du vecteur.&lt;/li>
&lt;/ul>
&lt;p>La similarité cosinus prend une valeur comprise entre -1 et 1.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Proche de 1&lt;/strong> : Les directions des deux vecteurs sont presque les mêmes (les sens sont très similaires)&lt;/li>
&lt;li>&lt;strong>Proche de 0&lt;/strong> : Les deux vecteurs sont orthogonaux (aucun rapport)&lt;/li>
&lt;li>&lt;strong>Proche de -1&lt;/strong> : Les directions des deux vecteurs sont opposées (les sens sont opposés)&lt;/li>
&lt;/ul>
&lt;p>Les bases de données vectorielles récentes (Chroma, FAISS, Qdrant, etc.) adoptent un algorithme de recherche des plus proches voisins approximatifs (ANN) appelé HNSW (Hierarchical Navigable Small World), optimisé pour rechercher des documents ayant une similarité cosinus élevée en millisecondes, même à partir de millions de données vectorielles.&lt;/p>
&lt;hr>
&lt;h1 id="3-pile-technologique-pour-construire-un-rag-local">3. Pile technologique pour construire un RAG local
&lt;/h1>&lt;p>Pour construire un RAG local complet qui ne dépend pas du cloud, nous tirerons parti de l&amp;rsquo;écosystème open source. Voici la pile technologique recommandée.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Modèle de langage (LLM)&lt;/strong>
&lt;ul>
&lt;li>Outils : &lt;code>Ollama&lt;/code> ou &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>Modèles : Des modèles ouverts légers et performants tels que &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code>. Pour les tâches en japonais, des modèles ajustés pour le japonais comme &lt;code>Llama-3-ELYZA-JP-8B&lt;/code> sont appropriés.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Modèle de plongement (Embedding)&lt;/strong>
&lt;ul>
&lt;li>Modèles : &lt;code>intfloat/multilingual-e5-large&lt;/code> ou &lt;code>BAAI/bge-m3&lt;/code>. Lors de l&amp;rsquo;exécution locale, il est courant de les télécharger depuis Hugging Face et de les exécuter avec Sentence-Transformers.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Base de données vectorielle (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code> : Basée sur Python, son installation est extrêmement simple. Idéale pour le développement local.&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code> : Une bibliothèque de recherche vectorielle rapide développée par Meta.&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code> : À plus grande échelle et destinées aux environnements de production.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Framework d&amp;rsquo;orchestration&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code> : Le standard de facto pour relier les composants (Chain).&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code> : Un framework de connexion de données spécialement conçu pour le RAG.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Cette fois, nous l&amp;rsquo;implémenterons avec la combinaison la plus simple à introduire : &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="4-tutoriel-dimplémentation--construction-complète-dun-rag-local-avec-python">4. Tutoriel d&amp;rsquo;implémentation : Construction complète d&amp;rsquo;un RAG local avec Python
&lt;/h1>&lt;p>À partir d&amp;rsquo;ici, nous allons construire un RAG local tout en écrivant du code Python. Au préalable, veuillez installer Ollama sur votre PC et le lancer en arrière-plan. De plus, téléchargez un modèle sur Ollama (exemple : &lt;code>ollama run llama3&lt;/code>).&lt;/p>
&lt;h2 id="étape-1--installation-des-bibliothèques-nécessaires">Étape 1 : Installation des bibliothèques nécessaires
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="étape-2--vue-densemble-du-code-dimplémentation">Étape 2 : Vue d&amp;rsquo;ensemble du code d&amp;rsquo;implémentation
&lt;/h2>&lt;p>Voici un script Python complet pour lire un fichier PDF, le vectoriser et permettre à un LLM local de répondre aux questions.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Chargement des documents&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement des documents...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Spécifiez le chemin du PDF que vous souhaitez charger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Division en chunks (Text Splitting)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Diviser en tailles appropriées pour ne pas détruire le sens du texte&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Nombre maximum de caractères par chunk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Nombre de caractères qui se chevauchent entre les chunks (empêche la rupture du contexte)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;。&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;、&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Divisé en &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> chunks.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. Initialisation du modèle de plongement (Local HuggingFace Model)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Utilisation d&amp;#39;un modèle multilingue performant&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement du modèle de plongement...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># Si vous avez un GPU, &amp;#39;cuda&amp;#39; ou &amp;#39;mps&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. Construction de la base de données vectorielle (Chroma)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Construction de la base de données vectorielle...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Création du système de recherche (Retriever). Configuration pour récupérer les 3 documents les plus pertinents&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. Initialisation du LLM local (Ollama)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Connexion au LLM local...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Assurez-vous d&amp;#39;obtenir le modèle au préalable avec &amp;#39;ollama pull llama3&amp;#39; par exemple&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. Définition du modèle de prompt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Vous êtes un excellent assistant qui connaît bien les règlements de l&amp;#39;entreprise et les informations internes.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Veuillez répondre en détail à la question de l&amp;#39;utilisateur en français, en utilisant uniquement le contexte (informations de base) ci-dessous.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Si vous ne trouvez pas la réponse dans le contexte, ne devinez pas et répondez honnêtement « Je ne sais pas à partir des informations fournies ».
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Contexte】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Question】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Réponse】:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. Construction de la chaîne RAG&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Définir s&amp;#39;il faut renvoyer la source d&amp;#39;information&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PROMPT&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 8. Exécution de la question&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Veuillez m&amp;#39;expliquer les conditions de remboursement des frais de transport pour le télétravail.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Question : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Réponse】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Sources consultées】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- Page &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;inconnue&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="explication-des-points-clés-du-code">Explication des points clés du code
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong> :
C&amp;rsquo;est le diviseur le plus recommandé pour la division du langage naturel. Il tente de diviser dans l&amp;rsquo;ordre par paragraphe (&lt;code>\n\n&lt;/code>), ligne (&lt;code>\n&lt;/code>) et point (&lt;code>。&lt;/code>), en gardant les blocs de sens autant que possible tout en respectant la taille spécifiée &lt;code>chunk_size&lt;/code>. En définissant &lt;code>chunk_overlap&lt;/code>, on évite de perdre des informations aux limites du contexte.&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong> :
&lt;code>intfloat/multilingual-e5-large&lt;/code> est un modèle de plongement open source très puissant qui prend en charge plusieurs langues. Sans utiliser d&amp;rsquo;API cloud (telles que &lt;code>text-embedding-ada-002&lt;/code> d&amp;rsquo;OpenAI), vous pouvez vectoriser le texte hors ligne en mémoire locale.&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong> :
Étant donné qu&amp;rsquo;il fonctionne en mémoire ou sur le stockage local (basé sur SQLite), il n&amp;rsquo;est pas nécessaire de mettre en place un serveur de base de données complexe. En spécifiant &lt;code>persist_directory&lt;/code>, vous pouvez ignorer le processus de vectorisation lors de la réexécution et charger la base de données à partir du disque.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-techniques-avancées-de-rag-advanced-rag-techniques">5. Techniques avancées de RAG (Advanced RAG Techniques)
&lt;/h1>&lt;p>Bien que le système RAG de base (Naive RAG) construit dans le tutoriel ci-dessus fonctionne, si une précision de réponse élevée est requise en production, l&amp;rsquo;introduction de techniques avancées telles que les suivantes sera nécessaire.&lt;/p>
&lt;h2 id="51-recherche-hybride-hybrid-search">5.1 Recherche hybride (Hybrid Search)
&lt;/h2>&lt;p>Bien que la recherche vectorielle excelle à saisir le « sens », elle peut avoir des difficultés avec les recherches de mots-clés exacts tels que des « noms propres spécifiques », des « numéros de modèles de produits » ou des « identifiants d&amp;rsquo;employés ».
Par conséquent, en effectuant parallèlement une &lt;strong>recherche sémantique&lt;/strong> basée sur la recherche vectorielle et une &lt;strong>recherche par mot-clé&lt;/strong> utilisant un algorithme tel que BM25, puis en évaluant et en fusionnant les deux résultats (en utilisant des méthodes telles que Reciprocal Rank Fusion ; RRF), il est possible de réduire considérablement les omissions de recherche.&lt;/p>
&lt;h2 id="52-re-classement-re-ranking">5.2 Re-classement (Re-ranking)
&lt;/h2>&lt;p>La recherche vectorielle est rapide, mais elle n&amp;rsquo;évalue pas nécessairement la pertinence contextuelle exacte du contexte. Un pipeline courant pour améliorer la précision de la recherche est le suivant :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Recherche initiale (First-stage Retrieval)&lt;/strong> : Récupérez largement et superficiellement environ 20 à 30 chunks pertinents à partir de la base de données vectorielle.&lt;/li>
&lt;li>&lt;strong>Réévaluation (Re-ranking)&lt;/strong> : Utilisez un autre modèle d&amp;rsquo;apprentissage automatique plus lourd appelé Cross-Encoder (par exemple : &lt;code>bge-reranker&lt;/code>, etc.) pour entrer la paire de la requête de l&amp;rsquo;utilisateur et du chunk récupéré, et recalculez le score de pertinence sémantique.&lt;/li>
&lt;li>&lt;strong>Sélection&lt;/strong> : Seuls les 3 à 5 premiers résultats ayant les scores les plus élevés sont passés au prompt du LLM en tant que contexte final.&lt;/li>
&lt;/ol>
&lt;p>Cette méthode empêche les informations bruyantes non pertinentes d&amp;rsquo;être transmises au LLM et peut considérablement augmenter la précision (Precision) des réponses.&lt;/p>
&lt;div class="mermaid">graph LR
Query["Requête"] --> VSearch["Recherche vectorielle (Top 20)"]
VSearch --> Reranker["Modèle de re-classement (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["Top 3 de haute précision"]
TopK --> LLM["Génération par le LLM"]&lt;/div>
&lt;h2 id="53-chunking-sémantique-et-recherche-de-document-parent">5.3 Chunking sémantique et recherche de document parent
&lt;/h2>&lt;p>Plutôt que de diviser mécaniquement le texte par un nombre fixe de caractères, il existe une technique appelée « Semantic Chunking » qui utilise l&amp;rsquo;IA pour détecter les changements de sens dans les phrases et les diviser.
De plus, dans une technique appelée « Parent Document Retriever (Recherche de document parent) », la vectorisation est effectuée en très petites unités (comme des phrases) pour la recherche afin d&amp;rsquo;obtenir une recherche très précise. Mais lorsqu&amp;rsquo;elle est transmise au LLM, c&amp;rsquo;est le « grand paragraphe d&amp;rsquo;origine (document parent) » contenant cette phrase qui est fourni, offrant ainsi un contexte suffisant au LLM.&lt;/p>
&lt;hr>
&lt;h1 id="6-défis-et-solutions-lors-de-lexploitation-dun-rag-local">6. Défis et solutions lors de l&amp;rsquo;exploitation d&amp;rsquo;un RAG local
&lt;/h1>&lt;p>Lors de la construction et de l&amp;rsquo;exploitation d&amp;rsquo;un RAG dans un environnement local, des obstacles spécifiques existent.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Épuisement de la VRAM (Mémoire vidéo)&lt;/strong> :
Pour faire fonctionner un LLM local à une vitesse pratique (des dizaines de tokens par seconde), le modèle doit être chargé dans la VRAM du GPU. Pour exécuter un modèle de classe 8B en fp16 (virgule flottante 16 bits), environ 16 Go de VRAM sont nécessaires. Cependant, en utilisant des technologies de &lt;strong>quantification (Quantization)&lt;/strong> (techniques de compression en 4 bits ou 8 bits telles que les formats GGUF ou AWQ), il est possible de le faire fonctionner suffisamment vite même avec 8 Go de VRAM (PC de jeu standard, etc.). Llama.cpp et Ollama prennent en charge ces formats quantifiés de manière native.&lt;/li>
&lt;li>&lt;strong>Limite de la fenêtre de contexte&lt;/strong> :
Si la quantité de contexte récupérée par la recherche est trop importante, elle peut dépasser la limite d&amp;rsquo;entrée du LLM (limite de tokens), ou le modèle peut oublier les parties intermédiaires de l&amp;rsquo;information (phénomène de Lost in the middle). L&amp;rsquo;ajustement du nombre de chunks extraits et la sélection stricte à l&amp;rsquo;aide de la technologie de re-classement mentionnée ci-dessus sont essentiels.&lt;/li>
&lt;li>&lt;strong>Gestion de la fraîcheur des données&lt;/strong> :
Lorsque le document source est mis à jour, les vecteurs du document correspondant dans la base de données vectorielle doivent également être mis à jour/supprimés (opérations CRUD). Étant donné que ChromaDB prend en charge les mises à jour basées sur les identifiants de documents, il est pratique de mettre en place un traitement par lots qui gère les valeurs de hachage des fichiers et ne synchronise que les différences.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="conclusion">Conclusion
&lt;/h1>&lt;p>Le RAG (Génération Augmentée par la Recherche) est un paradigme puissant qui fait évoluer l&amp;rsquo;IA d&amp;rsquo;un assistant généraliste typique vers « votre expert exclusif » ou un « expert spécialisé dans les opérations internes ».&lt;/p>
&lt;p>Nous avons vu que même pour des exigences hautement confidentielles où les services cloud ne peuvent pas être utilisés, un environnement « RAG local » complet peut être construit relativement facilement en combinant l&amp;rsquo;écosystème open source comme Ollama, LangChain et ChromaDB.&lt;/p>
&lt;p>En vous basant sur la compréhension mathématique de l&amp;rsquo;espace vectoriel, la division de texte et les approches avancées telles que le re-classement expliquées dans cet article, n&amp;rsquo;hésitez pas à développer votre propre système d&amp;rsquo;IA original en utilisant vos propres données. La vitesse d&amp;rsquo;évolution de l&amp;rsquo;IA locale est stupéfiante, et le système que vous construisez aujourd&amp;rsquo;hui peut voir ses performances mises à jour instantanément, simplement en le remplaçant par un modèle léger encore plus intelligent qui sortira demain.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Dans ce blog, nous continuerons à publier des articles approfondis sur la technologie de l&amp;rsquo;IA et le RAG. Si vous avez des questions ou des commentaires, n&amp;rsquo;hésitez pas à nous en faire part dans la section des commentaires.&lt;/em>&lt;/p></description></item></channel></rss>