> For the complete documentation index, see [llms.txt](https://unsloth.ai/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://unsloth.ai/docs/fr/modeles/tutorials/deepseek-v3-0324-how-to-run-locally.md).

# DeepSeek-V3-0324 : comment l'exécuter localement

Comment exécuter DeepSeek-V3-0324 localement en utilisant nos quants dynamiques qui récupèrent la précision

{% hint style="info" %}
Veuillez consulter <https://docs.unsloth.ai/basics/deepseek-r1-0528-how-to-run-locally> (Mise à jour du 28 mai 2025) pour apprendre à faire tourner DeepSeek plus rapidement et plus efficacement !
{% endhint %}

DeepSeek remet ça ! Après la sortie de V3, R1 Zero et R1 en décembre 2024 et janvier 2025, DeepSeek a mis à jour ses checkpoints / modèles pour V3 et a publié une mise à jour de mars !

Selon DeepSeek, MMLU-Pro a bondi de +5,3 % à 81,2 %. **GPQA +9,3 points de pourcentage**. AIME + 19,8 % et LiveCodeBench + 10,0 % ! Ils ont fourni un graphique montrant comment ils se comparaient au précédent checkpoint V3 et à d'autres modèles comme GPT 4.5 et Claude Sonnet 3.7. <mark style="background-color:blue;">**Mais comment faire tourner localement un modèle de 671 milliards de paramètres ?**</mark>

<table data-full-width="true"><thead><tr><th>Bits MoE</th><th>Type</th><th>Taille sur disque</th><th>Précision</th><th>Lien</th><th>Détails</th></tr></thead><tbody><tr><td>1,78 bit</td><td>IQ1_S</td><td><strong>173 Go</strong></td><td>D'accord</td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-IQ1_S">Lien</a></td><td>2,06/1,56 bit</td></tr><tr><td>1,93 bit</td><td>IQ1_M</td><td><strong>183 Go</strong></td><td>Correct</td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-IQ1_M">Lien</a></td><td>2.5/2.06/1.56</td></tr><tr><td>2,42 bit</td><td>IQ2_XXS</td><td><strong>203 Go</strong></td><td><mark style="background-color:blue;"><strong>Suggéré</strong></mark></td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-IQ2_XXS">Lien</a></td><td>2,5/2,06 bit</td></tr><tr><td>2,71 bit</td><td>Q2_K_XL</td><td><strong>231 Go</strong></td><td><mark style="background-color:purple;"><strong>Suggéré</strong></mark></td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-Q2_K_XL">Lien</a></td><td>3,5/2,5 bit</td></tr><tr><td>3,5 bit</td><td>Q3_K_XL</td><td><strong>320 Go</strong></td><td>Super</td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-Q3_K_XL">Lien</a></td><td>4,5/3,5 bit</td></tr><tr><td>4,5 bit</td><td>Q4_K_XL</td><td><strong>406 Go</strong></td><td>Excellent</td><td><a href="https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF/tree/main/UD-Q4_K_XL">Lien</a></td><td>5,5/4,5 bit</td></tr></tbody></table>

{% hint style="success" %}
L'upload original de DeepSeek V3 est en float8, ce qui prend 715 Go. L'utilisation de Q4\_K\_M réduit la taille du fichier de moitié à environ 404 Go, et notre quantification dynamique à 1,78 bit tient dans environ 151 Go. **Nous suggérons d'utiliser notre quantification 2,7 bits pour équilibrer taille et précision ! La version 2,4 bits fonctionne aussi très bien !**
{% endhint %}

## :gear: Paramètres officiels recommandés

Selon [DeepSeek](https://huggingface.co/deepseek-ai/DeepSeek-V3-0324), voici les paramètres recommandés pour l'inférence :

* <mark style="background-color:blue;">**Température de 0,3**</mark> (Peut-être 0,0 pour le code comme [vu ici](https://api-docs.deepseek.com/quick_start/parameter_settings))
* Min\_P de 0,00 (facultatif, mais 0,01 fonctionne bien, la valeur par défaut de llama.cpp est 0,1)
* Modèle de conversation : `<｜User｜>Créez un simple jeu Flappy Bird jouable en Python. Placez le jeu final dans une section markdown.<｜Assistant｜>`
* Un jeton BOS de `<｜begin▁of▁sentence｜>` est automatiquement ajouté lors de la tokenisation (ne l'ajoutez PAS manuellement !)
* DeepSeek a mentionné utiliser un <mark style="background-color:green;">**prompt système**</mark> aussi (facultatif) - il est en chinois : `Cet assistant est DeepSeek Chat, créé par DeepSeek.\nAujourd'hui, nous sommes le lundi 24 mars.` ce qui se traduit par : `L'assistant est DeepSeek Chat, créé par DeepSeek.\nAujourd'hui, nous sommes le lundi 24 mars.`
* <mark style="background-color:orange;">**Pour la quantification du cache KV, utilisez 8 bits, PAS 4 bits - nous avons constaté que c'était nettement moins performant.**</mark>

## 📖 Tutoriel : Comment faire tourner DeepSeek-V3 dans llama.cpp

1. Obtenez la dernière version `llama.cpp` sur [GitHub ici](https://github.com/ggml-org/llama.cpp). Vous pouvez également suivre les instructions de compilation ci-dessous. Modifiez `-DGGML_CUDA=ON` à `-DGGML_CUDA=OFF` si vous n'avez pas de GPU ou si vous souhaitez simplement une inférence CPU. **Pour les appareils Apple Mac / Metal**, définissez `-DGGML_CUDA=OFF` puis continuez comme d'habitude - la prise en charge de Metal est activée par défaut.

{% hint style="warning" %}
REMARQUE : l'utilisation de `-DGGML_CUDA=ON` pour les GPU peut prendre 5 minutes à compiler. Le CPU ne prend qu'1 minute à compiler. Les binaires précompilés de llama.cpp pourraient vous intéresser.
{% endhint %}

```bash
apt-get update
apt-get install pciutils build-essential cmake curl libcurl4-openssl-dev -y
git clone https://github.com/ggml-org/llama.cpp
cmake llama.cpp -B llama.cpp/build \
    -DBUILD_SHARED_LIBS=OFF -DGGML_CUDA=ON -DLLAMA_CURL=ON
cmake --build llama.cpp/build --config Release -j --clean-first --target llama-quantize llama-cli llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
```

2. Téléchargez le modèle via (après avoir installé `pip install huggingface_hub hf_transfer` ). Vous pouvez choisir `UD-IQ1_S`(quantification dynamique 1,78 bit) ou d'autres versions quantifiées comme `Q4_K_M` . <mark style="background-color:green;">**Je recommande d'utiliser notre quantification dynamique 2,7 bits**</mark><mark style="background-color:green;">**&#x20;**</mark><mark style="background-color:green;">**`UD-Q2_K_XL`**</mark><mark style="background-color:green;">**&#x20;**</mark><mark style="background-color:green;">**pour équilibrer taille et précision**</mark>. Plus de versions sur : <https://huggingface.co/unsloth/DeepSeek-V3-0324-GGUF>

{% code overflow="wrap" %}

```python
# !pip install huggingface_hub hf_transfer
import os
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
from huggingface_hub import snapshot_download
snapshot_download(
    repo_id = "unsloth/DeepSeek-V3-0324-GGUF-UD",
    local_dir = "unsloth/DeepSeek-V3-0324-GGUF-UD",
    allow_patterns = ["*UD-Q2_K_XL*"], # Quantification dynamique 2,7 bits (230 Go) Utilisez "*UD-IQ_S*" pour la quantification dynamique 1,78 bit (151 Go)
)
```

{% endcode %}

3. Exécutez le test Flappy Bird d'Unsloth comme décrit dans notre quantification dynamique 1,58 bit pour DeepSeek R1.
4. Modifier `--threads 32` pour le nombre de threads CPU, `--ctx-size 16384` pour la longueur de contexte, `--n-gpu-layers 2` pour le déchargement GPU de combien de couches. Essayez de l'ajuster si votre GPU manque de mémoire. Supprimez-le aussi si vous faites une inférence uniquement CPU.

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash">./llama.cpp/llama-cli \
    --model unsloth/DeepSeek-V3-0324-GGUF-UD/blob/main/UD-Q2_K_XL/DeepSeek-V3-0324-UD-Q2_K_XL-00001-of-00006.gguf \\
    <a data-footnote-ref href="#user-content-fn-1">--cache-type-k q8_0 </a>\\
    <a data-footnote-ref href="#user-content-fn-2">--threads 20</a> \\
    <a data-footnote-ref href="#user-content-fn-3">--n-gpu-layers 2</a> \\
    -no-cnv \
    --prio 3 \
    --temp 0,3 \\
    --min-p 0.01 \
    <a data-footnote-ref href="#user-content-fn-4">--ctx-size 4096</a> \\
    --seed 3407 \
    --prompt "&#x3C;｜User｜>Crée un jeu Flappy Bird en Python. Tu dois inclure les éléments suivants :\n1. Tu dois utiliser pygame.\n2. La couleur d’arrière-plan doit être choisie aléatoirement et être une teinte claire. Commence par une couleur bleu clair.\n3. Appuyer plusieurs fois sur ESPACE accélérera l’oiseau.\n4. La forme de l’oiseau doit être choisie aléatoirement parmi un carré, un cercle ou un triangle. La couleur doit être choisie aléatoirement parmi des couleurs foncées.\n5. Place en bas un sol coloré en brun foncé ou en jaune, choisi aléatoirement.\n6. Affiche un score en haut à droite. Incrémente-le si tu passes les tuyaux sans les heurter.\n7. Crée des tuyaux espacés aléatoirement avec suffisamment d’espace. Colore-les aléatoirement en vert foncé, brun clair ou dans une teinte de gris foncé.\n8. Lorsque tu perds, affiche le meilleur score. Le texte doit se trouver à l’intérieur de l’écran. Appuyer sur q ou Échap quittera le jeu. Pour redémarrer, appuie à nouveau sur ESPACE.\nLe jeu final doit se trouver dans une section markdown en Python. Vérifie ton code pour détecter les erreurs et corrige-les avant la section markdown finale.&#x3C;｜Assistant｜>"
</code></pre>

<details>

<summary>Si nous exécutons ce qui précède, nous obtenons 2 résultats très différents.<br><br><strong>Version standard 2 bits :</strong> Cliquez pour voir le résultat <em><mark style="color:rouge;"><strong>(avertissement de crise !)</strong></mark></em><br><strong>Version dynamique 2 bits :</strong> Voir le résultat ci-dessous :</summary>

<img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-5ab85f63c9fb12f0ce701dd3cfd540aa1503a636%2FOld.gif?alt=media" alt="" data-size="original">

Standard 2 bits. Échoue avec l'arrière-plan, échoue avec la collision

</details>

<div align="center"><figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-97735d09e3d399cf74f8e7112eef8ca56b0e10e9%2FNew.gif?alt=media" alt="" width="240"><figcaption><p>Dynamique 2 bits. Réussit à créer un jeu jouable.</p></figcaption></figure></div>

5. Comme DeepSeek-R1, V3 a 61 couches. Par exemple, avec un GPU de 24 Go ou un GPU de 80 Go, vous pouvez vous attendre à décharger après arrondi à l'entier inférieur (réduisez de 1 si cela dépasse la mémoire) :

| Quantification | Taille du fichier | GPU de 24 Go | GPU de 80 Go | 2 GPU de 80 Go |
| -------------- | ----------------- | ------------ | ------------ | -------------- |
| 1,73 bit       | 173 Go            | 5            | 25           | 56             |
| 2,22 bit       | 183 Go            | 4            | 22           | 49             |
| 2,51 bit       | 212 Go            | 2            | 19           | 32             |

### Exécution sur Mac / appareils Apple

Pour les appareils Apple Metal, faites attention à `--n-gpu-layers`. Si vous constatez que la machine manque de mémoire, réduisez cette valeur. Pour une machine avec 128 Go de mémoire unifiée, vous devriez pouvoir décharger environ 59 couches.

```bash
./llama.cpp/llama-cli \
    --model DeepSeek-R1-GGUF/DeepSeek-V3-0324-UD-IQ1_S/DeepSeek-V3-0324-UD-IQ1_S-00001-of-00003.gguf \\
    --cache-type-k q4_0 \
    --threads 16 \\
    --prio 2 \
    --temp 0.6 \
    --ctx-size 8192 \
    --seed 3407 \
    --n-gpu-layers 59 \
    -no-cnv \
    --prompt "<｜User｜>Crée un jeu Flappy Bird en Python.<｜Assistant｜>"
```

## :8ball: Test du heptagone

Nous testons également nos quantifications dynamiques via [r/Localllama](https://www.reddit.com/r/LocalLLaMA/comments/1j7r47l/i_just_made_an_animation_of_a_ball_bouncing/) qui teste le modèle sur la création d'un moteur physique de base simulant des balles tournant dans un heptagone fermé en mouvement.

<figure><img src="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-1371de5a93c6c5b0e43e8bb51980d84554b199f4%2Fsnapshot.jpg?alt=media" alt="" width="563"><figcaption><p>Le but est de faire tourner l'heptagone, et les balles à l'intérieur de l'heptagone doivent bouger.</p></figcaption></figure>

{% code overflow="wrap" %}

```bash
./llama.cpp/llama-cli \
    --model unsloth/DeepSeek-V3-0324-GGUF-UD/blob/main/UD-Q2_K_XL/DeepSeek-V3-0324-UD-Q2_K_XL-00001-of-00006.gguf \\
    --cache-type-k q8_0 \\
    --threads 20 \\
    --n-gpu-layers 2 \\
    -no-cnv \
    --prio 3 \
    --temp 0,3 \\
    --min-p 0.01 \
    --ctx-size 4096 \\
    --seed 3407 \
    <｜User｜>Écrivez un programme Python qui montre 20 balles rebondissant à l'intérieur d'un heptagone en rotation :\n- Toutes les balles ont le même rayon.\n- Toutes les balles portent un numéro de 1 à 20.\n- Toutes les balles tombent depuis le centre de l'heptagone au démarrage.\n- Les couleurs sont : #f8b862, #f6ad49, #f39800, #f08300, #ec6d51, #ee7948, #ed6d3d, #ec6800, #ec6800, #ee7800, #eb6238, #ea5506, #ea5506, #eb6101, #e49e61, #e45e32, #e17b34, #dd7a56, #db8449, #d66a35\n- Les balles doivent être soumises à la gravité et au frottement, et elles doivent rebondir de manière réaliste sur les parois en rotation. Il doit également y avoir des collisions entre les balles.\n- Le matériau de toutes les balles fait que la hauteur de rebond à l'impact ne dépassera pas le rayon de l'heptagone, mais sera supérieure au rayon de la balle.\n- Toutes les balles tournent avec du frottement, les numéros sur la balle peuvent servir à indiquer sa rotation.\n- L'heptagone tourne autour de son centre, et sa vitesse de rotation est de 360 degrés toutes les 5 secondes.\n- La taille de l'heptagone doit être suffisamment grande pour contenir toutes les balles.\n- N'utilisez pas la bibliothèque pygame ; implémentez vous-même les algorithmes de détection de collision et de réponse aux collisions, etc. Les bibliothèques Python suivantes sont autorisées : tkinter, math, numpy, dataclasses, typing, sys.\n- Tout le code doit être placé dans un seul fichier Python.<｜Assistant｜>
```

{% endcode %}

<table data-view="cards"><thead><tr><th></th><th data-type="files"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td>Version 2 bits non dynamique. Échec - <mark style="background-color:red;">AVERTISSEMENT DE CRISE</mark> encore !</td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-0e0d101cc282b869a97fc679da5a9e98141c6f62%2Funsloth-q2_k_rotate.txt?alt=media">unsloth-q2_k_rotate.txt</a></td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-d2579e8d1145572548ed69b0e335925f47130ba3%2FInShot_20250325_185636426.gif?alt=media">InShot_20250325_185636426.gif</a></td></tr><tr><td>Dynamique 2 bits. Résout réellement correctement le puzzle de l'heptagone !!</td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-96202dad58c0d0004cdb51408332ac78b425138f%2Funsloth-q2_k_xl_rotate.txt?alt=media">unsloth-q2_k_xl_rotate.txt</a></td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-669f5b08b6bf220a38dce445d4830fcd80d52be3%2FInShot_20250325_181710554.gif?alt=media">InShot_20250325_181710554.gif</a></td></tr><tr><td>Float8 original</td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-902430fe71d14f19cd31d3fe271f9a636e91304e%2Ffp8-heptagon.txt?alt=media">fp8-heptagon.txt</a></td><td><a href="https://550366147-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-4501a6aef616d02057b89e96baa9c1d5ed57666f%2FInShot_20250325_181423756.gif?alt=media">InShot_20250325_181423756.gif</a></td></tr></tbody></table>

La quantification dynamique 2,7 bits, qui ne fait que 230 Go, parvient réellement à résoudre le puzzle de l'heptagone ! La sortie complète pour les 3 versions (y compris le fp8 complet) est ci-dessous :

<details>

<summary>Code heptagone dynamique 2 bits</summary>

```python
import tkinter as tk
import math
import numpy as np
from dataclasses import dataclass
from typing import List, Tuple, Optional

# Constantes
HEPTAGON_RADIUS = 300
BALL_RADIUS = 20
GRAVITY = 0.2
FRICTION = 0.99
BOUNCE_FACTOR = 0.8
ROTATION_SPEED = 360 / 5  # degrés par seconde
SPIN_FRICTION = 0.98
BALL_COLORS = [
    "#f8b862", "#f6ad49", "#f39800", "#f08300", "#ec6d51",
    "#ee7948", "#ed6d3d", "#ec6800", "#ec6800", "#ee7800",
    "#eb6238", "#ea5506", "#ea5506", "#eb6101", "#e49e61",
    "#e45e32", "#e17b34", "#dd7a56", "#db8449", "#d66a35"
]

@dataclass
class Ball:
    x: float
    y: float
    vx: float
    vy: float
    number: int
    spin: float = 0.0
    color: str = "#000000"

@dataclass
class Wall:
    x1: float
    y1: float
    x2: float
    y2: float

class BouncingBalls:
    def __init__(self, root):
        self.root = root
        self.canvas = tk.Canvas(root, width=800, height=800, bg="white")
        self.canvas.pack()
        self.balls: List[Ball] = []
        self.walls: List[Wall] = []
        self.heptagon_angle = 0
        self.last_time = 0
        
        self.setup_balls()
        self.setup_heptagon()
        
        self.root.after(16, self.update)
        self.root.bind("<space>", self.reset_balls)
    
    def setup_balls(self):
        for i in range(20):
            ball = Ball(
                x=400,
                y=400,
                vx=np.random.uniform(-5, 5),
                vy=np.random.uniform(-5, 5),
                number=i+1,
                color=BALL_COLORS[i]
            )
            self.balls.append(ball)
    
    def setup_heptagon(self):
        # Créer les murs initiaux du heptagone
        self.update_heptagon_walls(0)
    
    def update_heptagon_walls(self, angle):
        self.walls = []
        center_x, center_y = 400, 400
        angle_rad = math.radians(angle)
        
        for i in range(7):
            angle1 = angle_rad + 2 * math.pi * i / 7
            angle2 = angle_rad + 2 * math.pi * (i + 1) / 7
            
            x1 = center_x + HEPTAGON_RADIUS * math.cos(angle1)
            y1 = center_y + HEPTAGON_RADIUS * math.sin(angle1)
            x2 = center_x + HEPTAGON_RADIUS * math.cos(angle2)
            y2 = center_y + HEPTAGON_RADIUS * math.sin(angle2)
            
            self.walls.append(Wall(x1, y1, x2, y2))
    
    def reset_balls(self, event=None):
        for ball in self.balls:
            ball.x = 400
            ball.y = 400
            ball.vx = np.random.uniform(-5, 5)
            ball.vy = np.random.uniform(-5, 5)
            ball.spin = np.random.uniform(-5, 5)
    
    def update(self):
        current_time = self.root.after_idle(self.root.after, 16, self.update)
        if self.last_time == 0:
            self.last_time = current_time
            return
        
        # Calculer le delta de temps (approximatif)
        dt = 0.016  # En supposant ~60 FPS
        
        # Mettre à jour la rotation de l'heptagone
        self.heptagon_angle += ROTATION_SPEED * dt
        self.update_heptagon_walls(self.heptagon_angle)
        
        # Mettre à jour les balles
        for ball in self.balls:
            # Appliquer la gravité
            ball.vy += GRAVITY
            
            # Appliquer le frottement
            ball.vx *= FRICTION
            ball.vy *= FRICTION
            ball.spin *= SPIN_FRICTION
            
            # Déplacer la balle
            ball.x += ball.vx
            ball.y += ball.vy
            
            # Vérifier les collisions avec les murs
            self.check_wall_collisions(ball)
            
            # Vérifier les collisions avec les autres balles
            for other in self.balls:
                if other.number != ball.number:
                    self.check_ball_collision(ball, other)
        
        # Dessiner tout
        self.draw()
    
    def check_wall_collisions(self, ball):
        for wall in self.walls:
            # Trouver le point le plus proche sur le segment du mur de la balle
            closest = self.closest_point_on_segment(
                wall.x1, wall.y1, wall.x2, wall.y2, ball.x, ball.y
            )
            
            # Calculer la distance au mur
            dx = ball.x - closest[0]
            dy = ball.y - closest[1]
            distance = math.sqrt(dx*dx + dy*dy)
            
            if distance < BALL_RADIUS:
                # Collision détectée
                # Calculer le vecteur normal
                nx = dx / distance
                ny = dy / distance
                
                # Calculer la vitesse relative le long de la normale
                v_rel = ball.vx * nx + ball.vy * ny
                
                if v_rel < 0:  # En mouvement vers le mur
                    # Calculer l'impulsion
                    j = -(1 + BOUNCE_FACTOR) * v_rel
                    
                    # Appliquer l'impulsion
                    ball.vx += j * nx
                    ball.vy += j * ny
                    
                    # Ajouter un peu de rotation en fonction de la collision
                    ball.spin += (ball.vx * ny - ball.vy * nx) * 0.1
                    
                    # Déplacer la balle hors de la collision
                    penetration = BALL_RADIUS - distance
                    ball.x += penetration * nx
                    ball.y += penetration * ny
    
    def check_ball_collision(self, ball1, ball2):
        dx = ball2.x - ball1.x
        dy = ball2.y - ball1.y
        distance = math.sqrt(dx*dx + dy*dy)
        
        if distance < 2 * BALL_RADIUS:
            # Collision détectée
            nx = dx / distance
            ny = dy / distance
            
            # Calculer la vitesse relative
            v_rel_x = ball2.vx - ball1.vx
            v_rel_y = ball2.vy - ball1.vy
            v_rel = v_rel_x * nx + v_rel_y * ny
            
            if v_rel < 0:  # En mouvement l'une vers l'autre
                # Calculer l'impulsion
                j = -(1 + BOUNCE_FACTOR) * v_rel / 2
                
                # Appliquer les impulsions
                ball1.vx -= j * nx
                ball1.vy -= j * ny
                ball2.vx += j * nx
                ball2.vy += j * ny
                
                # Ajouter de la rotation en fonction de la collision
                ball1.spin += (ball1.vx * ny - ball1.vy * nx) * 0.05
                ball2.spin += (ball2.vx * ny - ball2.vy * nx) * 0.05
                
                # Écarter les balles
                penetration = 2 * BALL_RADIUS - distance
                ball1.x -= penetration * nx * 0.5
                ball1.y -= penetration * ny * 0.5
                ball2.x += penetration * nx * 0.5
                ball2.y += penetration * ny * 0.5
    
    @staticmethod
    def closest_point_on_segment(x1, y1, x2, y2, x, y):
        # Vecteur du point au début du segment
        dx = x - x1
        dy = y - y1
        
        # Vecteur du segment
        sx = x2 - x1
        sy = y2 - y1
        
        # Projection du point sur le segment
        dot = dx * sx + dy * sy
        len_sq = sx * sx + sy * sy
        param = dot / len_sq if len_sq != 0 else -1
        
        if param < 0:
            return x1, y1
        elif param > 1:
            return x2, y2
        else:
            return x1 + param * sx, y1 + param * sy
    
    def draw(self):
        self.canvas.delete("all")
        
        # Dessiner l'heptagone
        points = []
        for wall in self.walls:
            points.extend([wall.x1, wall.y1])
        self.canvas.create_polygon(points, fill="", outline="black", width=2)
        
        # Dessiner les balles
        for ball in self.balls:
            # Dessiner la balle
            self.canvas.create_oval(
                ball.x - BALL_RADIUS, ball.y - BALL_RADIUS,
                ball.x + BALL_RADIUS, ball.y + BALL_RADIUS,
                fill=ball.color, outline="black"
            )
            
            # Dessiner le numéro avec une rotation basée sur le spin
            angle = ball.spin * 10  # Échelle du spin pour l'effet visuel
            self.canvas.create_text(
                ball.x, ball.y,
                text=str(ball.number),
                font=("Arial", 12, "bold"),
                angle=angle
            )

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Balles rebondissantes dans un heptagone en rotation")
    app = BouncingBalls(root)
    root.mainloop()
```

</details>

<details>

<summary>Code heptagone 2 bits non dynamique</summary>

```python
import tkinter as tk
import math
import random
from dataclasses import dataclass
from typing import List, Tuple, Optional
import sys

# Constantes
WIDTH, HEIGHT = 800, 800
HEPTAGON_RADIUS = 300
BALL_RADIUS = 15
GRAVITY = 0.5
FRICTION = 0.999
ELASTICITY = 0.8
ROTATION_SPEED = 2 * math.pi / 5  # 360 degrés toutes les 5 secondes
SPIN_DECAY = 0.99

# Couleurs pour les balles
BALL_COLORS = [
    "#f8b862", "#f6ad49", "#f39800", "#f08300", "#ec6d51",
    "#ee7948", "#ed6d3d", "#ec6800", "#ec6800", "#ee7800",
    "#eb6238", "#ea5506", "#ea5506", "#eb6101", "#e49e61",
    "#e45e32", "#e17b34", "#dd7a56", "#db8449", "#d66a35"
]

@dataclass
class Ball:
    x: float
    y: float
    vx: float
    vy: float
    radius: float
    color: str
    number: int
    spin: float = 0.0

@dataclass
class Heptagon:
    center_x: float
    center_y: float
    radius: float
    angle: float = 0.0

class BouncingBalls:
    def __init__(self, root):
        self.root = root
        self.canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="white")
        self.canvas.pack()
        
        self.heptagon = Heptagon(WIDTH//2, HEIGHT//2, HEPTAGON_RADIUS)
        self.balls = []
        self.setup_balls()
        
        self.root.after(0, self.update)
        self.root.mainloop()
    
    def setup_balls(self):
        center_x, center_y = WIDTH//2, HEIGHT//2
        for i in range(20):
            self.balls.append(Ball(
                x=center_x,
                y=center_y,
                vx=0,
                vy=0,
                radius=BALL_RADIUS,
                color=BALL_COLORS[i],
                number=i+1,
                spin=0
            ))
    
    def update(self):
        self.canvas.delete("all")
        
        # Mettre à jour l'angle de l'heptagone
        self.heptagon.angle += ROTATION_SPEED / 60  # En supposant 60 FPS
        
        # Dessiner l'heptagone
        self.draw_heptagon()
        
        # Mettre à jour et dessiner les balles
        for ball in self.balls:
            # Appliquer la gravité
            ball.vy += GRAVITY
            
            # Mettre à jour la position
            ball.x += ball.vx
            ball.y += ball.vy
            
            # Appliquer le frottement
            ball.vx *= FRICTION
            ball.vy *= FRICTION
            
            # Appliquer la décroissance du spin
            ball.spin *= SPIN_DECAY
            
            # Vérifier la collision avec les murs de l'heptagone
            self.check_heptagon_collision(ball)
            
            # Vérifier la collision avec les autres balles
            for other in self.balls:
                if other != ball:
                    if self.check_ball_collision(ball, other):
                        self.resolve_ball_collision(ball, other)
            
            # Dessiner la balle
            self.draw_ball(ball)
        
        self.root.after(16, self.update)  # ~60 FPS
    
    def draw_heptagon(self):
        center_x, center_y = self.heptagon.center_x, self.heptagon.center_y
        points = []
        for i in range(7):
            angle = self.heptagon.angle + i * 2 * math.pi / 7
            x = center_x + self.heptagon.radius * math.cos(angle)
            y = center_y + self.heptagon.radius * math.sin(angle)
            points.append((x, y))
        
        # Dessiner l'heptagone
        self.canvas.create_polygon(
            [points[0], points[1], points[2], points[3], 
             points[4], points[5], points[6]],
            outline="black", fill="", width=2
        )
    
    def draw_ball(self, ball):
        self.canvas.create_oval(
            ball.x - ball.radius,
            ball.y - ball.radius,
            ball.x + ball.radius,
            ball.y + ball.radius,
            fill=ball.color,
            outline="black"
        )
        
        # Dessiner le numéro
        self.canvas.create_text(
            ball.x, ball.y,
            text=str(ball.number),
            fill="black"
        )
    
    def check_heptagon_collision(self, ball):
        center_x, center_y = WIDTH//2, HEIGHT//2
        
        # Vérifier la distance depuis le centre
        dx = ball.x - center_x
        dy = ball.y - center_y
        dist = math.sqrt(dx**2 + dy**2)
        
        if dist + ball.radius > self.heptagon.radius:
            # Trouver le vecteur normal du centre vers la balle
            angle = math.atan2(dy, dx)
            normal_x = math.cos(angle)
            normal_y = math.sin(angle)
            
            # Replacer la balle à l'intérieur de l'heptagone
            overlap = (dist + ball.radius) - self.heptagon.radius
            ball.x -= overlap * normal_x
            ball.y -= overlap * normal_y
            
            # Réfléchir la vitesse
            dot_product = ball.vx * normal_x + ball.vy * normal_y
            ball.vx -= 2 * dot_product * normal_x * ELASTICITY
            ball.vy -= 2 * dot_product * normal_y * ELASTICITY
    
    def check_ball_collision(self, ball1, ball2):
        dx = ball2.x - ball1.x
        dy = ball2.y - ball1.y
        distance = math.sqrt(dx**2 + dy**2)
        return distance < (ball1.radius + ball2.radius)
    
    def resolve_ball_collision(self, ball1, ball2):
        dx = ball2.x - ball1.x
        dy = ball2.y - ball1.y
        distance = math.sqrt(dx**2 + dy**2)
        
        # Vecteur normal
        nx = dx / distance
        ny = dy / distance
        
        # Vitesse relative
        dvx = ball2.vx - ball1.vx
        dvy = ball2.vy - ball1.vy
        
        # Calculer l'impulsion
        impulse = 2 * (dvx * nx + dvy * ny) / 2
        impulse *= ELASTICITY
        
        # Appliquer l'impulsion
        ball1.vx -= impulse * nx
        ball1.vy -= impulse * ny
        ball2.vx += impulse * nx
        ball2.vy += impulse * ny
        
        # Séparer les balles pour éviter qu'elles se collent
        overlap = (ball1.radius + ball2.radius) - distance
        ball1.x -= overlap * nx / 2
        ball1.y -= overlap * ny / 2
        ball2.x += overlap * nx / 2
        ball2.y += overlap * ny / 2
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Balles rebondissantes dans un heptagone en rotation")
    app = BouncingBalls(root)
    app.run()
```

</details>

<details>

<summary>Code de l'heptagone Float8</summary>

```python
import tkinter as tk
import math
import numpy as np
from dataclasses import dataclass
from typing import List, Tuple, Optional

# Constantes
WIDTH, HEIGHT = 800, 800
CENTER_X, CENTER_Y = WIDTH // 2, HEIGHT // 2
GRAVITY = 0.2
FRICTION = 0.99
BALL_RADIUS = 15
HEPTAGON_RADIUS = 300
ROTATION_SPEED = 360 / 5  # degrés par seconde
ELASTICITY = 0.8
SPIN_FRICTION = 0.98

# Couleurs pour les balles
BALL_COLORS = [
    '#f8b862', '#f6ad49', '#f39800', '#f08300', '#ec6d51',
    '#ee7948', '#ed6d3d', '#ec6800', '#ec6800', '#ee7800',
    '#eb6238', '#ea5506', '#ea5506', '#eb6101', '#e49e61',
    '#e45e32', '#e17b34', '#dd7a56', '#db8449', '#d66a35'
]

@dataclass
class Ball:
    x: float
    y: float
    vx: float
    vy: float
    radius: float
    color: str
    number: int
    spin: float = 0.0

    def move(self):
        self.x += self.vx
        self.y += self.vy
        self.vy += GRAVITY
        self.vx *= FRICTION
        self.vy *= FRICTION
        self.spin *= SPIN_FRICTION

    def collide_with_ball(self, other: 'Ball'):
        dx = other.x - self.x
        dy = other.y - self.y
        distance = math.hypot(dx, dy)
        
        if distance < self.radius + other.radius:
            # Calculer la normale de collision
            nx = dx / distance
            ny = dy / distance
            
            # Calculer la vitesse relative
            dvx = other.vx - self.vx
            dvy = other.vy - self.vy
            
            # Calculer l'impulsion
            impulse = 2 * (dvx * nx + dvy * ny) / (1/self.radius + 1/other.radius)
            
            # Appliquer l'impulsion
            self.vx += impulse * nx / self.radius
            self.vy += impulse * ny / self.radius
            other.vx -= impulse * nx / other.radius
            other.vy -= impulse * ny / other.radius
            
            # Séparer les balles pour éviter qu'elles se collent
            overlap = (self.radius + other.radius - distance) / 2
            self.x -= overlap * nx
            self.y -= overlap * ny
            other.x += overlap * nx
            other.y += overlap * ny
            
            # Transférer un peu de spin
            transfer = impulse * 0.01
            self.spin -= transfer
            other.spin += transfer

class HeptagonBounceSimulator:
    def __init__(self, root):
        self.root = root
        self.canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg='white')
        self.canvas.pack()
        
        self.balls = self.create_balls()
        self.heptagon_angle = 0
        self.last_time = 0
        self.running = True
        
        self.root.bind('<space>', self.toggle_pause)
        self.root.bind('<Escape>', lambda e: root.destroy())
        
        self.last_time = self.root.after(0, self.update)
    
    def create_balls(self) -> List[Ball]:
        balls = []
        for i in range(20):
            # Démarrer toutes les balles au centre avec une petite vitesse aléatoire
            angle = np.random.uniform(0, 2 * math.pi)
            speed = np.random.uniform(0.5, 2)
            vx = math.cos(angle) * speed
            vy = math.sin(angle) * speed
            
            balls.append(Ball(
                x=CENTER_X,
                y=CENTER_Y,
                vx=vx,
                vy=vy,
                radius=BALL_RADIUS,
                color=BALL_COLORS[i],
                number=i+1,
                spin=np.random.uniform(-2, 2)
            ))
        return balls
    
    def toggle_pause(self, event):
        self.running = not self.running
        if self.running:
            self.last_time = self.root.after(0, self.update)
    
    def get_heptagon_vertices(self) -> List[Tuple[float, float]]:
        vertices = []
        for i in range(7):
            angle = math.radians(self.heptagon_angle + i * 360 / 7)
            x = CENTER_X + HEPTAGON_RADIUS * math.cos(angle)
            y = CENTER_Y + HEPTAGON_RADIUS * math.sin(angle)
            vertices.append((x, y))
        return vertices
    
    def check_ball_heptagon_collision(self, ball: Ball):
        vertices = self.get_heptagon_vertices()
        closest_dist = float('inf')
        closest_normal = (0, 0)
        closest_edge = None
        
        # Vérifier la collision avec chaque arête de l'heptagone
        for i in range(len(vertices)):
            p1 = vertices[i]
            p2 = vertices[(i + 1) % len(vertices)]
            
            # Vecteur de p1 à p2
            edge_x = p2[0] - p1[0]
            edge_y = p2[1] - p1[1]
            edge_length = math.hypot(edge_x, edge_y)
            
            # Normaliser le vecteur de l'arête
            edge_x /= edge_length
            edge_y /= edge_length
            
            # Vecteur normal (perpendiculaire à l'arête, pointant vers l'intérieur)
            nx = -edge_y
            ny = edge_x
            
            # Vecteur de p1 vers la balle
            ball_to_p1_x = ball.x - p1[0]
            ball_to_p1_y = ball.y - p1[1]
            
            # Projeter la balle sur la normale de l'arête
            projection = ball_to_p1_x * nx + ball_to_p1_y * ny
            
            # Si la projection est négative, la balle est à l'extérieur de l'heptagone
            if projection < ball.radius:
                # Trouver le point de l'arête le plus proche de la balle
                edge_proj = ball_to_p1_x * edge_x + ball_to_p1_y * edge_y
                edge_proj = max(0, min(edge_length, edge_proj))
                closest_x = p1[0] + edge_proj * edge_x
                closest_y = p1[1] + edge_proj * edge_y
                
                # Distance entre la balle et le point le plus proche sur l'arête
                dist = math.hypot(ball.x - closest_x, ball.y - closest_y)
                
                if dist < closest_dist:
                    closest_dist = dist
                    closest_normal = (nx, ny)
                    closest_edge = (p1, p2)
        
        if closest_dist < ball.radius:
            # Calculer la réponse au rebond
            dot_product = ball.vx * closest_normal[0] + ball.vy * closest_normal[1]
            
            # Appliquer le rebond avec élasticité
            ball.vx -= (1 + ELASTICITY) * dot_product * closest_normal[0]
            ball.vy -= (1 + ELASTICITY) * dot_product * closest_normal[1]
            
            # Ajouter un peu de spin en fonction de l'impact
            edge_vec = (closest_edge[1][0] - closest_edge[0][0], 
                        closest_edge[1][1] - closest_edge[0][1])
            edge_length = math.hypot(edge_vec[0], edge_vec[1])
            if edge_length > 0:
                edge_vec = (edge_vec[0]/edge_length, edge_vec[1]/edge_length)
                # Produit vectoriel de la vitesse et de la direction de l'arête
                spin_effect = (ball.vx * edge_vec[1] - ball.vy * edge_vec[0]) * 0.1
                ball.spin += spin_effect
            
            # Déplacer la balle à l'extérieur de l'heptagone pour éviter qu'elle se colle
            penetration = ball.radius - closest_dist
            ball.x += penetration * closest_normal[0]
            ball.y += penetration * closest_normal[1]
    
    def update(self):
        if not self.running:
            return
        
        # Effacer le canevas
        self.canvas.delete('all')
        
        # Mettre à jour la rotation de l'heptagone
        self.heptagon_angle += ROTATION_SPEED / 60  # En supposant ~60 FPS
        
        # Dessiner l'heptagone
        vertices = self.get_heptagon_vertices()
        self.canvas.create_polygon(vertices, outline='black', fill='', width=2)
        
        # Mettre à jour et dessiner les balles
        for i, ball in enumerate(self.balls):
            # Déplacer la balle
            ball.move()
            
            # Vérifier les collisions avec l'heptagone
            self.check_ball_heptagon_collision(ball)
            
            # Dessiner la balle
            self.canvas.create_oval(
                ball.x - ball.radius, ball.y - ball.radius,
                ball.x + ball.radius, ball.y + ball.radius,
                fill=ball.color, outline='black'
            )
            
            # Dessiner le numéro avec une rotation basée sur le spin
            angle = ball.spin * 10  # Échelonner le spin pour une rotation visible
            self.canvas.create_text(
                ball.x, ball.y,
                text=str(ball.number),
                font=('Arial', 10, 'bold'),
                angle=angle
            )
        
        # Vérifier les collisions balle-balle
        for i in range(len(self.balls)):
            for j in range(i + 1, len(self.balls)):
                self.balls[i].collide_with_ball(self.balls[j])
        
        # Programmer la prochaine mise à jour
        self.last_time = self.root.after(16, self.update)  # ~60 FPS

if __name__ == '__main__':
    root = tk.Tk()
    root.title('Balles rebondissantes dans un heptagone en rotation')
    simulator = HeptagonBounceSimulator(root)
    root.mainloop()
```

</details>

## :detective: Autres constats et conseils

1. Nous constatons, d'après des tests empiriques, que l'utilisation d'une quantification plus faible du cache KV (4 bits) semble dégrader la qualité de génération — davantage de tests sont nécessaires, mais nous suggérons d'utiliser `q8_0` la quantification du cache. L'objectif de la quantification est de prendre en charge des longueurs de contexte plus longues, puisque le cache KV utilise pas mal de mémoire.
2. Nous avons constaté que le `down_proj` dans ce modèle est extrêmement sensible à la quantification. Nous avons dû refaire certaines de nos quantifications dynamiques qui utilisaient 2 bits pour `down_proj` et nous utilisons maintenant 3 bits comme minimum pour toutes ces matrices.
3. L'utilisation de `llama.cpp` 's backend Flash Attention permet effectivement des vitesses de décodage un peu plus rapides. Utilisez `-DGGML_CUDA_FA_ALL_QUANTS=ON` lors de la compilation. Notez qu'il est également préférable de définir votre architecture CUDA comme indiqué dans <https://developer.nvidia.com/cuda-gpus> pour réduire les temps de compilation, puis définissez-la via `-DCMAKE_CUDA_ARCHITECTURES="80"`
4. L'utilisation d'une `min_p=0.01`suffit probablement. `llama.cpp`est par défaut à 0.1, ce qui n'est probablement pas nécessaire. Comme une température de 0.3 est de toute façon utilisée, nous aurons très probablement très peu de chances d'échantillonner des jetons à faible probabilité, donc supprimer les jetons très improbables est une bonne idée. DeepSeek recommande une température de 0.0 pour les tâches de codage.

[^1]: DOIT UTILISER 8 bits - pas 4 bits

[^2]: le nombre de threads CPU de votre machine

[^3]: Environ 2 pour un GPU de 24 Go. Environ 18 pour un GPU de 80 Go.

[^4]: Longueur de contexte


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://unsloth.ai/docs/fr/modeles/tutorials/deepseek-v3-0324-how-to-run-locally.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
