алгоритмы сжатия весов, механизмы инференса и требованиям к видеокартам для запуска языковых моделей
Языковые модели хранят параметры в float32 (4 байта) или float16 (2 байта). При 7 миллиардах параметров это 14–28 ГБ VRAM только на веса. Квантование заменяет числа с плавающей точкой целыми числами меньшей разрядности — int8 или int4.
Уменьшить объём памяти, занимаемый весами модели, без значительной потери качества ответов.
Числа FP16 (диапазон ≈ −65k…+65k) маппируются в INT4 (0..15) через масштабирующий коэффициент и нулевую точку.
Post-Training Quantization (PTQ) — без дообучения. Quantization-Aware Training (QAT) — квантование в процессе обучения.
W4A16 — веса int4, активации fp16. W8A8 — оба в int8. W4A8 — смешанный. GPTQ и AWQ используют W4A16.
Примерный расчёт: количество параметров × байт на параметр + overhead KV-кэша.
Generative Pre-Trained Transformer Quantization. Опубликован в 2022 году (Frantar et al., ETH Zurich). Использует информацию о кривизне функции потерь (гессиан) для компенсации ошибок квантования слой за слоем.
GPTQ решает задачу послойного сжатия: для каждого линейного слоя L найти квантованные веса Ŵ, минимизирующие ошибку на выходах слоя.
from transformers import AutoTokenizer from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig # 1. Загрузить модель и токенизатор model_id = "meta-llama/Llama-2-7b-hf" tokenizer = AutoTokenizer.from_pretrained(model_id) # 2. Конфиг квантования quantize_config = BaseQuantizeConfig( bits=4, # INT4 — оптимальный баланс group_size=128, # размер группы весов (128 стандарт) desc_act=False, # desc_act=True даёт лучшее качество, но медленнее ) # 3. Загрузить модель для квантования model = AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config) # 4. Калибровочные данные (128 примеров достаточно) examples = [tokenizer("Hello, my name is", return_tensors="pt")] # 5. Квантовать (занимает 5–60 минут в зависимости от модели) model.quantize(examples) # 6. Сохранить model.save_quantized("./llama2-7b-gptq-4bit", use_safetensors=True)
from transformers import AutoTokenizer, AutoModelForCausalLM # Transformers >= 4.40 поддерживает GPTQ нативно tokenizer = AutoTokenizer.from_pretrained("./llama2-7b-gptq-4bit") model = AutoModelForCausalLM.from_pretrained( "./llama2-7b-gptq-4bit", device_map="auto", torch_dtype="auto" ) inputs = tokenizer("Расскажи о квантовании весов:", return_tensors="pt").to("cuda") output = model.generate(**inputs, max_new_tokens=200) print(tokenizer.decode(output[0], skip_special_tokens=True))
Опубликован MIT Han Lab в июне 2023, получил Best Paper Award на MLSys 2024. Ключевая идея: не все веса одинаково важны — 1% «салиентных» весов критичен для качества, и их нужно защитить от квантования.
Авторы обнаружили: если отсортировать веса по величине соответствующих активаций, примерно 1% весов имеют аномально высокие активации. Квантование этих весов вызывает непропорционально большой рост perplexity.
from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_path = "meta-llama/Llama-2-7b-hf" quant_path = "./llama2-7b-awq-4bit" # Конфиг квантования AWQ quant_config = { "zero_point": True, # ассиметричное квантование "q_group_size": 128, # стандартный размер группы "w_bit": 4, # 4-битные веса "version": "GEMM" # GEMM (batch) или GEMV (single token) } # Загрузить модель model = AutoAWQForCausalLM.from_pretrained(model_path) tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) # Квантовать (быстрее GPTQ — нет вычисления гессиана) model.quantize(tokenizer, quant_config=quant_config) # Сохранить model.save_quantized(quant_path) tokenizer.save_pretrained(quant_path)
Три наиболее распространённых подхода к квантованию. Правильный выбор зависит от задачи: серверный инференс, локальный запуск или edge-устройства.
| Метод | Разрядность | Алгоритм | Скорость инфер. | Потеря качества | Где работает | Типичный размер 7B |
|---|---|---|---|---|---|---|
| FP16 (base) | 16 bit | — | Baseline | Нет | CUDA / Metal | ~14 ГБ |
| GPTQ | 2–8 bit | OBQ + Hessian | +15–30% | Небольшая | GPU (CUDA) | ~3.5–6 ГБ |
| AWQ | 4 bit | Activation scaling | +20–40% | Минимальная | GPU (CUDA) | ~3.5–5.7 ГБ |
| GGUF Q4_K_M | 4 bit | K-quant блоки | Зависит от CPU | Минимальная | CPU + GPU (offload) | ~4.4 ГБ |
| bitsandbytes NF4 | 4 bit | Normal float + DQ | Медленнее FP16 | Небольшая | GPU (CUDA) | ~4–5 ГБ |
| FP8 (W8A8) | 8 bit | Native hardware | +50–80% H100 | Минимальная | H100 / H200 / A100 | ~7 ГБ |
Open-source фреймворк для серверного инференса LLM. Разработан в UC Berkeley Sky Computing Lab, впервые представлен в сентябре 2023 на конференции SOSP. Решает две проблемы: фрагментацию памяти KV-кэша и недоиспользование GPU при статическом батчинге.
При авторегрессивной генерации модель предсказывает токены по одному. Чтобы не пересчитывать attention для всех предыдущих токенов, их Key/Value тензоры кешируются в GPU памяти. Проблемы традиционного подхода:
Память выделялась заранее под максимальную длину последовательности. Запрос на 50 токенов занимал память как 2048 — большая её часть тратилась впустую.
После завершения запросов в GPU памяти оставались «дыры» разного размера, которые не использовались новыми запросами.
GPU ждал, пока завершится самый длинный запрос в батче, прежде чем принять новые — огромное недоиспользование вычислительных ресурсов.
Два механизма, которые делают vLLM эффективным. PagedAttention заимствует идею виртуальной памяти из операционных систем. Continuous batching решает проблему простоя GPU.
Небольшая draft-модель генерирует несколько токенов, основная — проверяет их за один проход. Ускоряет генерацию при малой нагрузке.
Записывает последовательность CUDA операций в граф и воспроизводит его без CPU-overhead. Снижает задержку при маленьких батчах.
Одинаковые системные промпты (system prompt) кешируются между запросами. При повторном запросе с тем же началом prefill не пересчитывается.
Автоматически распределяет модель по нескольким GPU через параметр --tensor-parallel-size. Веса каждого слоя делятся между картами.
# Установка (требует CUDA 12.1+, Python 3.9–3.12) pip install vllm # Запуск OpenAI-совместимого API сервера vllm serve meta-llama/Llama-3-8B-Instruct \ --dtype auto \ --api-key token-123 # С квантованием AWQ vllm serve TheBloke/Llama-2-7B-Chat-AWQ \ --quantization awq \ --dtype half # С квантованием GPTQ vllm serve TheBloke/Llama-2-13B-chat-GPTQ \ --quantization gptq \ --dtype half \ --max-model-len 4096 # Мультигпу: 2 карты через tensor parallelism vllm serve meta-llama/Llama-2-70b-hf \ --tensor-parallel-size 2 \ --dtype auto
from openai import OpenAI client = OpenAI( base_url="http://localhost:8000/v1", api_key="token-123", ) response = client.chat.completions.create( model="meta-llama/Llama-3-8B-Instruct", messages=[{"role": "user", "content": "Объясни квантование LLM"}], max_tokens=512, temperature=0.7, ) print(response.choices[0].message.content)
Два ключевых параметра: объём VRAM (определяет, какую модель можно загрузить) и пропускная способность памяти в ГБ/с (определяет скорость генерации токенов). VRAM определяет потолок, пропускная способность — реальную скорость.
| GPU | VRAM | Пропускная способность | FP16 TFLOPS | Тип памяти | Категория | Цена (ориент.) |
|---|---|---|---|---|---|---|
| RTX 3060 | 360 GB/s | 12.7 | GDDR6 | Бюджетная | ~$280 | |
| RTX 3090 | 936 GB/s | 35.6 | GDDR6X | Consumer | ~$700–900 (б/у) | |
| RTX 4070 Ti Super | 672 GB/s | 40.0 | GDDR6X | Consumer | ~$800 | |
| RTX 4090 | 1,008 GB/s | 82.6 | GDDR6X | Consumer High-End | ~$1,600 | |
| RTX 5090 | 1,792 GB/s | ~209 | GDDR7 | Consumer Flagship | ~$2,000 | |
| RTX A6000 Ada | 960 GB/s | 91.1 | GDDR6 | Workstation | ~$5,000 | |
| L40S | 864 GB/s | 91.6 | GDDR6 | Datacenter | ~$7,000–9,000 | |
| A100 40GB | 1,555 GB/s | 77.0 | HBM2e | Enterprise | ~$10,000–14,000 | |
| A100 80GB | 1,935 GB/s | 77.0 | HBM2e | Enterprise | ~$15,000–20,000 | |
| H100 SXM | 3,350 GB/s | ~400 (FP8: 3958) | HBM3 | Enterprise | ~$30,000–40,000 | |
| H200 | 4,800 GB/s | ~400 (FP8: 3958) | HBM3e | Enterprise Flagship | ~$80,000+ |
| Модель | Параметры | FP16 (без сжатия) | INT8 / Q8 | INT4 / Q4 (AWQ/GPTQ) | Рекомендации GPU |
|---|---|---|---|---|---|
| Phi-3 Mini, Gemma 2B, Qwen 1.5 1.8B | 1.8–3B | ~4–6 ГБ | ~2–3 ГБ | ~1–2 ГБ | RTX 3060 12GB и выше, GTX 1080 Ti |
| Llama 3.2 3B, Phi-3 Small | 3–4B | ~6–8 ГБ | ~4–5 ГБ | ~2–3 ГБ | RTX 3060 12GB комфортно |
| Llama 3 8B, Mistral 7B, Qwen2 7B | 7–8B | ~14–16 ГБ | ~8–9 ГБ | ~4–5 ГБ | RTX 4070 Ti 16GB (FP16), RTX 3060 12GB (INT4) |
| Llama 3.1 8B (32K контекст) | 8B | ~18–20 ГБ | ~12 ГБ | ~6–7 ГБ | RTX 4090 24GB (FP16), RTX 3060 12GB (INT4) |
| Phi-3 Medium 14B, Qwen2 14B | 13–14B | ~26–28 ГБ | ~14 ГБ | ~8–9 ГБ | RTX 4090 24GB (INT8), RTX 3060 12GB (INT4, тесно) |
| Qwen 3 32B, DeepSeek-R1 32B | 32B | ~64 ГБ | ~32 ГБ | ~18–20 ГБ | L40S 48GB / 2×RTX 4090 (INT4), A100 80GB (FP16) |
| Llama 3.1 70B, Qwen2 72B | 70–72B | ~140 ГБ | ~70 ГБ | ~35–40 ГБ | 2×L40S / A100 80GB (INT4), 2×A100 80GB (FP16) |
| Llama 4 Scout (109B MoE, 17B active) | 109B total | ~218 ГБ | — | ~55 ГБ | H100 80GB (INT4), 4×A100 80GB (FP16) |
| DeepSeek V3 / R1 (671B MoE) | 671B total, 37B active | >700 ГБ | ~335 ГБ | ~335 ГБ (FP8) | 8×H200 141GB минимум |
| Llama 3.1 405B | 405B | ~810 ГБ | ~405 ГБ | ~200 ГБ | 4×H200 / 8×H100 (INT4) |
| GPU | Llama 3 8B (FP16) | Llama 3 8B (INT4 AWQ) | Llama 2 13B (INT4) | Llama 2 70B (INT4, multi-GPU) |
|---|---|---|---|---|
| RTX 3060 12GB | — (не влезает) | ~20–30 tok/s | — (не влезает) | — |
| RTX 4070 Ti 16GB | ~40–55 tok/s | ~60–80 tok/s | ~35–45 tok/s | — |
| RTX 4090 24GB | ~80–120 tok/s | ~140–180 tok/s | ~40–50 tok/s | ~15–25 tok/s (offload) |
| 2× RTX 4090 48GB | ~140–200 tok/s | ~220–280 tok/s | ~90–120 tok/s | ~35–45 tok/s |
| A100 80GB | ~200–280 tok/s | ~280–350 tok/s | ~150–200 tok/s | ~30–40 tok/s (1 GPU, INT4) |
| H100 SXM 80GB | ~400–600 tok/s | ~600–800 tok/s | ~300–450 tok/s | ~80–120 tok/s (1 GPU, INT4) |
| H200 141GB | ~500–700 tok/s | ~700–900 tok/s | ~400–550 tok/s | ~150–200 tok/s (1 GPU) |
| Модель | Системная RAM (минимум) | Рекомендованная RAM | Место на диске (FP16) | Место на диске (INT4) |
|---|---|---|---|---|
| 7–8B | 16 ГБ | 32 ГБ | ~14–16 ГБ | ~4–5 ГБ |
| 13–14B | 32 ГБ | 64 ГБ | ~26–28 ГБ | ~8–9 ГБ |
| 32–34B | 64 ГБ | 128 ГБ | ~64–68 ГБ | ~18–22 ГБ |
| 70B | 64 ГБ | 128 ГБ | ~140 ГБ | ~35–40 ГБ |
Системная RAM нужна для загрузки файлов модели перед переносом на GPU, CPU-offload слоёв, и работы ОС. NVMe SSD обязателен — загрузка 70B модели с HDD займёт 10+ минут, с NVMe — 1–2 минуты.
# Требования: NVIDIA GPU CUDA 12.1+, Python 3.10+ # 1. Установить vLLM pip install vllm # 2. Запустить с AWQ моделью (Llama 3 8B AWQ, ~5GB VRAM) vllm serve solidrust/Meta-Llama-3-8B-Instruct-hf-AWQ \ --quantization awq \ --dtype half \ --max-model-len 8192 \ --port 8000 # 3. Тест curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "solidrust/Meta-Llama-3-8B-Instruct-hf-AWQ", "messages": [{"role": "user", "content": "Hello!"}] }'
# Сборка с поддержкой CUDA git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DGGML_CUDA=ON cmake --build build --config Release -j # Скачать GGUF модель с HuggingFace # Пример: Llama-3.2-3B-Instruct Q4_K_M (~2GB) wget https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf # Запуск с GPU offload (ngl = number of GPU layers) ./build/bin/llama-cli \ -m Llama-3.2-3B-Instruct-Q4_K_M.gguf \ -ngl 33 \ -p "Объясни что такое квантование:"
Используйте GGUF через Ollama или llama.cpp. Простейшая установка, поддержка CPU offload, хорошее качество при Q4_K_M.
vLLM с AWQ или GPTQ моделями. Высокий throughput, поддержка батчинга, OpenAI-совместимый API, tensor parallelism.
llama.cpp с Metal backend или Ollama. Unified memory позволяет запускать большие модели — M4 Max 128GB вмещает Llama 3 70B Q4.
vLLM + FP8 (H100) или AWQ/GPTQ (A100). Для 70B и больше — обязательно multi-GPU с tensor parallelism.