Transformers тепер запускає квантизовані моделі llama.cpp
from_pretrained і почніть генерувати на власному комп’ютері.
Запуск моделей ШІ на ноутбуці став набагато простішим, і llama.cpp відіграв у цьому важливу роль. Його рушій інференсу забезпечує роботу таких локальних інструментів ШІ, як Ollama, LM Studio та Jan. Поряд із проєктами на кшталт MLX він допоміг зробити локальний інференс практичним варіантом для повсякденного використання.
Нещодавній приклад того, як може відчуватися локальний ШІ:
Ось де ми зараз. І, чесно кажучи, це здається справжньою магією 🧙♀️
— Julien Chaumond (@julien_c) 24 квітня 2026 року
Qwen3.6 27B працює всередині агента для програмування Pi через Llama.cpp на MacBook Pro
Для нетривіальних завдань у кодових базах @huggingface це дуже, дуже близько до використання найновішої версії Opus у Claude… pic.twitter.com/lsIxLoUneU
GGUF, розроблений командою llama.cpp, — широко використовуваний формат для локального інференсу. Команда також публікує квантизовані контрольні точки в ggml-org на Hub. Такі видавці, як Unsloth, LM Studio Community і bartowski, також надають готові до використання контрольні точки GGUF із різними рівнями квантизації, тож користувачі можуть вибрати версію, яка підходить їхній машині. Моделі GGUF завантажували мільйони разів.
Ми також хочемо спростити локальний запуск цих моделей за допомогою transformers. Сумісність корисна лише тоді, коли модель зручно запускати. Щоб наблизити продуктивність до llama.cpp, ми повторно використовуємо базові ядра ggml через бібліотеку kernels і зменшуємо накладні витрати в generate. Спочатку ми зосередилися на локальному інференсі на Apple Silicon, починаючи з архітектури Qwen3.5.
Що таке формат файлів GGUF?
GGUF пакує ваги моделі й метадані, зокрема інформацію про токенізатор і необов’язковий шаблон чату, в один файл. Він підтримує різні рівні квантизації, даючи змогу обміняти частину точності на менший обсяг пам’яті. Варіанти на кшталт Q4_K_M поєднують різну точність тензорів, використовуючи переважно 4-бітні ваги, водночас зберігаючи чутливі тензори з вищою точністю.
Ось як квантизація змінює розмір файлу Qwen3.5-4B від Unsloth:
| Варіант GGUF | Розмір файлу | Компроміс |
|---|---|---|
BF16 |
8.42 GB | Неквантизований еталон |
Q6_K |
3.53 GB | Більша точність, ніж у менших варіантів |
Q5_K_M |
3.14 GB | Компроміс між розміром і точністю |
Q4_K_M |
2.74 GB | Практична відправна точка для локального інференсу |
Ми радимо почати з Q4_K_M, а потім спробувати Q5_K_M або Q6_K, якщо у вас доступно більше пам’яті. Агресивніша квантизація може допомогти вмістити більші моделі, але компроміс щодо якості залежить від моделі та завдання. Оцінюйте її на тій роботі, для якої ви насправді хочете використовувати модель. У документації Hub щодо GGUF описано доступні типи квантизації.
Завантаження GGUF за допомогою transformers
Для початку вам потрібно:
- Mac на Apple Silicon.
- Версія PyTorch, підтримувана опублікованими збірками ядра ggml-quantization, зазвичай — два найновіші релізи PyTorch.
- Найновіша версія transformers (поки що main, до наступного релізу) і сумісна версія
kernels.
pip install -U "git+https://github.com/huggingface/transformers.git" kernels
Щоб завантажити модель GGUF, передайте її model_id на Hub і назву файлу як gguf_file у from_pretrained.
Додаткова конфігурація не потрібна: коли ваги залишаються запакованими на Metal, transformers автоматично завантажує сумісні ядра рівня ggml/Metal і використовує ggml-org/ggml-attn як реалізацію механізму уваги. Якщо це ядро неможливо отримати, модель переходить до "sdpa" з попередженням, а ви завжди можете примусово вибрати "sdpa", явно передавши attn_implementation="sdpa". Додаткові варіанти завантаження описано в документації GGUF.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "unsloth/Qwen3.5-4B-GGUF"
filename = "Qwen3.5-4B-Q4_K_M.gguf"
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
model = AutoModelForCausalLM.from_pretrained(
model_id,
gguf_file=filename
)
Це єдиний специфічний для GGUF крок. Усе після нього — стандартний API transformers:
messages = [{"role": "user", "content": "Explain why the sky is blue in a few sentences."}]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_dict=True,
return_tensors="pt",
).to(model.device)
with torch.inference_mode():
outputs = model.generate(**inputs, max_new_tokens=256)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Без сумісного ядра квантизації завантажувач переходить до деквантизації моделі й використовує більше пам’яті.
Запускайте GGUF через бажаний інтерфейс
Ви також можете використовувати ту саму контрольну точку з transformers serve, який надає API, сумісний з OpenAI:
pip install -U "transformers[serving] @ git+https://github.com/huggingface/transformers.git" kernels
transformers serve "unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf"
Аргумент моделі використовує формат <model_id>:<filename>.gguf: до двокрапки вказано репозиторій Hub (unsloth/Qwen3.5-4B-GGUF), а після неї — файл для завантаження (Qwen3.5-4B-Q4_K_M.gguf). Це дає змогу вибрати конкретний рівень квантизації з репозиторію, який може містити кілька варіантів.
Для моделей, чиї шаблони чату підтримують міркування, додайте --reasoning off, щоб пропустити його, або --reasoning on, щоб увімкнути. Значення за замовчуванням, --reasoning auto, дотримується налаштувань шаблону чату за замовчуванням. Докладніше дивіться в описі параметрів міркування.
Ви можете під’єднати такий клієнт, як Jan або Pi, додавши власного постачальника, сумісного з OpenAI, із такими налаштуваннями:
| Налаштування | Значення |
|---|---|
| Базова URL-адреса | http://localhost:8000/v1 |
| ID моделі | unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf |
transformers запускає модель на вашому Mac, а клієнт надає інтерфейс для спілкування. Цю саму кінцеву точку можуть використовувати інші клієнти, які підтримують цей API.
Порівняння з llama.cpp
Нашим орієнтиром для продуктивності локального інференсу є llama.cpp. Наведене нижче порівняння зосереджене на трьох контрольних точках GGUF: невеликій щільній моделі, більшій щільній моделі та моделі суміші експертів.
Стовпець llama.cpp отримано за допомогою інструмента llama-bench (збірка 5f55650a7, реліз b10200, бекенд Metal із ggml 0.18.0), запущеного як llama-bench -m <file> -p 0 -n 128 -r 3, який повідомляє tg128: швидкість генерації токенів для 128 декодованих токенів, усереднену за трьома повторами, без урахування обробки промпту. У стовпці transformers наведено результати generate для створення тих самих 128 токенів із 12-токенного промпту; використано найкращий із трьох прогрітих запусків, включно з попереднім заповненням.
Вимірювання виконано на MacBook Pro M2 Max із 32 ГБ об’єднаної пам’яті, macOS 26.6, PyTorch 2.12.1, kernels 0.17.0, підключеному до живлення.
Скрипт бенчмаркуimport time
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id, filename = "unsloth/Qwen3.5-4B-GGUF", "Qwen3.5-4B-Q4_K_M.gguf"
model = AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename)
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
inputs = tokenizer("The capital of France is Paris. The capital of Germany is", return_tensors="pt")
inputs = inputs.to(model.device)
with torch.inference_mode():
model.generate(**inputs, max_new_tokens=8, min_new_tokens=8, do_sample=False)
torch.mps.synchronize()
for _ in range(3):
time.sleep(90)
start = time.perf_counter()
model.generate(**inputs, max_new_tokens=128, min_new_tokens=128, do_sample=False)
torch.mps.synchronize()
print(f"{128 / (time.perf_counter() - start):.1f} tok/s")
Для іншого стовпця:
llama-bench -hf unsloth/Qwen3.5-4B-GGUF:Q4_K_M -p 0 -n 128 -r 3
Transformers близький до llama.cpp на всіх трьох контрольних точках. На графіку використано ті самі вимірювання, описані вище; він не означає ідентичних умов бенчмарку, оскільки вимірювання Transformers включає попереднє заповнення, тоді як llama-bench повідомляє пропускну здатність лише декодування.
transformers і llama.cpp
Коли GGML і llama.cpp приєдналися до Hugging Face, ми описали їхні взаємодоповнювальні ролі: llama.cpp забезпечує основу для локального інференсу, тоді як transformers — основу для визначення моделей. Підтримка GGUF зближує ці два проєкти.
llama.cpp залишається рекомендованим нами рушієм, якщо вашим пріоритетом є ефективний локальний інференс. Його спеціалізоване середовище виконання, керування пам’яттю та широка підтримка апаратного забезпечення створені саме для цієї мети. Ця інтеграція дає розробникам зручний спосіб працювати з тими самими контрольними точками GGUF усередині transformers:
- Експериментуйте з GGUF у Python і PyTorch. Переглядайте проміжні активації за допомогою хуків, змінюйте прямий прохід моделі або створюйте прототипи власних шарів за допомогою знайомих інструментів PyTorch.
- Оцінюйте моделі GGUF. Використовуйте наявні робочі процеси оцінювання transformers, щоб вимірювати якість квантизованих контрольних точок.
- Перевіряйте конвертації GGUF. Для нас як розробників завантаження оригінальної контрольної точки та її конвертованої версії GGUF у transformers спрощує перевірку правильності конвертації ваг з урахуванням похибки квантизації.
- Випробовуйте нові ідеї декодування. Використовуйте власні обробники логітів і критерії зупинки з
generateабо напишіть власний цикл генерації на Python. - Дообучайте з контрольної точки GGUF. Деквантизуйте ваги та продовжуйте роботу за стандартним робочим процесом навчання transformers.
Для останнього випадку використовуйте GgufConfig(dequantize=True):
import torch
from transformers import AutoModelForCausalLM, GgufConfig
model = AutoModelForCausalLM.from_pretrained(
"unsloth/Qwen3.5-4B-GGUF",
gguf_file="Qwen3.5-4B-Q4_K_M.gguf",
quantization_config=GgufConfig(dequantize=True),
dtype=torch.bfloat16,
)
Поза межами GGUF: ядра ggml для більшої кількості моделей
Більша можливість полягає в тому, щоб перенести продуктивність ggml на моделі, які llama.cpp не підтримує.
transformers уже надає реалізації цих архітектур на PyTorch. Завдяки доступності ядер ggml і схем квантизації в PyTorch ми можемо працювати над прискоренням підтримуваних ними операцій, не реалізуючи спочатку всю модель у llama.cpp. Це особливо корисно для нових архітектур, дослідницьких моделей і власних варіантів, які можуть ніколи не отримати спеціалізованої реалізації в llama.cpp.
Ця можливість виходить за межі самого формату GGUF. Ядро працює з тензорами; воно не вимагає, щоб уся модель походила з файлу GGUF. Ті самі будівельні блоки можна інтегрувати в інші моделі transformers і робочі процеси завантаження. Це також відкриває шлях до інших модальностей: моделі комп’ютерного зору, аудіомоделі та мультимодальні моделі могли б повторно використовувати сумісні ядра уваги, нормалізації та матричного множення, не потребуючи спочатку повної реалізації в llama.cpp. Кожна архітектура все одно потребує інтеграції та перевірки; початкові приклади GGUF тут охоплюють генерацію тексту.
Швидкий локальний інференс із Python і PyTorch
Ми також хотіли показати, яких результатів можна досягти, залишаючи модель і цикл генерації в Python. З правильними ядрами та ефективним циклом генерації Python і PyTorch можуть забезпечити високу продуктивність локального інференсу. Ядра виконують важкі обчислення, а цикл генерації підтримує завантаженість GPU, уникаючи непотрібної синхронізації.
Ми зосередилися на тому, щоб зробити жадібне виконання швидким без потреби в torch.compile. Для інтерактивного використання ми прагнули забезпечити швидкий запуск і стабільний потік токенів без пауз на компіляцію чи повторну компіляцію в разі зміни форм вхідних даних. Два основні компоненти цієї роботи — ядра та сам generate.
Повторне використання ядер Metal від ggml
Ядро — це невелика програма, яка виконує операцію на GPU. PyTorch надає реалізації загального призначення; спеціалізоване ядро може виконувати менше роботи, поєднувати кілька операцій або безпосередньо читати квантизовані ваги в збереженому форматі.
Бібліотека kernels дає нам змогу поширювати сумісні збірки ядер Metal від ggml на Hub і викликати їх із transformers. Це переносить напрацювання ggml у модель PyTorch, не замінюючи модель окремим середовищем виконання для інференсу.
| Ядро | Що воно робить |
|---|---|
ggml-quantization |
Зчитує запаковані квантизовані ваги для матричних операцій, зокрема вибраних експертів у моделі MoE. Воно не дає розгортати всю матрицю ваг перед кожною операцією декодування. |
ggml-norm |
Об’єднує операції нормалізації, зокрема RMSNorm із нульовим центруванням, який використовують Qwen3.5 і Qwen3.8. |
ggml-attn |
Надає механізм flash attention від ggml для обробки промпту та декодування токенів. |
ggml-gated-delta-net |
Прискорює gated delta network, який використовується в шарах лінійної уваги гібридних архітектур Qwen3.5 і Qwen3.8. |
topk |
Вибирає експертів для кожного токена в моделі MoE, поєднуючи маршрутизацію softmax і top-k. Це наша власна реалізація для Metal. |
Перші чотири пакети ґрунтуються на ядрах ggml; ядро top-k усуває окреме вузьке місце в маршрутизації MoE. Разом вони зменшують обсяг роботи GPU, необхідний для кожного згенерованого токена.
Щоб показати внесок ядер шарів, ми порівнюємо ті самі запаковані контрольні точки GGUF із ними та без них. Ядро квантизації ввімкнене в обох конфігураціях: його вимкнення також змінило б спосіб представлення ваг і вимірювало б інший компроміс.
Злагоджена робота CPU і GPU
Швидші ядра допомагають лише тоді, коли GPU має роботу. Під час генерації CPU планує операції GPU та керує циклом, який створює наступний токен. Зчитування результату з GPU може змусити CPU чекати завершення операцій у черзі. Навіть невелике очікування для кожного токена може помітно знизити пропускну здатність.
Це усувають дві зміни в generate, які покращують роботу всіх моделей transformers, а не лише під час запуску файлів GGUF:
- Раннє видалення непотрібної маски уваги (#48814). Коли підтримуваний вхід для декодера без паддінгу не містить заповнення, його маску заповнення, що складається лише з одиниць, можна видалити на початку генерації. Подальшому коду уваги більше не потрібно щоразу перевіряти цю маску, щоб визначити, чи можна її пропустити. Причинна увага при цьому зберігається.
- Відкладена перевірка зупинки (#47975). На підтримуваних шляхах
generateасинхронно копіює рішення про зупинку та використовує його на наступному кроці. CPU може продовжувати планувати роботу, поки працює GPU. Для потокових токенів використовується такий самий підхід, а будь-який додатковий крок після умови зупинки видаляється з результату.
Ці зміни покращують цикл генерації навколо моделі, тому їхня користь виходить за межі GGUF. Вони доповнюють роботу над ядрами: ядра зменшують вартість операції, а менша кількість точок синхронізації дає змогу накладати планування CPU та виконання GPU.
У цих вимірюваннях усі ядра шарів увімкнено; стовпці ізольовано показують зміни в циклі генерації.
Поточні обмеження та наступні кроки
Початкова мета — одна інтерактивна розмова на Apple Silicon. Варто пам’ятати про кілька обмежень:
- Запакований шлях інференсу наразі доступний лише для MPS. Імпорт GGUF через деквантизацію залишається окремою опцією; підтримка формату файлів не означає, що запаковані ядра доступні на кожному пристрої.
- Потрібно ще попрацювати над паддінгом і пакетною обробкою. Незаповнені входи отримують перевагу від описаної вище оптимізації маски. Заповнені пакети не можуть скористатися тим самим спрощенням і можуть мати нижчу продуктивність. Ми хочемо поширити цю роботу на
generate_batchу MPS. - Підтримка архітектур обмежена. Запакований завантажувач наразі охоплює щільну архітектуру Qwen3.5 і архітектуру MoE, зокрема сумісні контрольні точки Qwen3.8. Додати підтримку інших архітектур відносно просто, і ми поступово розширюватимемо охоплення.
Якщо у вас є модель GGUF, яку ви хотіли б використовувати в transformers, створіть issue, указавши контрольну точку та ваш сценарій використання. Це допоможе нам визначити пріоритети підтримки моделей, які люди запускають локально.
Подяки
Ми хотіли б подякувати Arthur Zucker за започаткування цієї роботи та перевірку всіх моїх PR, а також Cyril Vallez за PR, пов’язані з generate. Ми вдячні Sayak Paul, команді llama.cpp та Bertrand Chevalier за допомогу в інтеграції ядер. Ми також дякуємо Aritra Roy Gosthipaty і Pedro Cuenca за перевірку цієї публікації в блозі, а також Lysandre Debut за керівництво проєктом.
Моделі, згадані в цій статті 1
Спільнота
· Зареєструйтеся або увійдіть, щоб залишити коментар
Моделі, згадані в цій статті 1
Перекладено автоматично з англійської. Оригінал статті — за посиланням нижче.