Как модель попадает из Hugging Face в GGUF: архитектура, конвертация и квантование

Когда пользователь видит команды:

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.

Это два совершенно разных уровня работы.


1. Весь pipeline

Разработчик модели
        ↓
публикует 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

2. Название модели и архитектура — не одно и то же

Могут существовать:

CompanyA-Coder-32B
CompanyB-Reasoner-32B
My-Finetune-32B

но все они использовать:

Qwen3ForCausalLM

или:

LlamaForCausalLM

У них разные веса и обучение, но один вычислительный граф.

Для inference engine это принципиально: если архитектура уже реализована, новые checkpoints этой архитектуры обычно можно конвертировать без изменения исходного кода llama.cpp.


3. Что runtime должен знать об архитектуре

Чтобы выполнить forward pass, llama.cpp должен понимать:

какие tensors существуют
как устроены layers
как считать attention
как считать MLP
как устроен MoE
какие normalization используются
как работает RoPE
сколько attention heads
сколько KV heads
как работает router
есть ли recurrent state
есть ли MTP/NextN

Одного набора чисел в .safetensors недостаточно.

Runtime должен знать, какие математические операции делать с этими весами.


4. Почему нельзя просто взять любую модель из Transformers

Hugging Face Transformers может загрузить:

{
  "architectures": ["SomeNewModelForCausalLM"]
}

и вызвать Python-класс модели с его forward().

llama.cpp не исполняет этот Python-код.

Он реализует модель самостоятельно через GGML/C++.

Поэтому если появляется совершенно новая:

SuperNewArchitectureForCausalLM

скрипт конвертации не может автоматически вывести из .safetensors, как работает новый attention, recurrent block или MoE router.

Нужна ручная реализация архитектуры.


5. Что делает 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 может быть намного хитрее простого переименования.


6. Что происходит, если architecture неизвестна

Допустим:

{
  "architectures": ["MegaDeltaMoEForCausalLM"]
}

а converter не знает такой модели.

Conversion завершится ошибкой уровня:

Model MegaDeltaMoEForCausalLM is not supported

Никакой:

--outtype q4_K_M

не решит проблему.

Проблема не в битности весов, а в отсутствии реализации модели в runtime.


7. Добавление новой архитектуры — уже разработка llama.cpp

Если вычислительный граф действительно новый, нужно пройти путь примерно такого вида:

Transformers implementation
        ↓
анализ архитектуры
        ↓
GGUF metadata
        ↓
tensor mapping
        ↓
model loader
        ↓
GGML compute graph
        ↓
CPU/CUDA/Metal/etc.
        ↓
tests

Это уже не пользовательская операция.


8. Что приходится добавлять для новой модели

Обычно нужны:

Architecture type

Runtime должен отличать новый тип модели.

Metadata

Например:

number of experts
experts per token
state dimensions
attention pattern
rope parameters

Tensor mapping

HF tensor X
→
GGUF tensor Y

Compute graph

Самая важная часть:

как из входных hidden states и tensors получить следующий hidden state

Новые операции

Если модель использует новый mathematical primitive, возможно, его ещё нет в GGML — тогда добавляется и он.


9. Новая модель не всегда означает новую архитектуру

Допустим завтра выходит:

AmazingCoder-32B

но внутри:

Qwen3ForCausalLM

Если tensor layout совместим с уже реализованным Qwen3, новая поддержка llama.cpp не требуется.

Обычный пользователь может:

HF checkpoint
↓
BF16 GGUF
↓
Q4_K_M

10. Fine-tune обычно не требует новой поддержки

Если было:

Qwen3-32B

и его дообучили:

SFT
DPO
RLHF
continued pretraining
merged LoRA

архитектура обычно остаётся прежней.

Изменяются веса, а не вычислительный граф.

Поэтому private fine-tune на уже поддерживаемой архитектуре — типичный случай, когда пользователь совершенно нормально квантирует модель сам.


11. Когда fine-tune может перестать быть совместимым

Если авторы изменили не только веса, но и структуру:

добавили новые experts
изменили attention
добавили recurrent layers
добавили новый MTP module
изменили tensor layout

это уже может потребовать изменений converter/runtime.

