<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>GGUF on kenji.blog</title><link>http://kenji.blog/ru/tags/gguf/</link><description>Recent content in GGUF on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ru</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 00:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ru/tags/gguf/index.xml" rel="self" type="application/rss+xml"/><item><title>Объяснение работы технологии квантования llama.cpp (GGUF)</title><link>http://kenji.blog/ru/p/llama-cpp-quantization-gguf/</link><pubDate>Fri, 11 Sep 2026 00:00:00 +0900</pubDate><guid>http://kenji.blog/ru/p/llama-cpp-quantization-gguf/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-quantization-gguf/img/eyecatch.jpg" alt="Featured image of post Объяснение работы технологии квантования llama.cpp (GGUF)" />&lt;h2 id="1-введение-почему-llm-нужно-квантование">1. Введение: Почему LLM нужно квантование?
&lt;/h2>&lt;p>Эволюция больших языковых моделей (LLM: Large Language Models) в последние годы поразительна, но за ней скрываются серьезные проблемы: &amp;ldquo;истощение вычислительных ресурсов&amp;rdquo; и &amp;ldquo;узкое место пропускной способности памяти&amp;rdquo;. Например, если загрузить модель с 70 миллиардами параметров (70B), такую как Llama 3, в память с использованием стандартных 16-битных чисел с плавающей запятой (FP16), только параметры займут около 140 ГБ VRAM/RAM. Если к этому добавить контекст во время логического вывода (KV кэш), модель не будет работать без кластеризации нескольких высококлассных GPU для дата-центров (NVIDIA A100 80GB или H100 80GB).&lt;/p>
&lt;p>Спасителем, появившимся для запуска LLM индивидуальными разработчиками и на периферийных устройствах (MacBook или обычные игровые ПК), стал &lt;strong>llama.cpp&lt;/strong> и лежащая в его основе &lt;strong>технология квантования (Quantization)&lt;/strong>. В частности, формат файлов &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> и продвинутый алгоритм блочного квантования, известный как &lt;strong>k-quants&lt;/strong>, представляют собой революционный метод сжатия размера модели в несколько раз, максимально ограничивая при этом снижение точности модели (Perplexity).&lt;/p>
&lt;p>В этой статье мы подробно объясним квантование в llama.cpp, начиная с математических основ, различий с форматом GGML, детальной структуры формата GGUF и заканчивая внутренними механизмами k-quants.&lt;/p>
&lt;hr>
&lt;h2 id="2-математические-основы-квантования-quantization">2. Математические основы квантования (Quantization)
&lt;/h2>&lt;p>В контексте LLM квантование относится к операции отображения непрерывных значений (или высокоточных чисел с плавающей запятой) в дискретные значения с меньшим количеством бит (INT8, INT4, INT3 и т.д.).&lt;/p>
&lt;h3 id="21-базовые-формулы-линейного-квантования">2.1. Базовые формулы линейного квантования
&lt;/h3>&lt;p>Самым простым подходом является линейное квантование (Min-Max квантование). Пусть $W$ - исходный тензор весов с высокой точностью, а $W_q$ - квантованный целочисленный тензор.&lt;/p>
$$ W_q = \text{round}\left( \frac{W}{S} \right) + Z $$
&lt;p>Где,&lt;/p>
&lt;ul>
&lt;li>$S$ - это &lt;strong>масштабный коэффициент (Scale Factor)&lt;/strong>, определяющий размер шага (разрешение) квантования.&lt;/li>
&lt;li>$Z$ - это &lt;strong>нулевая точка (Zero-point)&lt;/strong>, значение смещения для сдвига, определяющее, какому целому значению после квантования соответствует вещественный $0.0$.&lt;/li>
&lt;li>$\text{round}(\cdot)$ - функция округления до ближайшего целого.&lt;/li>
&lt;/ul>
&lt;p>При обратном квантовании (Dequantization) во время логического вывода восстанавливаются приблизительные вещественные веса $\tilde{W}$.&lt;/p>
$$ \tilde{W} = S \times (W_q - Z) $$
&lt;h3 id="22-симметричное-и-асимметричное-квантование">2.2. Симметричное и асимметричное квантование
&lt;/h3>&lt;p>В зависимости от обработки нулевой точки $Z$, методы делятся на два основных типа.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Асимметричное квантование (Asymmetric Quantization)&lt;/strong>
Отображение использует минимальное значение данных $W_{\min}$ и максимальное значение $W_{\max}$.
&lt;/p>
$$ S = \frac{W_{\max} - W_{\min}}{2^b - 1}, \quad Z = \text{round}\left(-\frac{W_{\min}}{S}\right) $$
&lt;p>
Где $b$ - количество бит квантования (например, для 4 бит $2^4-1 = 15$). Поскольку необходимо хранить $Z$, незначительно увеличиваются накладные расходы на вычисления и память.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Симметричное квантование (Symmetric Quantization)&lt;/strong>
Отображение центрируется вокруг нуля с использованием максимального абсолютного значения данных ($Z=0$).
&lt;/p>
$$ S = \frac{\max(|W_{\max}|, |W_{\min}|)}{2^{b-1} - 1}, \quad Z = 0 $$
&lt;p>
Раннее квантование llama.cpp (например, унаследованное Q4_0) использовало симметричное квантование. Поскольку член $Z$ отсутствует, преимуществом является значительное ускорение вычислений скалярного произведения с помощью инструкций SIMD.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-эволюция-от-ggml-к-gguf-и-структура-файла">3. Эволюция от GGML к GGUF и структура файла
&lt;/h2>&lt;p>Говоря о llama.cpp, нельзя не упомянуть &lt;strong>GGML&lt;/strong>, библиотеку тензорных вычислений, написанную на C++, и производный от нее формат файлов &lt;strong>GGUF&lt;/strong>.&lt;/p>
&lt;h3 id="31-проблемы-ggml">3.1. Проблемы GGML
&lt;/h3>&lt;p>Ранний llama.cpp использовал формат &lt;code>ggml&lt;/code> (и его варианты, такие как &lt;code>ggjt&lt;/code>). Однако у них были следующие проблемы:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Отсутствие расширяемости:&lt;/strong> Магические числа и гиперпараметры были жестко закодированы (hardcoded) с фиксированной длиной и порядком, что приводило к разрушительным изменениям каждый раз при добавлении новой архитектуры модели (например, Llama, Falcon, Mixtral и т.д.) или нового токенизатора.&lt;/li>
&lt;li>&lt;strong>Потеря обратной совместимости:&lt;/strong> Формат часто обновлялся, из-за чего старые файлы моделей часто переставали читаться в последних версиях llama.cpp.&lt;/li>
&lt;/ul>
&lt;h3 id="32-рождение-формата-gguf">3.2. Рождение формата GGUF
&lt;/h3>&lt;p>&lt;strong>GGUF&lt;/strong>, представленный в августе 2023 года, является универсальным форматом, разработанным для решения этих проблем. Его главная особенность - принятие &lt;strong>структуры метаданных на основе пар ключ-значение (Key-Value)&lt;/strong>.&lt;/p>
&lt;p>Следующая диаграмма Mermaid абстрактно показывает файловую структуру GGUF.&lt;/p>
&lt;div class="mermaid">graph TD
A["Файл GGUF"] --> B["Заголовок (Magic, Version)"]
A --> C["Метаданные (Пары Ключ-Значение)"]
A --> D["Информация о тензоре (Name, Shape, Offset)"]
A --> E["Данные тензора (Binary payload)"]
C --> C1["general.architecture: llama"]
C --> C2["llama.context_length: 4096"]
C --> C3["tokenizer.ggml.tokens: [...]"]
E --> E1["Веса Слоя 0"]
E --> E2["Веса Слоя 1"]
E --> E3["..."]&lt;/div>
&lt;p>&lt;strong>Основные преимущества GGUF:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Гибкость:&lt;/strong> Все настройки, такие как гиперпараметры модели, конфигурация RoPE (Rotary Positional Embedding), данные словаря токенизатора и т.д., хранятся в виде именованных пар Key-Value. Неизвестные ключи игнорируются, что упрощает добавление новых функций.&lt;/li>
&lt;li>&lt;strong>Независимость от порядка байтов (Endianness):&lt;/strong> GGUF по умолчанию использует порядок от младшего к старшему (Little-endian), но имеет явный флаг, что делает его безопасно переносимым между различными архитектурами.&lt;/li>
&lt;li>&lt;strong>Оптимизация для mmap (отображение в память):&lt;/strong> Данные тензоров выровнены (с отступами) по определенным границам, что позволяет отображать их напрямую с диска в адресное пространство памяти с помощью системного вызова ОС &lt;code>mmap()&lt;/code>. Благодаря этому время инициализации при загрузке модели практически равно нулю.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-глубины-k-quants-продвинутое-блочное-квантование">4. Глубины k-quants: Продвинутое блочное квантование
&lt;/h2>&lt;p>Истинная ценность формата GGUF заключается в механизме &lt;strong>k-quants (K-quantization)&lt;/strong>, отвечающем за сжатие весов модели.&lt;/p>
&lt;p>Обычно веса нейронной сети близки к нормальному распределению, если рассматривать слой целиком, но локально существуют выбросы (Outliers). Если квантовать веса всего слоя с помощью единого масштабного коэффициента $S$, масштаб будет искажен выбросами, и информация о малых весах будет полностью потеряна.&lt;/p>
&lt;p>Чтобы предотвратить это, llama.cpp выполняет &lt;strong>блочное квантование (Block-wise Quantization)&lt;/strong>. Тензор весов разбивается на небольшие блоки (например, по 32 или 256 элементов), и каждому блоку присваивается свой собственный масштабный коэффициент (и нулевая точка).&lt;/p>
&lt;h3 id="41-ограничения-унаследованного-квантования-q4_0-q4_1">4.1. Ограничения унаследованного квантования (Q4_0, Q4_1)
&lt;/h3>&lt;p>В раннем &lt;code>Q4_0&lt;/code> блок состоял из 32 весов FP16 и имел один общий масштабный коэффициент FP16.&lt;/p>
&lt;ul>
&lt;li>Размер блока: 32&lt;/li>
&lt;li>Память: 1 масштаб (16 бит) + 32 4-битных веса (128 бит) = 144 бита&lt;/li>
&lt;li>Эффективное количество бит на элемент (bpw: bits per weight): $144 / 32 = 4.5$ bpw&lt;/li>
&lt;/ul>
&lt;p>Хотя это уже было довольно эффективно, проявились пределы точности и степени сжатия. Тогда и появился &lt;strong>k-quants&lt;/strong>, имеющий более сложную и продуманную иерархическую структуру.&lt;/p>
&lt;h3 id="42-иерархическая-структура-суперблоков-и-субблоков-пример-q4_k_m">4.2. Иерархическая структура суперблоков и субблоков (Пример Q4_K_M)
&lt;/h3>&lt;p>k-quants имеет иерархическую структуру, состоящую из больших &amp;ldquo;Суперблоков (Super-block)&amp;rdquo; и содержащихся в них меньших &amp;ldquo;Субблоков (Sub-block)&amp;rdquo;. Это позволяет также квантовать сами метаданные (значения масштаба и т.д.), предельно снижая bpw при сохранении точности.&lt;/p>
&lt;p>Давайте рассмотрим структуру &lt;strong>Q4_K_M&lt;/strong>, которая является наиболее популярной конфигурацией. Q4_K_M использует суперблок из 256 элементов.&lt;/p>
&lt;div class="mermaid">graph TD
A["Суперблок (256 весов)"] --> B["Метаданные масштаба (FP16/INT8)"]
A --> C["Субблок 0 (32 веса, 4-бит)"]
A --> D["Субблок 1 (32 веса, 4-бит)"]
A --> E["..."]
A --> F["Субблок 7 (32 веса, 4-бит)"]
B --> B1["Супер-масштаб (FP16)"]
B --> B2["Суб-масштабы (8 x 6-бит)"]
B --> B3["Суб-минимумы (8 x 6-бит)"]&lt;/div>
&lt;p>Фактическая структура в C++ (GGML) концептуально определяется следующим образом:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Концептуальная структура block_q4_K в llama.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define QK_K 256
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">block_q4_K&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Супер-масштаб для всего суперблока (например, FP16 x 2)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">scales&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Упакованные данные: 6-битные масштабы и 6-битные минимумы (нулевые точки) для 8 субблоков (по 32 элемента)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">qs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">QK_K&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// Данные весов, квантованные до 4 бит (256 элементов / 2 = 128 байт)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Математический процесс деквантования (Dequantization):&lt;/strong>&lt;/p>
&lt;p>Приблизительное вещественное значение $\tilde{W}_{i, j}$ элемента $j$ ($0 \le j &lt; 32$) внутри субблока $i$ ($0 \le i &lt; 8$) вычисляется следующим образом:&lt;/p>
$$ \tilde{W}_{i, j} = S_{\text{super}} \times s_i \times (w_{i, j} - m_i) $$
&lt;ul>
&lt;li>$S_{\text{super}}$: Масштаб с плавающей запятой для всего суперблока&lt;/li>
&lt;li>$s_i$: 6-битный масштаб, квантованный для субблока $i$&lt;/li>
&lt;li>$m_i$: 6-битный минимум (нулевая точка), квантованный для субблока $i$&lt;/li>
&lt;li>$w_{i, j}$: 4-битный квантованный вес ($0 \dots 15$)&lt;/li>
&lt;/ul>
&lt;p>Благодаря этой иерархической структуре, сохраняя способность адаптироваться к выбросам, резко сокращается объем памяти, занимаемый самими масштабными коэффициентами. Q4_K_M достигает в целом около &lt;strong>4.8 bpw&lt;/strong>.&lt;/p>
&lt;h3 id="43-разнообразие-опций-k-quants">4.3. Разнообразие опций k-quants
&lt;/h3>&lt;p>llama.cpp предлагает множество вариаций в зависимости от цели. Суффиксы (S, M, L) после &amp;ldquo;K&amp;rdquo; обозначают размер (маленький, средний, большой).&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Формат&lt;/th>
&lt;th style="text-align:center">BPW (Bits per Weight)&lt;/th>
&lt;th style="text-align:left">Обзор и особенности&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q2_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">2.5～3.3&lt;/td>
&lt;td style="text-align:left">Экстремальное сжатие. Значительное падение точности, но подходит для сред с крайне малым объемом VRAM.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q3_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">3.3&lt;/td>
&lt;td style="text-align:left">Стандарт для 3-битного квантования. Уступает Q4, но часто остается в пределах допустимого.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q4_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">4.8&lt;/td>
&lt;td style="text-align:left">&lt;strong>Рекомендуемая золотая середина&lt;/strong>. Баланс между уменьшением размера модели вдвое и сохранением точности.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q5_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">5.5&lt;/td>
&lt;td style="text-align:left">Когда требуется более высокая точность. Промежуточное положение между Q4 и FP16.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q6_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">6.6&lt;/td>
&lt;td style="text-align:left">Сохраняет Perplexity почти на уровне FP16, но размер файла больше.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q8_0&lt;/strong>&lt;/td>
&lt;td style="text-align:center">8.5&lt;/td>
&lt;td style="text-align:left">Эквивалент INT8. Используется в основном для промежуточных тензоров при логическом выводе вычислений и только в финальных слоях.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>※ Фактический BPW усредняется по всей модели, поскольку выполняется смешанное квантование (Mixed Quantization) в зависимости от тензоров модели (например, проекции Q/K/V в Attention или веса в FFN). Внутри производится оптимизация, при которой важные тензоры квантуются в Q6, а остальные - в Q4.&lt;/p>
&lt;hr>
&lt;h2 id="5-оптимизация-производительности-при-логическом-выводе-архитектуры-simd-и-cuda">5. Оптимизация производительности при логическом выводе: архитектуры SIMD и CUDA
&lt;/h2>&lt;p>Простая загрузка модели GGUF в память не делает логический вывод быстрым. Большая часть логического вывода в LLM - это «умножение матрицы на вектор (Matrix-Vector Multiplication, или GEMV, или Matrix-Matrix, GEMM)». Ключ к успеху - это то, как ускорить операцию умножения и сложения между квантованными весами и активациями (входными данными), хранящимися в FP16 (или FP32).&lt;/p>
&lt;h3 id="51-использование-инструкций-simd-в-процессорных-средах">5.1. Использование инструкций SIMD в процессорных средах
&lt;/h3>&lt;p>Невероятная скорость, с которой llama.cpp работает при логическом выводе на CPU, обусловлена оптимизацией &lt;strong>SIMD (Single Instruction, Multiple Data)&lt;/strong> на уровне ассемблера.
Например, он в полной мере использует наборы инструкций &lt;strong>AVX2&lt;/strong> и &lt;strong>AVX-512&lt;/strong> на процессорах Intel/AMD, и &lt;strong>ARM NEON&lt;/strong> на Apple Silicon.&lt;/p>
&lt;p>Во время логического вывода не тратится время на возвращение $W_q$ в формат FP32 (деквантование) перед умножением.
Сторона активации также динамически квантуется блоками (Dynamic Quantization, обычно в INT8), и целочисленные операции &lt;strong>INT8 $\times$ INT4&lt;/strong> вычисляются сразу с использованием специальных инструкций скалярного произведения SIMD (например, &lt;code>vdpaddd&lt;/code> или &lt;code>_mm256_madd_epi16&lt;/code>). В конечном аккумуляторе происходит преобразование обратно в FP32 и умножение на масштабный коэффициент, что обеспечивает поразительную пропускную способность.&lt;/p>
&lt;h3 id="52-разгрузка-в-средах-gpu-cublas--cuda">5.2. Разгрузка в средах GPU (cuBLAS / CUDA)
&lt;/h3>&lt;p>Современный llama.cpp имеет надежную поддержку не только CPU, но и GPU NVIDIA (CUBLAS / CUDA).
Можно выгрузить (offload) некоторые или все слои файла GGUF в VRAM (опция &lt;code>--n-gpu-layers&lt;/code>).&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User
participant CPU_RAM as CPU и RAM (mmap)
participant VRAM as GPU VRAM
participant Compute as Тензорные ядра
User->>CPU_RAM: Загрузка GGUF (mmap)
CPU_RAM->>VRAM: Выгрузка слоев (напр. 30/32 слоев)
Note over CPU_RAM, VRAM: Данные остаются квантованными в VRAM
User->>Compute: Прямой проход (Входные токены)
Compute->>VRAM: Извлечение квантованных весов
Compute->>Compute: Динамическое деквантование в FP16 в SRAM (on-the-fly)
Compute->>Compute: Умножение матриц (cuBLAS / Пользовательские ядра)
Compute->>User: Вывод логитов (Logits)&lt;/div>
&lt;p>При вычислениях на GPU пропускная способность памяти (Memory Bandwidth) VRAM становится самым большим узким местом. Поскольку веса сжаты с помощью k-quants, объем данных, передаваемых из VRAM в вычислительные блоки GPU (SM: Streaming Multiprocessor или Tensor Cores), сокращается в 3-4 раза. В тот момент, когда веса достигают вычислительного блока, они динамически деквантуются (разворачиваются) в FP16, и с помощью Tensor Cores выполняется сверхбыстрое умножение матриц.
Другими словами, можно сказать, что квантование выполняется &lt;strong>не для &amp;ldquo;уменьшения объема вычислений&amp;rdquo;, а для &amp;ldquo;уменьшения объема передаваемых данных из памяти&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="6-конкретные-примеры-компромисса-между-использованием-памяти-и-производительностью">6. Конкретные примеры компромисса между использованием памяти и производительностью
&lt;/h2>&lt;p>Здесь, на примере модели Llama 3 8B, давайте посмотрим на требования к спецификациям для каждого уровня квантования GGUF. (Цифры являются приблизительными ориентирами.)&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Модель / Квантование&lt;/th>
&lt;th style="text-align:left">Размер файла&lt;/th>
&lt;th style="text-align:left">Требуемая VRAM/RAM&lt;/th>
&lt;th style="text-align:left">Скорость вывода (ориентир)&lt;/th>
&lt;th style="text-align:left">Снижение Perplexity&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (FP16)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 16 ГБ&lt;/td>
&lt;td style="text-align:left">от 18 ГБ&lt;/td>
&lt;td style="text-align:left">Базовая&lt;/td>
&lt;td style="text-align:left">Нет (Base)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q8_0)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 8.5 ГБ&lt;/td>
&lt;td style="text-align:left">от 10 ГБ&lt;/td>
&lt;td style="text-align:left">Высокая&lt;/td>
&lt;td style="text-align:left">Почти нулевое&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q6_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 6.6 ГБ&lt;/td>
&lt;td style="text-align:left">от 8 ГБ&lt;/td>
&lt;td style="text-align:left">Очень высокая&lt;/td>
&lt;td style="text-align:left">Минимальное&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q4_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 4.9 ГБ&lt;/td>
&lt;td style="text-align:left">от 6.5 ГБ&lt;/td>
&lt;td style="text-align:left">Самая быстрая / Оптимальная&lt;/td>
&lt;td style="text-align:left">В допустимых пределах / Небольшое&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q3_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 3.9 ГБ&lt;/td>
&lt;td style="text-align:left">от 5.5 ГБ&lt;/td>
&lt;td style="text-align:left">Самая быстрая&lt;/td>
&lt;td style="text-align:left">Немного заметное&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q2_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Около 3.0 ГБ&lt;/td>
&lt;td style="text-align:left">от 4.5 ГБ&lt;/td>
&lt;td style="text-align:left">Высокая&lt;/td>
&lt;td style="text-align:left">Очевидное снижение&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Внимание (Влияние KV-кэша):&lt;/strong>
При логическом выводе LLM, когда длина контекста (количество токенов промпта) увеличивается, потребление памяти взрывообразно растет не только из-за весов модели, но и из-за &lt;strong>KV-кэша&lt;/strong>, который сохраняет прошлые состояния Attention.
Например, если длина контекста составляет 8192 токена, только KV-кэш будет потреблять несколько гигабайт. Поэтому при реальном использовании необходимо обеспечить запас (Headroom) в размере &lt;code>Размер файла модели + около 1.5 ГБ ~ 3 ГБ&lt;/code>. Причина, по которой рекомендуется Q4_K_M, заключается в том, что это идеальная линия, при которой даже с учетом резервирования этого KV-кэша модель безопасно работает на типичном графическом процессоре с 8 ГБ VRAM (например, RTX 3060 / 4060).&lt;/p>
&lt;p>В последних версиях llama.cpp также была добавлена &lt;strong>функция квантования самого KV-кэша в Q8_0 или Q4_0&lt;/strong>, и постоянно ведется работа по дальнейшему увеличению длины контекста.&lt;/p>
&lt;hr>
&lt;h2 id="7-заключение">7. Заключение
&lt;/h2>&lt;p>В этой статье мы глубоко погрузились во внутреннюю структуру формата GGUF и технологии квантования k-quants, которые являются сердцем llama.cpp.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Гибкость GGUF:&lt;/strong> Структура метаданных типа &amp;ldquo;ключ-значение&amp;rdquo; создала надежную экосистему, которая может идти в ногу с быстрой эволюцией LLM (появление новых архитектур моделей) без разрушительных изменений.&lt;/li>
&lt;li>&lt;strong>Экстремальное сжатие с помощью k-quants:&lt;/strong> Иерархическое управление масштабными коэффициентами суперблоков и субблоков позволило добиться удивительного сжатия - в среднем 4.8 бита на вес (Q4_K_M) - с сохранением информации о выбросах.&lt;/li>
&lt;li>&lt;strong>Устранение узкого места пропускной способности памяти:&lt;/strong> Продвинутые реализации ядер для SIMD и CUDA позволили выполнять вычисления с динамическим деквантованием (on-the-fly), что сократило объем передаваемых данных из VRAM и значительно повысило скорость логического вывода.&lt;/li>
&lt;/ol>
&lt;p>Технологическое мастерство llama.cpp, способствующее демократизации ИИ, выходит за рамки простого инструмента и, без преувеличения, является одной из вершин современной программной инженерии. Поняв алгоритм квантования и структуру формата GGUF, вы сможете более точно выбирать оптимальную модель для вашей среды и выполнять настройку производительности.&lt;/p>
&lt;h3 id="полезные-ссылки">Полезные ссылки
&lt;/h3>&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp GitHub Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml/blob/master/docs/gguf.md" target="_blank" rel="noopener"
>GGUF Format Specification&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp/pull/1684" target="_blank" rel="noopener"
>K-quants Implementation PR&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>(Конец)&lt;/p></description></item></channel></rss>