# Backends experts

Toutes les implémentations de Mixture-of-Experts (MoE) effectuent le même calcul de haut niveau. Pour chaque jeton, un routeur sélectionne *k* experts. L'état caché du jeton est ensuite projeté à travers les paramètres des experts sélectionnés et agrégé avec les poids de routage. La différence entre les backends d'experts réside dans *la manière* dont ces multiplications de matrices d'experts sont exécutées.

`ExpertsInterface` fournit des backends d’experts optimisés. Il découple l’implémentation des experts du code du modèle afin de simplifier l’expérimentation avec différentes fonctions. Ajoutez de nouveaux backends via la même interface.

| experts backend | description | GPU | CPU |
| --- | --- | --- | --- |
| `"eager"` | Implémentation de référence qui itère sur les experts sélectionnés et applique des projections sur leurs jetons. | Des performances de référence raisonnables sans nécessiter de compilation. | Plus lent que `grouped_mm` mais plus rapide que `batched_mm`. |
| `"batched_mm"` | Duplique les paramètres d’expert sélectionnés pour chaque jeton et projette tous les jetons dans une seule GEMM par lots à l’aide de [torch.bmm](https://docs.pytorch.org/docs/stable/generated/torch.bmm.html). | Le plus rapide pour les petites entrées, en particulier avec la compilation. Utilise plus de mémoire en raison de la duplication des paramètres. | Non recommandé (nettement plus lent que les autres backends). |
| `"grouped_mm"` | Trie les jetons par les experts sélectionnés et utilise [torch.nn.functional.grouped_mm](https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.grouped_mm.html) pour projeter tous les jetons en une seule GEMM groupée (nécessite PyTorch 2.9+). | Idéal pour les entrées de grande taille et plus efficace en mémoire car il évite de dupliquer les paramètres des experts. Rapide avec la compilation. | Backend le plus efficace pour toutes les tailles d'entrée. |
| `"deepgemm"` | Trie les jetons par expert sélectionné et projette tous les jetons dans une seule GEMM groupée alignée sur TMA à l'aide des noyaux [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) de [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). | Backend natif pour les modèles DeepSeek sur Hopper (SM90+) et Blackwell (SM100+) ; prend en charge `bfloat16` et les experts quantifiés en FP8/FP4. | Non pris en charge (CUDA uniquement). |
| `"deepgemm_megamoe"` | Fusionne la distribution parallèle d’experts, le MLP à porte (projection ascendante, SwiGLU, projection descendante) et la combinaison EP en un seul noyau DeepGEMM Mega MoE, en superposant les transferts NVLink au calcul des tensor cores. | Uniquement sur Blackwell (SM100+), pour les experts quantifiés en FP4 exécutés avec un parallélisme d'experts. | Non pris en charge (CUDA uniquement). |
| `"sonicmoe"` | Fusionne le calcul avant routé `bfloat16` MoE (dispatch du routeur, projection montée avec porte, activation, projection descendante) dans des noyaux grouped-GEMM CuteDSL (de la bibliothèque [quack](https://github.com/Dao-AILab/quack)) issus de [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe). | Débit de pointe sur Hopper (SM90+) pour les experts `bfloat16` avec une activation à porte (SwiGLU/GeGLU/ReGLU), en particulier pour l'entraînement. | Non pris en charge (CUDA uniquement). |

Les backends `"batched_mm"` et `"grouped_mm"` exécutent également les experts quantisés en FP8 et FP4 (`int8`-packed) via le noyau Triton finegrained-fp8, en lisant des échelles `float32` ou UE8M0. Ils servent de solution de repli pour les points de contrôle quantisés lorsque le backend `"deepgemm"` n'est pas disponible.

## Bascule de l'étape de décodage

Sur GPU, un modèle chargé avec `experts_implementation="grouped_mm"` bascule automatiquement sur `"batched_mm"` pour la phase de décodage de la génération, ce qui est nettement plus rapide pour de faibles nombres de jetons. L'arrière-plan d'origine est rétabli une fois la génération terminée. Sur CPU, `grouped_mm` reste actif tout au long de la génération, car il est plus efficace quelle que soit la taille de l'entrée.

Le commutateur atteint les couches MoE du modèle de niveau supérieur et de tout backbone de sous-configuration, tel que le `text_config` d'un modèle vision-langage. Seules les entrées `grouped_mm` basculent vers `batched_mm`. Les experts exécutés sur tout autre backend le conservent.

## Définir un backend d'experts

Utilisez l'argument `experts_implementation` dans [from_pretrained()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.from_pretrained) pour instancier un modèle avec un backend d'experts spécifique.

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen1.5-MoE-A2.7B",
    dtype="bfloat16",
    experts_implementation="batched_mm",
)
```

Basculez entre les backends d'experts à l'exécution sans recharger le modèle à l'aide de [set_experts_implementation()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.set_experts_implementation).

```py
model.set_experts_implementation("eager")
```

Lisez le backend actuellement en cours d’exécution avec [get_experts_implementation()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.get_experts_implementation). Il renvoie un `dict` contenant une entrée pour le modèle et une entrée par sous-configuration.

```py
model.get_experts_implementation()
# {"": "grouped_mm", "text_config": "grouped_mm", "vision_config": "eager"}
```

## Backend d'experts spécifiques au backbone

Les modèles multimodaux peuvent avoir plusieurs sous-configurations (par exemple, différents backbones). Vous pouvez définir un backend d'experts différent pour chaque sous-configuration en passant un `dict` à `experts_implementation` au moment du chargement.

Les clés de la correspondance doivent correspondre aux noms des sous-configurations.

```py
from transformers import AutoModelForImageTextToText

experts_implementation_per_backbone = {
    "text_config": "grouped_mm",
    "vision_config": "eager",
}

model = AutoModelForImageTextToText.from_pretrained(
    "Qwen/Qwen3-VL-Moe",
    experts_implementation=experts_implementation_per_backbone,
)
```

Définissez le backend des experts globalement avec une clé vide.

```py
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen1.5-MoE-A2.7B",
    experts_implementation={"": "batched_mm"},
)
```

## DeepGEMM

Le backend `"deepgemm"` achemine les produits matriciels d'experts via les noyaux [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) distribués par [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). Il fonctionne avec des experts non quantifiés en `bfloat16` et avec des experts quantisés en FP8/FP4 chargés via [Fine-grained FP8](./quantization/finegrained_fp8).

Le backend `"deepgemm"` nécessite :

- GPU CUDA avec une capacité de calcul ≥ 9.0 (Hopper ou plus récent).
- Un kit CUDA complet avec `nvcc` pour la compilation JIT du noyau, version 12.3 ou ultérieure sur Hopper et 12.9 ou ultérieure sur Blackwell. Une installation runtime-only ne contient pas `nvcc` et est rejetée. Transformers localise le kit via `CUDA_HOME`, `CUDA_PATH`, `nvcc` sur `PATH`, puis `/usr/local/cuda`.
- Le package [kernels](https://github.com/huggingface/kernels).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "deepseek-ai/DeepSeek-V3",
    dtype="bfloat16",
    experts_implementation="deepgemm",
)
```

Le noyau est chargé de manière paresseuse lors du premier passage avant.

### Experts quantisés en FP8 et FP4

Les points de contrôle de type DeepSeek sont généralement pré-quantifiés et incluent leur propre configuration de quantification, il n'est donc pas nécessaire de passer une [FineGrainedFP8Config](/docs/transformers/main/fr/main_classes/quantization#transformers.FineGrainedFP8Config). L'arrière-plan `"deepgemm"` sélectionne automatiquement le noyau de GEMM groupé FP8 (ou FP4 sur Blackwell). DeepGEMM exige des échelles d'activation dynamiques par ligne (`activation_scheme="dynamic"`) et rejette la quantification d'activation statique (par tenseur).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "deepseek-ai/DeepSeek-V3",
    experts_implementation="deepgemm",
)
```

Pour les poids d'experts en FP4 (style DeepSeek V4), le GPU doit être SM100+ (Blackwell). La configuration du checkpoint définit généralement `expert_dtype="fp4"` et `scale_fmt="ue8m0"`.

> [!NOTE]
> Sur Blackwell (SM100+), les noyaux d’experts `"deepgemm"` et `"deepgemm_megamoe"` exigent des échelles d’experts UE8M0 qui soient des puissances de deux. Un point de contrôle quantisé avec des échelles `float32` simples (`scale_fmt="float"`) lève une `ValueError` lors de la première passe avant plutôt que de corrompre silencieusement la sortie. Chargez un point de contrôle quantisé avec `scale_fmt="ue8m0"`, ou passez à `grouped_mm` ou `batched_mm`, qui consomment directement les échelles de bloc `float32`. Hopper (SM90+) consomme des échelles `float32` sur le chemin DeepGEMM sans conversion.

La principale raison de passer un [FineGrainedFP8Config](/docs/transformers/main/fr/main_classes/quantization#transformers.FineGrainedFP8Config) pour un point de contrôle pré-quantifié est de le déquantifier en `bfloat16`, auquel cas les experts s'exécutent en `bfloat16` plutôt que sur le chemin DeepGEMM FP8/FP4.

```py
from transformers import AutoModelForCausalLM, FineGrainedFP8Config

