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

{% 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 à exécuter DeepSeek plus rapidement et plus efficacement !
{% endhint %}

DeepSeek remet ça ! Après avoir publié 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 %**. AIME + 19,8 % et LiveCodeBench + 10,0 % ! Ils ont fourni un graphique montrant comment ils se comparaient au checkpoint V3 précédent et à d'autres modèles comme GPT 4.5 et Claude Sonnet 3.7. <mark style="background-color:blue;">**Mais comment exécuter 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>OK</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>Moyenne</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>Meilleure</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 divise par deux la taille du fichier pour atteindre 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 ! Celle à 2,4 bits fonctionne également 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 car [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 chat : `<｜User｜>Créez un jeu Flappy Bird simple et jouable en Python. Placez le jeu final dans une section Markdown.<｜Assistant｜>`
* Un jeton BOS de `<｜begin▁of▁sentence｜>` est ajouté automatiquement lors de la tokenisation (ne l'ajoutez PAS manuellement !)
* DeepSeek a également mentionné utiliser un <mark style="background-color:green;">**prompt système**</mark> (facultatif) - il est en chinois : `该助手为DeepSeek Chat，由深度求索公司创造。\n今天是3月24日，星期一。` ce qui se traduit par : `L'assistant est DeepSeek Chat, créé par DeepSeek.\nAujourd'hui, nous sommes lundi 24 mars.`
* <mark style="background-color:orange;">**Pour la quantification du cache KV, utilisez 8 bits, PAS 4 bits - nous avons constaté qu'elle donne des résultats nettement moins bons.**</mark>

## 📖 Tutoriel : Comment exécuter 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. Changez `-DGGML_CUDA=ON` en `-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 du contexte, `--n-gpu-layers 2` pour le déchargement GPU, selon le nombre de couches. Essayez de l’ajuster si votre GPU manque de mémoire. Supprimez-le aussi si vous n'avez qu'une inférence 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. Vous devez inclure ces éléments :\n1. Vous devez utiliser pygame.\n2. La couleur de fond doit être choisie aléatoirement et être une teinte claire. Commencez avec 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 sombres.\n5. Placez en bas un sol coloré en brun foncé ou en jaune, choisi aléatoirement.\n6. Affichez un score en haut à droite. Incrémentez-le si vous passez les tuyaux sans les toucher.\n7. Créez des tuyaux espacés aléatoirement avec suffisamment d'espace. Coloriez-les aléatoirement en vert foncé, marron clair ou gris foncé.\n8. Lorsque vous perdez, affichez le meilleur score. Faites apparaître le texte à l'intérieur de l'écran. Appuyer sur q ou Échap quittera le jeu. Pour recommencer, appuyez à nouveau sur ESPACE.\nLe jeu final doit être placé dans une section markdown en Python. Vérifiez votre code pour détecter les erreurs et corrigez-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="/files/89f6fef1baa9e78c0b5fa6b9e4ddfdc7809bb35a" alt="" data-size="original">

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

</details>

<div align="center"><figure><img src="/files/d1c29ba544e0873464ff21aacf0059cd69467c14" alt="" width="240"><figcaption><p>2 bits dynamique. Réussit à créer un jeu jouable.</p></figcaption></figure></div>

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

| Quant   | Taille du fichier | GPU 24 Go | GPU 80 Go | 2x GPU 80 Go |
| ------- | ----------------- | --------- | --------- | ------------ |
| 1.73bit | 173 Go            | 5         | 25        | 56           |
| 2.22bit | 183 Go            | 4         | 22        | 49           |
| 2.51bit | 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 de 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 de l'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 pour simuler des balles tournant dans une forme d’heptagone fermée en mouvement.

<figure><img src="/files/5ad09430f143429592eabf7ce1de2675e8306829" alt="" width="563"><figcaption><p>Le but est de faire tourner l'heptagone, et les balles dans 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 \
    --prompt "<｜User｜>Écrivez un programme Python qui affiche 20 balles rebondissant à l'intérieur d'un heptagone en rotation :\n- Toutes les balles ont le même rayon.\n- Chaque balle porte 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 affectées par la gravité et le 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 détermine que la hauteur de rebond après impact ne doit pas dépasser le rayon de l'heptagone, mais doit être supérieure au rayon de la balle.\n- Toutes les balles tournent avec frottement, les numéros sur les balles peuvent être utilisés pour indiquer leur rotation.\n- L'heptagone tourne autour de son centre, et la 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 la 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>2 bits non dynamique. Échec - <mark style="background-color:red;">AVERTISSEMENT DE CRISE</mark> encore !</td><td><a href="/files/b8d6468d5ed242673e812ceab1db18a33e4bfb23">/files/b8d6468d5ed242673e812ceab1db18a33e4bfb23</a></td><td><a href="/files/0ae7172430ec8c11266ccdabc6fde58cb55f3434">/files/0ae7172430ec8c11266ccdabc6fde58cb55f3434</a></td></tr><tr><td>2 bits dynamique. Résout réellement correctement le puzzle de l'heptagone !!</td><td><a href="/files/51f04377aae4f7304b19ae4b4f05a4f9599e503d">/files/51f04377aae4f7304b19ae4b4f05a4f9599e503d</a></td><td><a href="/files/63cad9b744b1cb93d94d157583594ead33324d54">/files/63cad9b744b1cb93d94d157583594ead33324d54</a></td></tr><tr><td>Float8 d'origine</td><td><a href="/files/a09339a83b74113528eda1d08001188b3857460d">/files/a09339a83b74113528eda1d08001188b3857460d</a></td><td><a href="/files/eec41f07f89dc2ace038a41700636103b829ab66">/files/eec41f07f89dc2ace038a41700636103b829ab66</a></td></tr></tbody></table>

La quantification dynamique 2,7 bits, qui ne fait que 230 Go, parvient en fait à 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 de l'heptagone 2 bits dynamique</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 parois initiales de l'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 parois
            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)
        
        # Tout dessiner
        self.draw()
    
    def check_wall_collisions(self, ball):
        for wall in self.walls:
            # Trouver le point le plus proche sur le segment de 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 selon 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 selon la collision
                    ball.spin += (ball.vx * ny - ball.vy * nx) * 0.1
                    
                    # Sortir la balle 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 une rotation selon 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 vers le 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  # Mettre l'effet de spin à l'échelle pour un 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 de l'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 parois 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 par rapport au 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)
            
            # Ramener 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 ne 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 ne 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 une partie du 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):
            # Faire apparaître 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 côté 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 du bord
            edge_x /= edge_length
            edge_y /= edge_length
            
            # Vecteur normal (perpendiculaire au bord, 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 du bord
            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 le plus proche sur le bord 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 le bord
                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 du bord
                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 ne 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  # Mettre à l'échelle 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: Résultats supplémentaires et conseils

1. Nous constatons que l'utilisation d'une quantification plus faible du cache KV (4 bits) semble dégrader la qualité de génération d'après des tests empiriques - 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, car le cache KV utilise une quantité non négligeable de mémoire.
2. Nous avons trouvé 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 désormais 3 bits comme minimum pour toutes ces matrices.
3. L'utilisation de `llama.cpp` du backend Flash Attention de donne 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> afin de réduire les temps de compilation, puis de la définir via `-DCMAKE_CUDA_ARCHITECTURES="80"`
4. L'utilisation d'un `min_p=0.01`est probablement suffisante. `llama.cpp`par défaut à 0.1, ce qui n'est probablement pas nécessaire. Puisqu'une température de 0.3 est de toute façon utilisée, il est très peu probable que nous échantillonnions 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]: 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: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
