Почему Qwen Coder 30B не видит дальше своего носа
Ты загружаешь Qwen Coder 30B, пытаешься скормить ему большой кусок кода — и получаешь холодное сообщение "exceeds context size". Знакомо? Эта ошибка не просто ограничение — это крик о помощи от твоего GPU. Модель хочет больше памяти, чем у неё есть. И она не виновата.
Важно: Ошибка появляется не потому что модель глупая. Проблема в том, что контекст в 32K токенов требует примерно 2-4 ГБ дополнительной VRAM только на attention-матрицы. А у тебя их и так нет.
Что происходит под капотом
Когда ты указываешь --ctx-size 32768, llama.cpp резервирует память под всю возможную последовательность. Для Qwen 30B с 32 слоями это примерно:
- Веса модели: ~60 ГБ в FP16, ~30 ГБ в INT8
- Кэш KV: (32768 * 32 * 2 * 8) ≈ 16 ГБ в FP16
- Промежуточные активации: ещё 2-8 ГБ в зависимости от batch size
Итого: даже с квантованием до INT8 тебе нужно минимум 48 ГБ VRAM. А у тебя 32 ГБ. Математика против нас.
Решение: не увеличивать память, а уменьшать аппетиты
Есть два пути: оптимизировать использование памяти или уменьшить размер модели. Мы пойдём обоими одновременно.
1 Квантование: превращаем слоны в мышей
Квантование — это не просто "сжатие модели". Это перевод весов из формата с плавающей точкой (FP16, 16 бит на вес) в целочисленный (INT4, 4 бита). Разница в памяти — в 4 раза. Но есть нюанс: качество падает.
Конвертируем оригинальную модель в GGUF:
# Клонируем llama.cpp если ещё нет
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j$(nproc)
# Конвертируем в GGUF Q4_K_M (рекомендуемый баланс)
python convert.py \
--outfile qwen-coder-30b-q4_k_m.gguf \
--outtype q4_k_m \
~/models/Qwen/Qwen2.5-Coder-30B-Instruct/
# Или Q5_K_M для лучшего качества
python convert.py \
--outfile qwen-coder-30b-q5_k_m.gguf \
--outtype q5_k_m \
~/models/Qwen/Qwen2.5-Coder-30B-Instruct/
Размеры после конвертации:
| Формат | Размер файла | VRAM при загрузке | Качество кодинга |
|---|---|---|---|
| FP16 (оригинал) | ~60 ГБ | >60 ГБ | Эталонное |
| Q8_0 | ~30 ГБ | ~32 ГБ | Почти идеальное |
| Q5_K_M | ~19 ГБ | ~21 ГБ | Отличное |
| Q4_K_M | ~16 ГБ | ~18 ГБ | Хорошее |
Если хочешь глубоко разобраться в отличиях форматов, посмотри полный гайд по квантованию где сравниваем все методы на реальных задачах.
2 Настройка llama.cpp: заставляем его считать по-другому
Теперь главное — правильно запустить. Вот как НЕ надо делать:
# Так сработает на 5 минут, потом OOM
./main -m qwen-coder-30b-q4_k_m.gguf \
--ctx-size 32768 \
--gpu-layers -1 \
--batch-size 512 \
--mlock
Проблема в --batch-size 512. Это слишком много для 32K контекста. И в --gpu-layers -1 — он загрузит все слои в VRAM, но оставит мало места для кэша.
Правильная команда для 32 ГБ VRAM:
./main -m qwen-coder-30b-q4_k_m.gguf \
--ctx-size 16384 \ # Уменьшаем до реально используемого
--gpu-layers 28 \ # Оставляем 4 слоя для CPU
--batch-size 256 \ # Оптимально для кодинга
--threads 8 \
--mlock \
--no-mmap \
--temp 0.1 \
--repeat-penalty 1.1
Секрет: Флаг --no-mmap отключает memory mapping. Это увеличивает время загрузки, но даёт предсказуемое использование памяти. Без него llama.cpp может резервировать память "на вырост" и вылететь при генерации.
А если нужны именно 32K токенов?
Придётся жертвовать. Вот рабочий вариант:
# Для контекста 32768 на 32 ГБ VRAM
./main -m qwen-coder-30b-q4_k_m.gguf \
--ctx-size 32768 \
--gpu-layers 24 \ # Ещё меньше слоёв на GPU
--batch-size 128 \ # Маленький batch
--flash-attn \ # Если собрано с поддержкой
--no-kv-offload \ # Не выгружаем кэш (быстрее)
--parallel 1 \
--mlock
Или используем --ngl 20 вместо --gpu-layers 24 — это синонимы, но в разных версиях llama.cpp.
Тонкая настройка: что ещё можно выжать
Оптимизация через слои
Qwen Coder 30B имеет 32 слоя. Каждый слой на GPU — это ~300 МБ VRAM в Q4_K_M. Посчитаем:
- 20 слоёв на GPU: 20 * 300 МБ = 6 ГБ
- Кэш KV для 32K: ~8 ГБ
- Остальное: ~2 ГБ
- Итого: 16 ГБ — влезает!
Но 12 слоёв на CPU будут тормозить. Решение: найти баланс. Начни с 24 слоёв на GPU, уменьшай если вылетает.
Batch size — не то, что кажется
Большой batch size ускоряет обработку промпта, но съедает память квадратично. Формула простая:
# Память для attention ~ batch_size * ctx_size * layers
# При batch=512 и ctx=32768: 512 * 32768 * 32 = 537M элементов
# В FP16: 537M * 2 байта = 1 ГБ только на одну матрицу!
Поэтому batch=256 — разумный компромисс.
Если ничего не помогает
Бывает. Тогда идём на крайние меры:
1. Используем vLLM вместо llama.cpp
vLLM эффективнее управляет памятью благодаря PagedAttention. Но сложнее в настройке.
2. Берем меньшую модель
Qwen Coder 14B в Q4_K_M занимает ~8 ГБ. Контекст 32K — легко. Качество? На 20% хуже для сложного кода, но для большинства задач достаточно. Сравнивал в статье про Qwen3 на 12 ГБ VRAM.
3. Разбиваем контекст
Если нужно проанализировать 100К строк кода — не грузи всё сразу. Разбей на чанки по 8К, обработай отдельно, потом сведи результаты. Есть техники в гайде по долгой памяти.
make clean && make -j$(nproc) LLAMA_CUDA=1 с последней версией из git.Частые ошибки и как их избежать
| Ошибка | Причина | Решение |
|---|---|---|
| "CUDA out of memory" после 10 токенов | Кэш KV растёт по мере генерации | Уменьши --ctx-size или используй --kv-offload |
| Модель загружается, но не отвечает | Слишком много слоёв на CPU, deadlock | Увеличь --gpu-layers или используй --no-mmap |
| Скорость 0.5 токен/сек | Большинство слоёв на CPU | Попробуй Q3_K_M чтобы больше слоёв влезло в VRAM |
| "Model size exceeds context size" при конвертации | Старая версия convert.py | Обнови llama.cpp и переконвертируй |
Проверка: работает ли теперь?
Запусти тест:
# Генерируем длинный промпт для проверки
cat > test_prompt.txt << EOF
Analyze this Python code and suggest improvements:
def process_data(data):
result = []
for item in data:
if item['type'] == 'A':
processed = item['value'] * 2
elif item['type'] == 'B':
processed = item['value'] / 2
else:
processed = item['value']
result.append(processed)
return result
# [добавь ещё 5000 строк кода для теста контекста]
EOF
# Запускаем с замером памяти
./main -m qwen-coder-30b-q4_k_m.gguf \
--ctx-size 16384 \
--gpu-layers 28 \
--batch-size 256 \
--file test_prompt.txt \
--n-predict 512 \
--verbose 2>&1 | grep -E "(total VRAM|ctx size|layers)"
Если видишь "total VRAM used: 28.4G" и модель отвечает — победа.
Что в итоге
Проблема "exceeds context size" в Qwen Coder 30B решается комбинацией:
- Квантование до Q4_K_M или Q5_K_M — уменьшаем модель в 3-4 раза
- Настройка --gpu-layers — оставляем часть слоёв на CPU
- Реалистичный --ctx-size — не 32768, а 16384 (всё равно редко используешь больше)
- Оптимизация --batch-size — 256 вместо 512
Самое главное: не пытайся запихнуть невпихуемое. 32K контекст на 30B модели с 32 ГБ VRAM — это на грани. Иногда лучше взять Qwen Coder 14B с 32K контекстом, чем 30B с 8K.
И последний совет: следи за обновлениями llama.cpp. Каждый месяц появляются новые оптимизации памяти. То что не работало вчера — заработает завтра. Как минимум, пересобирай раз в месяц.