model = AutoModelForCausalLM.from_pretrained(
    "deepseek-ai/DeepSeek-V3",
    quantization_config=FineGrainedFP8Config(dequantize=True),
    experts_implementation="deepgemm",
)
```

### Mega MoE fusionné sur Blackwell

Sur Blackwell (SM100+), définissez `experts_implementation="deepgemm_megamoe"` pour exécuter un noyau fusionné unique qui combine la distribution parallèle des experts, la projection ascendante, SwiGLU, la projection descendante et la combinaison EP, en superposant les transferts NVLink au calcul des tensor cores.

Ce backend nécessite :

- Un GPU Blackwell (capacité de calcul ≥ 10.0) avec un kit CUDA (`nvcc`) 12.9 ou ultérieur.
- Poids d'experts en FP4 appariés avec des échelles de poids UE8M0 (le point de contrôle pré-quantifié déclare généralement `expert_dtype="fp4"` et `scale_fmt="ue8m0"` dans sa configuration).
- Un groupe de processus `torch.distributed` pour le groupe parallèle d'experts, fourni automatiquement par l'habillage parallèle d'experts lorsque `ep_size > 1`.

```py
import os

from transformers import AutoModelForCausalLM, DistributedConfig

distributed_config = DistributedConfig(
    tp_size=int(os.environ["WORLD_SIZE"]),
    ep_size=int(os.environ["WORLD_SIZE"]),
)
model = AutoModelForCausalLM.from_pretrained(
    "deepseek-ai/DeepSeek-V4",
    experts_implementation="deepgemm_megamoe",
    distributed_config=distributed_config,
)
```

## SonicMoE

Le backend `"sonicmoe"` fusionne le calcul avant routé MoE (dispatch, projection gated up, activation, projection down) dans un ensemble de noyaux CuteDSL grouped-GEMM hautement optimisés, construits sur la bibliothèque [quack](https://github.com/Dao-AILab/quack) et distribués par [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe).

Le backend `"sonicmoe"` nécessite :

- GPU CUDA avec une capacité de calcul ≥ 9.0 (Hopper ou plus récent).
- Le package [kernels](https://github.com/huggingface/kernels) et le package `nvidia-cutlass-dsl`.
- Experts avec une activation à porte (`silu`, `gelu` ou `relu`, mappée sur SwiGLU/GeGLU/ReGLU).

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen1.5-MoE-A2.7B",
    dtype="bfloat16",
    experts_implementation="sonicmoe",
)
```

