Перейти к содержанию
Публикация AiManual

Qwen Coder 30B вылетает с 'exceeds context size'? Разбираемся с llama.cpp и квантованием

Пошаговое решение ошибки 'exceeds context size' в Qwen Coder 30B. Настройка llama.cpp, квантование модели, увеличение контекста до 32K токенов на 32 ГБ VRAM.

Коротко

Что будет в материале

  1. 01

    Почему Qwen Coder 30B не видит дальше своего носа

  2. 02

    Решение: не увеличивать память, а уменьшать аппетиты

  3. 03

    Тонкая настройка: что ещё можно выжать

  4. 04

    Если ничего не помогает

Почему 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 раза. Но есть нюанс: качество падает.

💡
Не все квантования одинаковы. Q4_K_M сохраняет больше качества чем Q4_0. Q5_K_M почти неотличим от FP16 для кодинга. Выбирай Q5_K_M если есть место, Q4_K_M если нужно максимальное сжатие.

Конвертируем оригинальную модель в 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К, обработай отдельно, потом сведи результаты. Есть техники в гайде по долгой памяти.

💡
Проверь сборку llama.cpp. Если собирал год назад — пересобери. За последние 6 месяцев оптимизировали память на 30%. Используй 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 решается комбинацией:

  1. Квантование до Q4_K_M или Q5_K_M — уменьшаем модель в 3-4 раза
  2. Настройка --gpu-layers — оставляем часть слоёв на CPU
  3. Реалистичный --ctx-size — не 32768, а 16384 (всё равно редко используешь больше)
  4. Оптимизация --batch-size — 256 вместо 512

Самое главное: не пытайся запихнуть невпихуемое. 32K контекст на 30B модели с 32 ГБ VRAM — это на грани. Иногда лучше взять Qwen Coder 14B с 32K контекстом, чем 30B с 8K.

И последний совет: следи за обновлениями llama.cpp. Каждый месяц появляются новые оптимизации памяти. То что не работало вчера — заработает завтра. Как минимум, пересобирай раз в месяц.