# Backends de expertos

Todas las implementaciones de Mixture-of-Experts (MoE) realizan el mismo cálculo de alto nivel. Para cada token, un router selecciona *k* expertos. A continuación, el estado oculto del token se proyecta a través de los parámetros de los expertos seleccionados y se agrega con los pesos de enrutamiento. La diferencia entre los backends de expertos radica en *cómo* se ejecutan esas multiplicaciones de matrices de expertos.

La `ExpertsInterface` proporciona backends de expertos optimizados. Desacopla la implementación de los expertos del código del modelo para simplificar la experimentación con diferentes funciones. Añade nuevos backends a través de la misma interfaz.

| backend de expertos | descripción | GPU | CPU |
| --- | --- | --- | --- |
| `"eager"` | Implementación de referencia que itera sobre los expertos seleccionados y aplica proyecciones a sus tokens. | Rendimiento de línea base razonable sin necesidad de compilación. | Más lento que `grouped_mm` pero más rápido que `batched_mm`. |
| `"batched_mm"` | Duplica los parámetros del experto seleccionado para cada token y proyecta todos los tokens en un solo GEMM por lotes usando [torch.bmm](https://docs.pytorch.org/docs/stable/generated/torch.bmm.html). | Más rápido para entradas pequeñas, especialmente con compilación. Utiliza más memoria debido a la duplicación de parámetros. | No recomendado (significativamente más lento que otros backends). |
| `"grouped_mm"` | Ordena los tokens según los expertos seleccionados y utiliza [torch.nn.functional.grouped_mm](https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.grouped_mm.html) para proyectar todos los tokens en un solo GEMM agrupado (requiere PyTorch 2.9+). | Ideal para entradas más grandes y más eficiente en memoria, ya que evita duplicar los parámetros de los expertos. Rápido con compilación. | Backend más eficiente para todos los tamaños de entrada. |
| `"deepgemm"` | Ordena los tokens por el experto seleccionado y proyecta todos los tokens en un único GEMM agrupado alineado con TMA, utilizando los kernels de [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) de [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). | Backend nativo para modelos de DeepSeek en Hopper (SM90+) y Blackwell (SM100+); admite `bfloat16` y expertos cuantizados en FP8/FP4. | No compatible (solo CUDA). |
| `"deepgemm_megamoe"` | Fusiona el despacho de paralelismo de expertos, el MLP con compuerta (proyección ascendente, SwiGLU, proyección descendente) y la combinación de EP en un único kernel DeepGEMM Mega MoE, superponiendo las transferencias NVLink con el cálculo de tensor cores. | Solo Blackwell (SM100+), para expertos cuantizados en FP4 que se ejecutan con paralelismo de expertos. | No compatible (solo CUDA). |
| `"sonicmoe"` | Fusiona el paso hacia adelante de MoE en `bfloat16` con enrutamiento (despacho del router, proyección ascendente con puerta, activación, proyección descendente) en kernels de GEMM agrupado de CuteDSL (de la biblioteca [quack](https://github.com/Dao-AILab/quack)) de [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe). | Rendimiento de vanguardia en Hopper (SM90+) para expertos en `bfloat16` con una activación con puerta (SwiGLU/GeGLU/ReGLU), especialmente para el entrenamiento. | No compatible (solo CUDA). |

Los backends `"batched_mm"` y `"grouped_mm"` también ejecutan expertos cuantizados en FP8 y FP4 (empaquetados en `int8`) a través del kernel finegrained-fp8 de Triton, leyendo escalas en `float32` o UE8M0. Actúan como alternativa para los puntos de control cuantizados cuando el backend `"deepgemm"` no está disponible.

## Cambio de etapa de decodificación

En GPU, un modelo cargado con `experts_implementation="grouped_mm"` cambia automáticamente a `"batched_mm"` para la etapa de decodificación de la generación, lo cual es significativamente más rápido con un menor número de tokens. El backend original se restaura una vez finalizada la generación. En CPU, `grouped_mm` permanece activo durante toda la generación, ya que es más eficiente en todos los tamaños de entrada.

El conmutador alcanza las capas MoE en el modelo de nivel superior y en cualquier backbone de subconfiguración, como el `text_config` de un modelo de visión-lenguaje. Solo las entradas `grouped_mm` se conmutan a `batched_mm`. Los expertos que ejecutan cualquier otro backend lo mantienen.

## Establecer un backend de expertos

Use el argumento `experts_implementation` en [from_pretrained()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.from_pretrained) para instanciar un modelo con un backend de expertos específico.

```py
from transformers import AutoModelForCausalLM

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

Cambie entre backends de expertos en tiempo de ejecución sin recargar el modelo usando [set_experts_implementation()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.set_experts_implementation).

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

Lee el backend que se está ejecutando actualmente con [get_experts_implementation()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.get_experts_implementation). Devuelve un `dict` con una entrada para el modelo y una entrada por cada sub-configuración.

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

## Backend de expertos específicos del backbone

Los modelos multimodales pueden tener varias subconfiguraciones (por ejemplo, backbones diferentes). Puede establecer un backend de expertos diferente para cada subconfiguración pasando un `dict` a `experts_implementation` en el momento de la carga.

Las claves en el mapeo deben coincidir con los nombres de subconfiguraciones.

```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,
)
```

Establece el backend de expertos globalmente con una clave vacía.

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

## DeepGEMM

El backend `"deepgemm"` enruta las multiplicaciones de matrices de expertos a través de los kernels de [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) distribuidos por [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). Funciona con expertos `bfloat16` sin cuantizar y con expertos cuantizados en FP8/FP4 cargados a través de [Fine-grained FP8](./quantization/finegrained_fp8).

El backend `"deepgemm"` requiere:

- GPU CUDA con capacidad de cálculo ≥ 9.0 (Hopper o más reciente).
- Un kit de herramientas CUDA completo con `nvcc` para la compilación JIT del kernel, versión 12.3 o posterior en Hopper y 12.9 o posterior en Blackwell. Una instalación solo de tiempo de ejecución no incluye `nvcc` y se rechaza. Transformers localiza el kit de herramientas a través de `CUDA_HOME`, `CUDA_PATH`, `nvcc` en `PATH` y, a continuación, `/usr/local/cuda`.
- El paquete [kernels](https://github.com/huggingface/kernels).

```py
from transformers import AutoModelForCausalLM

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

El kernel se carga de forma perezosa en la primera pasada hacia adelante.

### Expertos cuantizados en FP8 y FP4

Los puntos de control de estilo DeepSeek suelen estar pre-cuantizados y llevan su propia configuración de cuantización, por lo que no es necesario pasar una [FineGrainedFP8Config](/docs/transformers/main/es/main_classes/quantization#transformers.FineGrainedFP8Config). El backend `"deepgemm"` selecciona automáticamente el kernel de GEMM agrupado FP8 (o FP4 en Blackwell). DeepGEMM requiere escalas de activación dinámicas por fila (`activation_scheme="dynamic"`) y rechaza la cuantización de activaciones estática (por tensor).

```py
from transformers import AutoModelForCausalLM

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

Para los pesos de expertos empaquetados en FP4 (estilo DeepSeek V4), la GPU debe ser SM100+ (Blackwell). La configuración del checkpoint suele establecer `expert_dtype="fp4"` y `scale_fmt="ue8m0"`.

> [!NOTE]
> En Blackwell (SM100+), los kernels de expertos `"deepgemm"` y `"deepgemm_megamoe"` requieren escalas de expertos UE8M0 que sean potencias de dos. Un checkpoint cuantizado con escalas `float32` simples (`scale_fmt="float"`) genera un `ValueError` en la primera pasada en lugar de corromper silenciosamente la salida. Carga un checkpoint cuantizado con `scale_fmt="ue8m0"`, o cambia a `grouped_mm` o `batched_mm`, que consumen directamente escalas de bloque `float32`. Hopper (SM90+) consume escalas `float32` en la ruta DeepGEMM sin conversión.

La principal razón para pasar una [FineGrainedFP8Config](/docs/transformers/main/es/main_classes/quantization#transformers.FineGrainedFP8Config) para un checkpoint pre-cuantizado es descuantizarlo de vuelta a `bfloat16`, en cuyo caso los expertos se ejecutan en `bfloat16` en lugar de en la ruta DeepGEMM de FP8/FP4.

```py
from transformers import AutoModelForCausalLM, FineGrainedFP8Config

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

### Fused Mega MoE en Blackwell

En Blackwell (SM100+), establezca `experts_implementation="deepgemm_megamoe"` para ejecutar un solo kernel fusionado que combina el despacho paralelo de expertos, la proyección ascendente, SwiGLU, la proyección descendente y la combinación EP, superponiendo las transferencias NVLink con el cálculo de tensor cores.

Este backend requiere:

- Una GPU Blackwell (capacidad de cálculo ≥ 10.0) con un kit de herramientas CUDA (`nvcc`) 12.9 o posterior.
- Pesos de expertos empaquetados en FP4 junto con escalas de pesos UE8M0 (el punto de control pre-cuantizado suele declarar `expert_dtype="fp4"` y `scale_fmt="ue8m0"` en su configuración).
- Un grupo de procesos de `torch.distributed` para el grupo de paralelismo de expertos, que el envoltorio de paralelismo de expertos proporciona automáticamente cuando `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

El backend `"sonicmoe"` fusiona el paso hacia adelante del MoE enrutado (despacho, proyección hacia arriba con puerta, activación, proyección hacia abajo) en un conjunto de kernels de GEMM agrupado CuteDSL altamente optimizados, construidos sobre la biblioteca [quack](https://github.com/Dao-AILab/quack) y distribuidos por [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe).

El backend `"sonicmoe"` requiere:

- GPU CUDA con capacidad de cálculo ≥ 9.0 (Hopper o más reciente).
- El paquete [kernels](https://github.com/huggingface/kernels) y el paquete `nvidia-cutlass-dsl`.
- Expertos con una activación con puerta (`silu`, `gelu` o `relu`, mapeados a SwiGLU/GeGLU/ReGLU).

```py
from transformers import AutoModelForCausalLM

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

Si no se cumplen los requisitos, el método forward lanza `ImportError` y debe elegir una `experts_implementation` diferente.

## torch.compile

Los backends `"eager"`, `"batched_mm"` y `"grouped_mm"` son compatibles con `torch.compile` en distintos grados. La siguiente tabla resume su compatibilidad. Los backends `"deepgemm"`, `"deepgemm_megamoe"` y `"sonicmoe"` se enrutan a través de kernels CUDA externos y no están cubiertos por esta tabla.

| Implementación          | modos de compilación                    | dtypes                           | `fullgraph=True` |
| ----------------------- | ------------------------------------ | -------------------------------- | ---------------- |
| `grouped_mm`            | `None`, `max-autotune-no-cudagraphs` | `bfloat16`                       | Sí              |
| `grouped_mm` (alternativa) | `None`, `max-autotune-no-cudagraphs` | `bfloat16`, `float16`, `float32` | Sí              |
| `batched_mm`            | todos                                  | `bfloat16`, `float16`, `float32` | Sí              |
| `eager`                 | todos                                  | `bfloat16`, `float16`, `float32` | No               |

Notas:

- El backend de expertos `grouped_mm` actualmente solo admite `bfloat16` cuando se compila con `torch.compile`. Además, no es compatible con CUDA graphs, por lo que debe usar `mode=None` o `mode="max-autotune-no-cudagraphs"` al compilar.
- El backend de expertos `eager` utiliza una operación dependiente de los datos para determinar qué expertos se usan en una pasada hacia adelante. Esta operación no es compatible con la compilación de grafo completo (`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

Este [benchmark](https://github.com/user-attachments/files/24125816/bench.py) compara diferentes tamaños de entrada e implementaciones de expertos con y sin `torch.compile`.

