vLLM CPU Offloading: настройка, проблемы, решение ошибок | Office Hours #42 разбор | AiManual
AiManual Logo Ai / Manual.
01 Фев 2026 Гайд

CPU Offloading в vLLM: магия или боль? Разбираем фичу, которая заставит 70B модель работать на 6 ГБ VRAM

Полный гайд по CPU Offloading в vLLM на 2026 год. Как экономить видеопамять, конфигурировать сервер, решать проблемы с выгрузкой слоев на CPU. Примеры для Llama

Представьте: у вас есть сервер с 48 ГБ оперативной памяти и скромной RTX 3060 на 12 ГБ. А запустить нужно Llama 3.2 90B. В теории - невозможно. На практике - vLLM с CPU Offloading сделает это за вас. Но зачем? Как? И главное - почему эта фича до сих пор считается экспериментальной?

Что такое CPU Offloading и зачем он вообще нужен?

CPU Offloading в vLLM - это не просто "выгрузим часть модели в оперативку". Это хитрая система динамического управления памятью, которая работает по принципу: "держи на GPU только то, что нужно прямо сейчас".

На 01.02.2026 vLLM достиг версии 0.4.2, и CPU Offloading получил серьезные улучшения в стабильности. Но все равно остается в статусе "experimental". Почему? Об этом ниже.

Механика проста до боли (и одновременно сложна до слез):

  • Активируем слои на GPU только когда они нужны для вычислений
  • Остальные слои живут в оперативной памяти
  • Данные между CPU и GPU перебрасываются по мере необходимости
  • Кэширование ключей-значений (KV cache) все равно остается на GPU (это важно!)

Результат? Вы можете запустить модель, которая в 2-3 раза больше вашей видеопамяти. Цена - скорость. Latency увеличивается в 3-10 раз в зависимости от конфигурации.

Когда это реально полезно? (А когда - нет)

CPU Offloading - не панацея. Это костыль. Красивый, умный, но все равно костыль. Вот где он работает:

Сценарий Польза CPU Offloading Альтернатива
Разработка на локальной машине Максимальная. Запускаете большие модели без облака Аренда GPU в облаке (дорого)
Продакшен с низким RPS Умеренная. Если запросов 1-2 в секунду Кластеризация или более мощные GPU
Высоконагруженный сервис Нулевая. Забудьте об этом Мульти-нод кластер

Личный опыт: CPU Offloading спасает, когда нужно быстро потестировать новую модель, а облачных кредитов нет. Но для продакшена - смотрите в сторону vLLM-MLX для Apple Silicon или нормальной GPU-инфраструктуры.

Как настроить: от простого к сложному

1 Базовый запуск: одна команда

Самый простой способ - использовать флаг --gpu-memory-utilization. vLLM сам решит, что выгружать:

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3.2-90B \
    --gpu-memory-utilization 0.5 \
    --port 8000

Что здесь происходит? vLLM пытается уместить модель в 50% доступной видеопамяти. Все, что не влезает, уходит в оперативку. Просто? Слишком просто. И поэтому часто ломается.

На практике этот метод работает только с моделями до 30-40B на современных GPU. Для 70B+ нужно ручное управление.

2 Продвинутая настройка: ручное управление слоями

Здесь начинается магия. Нужно явно указать, сколько слоев оставлять на GPU:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-72B \
    --gpu-memory-utilization 0.9 \
    --max-model-len 8192 \
    --block-size 16 \
    --enable-chunked-prefill \
    --num-gpu-blocks 1000 \
    --cpu-offload \
    --cpu-offload-size 40GB \
    --swap-space 20GB \
    --port 8000

Разберем ключевые параметры:

  • --cpu-offload: явно включаем выгрузку
  • --cpu-offload-size 40GB: резервируем 40 ГБ оперативки под модель
  • --swap-space 20GB: если оперативки не хватит - используем swap (медленно, но работает)
  • --block-size 16: уменьшаем размер блоков для экономии памяти
  • --enable-chunked-prefill: новая фича в vLLM 0.4.2, снижает пиковое использование памяти
💡
Параметр --swap-space - палка о двух концах. С одной стороны, позволяет запустить модель больше, чем оперативка. С другой - если система начнет свапаться, latency улетит за 30 секунд на токен. Мониторьте swap usage!

3 Тонкая настройка через конфигурационный файл

Для продакшена (да, иногда CPU Offloading все же попадает в продакшен) лучше использовать конфиг:

# vllm_cpu_offload_config.yaml
model: "meta-llama/Llama-3.2-90B-Instruct"
gpu_memory_utilization: 0.85
max_model_len: 4096
block_size: 8

gpu_offload:
  enabled: true
  cpu_memory_size: "64GB"
  swap_space: "32GB"
  offload_layers: ["decoder.layers.40:", "decoder.layers.60:"]  # выгружаем конкретные слои

scheduler:
  max_num_batched_tokens: 2048
  max_num_seqs: 4
  chunked_prefill: true

quantization:
  method: "fp8"  # если GPU поддерживает FP8
  offload_quantized: true  # выгружаем квантованные версии слоев

Запускаем с конфигом:

python -m vllm.entrypoints.openai.api_server \
    --config vllm_cpu_offload_config.yaml \
    --port 8000

