Проблема: почему мы не можем просто взять больше видеопамяти?
Когда речь заходит о запуске больших языковых моделей (70B+ параметров) локально, первая мысль — купить более мощную видеокарту. Но проблема в том, что даже самые топовые потребительские GPU (RTX 4090 с 24GB) не вмещают модель целиком. Для инференса Llama 3 70B в FP16 требуется около 140GB памяти — это больше, чем у любой одиночной карты на рынке.
Ключевое понимание: Масштабирование — это не просто «больше железа», а архитектурный подход к распределению вычислений и данных между несколькими устройствами.
В этой статье мы разберем весь путь — от оптимизаций для одной карты до полноценного кластера GPU, с фокусом на практическую реализацию и анализ затрат.
Уровень 1: Оптимизация для одной GPU
Прежде чем бросаться покупать вторую карту, убедитесь, что вы выжали максимум из имеющейся. Основные методы:
Квантование: искусство сжатия
Квантование снижает точность чисел в модели с FP16 (16 бит) до INT8 (8 бит), INT4 (4 бита) или даже ниже. Это дает 2-4x экономию памяти ценой небольшой потери качества.
# Пример загрузки модели с квантованием в GGUF формате
from llama_cpp import Llama
# Загрузка 4-битной модели Llama 3 70B
llm = Llama(
model_path="./llama-3-70b.Q4_K_M.gguf",
n_gpu_layers=-1, # Все слои на GPU
n_ctx=4096
)
CPU Offloading: когда GPU недостаточно
Если модель не помещается полностью в VRAM, часть слоев можно выгрузить в оперативную память. Это медленнее, но работает.
# Пример с llama.cpp и частичной загрузкой на GPU
llm = Llama(
model_path="./llama-3-70b.Q4_K_M.gguf",
n_gpu_layers=35, # Только 35 слоев на GPU, остальные на CPU
n_ctx=2048
)
Предупреждение: CPU offloading резко снижает скорость генерации (до 10-20x медленнее). Используйте только для экспериментов или нечастых запросов.
Уровень 2: Несколько GPU в одном компьютере
Когда одной карты действительно недостаточно, добавляем вторую (и третью). Здесь начинается настоящее распределение вычислений.
Tensor Parallelism: разделение матриц
Tensor Parallelism (TP) делит матричные операции модели между GPU. Каждая карта вычисляет свою часть, затем результаты синхронизируются.
Как это работает:
- Матрица весов делится по столбцам или строкам
- Каждый GPU получает свой фрагмент
- Входные данные передаются всем GPU
- Каждый GPU вычисляет результат для своего фрагмента
- Результаты собираются и комбинируются
# Пример настройки Tensor Parallelism в vLLM
from vllm import LLM, SamplingParams
llm = LLM(
model="meta-llama/Llama-3-70b",
tensor_parallel_size=2, # Делим между 2 GPU
quantization="awq", # Дополнительное сжатие
gpu_memory_utilization=0.9
)
Pipeline Parallelism: распределение слоев
В Pipeline Parallelism (PP) разные слои модели размещаются на разных GPU. Данные проходят через «конвейер» устройств.
| Стратегия | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
| Tensor Parallelism | Низкая задержка, хорошая утилизация | Требует быстрой связи между GPU | 2-4 GPU в одной системе |
| Pipeline Parallelism | Работает с медленными соединениями | Высокая задержка, пузыри конвейера | Кластеры с медленной сетью |
| Data Parallelism | Простая реализация | Требует копии модели на каждом GPU | Обучение, батч-инференс |
1 Выбор железа: RTX 4090 или профессиональные карты?
Для многокарточных конфигураций критически важна пропускная способность связи между GPU. NVLink обеспечивает в 10-20 раз большую скорость, чем PCIe.
Если вы планируете использовать Tensor Parallelism, читайте наше подробное сравнение RTX Pro 6000 vs. RTX 4090 для локальных LLM, где мы разбираем этот вопрос детально.
2 Практическая настройка: 2x RTX 4090 с Tensor Parallelism
# Установка vLLM с поддержкой Tensor Parallelism
pip install vllm
# Проверка доступных GPU
nvidia-smi --query-gpu=name,memory.total --format=csv
# Запуск инференса на 2 GPU
export CUDA_VISIBLE_DEVICES=0,1
python -c "
from vllm import LLM, SamplingParams
llm = LLM(
model='meta-llama/Llama-3-70b',
tensor_parallel_size=2,
max_model_len=4096,
gpu_memory_utilization=0.85
)
sampling_params = SamplingParams(temperature=0.7, max_tokens=512)
outputs = llm.generate(['Что такое tensor parallelism?'], sampling_params)
print(outputs[0].outputs[0].text)
"
Уровень 3: Кластер GPU (распределенная система)
Когда нужны десятки миллиардов параметров или высокая пропускная способность (throughput), переходим к кластерам.
Архитектурные подходы к кластеризации
1. Модель-центричный подход (Model-Centric)
Одна большая модель распределяется по многим GPU. Используется комбинация Tensor и Pipeline Parallelism.
2. Запрос-центричный подход (Request-Centric)
Несколько копий модели размещаются на разных узлах. Запросы распределяются через балансировщик нагрузки.
3 Настройка кластера с Ray и vLLM
Ray — популярный фреймворк для распределенных вычислений в Python. Вот как настроить кластер:
# ray_cluster.py
import ray
from ray import serve
from vllm.engine.arg_utils import AsyncEngineArgs
from vllm.engine.async_llm_engine import AsyncLLMEngine
# Инициализация Ray кластера
ray.init(address="auto") # Подключаемся к существующему кластеру
@serve.deployment(ray_actor_options={"num_gpus": 4})
class VLLMDeployment:
def __init__(self):
engine_args = AsyncEngineArgs(
model="meta-llama/Llama-3-70b",
tensor_parallel_size=4,
gpu_memory_utilization=0.9,
max_num_seqs=256
)
self.engine = AsyncLLMEngine.from_engine_args(engine_args)
async def generate(self, prompt):
# Логика генерации
return await self.engine.generate(prompt)
# Развертывание
app = VLLMDeployment.bind()
# Запуск Ray кластера
# На узле-мастере:
ray start --head --port=6379
# На рабочих узлах:
ray start --address='MASTER_IP:6379'
# Запуск сервиса
serve run ray_cluster:app
Оптимизация стоимости: считаем TCO
Масштабирование — это всегда компромисс между производительностью и стоимостью. Рассмотрим ключевые метрики:
| Конфигурация | Оценка стоимости | Tokens/сек (70B) | Стоимость/1M tokens | Лучший сценарий |
|---|---|---|---|---|
| 1x RTX 4090 + CPU offload | ~2000$ | 0.5-2 | Высокая (электричество) | Эксперименты, редкие запросы |
| 2x RTX 4090 (TP) | ~4000$ | 15-25 | Оптимальная | Малое производство |
| 4x RTX 6000 Ada | ~20000$ | 40-60 | Средняя | Средний трафик |
| 8x A100 80GB кластер | ~100000$+ | 100+ | Низкая (на масштабе) | Высоконагруженный сервис |
Экономический факт: После 4-8 GPU закон убывающей отдачи начинает работать против вас. Каждая следующая карта дает всё меньший прирост производительности на доллар.
Распространенные ошибки и как их избежать
Даже опытные инженеры допускают эти ошибки при масштабировании LLM:
Ошибка 1: Игнорирование пропускной способности PCIe
При использовании Tensor Parallelism данные постоянно передаются между GPU. PCIe 4.0 x16 дает 32 GB/s, а NVLink 3.0 — до 600 GB/s. Разница в 20 раз!
Если вы используете несколько карт без NVLink, выбирайте Pipeline Parallelism или уменьшайте tensor_parallel_size.
Ошибка 2: Неоптимальное распределение памяти
По умолчанию многие фреймворки резервируют память «жадно». Установите gpu_memory_utilization=0.85-0.9, чтобы оставить место для кэша KV и системных нужд.
# Оптимальные настройки памяти для vLLM
llm = LLM(
model="mistralai/Mistral-7B",
tensor_parallel_size=2,
gpu_memory_utilization=0.87, # Не 1.0!
max_model_len=8192,
swap_space=4 # GB swap для оффлоадинга
)
Ошибка 3: Неправильный выбор стратегии параллелизма
Data Parallelism отлично подходит для обучения и батч-инференса, но для онлайн-инференса с одним запросом он бесполезен — модель всё равно должна помещаться в память одной карты.
Для онлайн-инференса больших моделей используйте Tensor или Pipeline Parallelism.
FAQ: частые вопросы о масштабировании LLM
Вопрос: Можно ли смешивать разные GPU в одном кластере?
Ответ: Технически возможно, но не рекомендуется. Разная память, архитектура и производительность создадут «узкие места». Самый медленный GPU определит общую скорость.
Вопрос: Что лучше — 4x RTX 4090 или 2x RTX 6000 Ada?
Ответ: Для Tensor Parallelism важна скорость связи. 2x RTX 6000 с NVLink часто обгоняют 4x RTX 4090 без NVLink, несмотря на меньший общий объем VRAM.
Вопрос: Как мониторить производительность распределенной системы?
Используйте комбинацию инструментов:
nvidia-smiдля мониторинга GPUnvtopдля удобного просмотра- Prometheus + Grafana для метрик кластера
- Встроенные метрики vLLM/Text Generation Inference
Вопрос: Стоит ли использовать облачные инстансы вместо железа?
Ответ: Для production с переменной нагрузкой — да. Для постоянной высокой нагрузки (более 70% утилизации) локальное железо окупается за 6-12 месяцев. Считайте TCO (Total Cost of Ownership).
Заключение: путь от новичка до эксперта
Масштабирование локальных LLM — это последовательный путь:
- Оптимизация одной карты: Квантование, оффлоадинг, выбор правильного формата
- Добавление второй карты: Tensor Parallelism, настройка NVLink/PCIe
- Мульти-нод система: Ray/Kubernetes, балансировка нагрузки
- Продакшн-кластер: Мониторинг, автоматическое масштабирование, репликация
Каждый шаг требует понимания компромиссов между стоимостью, сложностью и производительностью. Начинайте с малого, измеряйте производительность на реальных нагрузках и масштабируйтесь только когда это действительно необходимо.
Помните: идеальной конфигурации не существует. Ваш выбор должен зависеть от конкретных требований — задержки (latency), пропускной способности (throughput), бюджета и экспертизы команды.
Последний совет: Прежде чем масштабировать «вширь» (больше GPU), оптимизируйте «вглубь» (лучшее использование имеющихся ресурсов). Часто 30% прироста можно получить просто настройкой параметров, без покупки нового железа. Подробнее об оптимизации читайте в нашем практическом гайде по избежанию ошибок при запуске LLM.