Mixture of Experts (MoE): как Mixtral и Qwen-MoE дают производительность 70B на железе 7B

opensourceaillmmoearchitectureperformanceit
← Back to Blog

Введение: почему все говорят о MoE?

Вы видите в Hugging Face две модели: Llama 3 70B и Mixtral 8x7B. Первая — 70 миллиардов параметров. Вторая — 47 миллиардов активных. Но Mixtral работает быстрее Llama 3 70B при том же качестве ответов.

Как это возможно? Секрет в Mixture of Experts — архитектуре, которая разделяет модель на независимые "эксперты", активируя только нужных для каждого токена.

В этой статье разберём:

  • Что такое MoE и как работает routing
  • Почему MoE масштабируется лучше Dense моделей
  • Как устроен Mixtral 8x7B и Qwen1.5-32B-Chat
  • Какие компромиссы у MoE (скорость, память, обучение)
  • Когда MoE имеет смысл, а когда — нет

Проблема: почему Dense модели дороги?

Dense трансформер

Обычная LLM (Dense) обрабатывает каждый токен через все параметры:

Токен "Привет" → [Все 7B параметров] → токен "Как"
Токен "Как" → [Все 7B параметров] → токен "дела"
Токен "дела" → [Все 7B параметров] → токен "?"

Каждый forward pass проходит через все слои и все FFN (feed-forward) слои:

# Dense FFN слой
def dense_ffn(x):
    # x: [batch, hidden_dim]
    h = gelu(x @ W1) @ W2  # W1: [hidden_dim, intermediate_dim]
    return h

Для Llama 3 70B:

  • hidden_dim = 8192
  • intermediate_dim = 28672 (×3.5 для двух проекций)
  • FFN параметры: 8192 × 28672 × 2 × 80 слоев ≈ 376B параметров (только FFN!)

Стоимость инференса Dense модели

Llama 3 70B FP16:
  Параметры: 140 GB (FP16)
  VRAM при инференсе: ~140 GB (только веса)
  GPU: 4×A100 80GB или 8×A100 40GB
  Скорость: ~30 tok/s на 4×A100

Llama 3 8B FP16:
  Параметры: 16 GB (FP16)
  VRAM: ~16 GB
  GPU: 1×RTX 4090
  Скорость: ~120 tok/s

Проблема: качество растёт с размером, но стоимость инференса растёт линейно.


Решение: Mixture of Experts

Основная идея

Вместо одного большого FFN слоя — несколько маленьких экспертов. Для каждого токена выбирается 1-2 эксперта:

Dense модель (7B):
  FFN: 1 слой × 7B параметров → каждый токен проходит через ВСЕ

MoE модель (7B effective):
  FFN: 8 экспертов × 1B параметров → каждый токен проходит через 1-2
  Routing: 0.1% параметров на выбор эксперта
Токен "Привет" → Router → Expert_3 → output
Токен "Код"   → Router → Expert_7 → output
Токен "Медицина" → Router → Expert_1 → output

Архитектура MoE слоя

class MoELayer(nn.Module):
    def __init__(self, num_experts=8, top_k=2):
        super().__init__()
        self.experts = nn.ModuleList([
            FFNExpert(hidden_dim, intermediate_dim) 
            for _ in range(num_experts)
        ])
        self.router = Router(hidden_dim, num_experts)
        self.top_k = top_k
    
    def forward(self, x):
        batch, seq_len, hidden = x.shape
        
        # Routing: для каждого токена выбираем top-k экспертов
        routing_weights = self.router(x)  # [batch, seq_len, num_experts]
        top_k_weights, top_k_indices = routing_weights.topk(self.top_k)
        
        # Вычисляем output для каждого выбранного эксперта
        output = torch.zeros_like(x)
        for i, expert in enumerate(self.experts):
            mask = (top_k_indices == i).any(dim=-1)  # [batch, seq_len]
            if mask.any():
                expert_output = expert(x[mask])
                weight = top_k_weights[mask][:, top_k_indices[mask] == i].sum(dim=-1)
                output[mask] += expert_output * weight.unsqueeze(-1)
        
        return output

Router: как принимается решение

class Router(nn.Module):
    def __init__(self, hidden_dim, num_experts):
        super().__init__()
        self.gate = nn.Linear(hidden_dim, num_experts)
    
    def forward(self, x):
        logits = self.gate(x)  # [batch, seq_len, num_experts]
        weights = F.softmax(logits, dim=-1)
        return weights