Ключевой вопрос:

изменились только параметры или сам вычислительный граф?


12. Правильный pipeline: HF → BF16 GGUF

Первый этап:

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 высокой точности.


13. Потом: BF16 GGUF → quantized 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.


14. Почему conversion и quantization разделены

У них разные задачи.

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/...

15. Почему 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 работает сразу для множества архитектур.


16. Но quantizer не полностью «слеп к архитектуре»

Хороший recipe учитывает, что разные tensors имеют разную чувствительность:

attention
output head
embedding
expert
router
shared expert

Некоторые tensors:

  • квантуются более точно;
  • получают другой datatype;
  • иногда не квантуются вовсе.

Но это всё равно намного проще, чем реализовать полный forward graph.


17. Обычный пользователь вполне может делать Q4 сам

Если архитектура уже поддерживается:

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 здесь не нужно.


18. Тогда зачем существуют Unsloth и другие quant-makers

Потому что:

сделать Q4_K_M

и:

сделать лучший quant при заданном размере

— разные задачи.

Можно просто применить generic recipe.

А можно исследовать sensitivity и сделать mixed quant:

attention → выше precision
experts → ниже precision
output head → выше precision
часть gates → почти lossless

При похожем размере второй вариант может сохранить больше качества.


19. Importance matrix

Для более качественного квантования можно собрать statistics на calibration data.

Идея:

какие направления weights реально важны

оцениваются по активациям модели.

В llama.cpp для этого существует механизм imatrix.

Условно:

BF16 model
+
calibration text
↓
llama-imatrix
↓
importance data
↓
llama-quantize
↓
importance-aware GGUF

Это уже продвинутый workflow.


20. Зачем calibration data

Представим:

Tensor A:
ошибка quant почти не влияет на logits

Tensor B:
даже маленькая ошибка сильно влияет

Квантизовать их одинаково не всегда разумно.

Можно выгоднее распределить битовый бюджет:

A → агрессивнее
B → точнее

И получить лучшее качество при том же среднем размере.


21. Что делает Unsloth Dynamic

Unsloth Dynamic использует модель-специфический mixed recipe.

Идея:

разные layers/tensors
→ разная sensitivity
→ разная precision

Поэтому появляются:

UD-Q4_K_M
UD-IQ4_NL
UD-Q4_K_XL

Это не просто прямой вызов обычного Q4_K_M.


22. Ценность Unsloth не в том, что «только они умеют сделать GGUF»

Обычный Q4 способен сделать любой пользователь.

Ценность quant-maker-а скорее в:

calibration
benchmarking
mixed recipes
tensor overrides
quality testing
automation
publication
compatibility checking

То есть это отдельная инженерная специализация.


23. Три уровня сложности

Уровень 1 — пользователь

поддерживаемый HF checkpoint
→ BF16 GGUF
→ Q4_K_M

Программирование runtime не требуется.

Уровень 2 — quant engineer

imatrix
tensor sensitivity
mixed precision
KL/perplexity
dynamic recipe

Это уже оптимизация качества на бит.

Уровень 3 — runtime developer

новая architecture
→ converter
→ metadata
→ graph
→ kernels
→ cache/state
→ tests

Вот это полноценная разработка llama.cpp.


24. Кто добавляет новую архитектуру

Не обязательно vendor модели.

Это может быть:

автор модели
maintainer llama.cpp
community contributor
Unsloth
независимый разработчик
другая компания

Кто первым реализует корректную поддержку и доведёт её до merge.


25. Почему vendor-у выгодно это делать

Open-weight модель гораздо проще распространять, если она быстро работает в:

Transformers
llama.cpp
vLLM
SGLang
MLX
ExLlama

Поэтому крупные model vendors всё чаще помогают runtime ecosystem ещё до или сразу после релиза.

Но это не обязательное правило.


26. Community часто делает поддержку сама

Если модель популярна, после релиза быстро появляются:

runtime patches
GGUF converters
quant repositories
benchmark reports

Если архитектура похожа на существующую, процесс быстрый.

Если внутри новый recurrent/attention mechanism — намного сложнее.


27. Почему похожие tensor names ничего не гарантируют

Допустим остались:

q_proj
k_proj
v_proj

но изменились:

attention mask
position encoding
cache semantics
normalization order
gating

Математика уже другая.

Поэтому нельзя автоматически поддержать модель только по именам tensors.


28. Особый случай: MoE

MoE добавляет:

router
experts
shared experts
top-k selection
routing weights

Runtime должен точно повторять reference implementation.

Ошибка в router normalization или expert ordering способна полностью изменить результат.


29. Особый случай: hybrid/recurrent model

Современные модели могут сочетать:

full attention
+
linear/recurrent layers
+
MoE

Тогда нужно поддержать не только forward, но и:

prefill state
decode state
context reuse
rollback
speculative decoding
batching

Это существенно сложнее обычной Llama-подобной архитектуры.


30. Особый случай: MTP / NextN

Основная модель может уже поддерживаться, а MTP — ещё нет.

Для MTP нужно дополнительно:

загрузить MTP weights
создать draft context
реализовать speculative verification
управлять cache/state

Поэтому support основной модели и support её MTP-режима — не обязательно одно и то же.


31. Почему converter и runtime развиваются вместе

Если появилась новая характеристика:

num_experts_per_token
state_size
attention interval
MTP depth

нужно:

добавить metadata key
↓
научить converter записывать его
↓
научить runtime читать
↓
использовать в graph

GGUF converter и implementation архитектуры связаны.


32. GGUF не является универсальным байткодом нейросети

Это важный концептуальный момент.

GGUF не хранит произвольный executable computation graph.

Он хранит:

architecture id
metadata
tensors
tokenizer

А код самой архитектуры находится в llama.cpp.

То есть:

GGUF
≠
полное описание программы модели

33. Почему handwritten runtime устроен именно так

Это даёт:

оптимизированные kernels
контроль памяти
fused operations
architecture-specific fast paths
CPU portability
CUDA/Metal tuning

Цена — необходимость вручную добавлять новые архитектуры.


34. Почему Transformers обычно поддерживает новую архитектуру раньше

Vendor может написать:

class NewModelForCausalLM(...)

и реализовать forward() на PyTorch.

Низкоуровневые tensor operations выполняет PyTorch.

llama.cpp переводит модель в собственный GGML graph, поэтому интеграция требует больше ручной работы.


35. Зато после интеграции llama.cpp получает сильные преимущества

После того как architecture добавлена, пользователь получает:

CPU inference
GPU offload
quantized kernels
mmap
GGUF
llama-server
multiple backends

без обязательного Python/PyTorch runtime.


36. Почему нужен исходный BF16/FP16 checkpoint

Для качественной квантизации лучше идти:

BF16/FP16
↓
Q4

а не:

Q8
↓
Q4

и тем более не:

Q4
↓
другой Q4

Повторное квантование накапливает ошибку.


37. Почему нельзя восстановить Q5 из Q4

Если исходный вес:

0.137842

после Q4 стал:

0.125

то при Q4 → Q5 исходное значение уже потеряно.

Новый формат точнее представит 0.125, но не восстановит 0.137842.

Поэтому хороший quant-maker использует original high-precision weights.


38. Нужно ли иметь GPU для обычного GGUF quant

Не обязательно.

Классическая GGUF quantization может выполняться на CPU.

Главные ограничения:

RAM
disk
time

Большая модель требует много временного места: исходные BF16 weights, BF16 GGUF и финальный quant могут одновременно занимать сотни гигабайт.


39. Когда имеет смысл квантовать самому

Самостоятельная quantization полезна, если:

  • нужного quant-а ещё нет;
  • нужен частный fine-tune;
  • нужен нестандартный размер;
  • нужен свой imatrix;
  • модель нельзя публиковать наружу;
  • хочется экспериментировать с tensor recipes;
  • нужен quant сразу после собственного обучения.

40. Private fine-tune — отличный пример

Допустим компания дообучила:

Qwen3-14B

на внутренних данных.

Architecture уже поддерживается llama.cpp.

Pipeline:

private HF checkpoint
↓
convert_hf_to_gguf.py
↓
BF16 GGUF
↓
llama-quantize
↓
private Q4_K_M.gguf

