Квантование моделей Llama с помощью GGML и llama.cpp

Quantization of Llama models using GGML and llama.cpp

GGML против GPTQ против NF4

Изображение автора

Из-за огромного размера моделей естественного языка (LLM), квантование стало неотъемлемой техникой для их эффективного выполнения. Уменьшение точности их весов позволяет сэкономить память и ускорить вывод, сохраняя при этом большую часть производительности модели. Недавно 8-битное и 4-битное квантование открыли возможность выполнения LLM на потребительском оборудовании. В сочетании с выпуском моделей Llama и эффективных по параметрам техник их настройки (LoRA, QLoRA), это создало богатую экосистему локальных LLM, которые теперь конкурируют с GPT-3.5 и GPT-4 от OpenAI.

Помимо неосознанного подхода, рассмотренного в этой статье, существуют три основные техники квантования: NF4, GPTQ и GGML. NF4 – это статический метод, используемый QLoRA для загрузки модели с точностью 4 бита для выполнения настройки. В предыдущей статье мы изучили метод GPTQ и квантовали собственную модель для выполнения на потребительском графическом процессоре (GPU). В этой статье мы познакомимся с методом GGML, узнаем, как квантовать модели Llama, и предоставим советы и хитрости для достижения наилучших результатов.

Вы можете найти код на Google Colab и GitHub.

Что такое GGML?

GGML – это библиотека на языке C, сосредоточенная на машинном обучении. Она была создана Георги Гергановым, отсюда и инициалы “GG”. Эта библиотека предоставляет не только основные элементы для машинного обучения, такие как тензоры, но и уникальный двоичный формат для распространения LLM.

Недавно этот формат был изменен на GGUF. Этот новый формат разработан с учетом возможности расширения, чтобы новые функции не нарушали совместимость с существующими моделями. Он также централизует всю метаданные в одном файле, такие как специальные токены, параметры масштабирования RoPE и т. д. Вкратце, он решает несколько исторических проблем и должен быть готов к будущему. Для получения дополнительной информации вы можете прочитать спецификацию по этому адресу. В остальной части статьи мы будем называть “моделями GGML” все модели, которые используют GGUF или предыдущие форматы.

GGML была разработана для использования вместе с библиотекой llama.cpp, также созданной Георги Гергановым. Библиотека написана на языке C/C++ для эффективного вывода моделей Llama. Она может загружать модели GGML и выполнять их на ЦП. Изначально это было главным отличием от моделей GPTQ, которые загружаются и выполняются на графическом процессоре (GPU). Однако теперь вы можете передать некоторые слои своей LLM на GPU с помощью llama.cpp. Для примера, для модели с 7 млрд параметров есть 35 слоев. Это значительно ускоряет вывод и позволяет выполнять LLM, которые не помещаются в VRAM.

Изображение автора

Если командная строка – это ваше, llama.cpp и поддержка GGUF были интегрированы во многие графические интерфейсы, такие как oobabooga’s text-generation-web-ui, koboldcpp, LM Studio или ctransformers. Вы можете просто загрузить свои модели GGML с помощью этих инструментов и взаимодействовать с ними так же, как с ChatGPT. К счастью, многие квантованные модели уже доступны на Hugging Face Hub. Вы быстро заметите, что большинство из них квантованы TheBloke, популярной фигурой в сообществе LLM.

В следующем разделе мы рассмотрим, как квантовать собственные модели и выполнять их на потребительском графическом процессоре (GPU).

Как квантовать LLM с помощью GGML?

Давайте посмотрим на файлы в репозитории TheBloke/Llama-2–13B-chat-GGML. Мы видим 14 разных моделей GGML, соответствующих разным типам квантования. Они следуют определенной схеме именования: “q” + количество бит, используемых для хранения весов (точность) + определенный вариант. Вот список всех возможных методов квантования и соответствующих им случаев использования, основанный на модельных картах, созданных TheBloke:

  • q2_k: Использует Q4_K для тензоров attention.vw и feed_forward.w2, Q2_K для остальных тензоров.
  • q3_k_l: Использует Q5_K для тензоров attention.wv, attention.wo и feed_forward.w2, иначе Q3_K
  • q3_k_m: Использует Q4_K для тензоров attention.wv, attention.wo и feed_forward.w2, иначе Q3_K
  • q3_k_s: Использует Q3_K для всех тензоров
  • q4_0: Оригинальный метод квантования, 4-битный.
  • q4_1: Более высокая точность, чем q4_0, но не такая высокая, как q5_0. Однако имеет более быстрое выводное значение, чем модели q5.
  • q4_k_m: Использует Q6_K для половины тензоров attention.wv и feed_forward.w2, иначе Q4_K
  • q4_k_s: Использует Q4_K для всех тензоров
  • q5_0: Более высокая точность, более высокое использование ресурсов и более медленное выводное значение.
  • q5_1: Еще более высокая точность, использование ресурсов и более медленное выводное значение.
  • q5_k_m: Использует Q6_K для половины тензоров attention.wv и feed_forward.w2, иначе Q5_K
  • q5_k_s: Использует Q5_K для всех тензоров
  • q6_k: Использует Q8_K для всех тензоров
  • q8_0: Почти неотличимо от float16. Высокое использование ресурсов и медленное. Не рекомендуется для большинства пользователей.