Si les prérequis ne sont pas remplis, la méthode forward lève `ImportError` et vous devez choisir une autre valeur pour `experts_implementation`.

## torch.compile

Les backends `"eager"`, `"batched_mm"` et `"grouped_mm"` sont compatibles avec `torch.compile` dans des mesures variables. Le tableau suivant résume leur compatibilité. Les backends `"deepgemm"`, `"deepgemm_megamoe"` et `"sonicmoe"` passent par des noyaux CUDA externes et ne sont pas couverts par ce tableau.

| Implémentation          | modes de compilation                    | dtypes                           | `fullgraph=True` |
| ----------------------- | ------------------------------------ | -------------------------------- | ---------------- |
| `grouped_mm`            | `None`, `max-autotune-no-cudagraphs` | `bfloat16`                       | Oui              |
| `grouped_mm` (repli) | `None`, `max-autotune-no-cudagraphs` | `bfloat16`, `float16`, `float32` | Oui              |
| `batched_mm`            | tous                                  | `bfloat16`, `float16`, `float32` | Oui              |
| `eager`                 | tous                                  | `bfloat16`, `float16`, `float32` | Non               |

Remarques :

- Le backend d'experts `grouped_mm` prend actuellement en charge uniquement `bfloat16` lors de la compilation avec `torch.compile`. De plus, il n'est pas compatible avec les graphes CUDA, il faut donc utiliser `mode=None` ou `mode="max-autotune-no-cudagraphs"` lors de la compilation.
- Le backend d'experts `eager` utilise une opération dépendante des données pour déterminer quels experts sont utilisés lors d'un passage avant. Cette opération n'est pas compatible avec la compilation complète du graphe (`fullgraph=True`).

```py
import torch
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen1.5-MoE-A2.7B",
    dtype="bfloat16",
    experts_implementation="grouped_mm",
    device_map="auto",
).eval()

# Works for grouped_mm (no CUDA graphs)
model.forward = torch.compile(model.forward, mode="max-autotune-no-cudagraphs")
```

## Benchmarks

Ce [benchmark](https://github.com/user-attachments/files/24125816/bench.py) compare différentes tailles d'entrée et implémentations d'experts, avec et sans `torch.compile`.