Ключевая проблема: если все токены идут к одному эксперту — баланс нарушен. Нужны механизмы балансировки.


Балансировка экспертов

Проблема: Expert collapse

Без контроля router отправляет все токены к "самому лучшему" эксперту. Остальные простаивают.

Без балансировки:
  Expert 0: 60% токенов
  Expert 1: 20% токенов
  Expert 2: 10% токенов
  Expert 3-7: по 2-3% токенов
  
  Фактически работает только 2 эксперта из 8!

Решение: Auxiliary Load Balancing Loss

Добавляем loss, который штрафует за дисбаланс:

def load_balancing_loss(routing_probs, x):
    """
    Штрафуем за дисбаланс нагрузки между экспертами.
    """
    num_tokens_per_expert = torch.zeros(num_experts)
    for layer in range(num_layers):
        tokens_mask = (x == expert_idx).float()
        num_tokens_per_expert += (routing_probs[layer] * tokens_mask).sum(dim=[0, 1])
    
    total_tokens = num_tokens_per_expert.sum()
    compute_fraction = num_tokens_per_expert / total_tokens
    
    ideal = torch.ones(num_experts) / num_experts
    
    loss = F.mse(compute_fraction, ideal)
    return loss

Inference: балансировка не нужна

При инференсе router обучен и работает детерминированно. Балансировка нужна только при обучении.


Реальные архитектуры MoE

Mixtral 8x7B

Mixtral 8x7B = 8 экспертов, но активны 2 на токен

Параметры:
  Dense слои (Embedding, LM Head, RMSNorm): ~7B
  MoE FFN: 8 экспертов × 1B каждый = 8B
  Активные параметры: 2 × 1B = 2B на токен
  
  Итого: 47B total, 12.9B active

Архитектура:
  32 слоя, из них:
    8 — dense FFN
    24 — MoE FFN (8 экспертов, top-k=2)
Сравнение:
  Mixtral 8x7B:   47B total, 12.9B active → ~скорость 7B модели
  Llama 3 70B:    70B total, 70B active   → ~скорость 70B модели
  Llama 3 8B:     8B total, 8B active     → ~скорость 8B модели

Mixtral 8x7B по качеству ближе к 70B, но по скорости — к 7B.

Qwen1.5-32B-Chat

Qwen1.5-32B использует MoE с 4 экспертами, top-k=1

  48 слоев, каждый — MoE с 4 экспертами
  Каждый эксперт: ~8B параметров
  Активно: 1 × 8B = 8B на токен
  Total: 32B параметров

DeepSeek-V2 / V3

DeepSeek-V2: Multi-Token Prediction + Fine-Grained Expert Division

  60 экспертов, каждый токен → 2 эксперта
  Каждый эксперт обрабатывает только часть features
  KV cache compression: shared KV heads
  
  Result: 236B total, 21B active
  Качество на уровне моделей с 500B+ параметров

MoE vs Dense: сравнение

Производительность

Модель          | Параметры | Active | VRAM (FP16) | tok/s (A100 80GB)
----------------|-----------|--------|-------------|------------------
Llama 3 8B      | 8B        | 8B     | 16 GB       | 180
Llama 3 70B     | 70B       | 70B    | 140 GB      | 30 (4xA100)
Mixtral 8x7B    | 47B       | 12.9B  | 94 GB       | 100 (2xA100)
Qwen1.5-32B     | 32B       | 8B     | 64 GB       | 60 (2xA100)

Память

MoE экономит память потому что:
  1. Все эксперты хранятся в памяти, но вычисляются не все
  2. KV Cache зависит от seq_len, а не от числа параметров
  3. Активные параметры меньше -> меньше compute -> меньше промежуточных активаций

VRAM = weights + kv_cache + activations

Llama 3 70B:
  weights: 140 GB (FP16)
  kv_cache (32K): ~2 GB
  activations: ~10 GB
  Total: ~152 GB -> нужно 2xA100 80GB

Mixtral 8x7B:
  weights: 94 GB (FP16)
  kv_cache (32K): ~2 GB
  activations: ~4 GB (active params меньше)
  Total: ~100 GB -> нужно 2xA100 80GB (с запасом)

Обучение

MoE сложнее обучать:
  1. Router должен научиться балансировать нагрузку
  2. Experts должны специализироваться
  3. Gradient flow сложнее (top-k выбор = не дифференцируемо)
  4. Нужен larger batch size для стабильности
  5. Training loss oscillates сильнее

