Когда пользователь видит команды:
python llama.cpp/convert_hf_to_gguf.py ./my-hf-model \
--outfile ./my-model-bf16.gguf \
--outtype bf16
а затем:
./llama.cpp/build/bin/llama-quantize \
./my-model-bf16.gguf \
./my-model-Q4_K_M.gguf \
Q4_K_M
может показаться, что любую модель из Hugging Face можно самостоятельно превратить в GGUF.
Это не так.
Главное правило:
Квантовать можно checkpoint уже поддерживаемой архитектуры. Если сама архитектура неизвестна llama.cpp, сначала кто-то должен реализовать её поддержку в runtime.
Это два совершенно разных уровня работы.
Разработчик модели
↓
публикует BF16/FP16 checkpoint
↓
Hugging Face
↓
llama.cpp знает architecture?
│
┌────┴────┐
│ │
да нет
│ │
▼ ▼
HF → GGUF сначала нужна
│ поддержка архитектуры
▼
BF16/F16 GGUF
↓
llama-quantize
↓
Q8 / Q6 / Q5 / Q4 / Q3 / IQ / ...
↓
готовый GGUF
Здесь есть три разных действия:
Architecture support
=
понимать математику модели
Conversion
=
переложить известные tensors в GGUF
Quantization
=
сжать эти tensors
Могут существовать:
CompanyA-Coder-32B
CompanyB-Reasoner-32B
My-Finetune-32B
но все они использовать:
Qwen3ForCausalLM
или:
LlamaForCausalLM
У них разные веса и обучение, но один вычислительный граф.
Для inference engine это принципиально: если архитектура уже реализована, новые checkpoints этой архитектуры обычно можно конвертировать без изменения исходного кода llama.cpp.
Чтобы выполнить forward pass, llama.cpp должен понимать:
какие tensors существуют
как устроены layers
как считать attention
как считать MLP
как устроен MoE
какие normalization используются
как работает RoPE
сколько attention heads
сколько KV heads
как работает router
есть ли recurrent state
есть ли MTP/NextN
Одного набора чисел в .safetensors недостаточно.
Runtime должен знать, какие математические операции делать с этими весами.
Hugging Face Transformers может загрузить:
{
"architectures": ["SomeNewModelForCausalLM"]
}
и вызвать Python-класс модели с его forward().
llama.cpp не исполняет этот Python-код.
Он реализует модель самостоятельно через GGML/C++.
Поэтому если появляется совершенно новая:
SuperNewArchitectureForCausalLM
скрипт конвертации не может автоматически вывести из .safetensors, как работает новый attention, recurrent block или MoE router.
Нужна ручная реализация архитектуры.
convert_hf_to_gguf.pyЭто не просто:
safetensors → другой файл
Конвертер выполняет архитектурно-зависимую работу:
1. определяет architecture
2. читает config.json
3. сопоставляет HF tensor names с GGUF tensor names
4. записывает metadata
5. обрабатывает tokenizer
6. при необходимости преобразует tensors
7. сохраняет GGUF
Например HF tensor:
model.layers.12.self_attn.q_proj.weight
может стать:
blk.12.attn_q.weight
Но для сложных архитектур mapping может быть намного хитрее простого переименования.
Допустим:
{
"architectures": ["MegaDeltaMoEForCausalLM"]
}
а converter не знает такой модели.
Conversion завершится ошибкой уровня:
Model MegaDeltaMoEForCausalLM is not supported
Никакой:
--outtype q4_K_M
не решит проблему.
Проблема не в битности весов, а в отсутствии реализации модели в runtime.
Если вычислительный граф действительно новый, нужно пройти путь примерно такого вида:
Transformers implementation
↓
анализ архитектуры
↓
GGUF metadata
↓
tensor mapping
↓
model loader
↓
GGML compute graph
↓
CPU/CUDA/Metal/etc.
↓
tests
Это уже не пользовательская операция.
Обычно нужны:
Runtime должен отличать новый тип модели.
Например:
number of experts
experts per token
state dimensions
attention pattern
rope parameters
HF tensor X
→
GGUF tensor Y
Самая важная часть:
как из входных hidden states и tensors получить следующий hidden state
Если модель использует новый mathematical primitive, возможно, его ещё нет в GGML — тогда добавляется и он.
Допустим завтра выходит:
AmazingCoder-32B
но внутри:
Qwen3ForCausalLM
Если tensor layout совместим с уже реализованным Qwen3, новая поддержка llama.cpp не требуется.
Обычный пользователь может:
HF checkpoint
↓
BF16 GGUF
↓
Q4_K_M
Если было:
Qwen3-32B
и его дообучили:
SFT
DPO
RLHF
continued pretraining
merged LoRA
архитектура обычно остаётся прежней.
Изменяются веса, а не вычислительный граф.
Поэтому private fine-tune на уже поддерживаемой архитектуре — типичный случай, когда пользователь совершенно нормально квантирует модель сам.
Если авторы изменили не только веса, но и структуру:
добавили новые experts
изменили attention
добавили recurrent layers
добавили новый MTP module
изменили tensor layout
это уже может потребовать изменений converter/runtime.
Ключевой вопрос:
изменились только параметры или сам вычислительный граф?
Первый этап:
python llama.cpp/convert_hf_to_gguf.py \
./models/my-hf-model \
--outfile ./models/my-model-bf16.gguf \
--outtype bf16
На выходе:
my-model-bf16.gguf
Это GGUF высокой точности.
Например:
./llama.cpp/build/bin/llama-quantize \
./models/my-model-bf16.gguf \
./models/my-model-Q4_K_M.gguf \
Q4_K_M
Можно сделать и другие варианты:
Q8_0
Q6_K
Q5_K_M
Q4_K_M
Q4_K_S
Q3_K_M
IQ4_XS
...
в зависимости от того, что поддерживает текущий quantizer.
У них разные задачи.
convert_hf_to_gguf.pyрешает:
architecture
tensor mapping
metadata
tokenizer
layout
llama-quantizeрешает:
как представить уже понятные tensors меньшим количеством бит
Получается:
HF
↓ architecture-specific conversion
GGUF BF16
↓ numeric quantization
GGUF Q4/Q5/IQ/...
llama-quantize намного универсальнее converter-аКогда модель уже в корректном GGUF, tensors имеют понятные runtime-роли:
blk.0.attn_q.weight
blk.0.attn_k.weight
blk.0.ffn_up.weight
...
Quantizer в основном решает численную задачу:
BF16 matrix
↓
Q4_K / Q5_K / IQ4 / ...
Поэтому один quantization infrastructure работает сразу для множества архитектур.
Хороший recipe учитывает, что разные tensors имеют разную чувствительность:
attention
output head
embedding
expert
router
shared expert
Некоторые tensors:
Но это всё равно намного проще, чем реализовать полный forward graph.
Если архитектура уже поддерживается:
python convert_hf_to_gguf.py ./model \
--outfile model-bf16.gguf \
--outtype bf16
llama-quantize \
model-bf16.gguf \
model-Q4_K_M.gguf \
Q4_K_M
Никакой разработки llama.cpp здесь не нужно.
Потому что:
сделать Q4_K_M
и:
сделать лучший quant при заданном размере
— разные задачи.
Можно просто применить generic recipe.
А можно исследовать sensitivity и сделать mixed quant:
attention → выше precision
experts → ниже precision
output head → выше precision
часть gates → почти lossless
При похожем размере второй вариант может сохранить больше качества.
Для более качественного квантования можно собрать statistics на calibration data.
Идея:
какие направления weights реально важны
оцениваются по активациям модели.
В llama.cpp для этого существует механизм imatrix.
Условно:
BF16 model
+
calibration text
↓
llama-imatrix
↓
importance data
↓
llama-quantize
↓
importance-aware GGUF
Это уже продвинутый workflow.
Представим:
Tensor A:
ошибка quant почти не влияет на logits
Tensor B:
даже маленькая ошибка сильно влияет
Квантизовать их одинаково не всегда разумно.
Можно выгоднее распределить битовый бюджет:
A → агрессивнее
B → точнее
И получить лучшее качество при том же среднем размере.
Unsloth Dynamic использует модель-специфический mixed recipe.
Идея:
разные layers/tensors
→ разная sensitivity
→ разная precision
Поэтому появляются:
UD-Q4_K_M
UD-IQ4_NL
UD-Q4_K_XL
Это не просто прямой вызов обычного Q4_K_M.
Обычный Q4 способен сделать любой пользователь.
Ценность quant-maker-а скорее в:
calibration
benchmarking
mixed recipes
tensor overrides
quality testing
automation
publication
compatibility checking
То есть это отдельная инженерная специализация.
поддерживаемый HF checkpoint
→ BF16 GGUF
→ Q4_K_M
Программирование runtime не требуется.
imatrix
tensor sensitivity
mixed precision
KL/perplexity
dynamic recipe
Это уже оптимизация качества на бит.
новая architecture
→ converter
→ metadata
→ graph
→ kernels
→ cache/state
→ tests
Вот это полноценная разработка llama.cpp.
Не обязательно vendor модели.
Это может быть:
автор модели
maintainer llama.cpp
community contributor
Unsloth
независимый разработчик
другая компания
Кто первым реализует корректную поддержку и доведёт её до merge.
Open-weight модель гораздо проще распространять, если она быстро работает в:
Transformers
llama.cpp
vLLM
SGLang
MLX
ExLlama
Поэтому крупные model vendors всё чаще помогают runtime ecosystem ещё до или сразу после релиза.
Но это не обязательное правило.
Если модель популярна, после релиза быстро появляются:
runtime patches
GGUF converters
quant repositories
benchmark reports
Если архитектура похожа на существующую, процесс быстрый.
Если внутри новый recurrent/attention mechanism — намного сложнее.
Допустим остались:
q_proj
k_proj
v_proj
но изменились:
attention mask
position encoding
cache semantics
normalization order
gating
Математика уже другая.
Поэтому нельзя автоматически поддержать модель только по именам tensors.
MoE добавляет:
router
experts
shared experts
top-k selection
routing weights
Runtime должен точно повторять reference implementation.
Ошибка в router normalization или expert ordering способна полностью изменить результат.
Современные модели могут сочетать:
full attention
+
linear/recurrent layers
+
MoE
Тогда нужно поддержать не только forward, но и:
prefill state
decode state
context reuse
rollback
speculative decoding
batching
Это существенно сложнее обычной Llama-подобной архитектуры.
Основная модель может уже поддерживаться, а MTP — ещё нет.
Для MTP нужно дополнительно:
загрузить MTP weights
создать draft context
реализовать speculative verification
управлять cache/state
Поэтому support основной модели и support её MTP-режима — не обязательно одно и то же.
Если появилась новая характеристика:
num_experts_per_token
state_size
attention interval
MTP depth
нужно:
добавить metadata key
↓
научить converter записывать его
↓
научить runtime читать
↓
использовать в graph
GGUF converter и implementation архитектуры связаны.
Это важный концептуальный момент.
GGUF не хранит произвольный executable computation graph.
Он хранит:
architecture id
metadata
tensors
tokenizer
А код самой архитектуры находится в llama.cpp.
То есть:
GGUF
≠
полное описание программы модели
Это даёт:
оптимизированные kernels
контроль памяти
fused operations
architecture-specific fast paths
CPU portability
CUDA/Metal tuning
Цена — необходимость вручную добавлять новые архитектуры.
Vendor может написать:
class NewModelForCausalLM(...)
и реализовать forward() на PyTorch.
Низкоуровневые tensor operations выполняет PyTorch.
llama.cpp переводит модель в собственный GGML graph, поэтому интеграция требует больше ручной работы.
После того как architecture добавлена, пользователь получает:
CPU inference
GPU offload
quantized kernels
mmap
GGUF
llama-server
multiple backends
без обязательного Python/PyTorch runtime.
Для качественной квантизации лучше идти:
BF16/FP16
↓
Q4
а не:
Q8
↓
Q4
и тем более не:
Q4
↓
другой Q4
Повторное квантование накапливает ошибку.
Если исходный вес:
0.137842
после Q4 стал:
0.125
то при Q4 → Q5 исходное значение уже потеряно.
Новый формат точнее представит 0.125, но не восстановит 0.137842.
Поэтому хороший quant-maker использует original high-precision weights.
Не обязательно.
Классическая GGUF quantization может выполняться на CPU.
Главные ограничения:
RAM
disk
time
Большая модель требует много временного места: исходные BF16 weights, BF16 GGUF и финальный quant могут одновременно занимать сотни гигабайт.
Самостоятельная quantization полезна, если:
Допустим компания дообучила:
Qwen3-14B
на внутренних данных.
Architecture уже поддерживается llama.cpp.
Pipeline:
private HF checkpoint
↓
convert_hf_to_gguf.py
↓
BF16 GGUF
↓
llama-quantize
↓
private Q4_K_M.gguf
Никакой помощи автора Qwen не требуется.
Потому что quant-maker уже потратил:
bandwidth
disk
RAM
compute
calibration
benchmarking
upload
Пользователь получает:
download
↓
llama-server -m model.gguf
Для массового использования это рациональнее.
Практически:
config.jsonНапример:
"architectures": ["Qwen3ForCausalLM"]
python convert_hf_to_gguf.py ./model
Если architecture неизвестна, converter сообщит об этом.
Посмотреть:
source
issues
PR
release notes
Если reputable quant-makers уже публикуют рабочие GGUF, архитектура почти наверняка поддерживается хотя бы свежим llama.cpp.
masterМодель могла получить поддержку вчера.
Старый бинарник может сказать:
unknown model architecture
unsupported tensor
unsupported operator
Хотя сам GGUF корректный.
Часто решение:
git pull
cmake --build ...
То есть обновить llama.cpp.
Даже если файл содержит:
architecture = newmodel
старый runtime не знает, что означает:
newmodel
GGUF хранит данные и metadata, а не C++/CUDA-код выполнения модели.
Условно:
Model vendor
│
├─ проектирует architecture
├─ обучает weights
└─ публикует HF checkpoint
│
▼
Runtime developers/community
│
├─ Transformers
├─ llama.cpp
├─ vLLM
├─ SGLang
└─ ExLlama
│
▼
Quant makers
│
├─ GGUF
├─ EXL3
├─ AWQ
├─ GPTQ
└─ другие formats
│
▼
End user
Роли могут пересекаться.
Unsloth — это не просто:
«ребята, которые умеют вызвать llama-quantize»
Их работа может включать:
поддержку новых моделей
conversion
dynamic recipes
calibration
mixed tensor quantization
benchmarking
MTP variants
документацию
массовую публикацию artifacts
То есть это скорее:
quantization engineering + distribution
Вот здесь:
HF architecture неизвестна llama.cpp
и особенно если модель использует новые operations или state semantics.
Тогда нужно читать:
modeling_*.py
понимать forward() и переносить его в GGML/C++.
Это уже inference-engine development.
Как только architecture поддержана:
HF checkpoint
↓
convert_hf_to_gguf.py
↓
BF16 GGUF
↓
llama-quantize
↓
Q4/Q5/IQ/...
Это вполне нормальная пользовательская процедура.
Есть:
Alex/Qwen3-Coder-14B-Finetune
Внутри:
Qwen3ForCausalLM
llama.cpp уже поддерживает Qwen3.
Тогда пользователь может сам сделать GGUF без изменения llama.cpp.
Есть:
Startup/NewRecurrentMoE-40B
Внутри:
NewRecurrentMoEForCausalLM
и новые:
recurrent operator
expert routing
cache state
Тогда conversion невозможен до появления runtime support.
Сначала:
реализовать NewRecurrentMoE
и только потом обсуждать:
Q4_K_M
IQ4_NL
Q5_K_M
Название:
Qwen3
→ Qwen3.6
может выглядеть как небольшой update.
Но если внутри поменялись:
attention
recurrent blocks
MoE
MTP
это уже новая работа для runtime.
Близость названий ничего не гарантирует.
Не спрашивать:
«Можно ли эту модель квантовать?»
Лучше два вопроса:
Может ли llama.cpp выполнить эту architecture?
Если нет — сначала разработка.
Если может, какой quant выбрать?
Это уже обычная пользовательская/quantization задача.
Само GGUF-квантование не является закрытой процедурой для разработчиков моделей.
Если architecture уже поддерживается, обычный пользователь вполне может самостоятельно:
Hugging Face checkpoint
→ GGUF
→ Q4_K_M
→ llama-server
Сложность начинается раньше — когда llama.cpp ещё не умеет выполнять саму архитектуру.
Тогда требуется не другой quantizer, а полноценная реализация модели в runtime.
А между этими уровнями существует отдельная специализация quant engineers: люди и команды, которые делают calibration, imatrix, mixed precision и model-specific recipes вроде Unsloth Dynamic.
Главная формулировка:
Добавление новой архитектуры в llama.cpp — работа runtime-разработчиков и community. Квантование уже поддержанной архитектуры — обычная пользовательская процедура. Создание действительно хорошего model-specific quant recipe — отдельная инженерная задача.
llama.cpp:
https://github.com/ggml-org/llama.cpp
HF → GGUF converter:
https://github.com/ggml-org/llama.cpp/blob/master/convert_hf_to_gguf.py
HOWTO по добавлению новой архитектуры:
https://github.com/ggml-org/llama.cpp/blob/master/docs/development/HOWTO-add-model.md
llama-quantize:
https://github.com/ggml-org/llama.cpp/blob/master/tools/quantize/README.md
Unsloth Dynamic 2.0:
https://unsloth.ai/blog/dynamic-v2