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

Обложка

Боль: 12B модель, 8 ГБ видеопамяти и мечта «чтобы летало»

В прошлый раз мы разобрались, как заставить локальный инференс работать на встроенной AMD-графике через ROCm-костыли. Следующая остановка — выбор модели, и вот тут начинается самое интересное. Потому что в любой туториал по Ollama зашита одна неявная ложь: «ставь модель покрупнее, будет умнее». А про то, что модель должна ещё и влезть в видеопамять, авторы деликатно молчат.

У меня на руках 8 ГБ VRAM (встроенная графика), и я хочу локальную модель, которая тянет роль субагента — то есть не просто болтает, а следует инструкциям, пишет команды, держит контекст задачи. Кандидаты: 12B-модель в fp16 (полная точность) и она же, но квантованная в Q4KM. Спойлер: одна из них оказалась настолько бесполезной, что я её выкинул в тот же вечер. Разберём, почему — и при чём тут квантование.

Что такое квантование по-человечески

Нейросеть — это куча чисел, которые называются весами. Каждое число хранится с какой-то точностью. В fp16 (float16, «половинная» точность) на один вес уходит 2 байта. Это уже компромисс: изначально модели тренируют в fp32 (4 байта), но для инференса fp16 почти всегда хватает — разницу на глаз не увидишь.

Квантование идёт дальше: мы сжимаем каждый вес до меньшего числа бит, жертвуя точностью. Названия вроде Q4KM расшифровываются просто:

Фишка в том, что квантование — это не тупое округление до 4 бит. Веса режут на блоки, у каждого блока свой масштаб (scale), и числа «вписывают» в эту сетку. Информация теряется, но умно — так, чтобы основная структура знаний уцелела.

Размер весов: арифметика, которая решает всё

Считается это в уме за пять секунд. Число параметров модели умножаем на байты на вес:

Вот и весь секрет. Одна и та же модель, один и тот же «мозг» — но fp16-версии нужен объём, которого у дешёвой видеокарты просто нет, а квантованной — почти хватает.

Наши замеры: fp16 vs Q4KM — что происходит на 8 ГБ

Когда модель не помещается в VRAM целиком, Ollama начинает сбрасывать часть слоёв в обычную оперативную память (или вообще на CPU). Инференс при этом не падает, а медленно и мучительно ползёт: каждый слой, живущий в RAM, надо гонять туда-сюда через шину.

Мои цифры на одной и той же 12B-модели:

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

#llm #selfhosting