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

DeepSeek est de retour ! Après avoir publié V3, R1 Zero et R1 en décembre 2024 et janvier 2025, DeepSeek a mis à jour leurs points de contrôle / modèles pour V3, et a publié une mise à jour en mars !

Selon DeepSeek, MMLU-Pro a bondi de +5,3 % pour atteindre 81,2 %. **GPQA +9,3 points %**. AIME + 19,8 % et LiveCodeBench + 10,0 % ! Ils ont fourni un graphique montrant comment ils se comparaient au point de contrôle 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 un modèle de 671 milliards de paramètres localement ?**</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>Moyen</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>Meilleur</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 de moitié la taille du fichier à environ 404 Go, et notre quantification dynamique 1,78 bit tient autour de 151 Go. **Nous suggérons d'utiliser notre quantification 2,7 bits pour équilibrer taille et précision ! La version 2,4 bits fonctionne également 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 codage comme [vu ici](https://api-docs.deepseek.com/quick_start/parameter_settings))
* Min\_P de 0,00 (optionnel, 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 jouable simple en Python. Placez le jeu final à l'intérieur d'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 mentionné l'utilisation d'un <mark style="background-color:green;">**prompt système**</mark> également (optionnel) - 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 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 cela donnait des résultats nettement moins bons.**</mark>

## 📖 Tutoriel : Comment exécuter DeepSeek-V3 dans llama.cpp

1. Obtenez la dernière `llama.cpp` sur [GitHub ici](https://github.com/ggml-org/llama.cpp). Vous pouvez aussi 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 voulez simplement de l'inférence CPU. **Pour les appareils Apple Mac / Metal**, définissez `-DGGML_CUDA=OFF` puis continuez comme d'habitude - le support Metal est activé par défaut.

{% hint style="warning" %}
REMARQUE l'utilisation de `-DGGML_CUDA=ON` pour les GPU peut prendre 5 minutes à compiler. Le CPU seul prend 1 minute pour compiler. Vous pourriez être intéressé par les binaires précompilés de llama.cpp.
{% 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`(quant 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*"], # Dynamique 2,7 bits (230 Go) Utilisez "*UD-IQ_S*" pour Dynamique 1,78 bit (151 Go)
)
```

{% endcode %}

3. Exécutez le test Flappy Bird d'Unsloth comme décrit dans notre Quant 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 sur GPU du nombre de couches. Essayez de l'ajuster si votre GPU manque de mémoire. Supprimez-le également si vous avez uniquement 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｜>Create a Flappy Bird game in Python. You must include these things:\n1. You must use pygame.\n2. The background color should be randomly chosen and is a light shade. Start with a light blue color.\n3. Pressing SPACE multiple times will accelerate the bird.\n4. The bird's shape should be randomly chosen as a square, circle or triangle. The color should be randomly chosen as a dark color.\n5. Place on the bottom some land colored as dark brown or yellow chosen randomly.\n6. Make a score shown on the top right side. Increment if you pass pipes and don't hit them.\n7. Make randomly spaced pipes with enough space. Color them randomly as dark green or light brown or a dark gray shade.\n8. When you lose, show the best score. Make the text inside the screen. Pressing q or Esc will quit the game. Restarting is pressing SPACE again.\nThe final game should be inside a markdown section in Python. Check your code for errors and fix them before the final markdown section.&#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> Cliquer pour voir le résultat <em><mark style="color:rouge;"><strong>(avertissement crises d'épilepsie !)</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">

2 bits standard. É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>2 bits dynamique. Réussit à créer un jeu jouable.</p></figcaption></figure></div>

5. Comme DeepSeek-R1, V3 a 61 couches. Par exemple, avec un GPU 24 Go ou 80 Go, vous pouvez vous attendre à décharger après arrondi vers le bas (réduire 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-le. Pour une machine à mémoire unifiée de 128 Go, 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｜>Create a Flappy Bird game in Python.<｜Assistant｜>"
```

## :8ball: Test Heptagone

Nous testons également nos quants 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 en créant un moteur physique basique pour simuler des balles tournant dans une forme heptagonale fermée 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>L'objectif est de faire tourner l'heptagone, et les balles à l'intérieur de l'heptagone doivent se déplacer.</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 montre 20 balles rebondissant à l'intérieur d'un heptagone tournant :\n- Toutes les balles ont le même rayon.\n- Toutes les balles ont un numéro de 1 à 20.\n- Toutes les balles tombent du 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 la friction, et elles doivent rebondir sur les parois en rotation de manière réaliste. Il doit également y avoir des collisions entre les balles.\n- Le matériau de toutes les balles fait que la hauteur du rebond suite à 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 friction, les numéros sur la balle peuvent être utilisés pour indiquer la rotation de la balle.\n- L'heptagone tourne autour de son centre, et la vitesse de rotation est de 360 degrés en 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- Tous les codes doivent être mis 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. Échoue - <mark style="background-color:red;">AVERTISSEMENT CRISES D'ÉPILEPSIE</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>2 bits dynamique. Résout en fait correctement le casse-tête 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>

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

<details>

<summary>Code 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 temps delta (approximatif)
        dt = 0.016  # Supposé ~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 la friction
            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 la paroi par rapport à la balle
            closest = self.closest_point_on_segment(
                wall.x1, wall.y1, wall.x2, wall.y2, ball.x, ball.y
            )
            
            # Calculer la distance à la paroi
            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:  # Se dirige vers la paroi
                    # 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 basée sur 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:  # Se dirigent l'un 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 basée sur 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 rotation basée sur la rotation (spin)
            angle = ball.spin * 10  # Échelle de la rotation 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("Bouncing Balls in Spinning Heptagon")
    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 en 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  # Supposé 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 la friction
            ball.vx *= FRICTION
            ball.vy *= FRICTION
            
            # Appliquer la décroissance de la rotation
            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 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)
            
            # 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 vélocité
            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
        
        # Vélocité 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 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("Bouncing Balls in a Spinning Heptagon")
    app = BouncingBalls(root)
    app.run()
```

</details>

<details>

<summary>Code 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 un peu de rotation
            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 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 à 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 le plus proche sur l'arête à 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 de la balle au 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 du 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 rotation selon 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 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 rotation basée sur la rotation (spin)
            angle = ball.spin * 10  # Mettre à l'échelle la rotation pour la rendre 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])
        
        # Planifier la prochaine mise à jour
        self.last_time = self.root.after(16, self.update)  # ~60 FPS

if __name__ == '__main__':
    root = tk.Tk()
    root.title('Bouncing Balls in a Spinning Heptagon')
    simulator = HeptagonBounceSimulator(root)
    root.mainloop()
```

</details>

## :detective: Constatations supplémentaires et conseils

1. Nous constatons que l'utilisation d'une quantification de cache KV plus basse (4 bits) semble dégrader la qualité de génération selon des tests empiriques - d'autres tests doivent être effectués, 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 trouvé le `down_proj` dans ce modèle extrêmement sensible à la quantification. Nous avons dû refaire certaines de nos quantifications dynamiques qui utilisaient 2 bits pour `down_proj` et maintenant nous utilisons 3 bits comme minimum pour toutes ces matrices.
3. L'utilisation de `llama.cpp` le backend Flash Attention de 's donne des vitesses de décodage quelque 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 de la définir via `-DCMAKE_CUDA_ARCHITECTURES="80"`
4. L'utilisation d'un(e) `min_p=0.01`est probablement suffisante. `llama.cpp`par défaut est 0.1, ce qui n'est probablement pas nécessaire. Puisqu'une température de 0.3 est utilisée de toute façon, il est très peu probable que nous échantillonnions des tokens de faible probabilité, donc supprimer les tokens 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]: Threads CPU que votre machine possède

[^3]: Environ 2 pour GPU 24 Go. Environ 18 pour GPU 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.
