Разбираемся с суффиксами квантования LLM: что на самом деле значат Q4_K_M, Q6_K и Q8_0
- пятница, 20 июня 2025 г. в 00:00:12
Привет!
Задумывались, какую версию квантованной LLM выбрать: Q4_K_M, Q6_K или Q8_0? Насколько Q6_K хуже справляется с задачами по сравнению с Q8_0? И что вообще означают все эти буквы в суффиксах?
Примечание: это адаптированный перевод моей статьи на Medium. Перевод был сделан при помощи мозга, а не нейросетей или Google Translate.
В статье разберёмся, что означают суффиксы вроде Q4_K_M, почему Q4 ≠ int4, и как не потеряться на собеседовании, если спросят про тонкости квантования.
Давайте разбираться!
Квантование — это всегда компромисс между точностью, скоростью и размером модели. Суффиксы вроде Q4_K_M помогают быстро понять, в какую сторону сдвинут этот баланс.
Что значат суффиксы:
Q
— означает, что модель квантована. Если углубляться в конкретный метод квантования - GWQ (group-wise quantization), поскольку есть другие, на данный момент менее распространённые.
Цифра после Q
(например, Q4
) — количество бит на один вес
K
— группировка весов (каждая группа имеет свой scale и zero-point)
0
— без группировки (устаревшая схема)
S
— small, низкая точность, выше скорость, но ниже качество
M
— medium, средняя точность
L
— large, высокая точность, самая медленная и точная
Что именно значит группировка (K и 0), разберём чуть позже.
Итак, давайте разберём, что конкретно означает суффикс Q4_K_M
:
Q4
— квантованная модель с 4-битными весами
K
— группировка весов (по 64 и более), с индивидуальным масштабом
M
— средняя точность (оптимальный баланс между качеством и размером)
Что означает, что на один вес приходится 4 или 8 бит? Веса — это числовые параметры, определяющие, насколько сильно каждый вход влияет на выход нейрона. Именно они участвуют в каждом шаге инференса: умножаются, складываются и передаются дальше по слоям модели.
Цифра перед b
в названии модели (например, Gemini-12b) указывает, сколько миллиардов весов в ней. Например, в Gemini-12b — 12 миллиардов весов, и при генерации одного токена может использоваться от 1 до 12 миллиардов весов в разных слоях сети. При обучении веса обычно сохраняются в формате Float32 или Float16 — то есть занимают 32 или 16 бит каждый.
Использовать такие модели в изначальном виде невозможно на обычном железе. Чтобы сделать модели легче, был введён процесс квантования — перевод весов из float в int с меньшим числом бит. Идея простая - уменьшить количество бит, в которых хранится значение каждого веса.
Казалось бы, можно просто обрезать Float32 до Int4 — но это не работает:
int8(0.123456) = 0
Наивное округление обнуляет значение и полностью теряет информацию. Даже если извлечь только мантиссу, она всё равно будет слишком длинной, чтобы уложиться в 4–6 бит — и точность резко упадёт.
Поэтому вместо грубого округления используют масштабирование (scale
), нулевую точку (zero point
) и группировку.
Пример:
Оригинальные веса: [0.11, 0.09, 0.12, 0.10, ..., 0.15]
Scale = 0.005
Zero point = 0.08
Квантованные значения: [6, 2, 8, 4, ..., 14]
В момент инференса веса восстанавливаются так:
вес = scale * квант + zero_point
При деквантовании (переводе int значений назад во float во время инференса) квантованные 6, 2, 8 становятся:
Как видим, даже при 4 битах на вес можно достичь приличной точности — благодаря масштабированию и группировке.
💡 Вывод: при Q4 квантовании мы НЕ просто сжимаем 32- и 16- битовые Float в Int4 - мы сохраняем метаданные для каждой группы, которые позволяют нам восстанавливать числа с высокой степенью точности.
Квантование весов часто сопровождается группировкой: значения делятся на блоки (группы), для каждой из которых отдельно вычисляются масштаб (scale) и нулевая точка (zero point). Это позволяет эффективно ужимать веса до 4–6 бит при минимальной потере точности.
Обычно веса делят на группы фиксированной длины — например, по 64 элемента подряд. Возникает логичный вопрос: подбираются ли значения в группы по схожести?
Нет. Группы формируются по порядку следования весов в памяти или в тензоре модели, а не по их значению. Это сохраняет структурную совместимость с моделью и обеспечивает эффективную работу на GPU. Например, квантизатор просто берёт первые 64 значения подряд — и формирует из них группу.
Это и означает суффикс K
: групповое квантование, которое позволяет адаптировать scale/zero point к локальному диапазону значений и добиться большей точности.
Если вместо K
указан 0
, как в Q4_0,
значит используется глобальный scale и zero point, общий для всего тензора (или строки тензора). Такая схема проще и быстрее, но менее точна: диапазон, покрываемый 4 битами, должен «влезть» во всё множество значений сразу. Это приводит к большей ошибке восстановления.
Иногда встречается и вариант с суффиксом 1
, например Q5_1
. Это, как и 0
, устаревший формат, похожий на Q4_0
, но с минимальными доработками: квантование применяется построчно к тензору (по одной строке за раз), с фиксированными scale и zero point на каждую строку.
Этот формат обычно чуть точнее, чем 0
, и быстрее, чем K
, но всё же заметно уступает по качеству современным групповым схемам.
💡 Вывод: Если есть выбор между K
, 0
и 1
— почти всегда стоит брать K
: она даёт лучшее соотношение точности и веса.
0
и 1
можно рассматривать только при жёстких ограничениях по железу, например, на мобильных или в real-time системах.
А можно ли измерить, насколько сильно квантование портит точность? Такая метрика существует и называется perplexity.
На русский её иногда переводят как «недоумение» или «растерянность модели», что звучит забавно, но по сути недалеко от правды.
Perplexity показывает, насколько хорошо языковая модель предсказывает текст. Чем она ниже — тем меньше “путаницы” и тем ближе модель к оригиналу без квантования.
В нашем случае особенно важна относительная perplexity — по сравнению с полной FP16/FP32-моделью.
Если запустить quantize --help
в проекте llama.cpp, можно увидеть таблицу со всеми вариантами квантования и их perplexity (цифры приведены для модели Vicuna 13b):
Allowed quantization types:
2 or Q4_0 : 3.50G, +0.2499 ppl @ 7B - small, very high quality loss - legacy, prefer using Q3_K_M
3 or Q4_1 : 3.90G, +0.1846 ppl @ 7B - small, substantial quality loss - legacy, prefer using Q3_K_L
8 or Q5_0 : 4.30G, +0.0796 ppl @ 7B - medium, balanced quality - legacy, prefer using Q4_K_M
9 or Q5_1 : 4.70G, +0.0415 ppl @ 7B - medium, low quality loss - legacy, prefer using Q5_K_M
10 or Q2_K : 2.67G, +0.8698 ppl @ 7B - smallest, extreme quality loss - not recommended
12 or Q3_K : alias for Q3_K_M
11 or Q3_K_S : 2.75G, +0.5505 ppl @ 7B - very small, very high quality loss
12 or Q3_K_M : 3.06G, +0.2437 ppl @ 7B - very small, very high quality loss
13 or Q3_K_L : 3.35G, +0.1803 ppl @ 7B - small, substantial quality loss
15 or Q4_K : alias for Q4_K_M
14 or Q4_K_S : 3.56G, +0.1149 ppl @ 7B - small, significant quality loss
15 or Q4_K_M : 3.80G, +0.0535 ppl @ 7B - medium, balanced quality - *recommended*
17 or Q5_K : alias for Q5_K_M
16 or Q5_K_S : 4.33G, +0.0353 ppl @ 7B - large, low quality loss - *recommended*
17 or Q5_K_M : 4.45G, +0.0142 ppl @ 7B - large, very low quality loss - *recommended*
18 or Q6_K : 5.15G, +0.0044 ppl @ 7B - very large, extremely low quality loss
7 or Q8_0 : 6.70G, +0.0004 ppl @ 7B - very large, extremely low quality loss - not recommended
1 or F16 : 13.00G @ 7B - extremely large, virtually no quality loss - not recommended
0 or F32 : 26.00G @ 7B - absolutely huge, lossless - not recommended
Обращаем внимание на пятую колонку — именно она показывает относительное отклонение. Q8_0
почти не уступает полной модели по точности, а вот Q2_K
теряет уже слишком много информации (ppl = +0.8698 — это уже критично).
По умолчанию, сами разработчики llama.cpp рекомендуют следующие варианты для продакшена:
Q4_K_M
Q5_K_S
Q5_K_M
Эта статья — базовое введение в квантование LLM. Мы сознательно не затрагивали продвинутые техники, такие как:
QAT (quantization‑aware training),
различия между статическим и динамическим квантованием,
и методы за пределами group‑wise quantization.
Также стоит отметить, что под одним и тем же суффиксом, например Q4_K_M
, могут скрываться разные реализации. Это связано с тем, что квантование не применяется к каждому тензору модели одинаково — обычно веса делятся на:
тензоры внимания (attention),
тензоры FFN‑блоков (feedforward),
и другие компоненты.
При этом не все тензоры одинаково важны для точности. Часто наиболее чувствительные части (например, внимание на ключах) оставляют менее агрессивно квантованными, чтобы сохранить качество. Но какие именно блоки считать критичными — зависит от разработчика, создавшего GGUF‑файл, и может отличаться от сборки к сборке.
Тем не менее, даже базовое понимание суффиксов вроде Q4_K_M
, Q6_K
, Q8_0
уже даёт практическую опору при выборе модели под конкретный бюджет, железо и задачи. А значит — позволяет избежать ненужных потерь точности там, где их можно было обойти.