Никакой помощи автора Qwen не требуется.


41. Почему большинство пользователей всё равно скачивают готовый GGUF

Потому что quant-maker уже потратил:

bandwidth
disk
RAM
compute
calibration
benchmarking
upload

Пользователь получает:

download
↓
llama-server -m model.gguf

Для массового использования это рациональнее.


42. Как понять, поддерживается ли модель

Практически:

Посмотреть config.json

Например:

"architectures": ["Qwen3ForCausalLM"]

Попробовать converter

python convert_hf_to_gguf.py ./model

Если architecture неизвестна, converter сообщит об этом.

Проверить llama.cpp repository

Посмотреть:

source
issues
PR
release notes

Проверить наличие свежих GGUF

Если reputable quant-makers уже публикуют рабочие GGUF, архитектура почти наверняка поддерживается хотя бы свежим llama.cpp.


43. Но сторонний GGUF может требовать свежий master

Модель могла получить поддержку вчера.

Старый бинарник может сказать:

unknown model architecture
unsupported tensor
unsupported operator

Хотя сам GGUF корректный.

Часто решение:

git pull
cmake --build ...

То есть обновить llama.cpp.


44. Почему GGUF сам не приносит реализацию архитектуры

Даже если файл содержит:

architecture = newmodel

старый runtime не знает, что означает:

newmodel

GGUF хранит данные и metadata, а не C++/CUDA-код выполнения модели.


45. Экосистема ролей

Условно:

Model vendor
│
├─ проектирует architecture
├─ обучает weights
└─ публикует HF checkpoint
        │
        ▼
Runtime developers/community
│
├─ Transformers
├─ llama.cpp
├─ vLLM
├─ SGLang
└─ ExLlama
        │
        ▼
Quant makers
│
├─ GGUF
├─ EXL3
├─ AWQ
├─ GPTQ
└─ другие formats
        │
        ▼
End user

Роли могут пересекаться.


46. Где здесь Unsloth

Unsloth — это не просто:

«ребята, которые умеют вызвать llama-quantize»

Их работа может включать:

поддержку новых моделей
conversion
dynamic recipes
calibration
mixed tensor quantization
benchmarking
MTP variants
документацию
массовую публикацию artifacts

То есть это скорее:

quantization engineering + distribution

47. Где начинается работа «не для простых смертных»

Вот здесь:

HF architecture неизвестна llama.cpp

и особенно если модель использует новые operations или state semantics.

Тогда нужно читать:

modeling_*.py

понимать forward() и переносить его в GGML/C++.

Это уже inference-engine development.


48. Где остаётся обычный пользовательский workflow

Как только architecture поддержана:

HF checkpoint
↓
convert_hf_to_gguf.py
↓
BF16 GGUF
↓
llama-quantize
↓
Q4/Q5/IQ/...

Это вполне нормальная пользовательская процедура.


49. Практический пример: новый fine-tune Qwen

Есть:

Alex/Qwen3-Coder-14B-Finetune

Внутри:

Qwen3ForCausalLM

llama.cpp уже поддерживает Qwen3.

Тогда пользователь может сам сделать GGUF без изменения llama.cpp.


50. Практический пример: совершенно новая архитектура

Есть:

Startup/NewRecurrentMoE-40B

Внутри:

NewRecurrentMoEForCausalLM

и новые:

recurrent operator
expert routing
cache state

Тогда conversion невозможен до появления runtime support.

Сначала:

реализовать NewRecurrentMoE

и только потом обсуждать:

Q4_K_M
IQ4_NL
Q5_K_M

51. Практический пример: новая версия старой семьи

Название:

Qwen3
→ Qwen3.6

может выглядеть как небольшой update.

Но если внутри поменялись:

attention
recurrent blocks
MoE
MTP

это уже новая работа для runtime.

Близость названий ничего не гарантирует.


52. Самая полезная ментальная модель

Не спрашивать:

«Можно ли эту модель квантовать?»

Лучше два вопроса:

1.

Может ли llama.cpp выполнить эту architecture?

Если нет — сначала разработка.

2.

Если может, какой quant выбрать?

Это уже обычная пользовательская/quantization задача.


53. Итог

Само 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