Sakhanda Wire
NVDA $230.86 +1.09% MSFT $512.80 -0.02% GOOGL $338.24 -1.70% META $725.93 +0.10% AMZN $248.23 -0.37%
← К новостям

Transformers теперь запускает квантизированные модели llama.cpp

Transformers теперь поддерживает кванты llama.cpp
Опубликовано 22 сентября 2026 года
Обновить на GitHub
Мы добавляем поддержку эффективного запуска моделей GGUF в transformers, чтобы вы могли использовать контрольные точки, размер которых соответствует памяти вашего ноутбука, через привычные API transformers. Выберите GGUF на Hub, загрузите его с помощью from_pretrained и начните генерацию на своём компьютере.

Запуск ИИ-моделей на ноутбуке стал гораздо проще, и llama.cpp сыграл в этом важную роль. Его механизм инференса лежит в основе таких локальных ИИ-инструментов, как Ollama, LM Studio и Jan. Наряду с проектами вроде MLX он помог сделать локальный инференс практичным вариантом для повседневного использования.

Недавний пример того, каким может быть локальный ИИ:

Вот где мы сейчас находимся. И, честно говоря, это кажется довольно волшебным 🧙‍♀️

Qwen3.6 27B работает внутри агента для программирования Pi через Llama.cpp на MacBook Pro

Для нетривиальных задач в кодовых базах @huggingface это очень, очень близко к использованию последней версии Opus в Claude… pic.twitter.com/lsIxLoUneU

— Julien Chaumond (@julien_c) 24 апреля 2026 года

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 ГБ Неквантованный вариант для сравнения
Q6_K 3.53 ГБ Более высокая точность по сравнению с меньшими вариантами
Q5_K_M 3.14 ГБ Компромисс между размером и точностью
Q4_K_M 2.74 ГБ Практичная отправная точка для локального инференса

Мы рекомендуем начать с 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

Сравнение пропускной способности генерации GGUF с llama.cpp

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, избегая ненужной синхронизации.

Мы стремились сделать выполнение в eager-режиме быстрым без необходимости использовать 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 Metal из 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

Переведено автоматически с английского. Оригинал статьи — по ссылке ниже.

Впервые опубликовано изданием Hugging Face

Читать оригинал на Hugging Face ↗

Текст и изображения принадлежат Hugging Face и приводятся здесь с указанием авторства и ссылкой на оригинальную публикацию.

← К новостям

Ещё новости

Все последние новости