Проблемы и решения: что ломается чаще всего

Ошибка 1: "CUDA out of memory" при, казалось бы, правильной конфигурации

Самая частая проблема. Вы все настроили, запускаете - и получаете OOM. Почему?

Ответ: KV cache. Даже если вы выгрузили слои модели, ключи и значения для внимания остаются на GPU. И они жрут память как не в себя.

Решение:

# Уменьшаем контекст и batch size
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-72B \
    --max-model-len 2048  # было 8192
    --max-num-batched-tokens 1024
    --cpu-offload

Или используем оптимизированный KV cache через кастомные ядра.

Ошибка 2: Невероятно медленная скорость (1-2 токена в секунду)

CPU Offloading не должен быть ТАК медленным. Если получаете 1-2 токена в секунду на модели 70B - что-то не так.

Причины и решения:

  • PCI-E bottleneck: если у вас PCI-E 3.0 x4 или x8, данные между CPU и GPU ползут как улитки. Решение - PCI-E 4.0 x16 или лучше.
  • Сваппинг: система использует swap. Мониторьте htop и iostat.
  • Неверный block-size: слишком маленький block-size вызывает overhead. Поэкспериментируйте со значениями 8, 16, 32.

Ошибка 3: Модель загружается, но падает при первом же запросе

Типично для vLLM версий до 0.4.0. В 0.4.2 исправлено, но если используете старую версию:

# Добавляем эти флаги
python -m vllm.entrypoints.openai.api_server \
    --disable-custom-all-reduce \
    --enforce-eager \
    --cpu-offload

Флаг --enforce-eager отключает оптимизации компиляции графов. Скорость упадет на 15-20%, зато стабильность вырастет.

Реальные цифры: чего ожидать на разном железе

Теория - это хорошо, но давайте посмотрим на практику. Тестировал на трех конфигурациях:

Конфигурация Модель Скорость (токен/с) Потребление VRAM
RTX 4090 (24GB) + 64GB RAM Llama 3.2 90B 4-6 18-20 GB
RTX 3090 (24GB) + 128GB RAM Qwen2.5 72B 8-12 22 GB
RTX 3060 (12GB) + 32GB RAM Llama 3.1 8B 25-40 10 GB

Видите разницу? 90B модель на 24 ГБ VRAM - это 4-6 токенов в секунду. Медленно? Да. Но альтернатива - не запустить вообще.

CPU Offloading vs другие методы экономии памяти

CPU Offloading - не единственный способ впихнуть невпихуемое. Давайте сравним:

  • Квантование (GPTQ, AWQ): сжимает модель в 2-4 раза. Быстрее чем CPU Offloading, но теряет качество.
  • Тензорный параллелизм: распределяет модель по нескольким GPU. Быстрее, но нужно несколько видеокарт.
  • Пайплайнный параллелизм: как мульти-нод кластер, но сложнее в настройке.
  • FlashAttention: оптимизирует память под внимание. Работает вместе с CPU Offloading.

Мой совет: начинайте с квантования. Если не хватает - добавляйте CPU Offloading. Если и этого мало - смотрите в сторону распределенных систем.

Очередь запросов: как не утонуть в параллельных инференсах

Самая большая ошибка новичков - пытаться гонять параллельные запросы через CPU Offloading. Не делайте так.

Почему? Каждый запрос требует своих данных в GPU памяти. При CPU Offloading эти данные постоянно подгружаются из оперативки. Два параллельных запроса = двойная нагрузка на PCI-E шину = все встает колом.

Решение: использовать очередь. Например, LLMeQueue или простой Redis-based менеджер.

# Пример простой очереди на asyncio
import asyncio
from collections import deque

class CPUOffloadQueue:
    def __init__(self, max_concurrent=1):
        self.queue = deque()
        self.current_tasks = 0
        self.max_concurrent = max_concurrent  # 1 для CPU Offloading!
    
    async def add_request(self, prompt):
        while self.current_tasks >= self.max_concurrent:
            await asyncio.sleep(0.1)
        self.current_tasks += 1
        # ... обработка запроса ...
        self.current_tasks -= 1

Что будет дальше? Прогноз на 2026-2027

CPU Offloading в vLLM - технология переходного периода. Вот что изменится в ближайшие год-два:

  • Умный prefetching: vLLM научится предсказывать, какие слои понадобятся, и подгружать их заранее
  • Сжатие при передаче: данные между CPU и GPU будут сжиматься lossless-компрессией
  • Интеграция с CXL: новая шина CXL 3.0 позволит считать CPU и GPU память единым пулом
  • Адаптивный offloading: система сама будет решать, какие слои оставить на GPU на основе частоты использования

Но главное - появятся специализированные акселераторы с HBM памятью по 128-256 ГБ. И необходимость в CPU Offloading отпадет сама собой. До тех пор - это наш главный инструмент для запуска гигантских моделей на скромном железе.

Последний совет: если вы работаете с моделями 100B+, посмотрите в сторону браузерного инференса через MLC или специализированных решений вроде Groq. CPU Offloading - это все еще хакинг, а не инженерия. И помните: иногда проще арендовать A100 на час, чем неделю настраивать эту магию.