Как правило, я рекомендую использовать Q5_K_M, так как он сохраняет большую часть производительности модели. В качестве альтернативы можно использовать Q4_K_M, если вы хотите сэкономить некоторую память. В целом, версии K_M лучше версий K_S. Я не могу рекомендовать версии Q2 или Q3, так как они значительно снижают производительность модели.

Теперь, когда мы знаем больше о доступных типах квантования, давайте посмотрим, как их использовать на реальной модели. Вы можете выполнить следующий код на бесплатном графическом процессоре T4 в Google Colab. Первый шаг состоит в компиляции llama.cpp и установке необходимых библиотек в нашу среду Python.

# Устанавливаем llama.cpp!git clone https://github.com/ggerganov/llama.cpp!cd llama.cpp && git pull && make clean && LLAMA_CUBLAS=1 make!pip install -r llama.cpp/requirements.txt

Теперь мы можем загрузить нашу модель. Мы будем использовать модель, которую мы настроили в предыдущей статье, mlabonne/EvolCodeLlama-7b.

MODEL_ID = "mlabonne/EvolCodeLlama-7b"# Загружаем модель!git lfs install!git clone https://huggingface.co/{MODEL_ID}

Этот шаг может занять некоторое время. После его завершения нам нужно преобразовать наш вес в формат GGML FP16.

MODEL_NAME = MODEL_ID.split('/')[-1]GGML_VERSION = "gguf"# Преобразовываем в fp16fp16 = f"{MODEL_NAME}/{MODEL_NAME.lower()}.{GGML_VERSION}.fp16.bin"!python llama.cpp/convert.py {MODEL_NAME} --outtype f16 --outfile {fp16}

Наконец, мы можем квантовать модель с использованием одного или нескольких методов. В данном случае, мы будем использовать ранее рекомендованные методы Q4_K_M и Q5_K_M. Этот шаг является единственным, который фактически требует наличия графического процессора.

QUANTIZATION_METHODS = ["q4_k_m", "q5_k_m"]for method in QUANTIZATION_METHODS:    qtype = f"{MODEL_NAME}/{MODEL_NAME.lower()}.{GGML_VERSION}.{method}.bin"    !./llama.cpp/quantize {fp16} {qtype} {method}

Наши две квантованные модели теперь готовы для вывода. Мы можем проверить размер bin-файлов, чтобы увидеть, насколько сжаты они. Модель FP16 занимает 13.5 ГБ, в то время как модель Q4_K_M занимает 4.08 ГБ (в 3.3 раза меньше), а модель Q5_K_M занимает 4.78 ГБ (в 2.8 раза меньше).

Давайте используем llama.cpp, чтобы эффективно запустить их. Поскольку мы используем GPU с 16 ГБ VRAM, мы можем передать каждый слой на GPU. В этом случае это представляет 35 слоев (7b-параметровая модель), поэтому мы будем использовать параметр -ngl 35. В следующем блоке кода мы также введем подсказку и метод квантования, который мы хотим использовать.

import osmodel_list = [file for file in os.listdir(MODEL_NAME) if GGML_VERSION in file]prompt = input("Введите вашу подсказку: ")chosen_method = input("Укажите метод квантования для запуска модели (варианты: " + ", ".join(model_list) + "): ")# Проверяем, что выбранный метод есть в спискеif chosen_method not in model_list:    print("Выбран недопустимый метод!")else:    qtype = f"{MODEL_NAME}/{MODEL_NAME.lower()}.{GGML_VERSION}.{method}.bin"    !./llama.cpp/main -m {qtype} -n 128 --color -ngl 35 -p "{prompt}"

Давайте зададим модели вопрос “Напишите функцию на Python для печати чисел Фибоначчи n-ого порядка” с использованием метода Q5_K_M. Если мы посмотрим на журналы, мы можем подтвердить, что мы успешно передали наши слои благодаря строке “llm_load_tensors: offloaded 35/35 layers to GPU”. Вот код, сгенерированный моделью:

def fib(n):    if n == 0 or n == 1:        return n    return fib(n - 2) + fib(n - 1)for i in range(1, 10):    print(fib(i))

Это не очень сложная подсказка, но она успешно сгенерировала работающий код за мгновение. С помощью этого GGML вы можете использовать свой локальный LLM в качестве помощника в терминале с интерактивным режимом (-i флаг). Обратите внимание, что это также работает на ноутбуках Mac с использованием Metal Performance Shaders (MPS) от Apple, что является отличным вариантом для запуска LLM.