Время обучения (эстимейт):
  Mixtral 8x7B: ~30 days на 2048 H100
  Llama 3 8B: ~14 days на 2048 H100
  Llama 3 70B: ~30 days на 2048 H100

MoE 47B обучается за то же время что Dense 70B, но требует больше GPU.

Специализация экспертов

Что изучают эксперты?

Исследования показывают, что эксперты MoE действительно специализируются:

Эксперт 0: больше работает с грамматикой и синтаксисом
Эксперт 1: больше работает с фактами и знаниями
Эксперт 2: больше работает с кодом
Эксперт 3: больше работает с творческими задачами
...
Анализ Mixtral 8x7B (activating experts per token type):

Токены кода (import, def, class):
  Expert 5: 34% (vs 12.5% expected)
  Expert 7: 28% (vs 12.5% expected)

Токены естественного языка:
  Expert 0: 31%
  Expert 2: 25%

Токены математических операций:
  Expert 4: 38%
  Expert 6: 22%

Почему это работает?

Каждый expert — это по сути маленький FFN слой.
При достаточном количестве экспертов и данных:
  - Expert A учится распознавать паттерны кода
  - Expert B учится работать с фактами
  - Expert C учится делать рассуждения
  
Router становится "диспетчером", который направляет
каждый токен к наиболее подходящему эксперту.

Практический запуск MoE моделей

Запуск Mixtral 8x7B через vLLM

pip install vllm

# Запуск сервера
python -m vllm.entrypoints.openai.api_server \
    --model mistralai/Mixtral-8x7B-Instruct-v0.1 \
    --tensor-parallel-size 2 \
    --max-model-len 32768 \
    --port 8000

# Запрос
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "mistralai/Mixtral-8x7B-Instruct-v0.1",
        "messages": [
            {"role": "user", "content": "Напиши функцию сортировки на Python"}
        ],
        "max_tokens": 512
    }'

Запуск через llama.cpp (GGUF)

# Скачиваем GGUF модель
# mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf (~27 GB)

./server -m mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf \
    -c 32768 \
    -ngl 90 \
    -t 8

# Q4_K_M квантизация: ~27 GB вместо ~94 GB (FP16)
# Активные параметры при инференсе: ~13 GB (как у 7B модели)

Запуск через Ollama

ollama pull mixtral:8x7b
ollama run mixtral:8x7b "Объясни квантование моделей"

Компромиссы MoE

Плюсы

  1. Масштабируемость: больше параметров = лучше качество, но compute растёт медленнее
  2. Скорость инференса: близко к Dense модели с числом активных параметров
  3. Специализация: эксперты учатся разным вещам
  4. Память: веса всех экспертов в памяти, но вычисляются только активные

Минусы

  1. Обучение: сложнее и менее стабильно чем Dense
  2. Router failure: если router сломался — качество резко падает
  3. Дебаггинг: сложнее понять, какой эксперт за что отвечает
  4. Память: все эксперты хранятся в VRAM, даже если не используются
  5. Не все слои MoE: обычно только FFN, attention остаётся dense

Когда MoE имеет смысл?

  • Да: нужно качество 70B+ модели, но нет 4xA100
  • Да: готовый инференс через API (vLLM, Ollama)
  • Да: обучение с нуля на большом корпусе данных
  • Нет: обучение на маленьком датасете (Dense лучше)
  • Нет: CPU инференс на ноутбуке (llama.cpp Dense 7B быстрее)
  • Нет: edge deployment (телефон, IoT)

Будущее MoE

Trends

2023: Mixtral 8x7B — MoE для масс
2024: DeepSeek-V2/V3 — 236B с 21B active
2025: Switch Transformers — 1 трлн параметров, 16B active
2026: ??? — MoE на CPU, MoE с dynamic experts

Исследования

  • Dynamic expert count: количество экспертов растёт по мере обучения
  • Feature-specific experts: каждый эксперт для конкретного feature
  • Cross-attention experts: эксперты общаются друг с другом
  • MoE + Mamba: комбинация с state space моделями

Итоги

  • MoE — это способ получить качество большой модели со скоростью маленькой
  • Mixtral 8x7B: 47B total, 12.9B active — качество 70B, скорость 7B
  • Балансировка экспертов — ключевая проблема при обучении
  • При инференсе MoE работает быстро и эффективно
  • Для production: vLLM с tensor parallelism
  • Для локального использования: llama.cpp GGUF Q4_K_M

MoE — не серебряная пуля. Но для задач, где нужен баланс "качество/стоимость", это лучший выбор на 2026 год.