Квантование: Q4 против fp16 — что мы теряем, когда VRAM всего 8 ГБ

Боль: 12B модель, 8 ГБ видеопамяти и мечта «чтобы летало»
В прошлый раз мы разобрались, как заставить локальный инференс работать на встроенной AMD-графике через ROCm-костыли. Следующая остановка — выбор модели, и вот тут начинается самое интересное. Потому что в любой туториал по Ollama зашита одна неявная ложь: «ставь модель покрупнее, будет умнее». А про то, что модель должна ещё и влезть в видеопамять, авторы деликатно молчат.
У меня на руках 8 ГБ VRAM (встроенная графика), и я хочу локальную модель, которая тянет роль субагента — то есть не просто болтает, а следует инструкциям, пишет команды, держит контекст задачи. Кандидаты: 12B-модель в fp16 (полная точность) и она же, но квантованная в Q4KM. Спойлер: одна из них оказалась настолько бесполезной, что я её выкинул в тот же вечер. Разберём, почему — и при чём тут квантование.
Что такое квантование по-человечески
Нейросеть — это куча чисел, которые называются весами. Каждое число хранится с какой-то точностью. В fp16 (float16, «половинная» точность) на один вес уходит 2 байта. Это уже компромисс: изначально модели тренируют в fp32 (4 байта), но для инференса fp16 почти всегда хватает — разницу на глаз не увидишь.
Квантование идёт дальше: мы сжимаем каждый вес до меньшего числа бит, жертвуя точностью. Названия вроде Q4KM расшифровываются просто:
- Q4 — вес занимает примерно 4 бита (0.5 байта) вместо 16.
- Q8 — 8 бит (1 байт), почти как fp16, но аккуратнее упаковано.
- KM — это про как именно сжимали: K-quants квантуют разные слои с разной точностью. Самые чувствительные части (внимание, выходной слой) держат в более высокой точности, а «мусорные» веса жмут сильнее. K_M — средний профиль, баланс качество/размер.
Фишка в том, что квантование — это не тупое округление до 4 бит. Веса режут на блоки, у каждого блока свой масштаб (scale), и числа «вписывают» в эту сетку. Информация теряется, но умно — так, чтобы основная структура знаний уцелела.
Размер весов: арифметика, которая решает всё
Считается это в уме за пять секунд. Число параметров модели умножаем на байты на вес:
- 12B в fp16: 12 млрд × 2 байта = 24 ГБ весов. В 8 ГБ не влезает вообще.
- 12B в Q4KM: ~4.5 бита на вес ≈ 6–7 ГБ. Влезает, но впритык.
- 4B в Q4KM: ~2–3 ГБ. Влезает с огромным запасом.
Вот и весь секрет. Одна и та же модель, один и тот же «мозг» — но fp16-версии нужен объём, которого у дешёвой видеокарты просто нет, а квантованной — почти хватает.
Наши замеры: fp16 vs Q4KM — что происходит на 8 ГБ
Когда модель не помещается в VRAM целиком, Ollama начинает сбрасывать часть слоёв в обычную оперативную память (или вообще на CPU). Инференс при этом не падает, а медленно и мучительно ползёт: каждый слой, живущий в RAM, надо гонять туда-сюда через шину.
Мои цифры на одной и той же 12B-модели:
- fp16 (24 ГБ весов, в VRAM не влезает): 8.1 ток/сек. Звучит терпимо, пока не понимаешь, что большая часть времени уходит не на вычисления, а на перекачку данных.
- Q4KM (~7 ГБ, целиком в VRAM): 14.8 ток/сек. Почти в два раза быстрее, при том что модель — та же самая.
Ирония: точная fp16-версия, которую в теории «жалко портить», на практике оказывается хуже по всем фронтам. Она и медленнее, и жрёт память, а прироста качества ты не видишь, потому что на задаче «следуй инструкции и верни отчёт» разница между fp16 и Q4KM не ощущается вовсе. Вывод был простой: fp16-версию я удалил с диска в первый же вечер. Хлам.
4B с квантованием: быстро, но тупее
Если Q4KM так хорош, почему бы не взять модель поменьше и не наслаждаться скоростью? Пробовал. 4B-модель в квантовке выдаёт 23.5 ток/сек — это уже почти «живой» интерфейс, отвечает мгновенно. Честно выполняет простые команды, пингует, делает curl, возвращает результат.
Но есть нюанс, и он критичный. На сложных инструкциях — «разбери конфиг, найди вот такие аномалии, сверь с тем-то и оформи по шаблону» — 4B начинает плавать. Держит мысль хуже, путает порядок шагов, теряет детали из длинного промпта. Окно контекста у неё меньше, и на многоходовых задачах это вылезает сразу.
Мораль: скорость — не всё. Для рутины 4B шикарна. Для роли субагента, которому надо не терять нить, 12B в Q4KM выигрывает у 4B по качеству при сопоставимой практичности. А вот fp16 не выигрывает ни у кого — это просто самый дорогой способ получить меньше токенов в секунду.
Почему «влезло в VRAM» важнее числа параметров
Тут главный сдвиг мышления. Новичок смотрит на число параметров: «12B умнее 4B, беру 12B». Опытный смотрит на то, влезает ли модель в VRAM целиком.
Потому что есть порог, за которым всё ломается качественно, а не количественно. Пока модель целиком в VRAM — скорость линейна и предсказуема. Как только хотя бы один слой уезжает в RAM — начинается деградация, которую никакой «более умный» размер не компенсирует. Грубо: модель, которая помещается в память, работает на скорости своей архитектуры; модель, которая не помещается, работает на скорости шины между CPU и GPU. И это два разных мира.
Отсюда простое правило для любого железа: лучше квантованная модель, которая влезла целиком, чем точная, которая не влезла. Сначала добейся того, чтобы всё было в VRAM, потом уже думай про число параметров.
Контекст — второй пожиратель памяти (KV-cache)
Отдельная грабля, про которую забывают все: веса — не единственное, что ест видеопамять. Второй пожиратель — это KV-cache.
Когда модель читает твой промпт и генерирует ответ, она для каждого токена запоминает промежуточные векторы ключей и значений (отсюда K и V) — чтобы «помнить», что было в начале разговора. Этот кэш растёт линейно с длиной контекста. И при большом окне он съедает память так же жадно, как и сами веса, а то и больше.
Вот почему «контекст 128K токенов» из спеки модели — это маркетинг, а не обещание, что вы реально этим воспользуетесь на 8 ГБ. Попробуй выставить контекст на максимум — и смотри, как VRAM заканчивается, слои опять уезжают в RAM, а токены в секунду катятся вниз. У меня 12B живёт с большим объявленным окном, но реально рабочий контекст я держу скромнее — иначе те же грабли, что с fp16. Маленькая модель вообще работает с урезанным окном, и это одна из причин, почему она «плавает» на длинных инструкциях: ей просто некуда складывать весь диалог.
Практический вывод: контекст — это тоже ручка, которой ты крутишь бюджет памяти. Хочешь длинный контекст — либо жертвуй точностью весов, либо бери модель поменьше, либо добавляй VRAM. Третьего не дано.
Практика: как считать бюджет и что мерить
Бюджет памяти — это просто сумма: вес модели (смотрим в описании квантовки) + KV-cache под выбранное окно + накладные расходы рантайма. Плюс оставь гигабайт-другой под саму ОС и рабочий стол, иначе графический драйвер начнёт истерить. Если сумма близка к объёму VRAM — ты уже на грани, готовься к сбросу слоёв.
Что мерить. Не верь ощущениям — верь ollama ps. Он показывает, сколько памяти реально заняла модель и — главное — куда она легла: 100% GPU или с процентом CPU/RAM. Если видишь отличный от нуля CPU — модель не влезла, дальше можешь не мерить скорость, сначала почини укладку в память. Скорость меряем в токенах в секунду на реальной задаче, а не на пустом «привет».
Почему чужие бенчмарки — не про ваше железо. В интернете кто-то пишет «12B на 8 ГБ летает, 20 ток/сек». Не верьте. Скорость зависит от кучи вещей, которых в том бенчмарке нет: у вас встроенная графика или дискретная, какой драйвер, включён ли ROCm (у AMD это отдельный танец с бубном), сколько слоёв реально уехало в RAM, какой контекст выставлен. Даже та же модель на «таких же 8 ГБ» у другого человека может дать совсем другие цифры — потому что железо другое. Единственный честный бенчмарк — тот, что вы сняли у себя, на своей модели, на своей задаче.
Вывод
Квантование — это не «испорченная модель», а инструмент укладки модели в реальную память. На 8 ГБ VRAM расклад простой: fp16 12B не влезает и ползёт со скоростью 8 ток/сек — мусор. Та же 12B в Q4KM влезает и даёт 14.8 ток/сек — рабочая лошадка. 4B в квантовке даёт 23.5 ток/сек, но слабее на сложных инструкциях. А главное правило — модель, которая целиком в VRAM, всегда бьёт ту, что не влезла, независимо от числа параметров. И не забывайте про контекст: он ест память не хуже весов.