Наконец, мы можем отправить нашу квантованную модель в новый репозиторий на Hugging Face Hub с суффиксом “-GGUF”. Сначала давайте войдем в систему и измените следующий блок кода, чтобы он соответствовал вашему имени пользователя.

!pip install -q huggingface_hubusername = "mlabonne"from huggingface_hub import notebook_login, create_repo, HfApinotebook_login()

Теперь мы можем создать репозиторий и загрузить наши модели. Мы используем параметр allow_patterns, чтобы выбрать, какие файлы загружать, чтобы не загружать всю директорию полностью.

api = HfApi()# Создаем репозиторийcreate_repo(    repo_id=f"{username}/{MODEL_NAME}-GGML",    repo_type="model",    exist_ok=True)# Загружаем бинарные моделиapi.upload_folder(    folder_path=MODEL_NAME,    repo_id=f"{username}/{MODEL_NAME}-GGML",    allow_patterns=f"*{GGML_VERSION}*",)

Мы успешно квантовали, запустили и загрузили модели GGML в Hugging Face Hub! В следующем разделе мы рассмотрим, как на самом деле GGML квантует эти модели.

Квантование с GGML

Способ квантования в GGML не настолько сложный, как в GPTQ. В основном он группирует блоки значений и округляет их до меньшей точности. Некоторые техники, такие как Q4_K_M и Q5_K_M, реализуют более высокую точность для критических слоев. В этом случае каждый вес хранится с точностью 4 бита, за исключением половины тензоров attention.wv и feed_forward.w2. Экспериментально эта смешанная точность демонстрирует хороший баланс между точностью и использованием ресурсов.

Если мы посмотрим в файл ggml.c, мы увидим, как определены блоки. Например, структура block_q4_0 определяется следующим образом:

#define QK4_0 32typedef struct {    ggml_fp16_t d;          // delta    uint8_t qs[QK4_0 / 2];  // полу-байты / кванты} block_q4_0;

В GGML веса обрабатываются блоками, каждый из которых состоит из 32 значений. Для каждого блока масштабный коэффициент (дельта) вычисляется из наибольшего значения веса. Затем все веса в блоке масштабируются, квантуются и эффективно упаковываются для хранения (полу-байты). Этот подход значительно сокращает требования к хранению, позволяя при этом относительно простое и детерминированное преобразование между исходными и квантованными весами.

Теперь, когда мы знаем больше о процессе квантования, мы можем сравнить результаты с NF4 и GPTQ.

NF4 против GGML против GPTQ

Какая техника лучше для 4-битного квантования? Чтобы ответить на этот вопрос, нам нужно представить разные бэкэнды, на которых работают эти квантованные LLM-модели. Для моделей GGML лучше всего использовать llama.cpp с моделями Q4_K_M. Для моделей GPTQ у нас есть два варианта: AutoGPTQ или ExLlama. Наконец, модели NF4 можно запустить непосредственно в трансформаторах с флагом --load-in-4bit.

Oobabooga провел несколько экспериментов в отличной блог-статье, в которой сравнивал разные модели по показателю перплексии (чем ниже, тем лучше):

Исходя из этих результатов, можно сказать, что модели GGML имеют небольшое преимущество по показателю перплексии. Разница не особо значительна, поэтому лучше сосредоточиться на скорости генерации в токенах в секунду. Лучшая техника зависит от вашей видеокарты: если у вас достаточно VRAM для размещения всей квантованной модели, самой быстрой будет GPTQ с ExLlama. Если это не так, вы можете выгрузить некоторые слои и использовать модели GGML с llama.cpp для запуска вашей LLM.

Вывод

В этой статье мы представили библиотеку GGML и новый формат GGUF для эффективного хранения этих квантованных моделей. Мы использовали его для квантования нашей собственной модели Llama в разных форматах (Q4_K_M и Q5_K_M). Затем мы запустили модель GGML и загрузили наши бинарные файлы на платформу Hugging Face Hub. Наконец, мы более подробно изучили код GGML, чтобы понять, как он фактически квантует веса, и сравнили его с NF4 и GPTQ.

Квантование – важный вектор демократизации LLM-моделей путем снижения стоимости их выполнения. В будущем смешанная точность и другие техники будут продолжать улучшать производительность, которую мы можем достичь с помощью квантованных весов. До этого момента надеюсь, что вам понравилась эта статья и вы узнали что-то новое.

Если вас интересует больше технического контента о LLM-моделях, следите за мной на VoAGI.

Статьи о квантовании

Часть 1: Введение в квантование весов

Сокращение размера больших языковых моделей с 8-битным квантованием

towardsdatascience.com

Часть 2: 4-битное квантование с GPTQ

Квантование собственных LLM-моделей с помощью AutoGPTQ

towardsdatascience.com

Узнайте больше о машинном обучении и поддержите мою работу одним кликом – станьте членом VoAGI здесь:

Как член VoAGI, часть вашего членского взноса идет писателям, которых вы читаете, и вы получаете полный доступ ко всем историям…

VoAGI.com