# Backends de Experts

Todas as implementações de Mixture-of-Experts (MoE) executam o mesmo cálculo de alto nível. Para cada token, um roteador seleciona *k* especialistas. O estado oculto do token é então projetado pelos parâmetros dos especialistas selecionados e agregado com os pesos de roteamento. A diferença entre os backends de especialistas é *como* essas multiplicações de matriz dos especialistas são executadas.

A `ExpertsInterface` fornece backends de experts otimizados. Ela desacopla a implementação dos experts do código do modelo para simplificar a experimentação com diferentes funções. Adicione novos backends por meio da mesma interface.

| backend de especialistas | descrição | GPU | CPU |
| --- | --- | --- | --- |
| `"eager"` | Implementação de referência que itera sobre os especialistas selecionados e aplica projeções em seus tokens. | Desempenho de referência razoável sem exigir compilação. | Mais lento que `grouped_mm`, mas mais rápido que `batched_mm`. |
| `"batched_mm"` | Duplica os parâmetros do especialista selecionado para cada token e projeta todos os tokens em um único GEMM em lote usando [torch.bmm](https://docs.pytorch.org/docs/stable/generated/torch.bmm.html). | Mais rápido para entradas pequenas, especialmente com compilação. Usa mais memória devido à duplicação de parâmetros. | Não recomendado (significativamente mais lento que outros backends). |
| `"grouped_mm"` | Ordena os tokens pelos especialistas selecionados e usa [torch.nn.functional.grouped_mm](https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.grouped_mm.html) para projetar todos os tokens em um único GEMM agrupado (requer PyTorch 2.9+). | Ideal para entradas maiores e mais eficiente em termos de memória, pois evita a duplicação dos parâmetros dos especialistas. Rápido com compilação. | Backend mais eficiente para todos os tamanhos de entrada. |
| `"deepgemm"` | Ordena os tokens pelo especialista selecionado e projeta todos os tokens em um único GEMM agrupado alinhado ao TMA, usando os kernels [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) de [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). | Backend nativo para modelos DeepSeek em Hopper (SM90+) e Blackwell (SM100+); suporta `bfloat16` e especialistas quantizados em FP8/FP4. | Não suportado (somente CUDA). |
| `"deepgemm_megamoe"` | Fuses o despacho expert-parallel, o MLP com gate (projeção para cima, SwiGLU, projeção para baixo) e a combinação EP em um único kernel DeepGEMM Mega MoE, sobrepondo as transferências NVLink ao cálculo nos tensor cores. | Somente Blackwell (SM100+), para especialistas quantizados em FP4 executados com paralelismo de especialistas. | Não suportado (somente CUDA). |
| `"sonicmoe"` | Funde o forward `bfloat16` roteado do MoE (dispatch do router, projeção up com gate, ativação, projeção down) em kernels de grouped-GEMM do CuteDSL (da biblioteca [quack](https://github.com/Dao-AILab/quack)) do [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe). | Desempenho de ponta em throughput em Hopper (SM90+) para especialistas em `bfloat16` com ativação com gate (SwiGLU/GeGLU/ReGLU), especialmente para treinamento. | Não suportado (somente CUDA). |

Os backends `"batched_mm"` e `"grouped_mm"` também executam especialistas quantizados em FP8 e FP4 (empacotados em `int8`) por meio do kernel Triton finegrained-fp8, lendo escalas em `float32` ou UE8M0. Eles atuam como fallback para checkpoints quantizados quando o backend `"deepgemm"` não está disponível.

## Comutação da etapa de decodificação

Na GPU, um modelo carregado com `experts_implementation="grouped_mm"` alterna automaticamente para `"batched_mm"` na etapa de decodificação da geração, o que é significativamente mais rápido para contagens menores de tokens. O backend original é restaurado assim que a geração termina. Na CPU, `grouped_mm` permanece ativo durante toda a geração, pois é mais eficiente em todos os tamanhos de entrada.

O switch atinge as camadas MoE no modelo de nível superior e em qualquer backbone de subconfiguração, como o `text_config` de um modelo de visão-linguagem. Apenas as entradas `grouped_mm` são alteradas para `batched_mm`. Os especialistas que executam qualquer outro backend mantêm o valor atual.

## Defina um backend de especialistas

Use o argumento `experts_implementation` em [from_pretrained()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.from_pretrained) para instanciar um modelo com um backend de experts específico.

```py
from transformers import AutoModelForCausalLM

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

Alterne entre backends de especialistas em tempo de execução sem recarregar o modelo usando [set_experts_implementation()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.set_experts_implementation).

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

Leia o backend que está sendo executado atualmente com [get_experts_implementation()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.get_experts_implementation). Ele retorna um `dict` com uma entrada para o modelo e uma entrada para cada sub-configuração.

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

## Backend de especialistas específicos do backbone

Modelos multimodais podem ter múltiplas subconfigurações (por exemplo, backbones diferentes). Você pode definir um backend de especialistas diferente para cada subconfiguração passando um `dict` para `experts_implementation` no momento do carregamento.

As chaves no mapeamento devem corresponder aos nomes das subconfigurações.

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

Defina o backend de especialistas globalmente com uma chave vazia.

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

## DeepGEMM

O backend `"deepgemm"` roteia os matmuls de especialistas por meio dos kernels [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) distribuídos por [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). Ele funciona com especialistas `bfloat16` sem quantização e com especialistas quantizados em FP8/FP4 carregados por meio de [Fine-grained FP8](./quantization/finegrained_fp8).

O backend `"deepgemm"` requer:

- GPU CUDA com capacidade de computação ≥ 9.0 (Hopper ou mais recente).
- Um toolkit CUDA completo com `nvcc` para a compilação JIT do kernel, versão 12.3 ou posterior em Hopper e 12.9 ou posterior em Blackwell. Uma instalação apenas de runtime não possui `nvcc` e é rejeitada. O Transformers localiza o toolkit por meio de `CUDA_HOME`, `CUDA_PATH`, `nvcc` no `PATH` e, em seguida, `/usr/local/cuda`.
- O pacote [kernels](https://github.com/huggingface/kernels).

```py
from transformers import AutoModelForCausalLM

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

O kernel é carregado de forma preguiçosa na primeira chamada de forward.

### Especialistas quantizados em FP8 e FP4

Checkpoints no estilo DeepSeek geralmente são pré-quantizados e possuem sua própria configuração de quantização, portanto, não é necessário passar um [FineGrainedFP8Config](/docs/transformers/main/pt/main_classes/quantization#transformers.FineGrainedFP8Config). O backend `"deepgemm"` seleciona automaticamente o kernel de GEMM agrupado FP8 (ou FP4 em Blackwell). O DeepGEMM requer escalas de ativação dinâmicas por linha (`activation_scheme="dynamic"`) e rejeita a quantização de ativação estática (por tensor).

```py
from transformers import AutoModelForCausalLM

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

Para pesos de especialistas empacotados em FP4 (estilo DeepSeek V4), a GPU deve ser SM100+ (Blackwell). A configuração do checkpoint geralmente define `expert_dtype="fp4"` e `scale_fmt="ue8m0"`.

> [!NOTE]
> No Blackwell (SM100+), os kernels de experts `"deepgemm"` e `"deepgemm_megamoe"` exigem escalas de experts UE8M0 que sejam potências de dois. Um checkpoint quantizado com escalas `float32` comuns (`scale_fmt="float"`) levanta um `ValueError` no primeiro forward, em vez de corromper silenciosamente a saída. Carregue um checkpoint quantizado com `scale_fmt="ue8m0"`, ou alterne para `grouped_mm` ou `batched_mm`, que consomem diretamente escalas de bloco `float32`. O Hopper (SM90+) consome escalas `float32` no caminho DeepGEMM sem conversão.

O principal motivo para passar um [FineGrainedFP8Config](/docs/transformers/main/pt/main_classes/quantization#transformers.FineGrainedFP8Config) para um checkpoint pré-quantizado é desquantizá-lo de volta para `bfloat16`, caso em que os especialistas são executados em `bfloat16` em vez do caminho 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",
)
```

### Fused Mega MoE no Blackwell

No Blackwell (SM100+), defina `experts_implementation="deepgemm_megamoe"` para executar um único kernel fundido que combina o despacho paralelo de especialistas, a projeção para cima, o SwiGLU, a projeção para baixo e a combinação de EP, sobrepondo as transferências NVLink ao cálculo nos tensor cores.

Este backend requer:

- Uma GPU Blackwell (capacidade de computação ≥ 10.0) com um toolkit CUDA (`nvcc`) 12.9 ou posterior.
- Pesos de especialistas empacotados em FP4 combinados com escalas de pesos UE8M0 (o checkpoint pré-quantizado normalmente declara `expert_dtype="fp4"` e `scale_fmt="ue8m0"` em sua configuração).
- Um grupo de processos `torch.distributed` para o grupo de paralelismo de especialistas, fornecido automaticamente pelo encapsulamento de paralelismo de especialistas quando `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

O backend `"sonicmoe"` funde o forward do MoE roteado (dispatch, projeção gated up, ativação, projeção down) em um conjunto de kernels CuteDSL grouped-GEMM altamente otimizados, construídos sobre a biblioteca [quack](https://github.com/Dao-AILab/quack) e distribuídos por [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe).

O backend `"sonicmoe"` requer:

- GPU CUDA com capacidade de computação ≥ 9.0 (Hopper ou mais recente).
- O pacote [kernels](https://github.com/huggingface/kernels) e o pacote `nvidia-cutlass-dsl`.
- Especialistas com ativação com gate (`silu`, `gelu` ou `relu`, mapeados para SwiGLU/GeGLU/ReGLU).

```py
from transformers import AutoModelForCausalLM

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

Se os requisitos não forem atendidos, o forward lança `ImportError` e você deve escolher uma `experts_implementation` diferente.

## torch.compile

Os backends `"eager"`, `"batched_mm"` e `"grouped_mm"` são compatíveis com `torch.compile` em diferentes graus. A tabela a seguir resume essa compatibilidade. Os backends `"deepgemm"`, `"deepgemm_megamoe"` e `"sonicmoe"` usam kernels CUDA externos e não estão cobertos por esta tabela.

| Implementação          | modos de compilação                    | dtypes                           | `fullgraph=True` |
| ----------------------- | ------------------------------------ | -------------------------------- | ---------------- |
| `grouped_mm`            | `None`, `max-autotune-no-cudagraphs` | `bfloat16`                       | Sim              |
| `grouped_mm` (alternativa) | `None`, `max-autotune-no-cudagraphs` | `bfloat16`, `float16`, `float32` | Sim              |
| `batched_mm`            | todos                                  | `bfloat16`, `float16`, `float32` | Sim              |
| `eager`                 | todos                                  | `bfloat16`, `float16`, `float32` | Não               |

Observações:

- O backend de especialistas `grouped_mm` atualmente suporta apenas `bfloat16` quando compilado com `torch.compile`. Além disso, ele não é compatível com CUDA graphs, portanto, você deve usar `mode=None` ou `mode="max-autotune-no-cudagraphs"` ao compilar.
- O backend de especialistas `eager` usa uma operação dependente dos dados para encontrar quais especialistas são usados em uma passagem de frente. Essa operação não é compatível com a compilação 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 tamanhos de entrada e implementações de especialistas com e sem `torch.compile`.

