Найпростіший спосіб конвертувати модель у GGUF та квантизувати її

Вітаю, мене звати Демʼєн. Сьогодні хочу обговорити перетворення моделі у формат GGUF. Воно необхідне для сумісності з багатьма inference-системами, як-от Ollama або LocalAI. Заздалегідь перепрошую за ламану мову, оскільки живу майже 10 років у Штатах.

Хоча готові GGUF-файли часто доступні на таких платформах, як Hugging Face, джерело та цілісність цих файлів можуть бути сумнівними. Вони потенційно можуть містити шкідливий код, який хоч і не завдасть безпосередньої шкоди вашому комп’ютеру, але може використати ваш графічний процесор у несанкціонованих цілях.

Треба зазначити, що початкова PyTorch-модель із сумнівних джерел теж може мати вбудований зловмисний код, і конвертація власними силами в GGUF тут вже не допоможе його прибрати. Формат файлу Safetensor саме покликаний розв’язати цю проблему.

Не використовуйте моделі в PyTorch та GGUF-форматах із невідомих джерел.

Quantization

Квантизація — це метод зменшення LLM-моделі та зайнятого нею простору в памʼяті через погіршення якості. Це досягається шляхом округлення значень із плавучою точкою, наприклад 32-бітне значення 0.123456789 в 16-бітному форматі буде 0.1234, після 8-бітної квантизації (Q8_0) у два рази гірше за попередню.

Квантизація дозволяє запускати моделі із десятками і сотнями мільярдів параметрів на менш потужному обладнанні, персональних компʼютерах і навіть на Raspberry Pi.

llama.cpp container

Якщо вам потрібен Full Precision F32, F16 або будь-який інший квантований формат, використання докер-контейнера llama.cpp є найзручнішим на macOS/Linux/Windows.

Кроки дуже прості: створимо теку, залогінимось у HuggingFace (поставте собі цей застосунок командного рядка), завантажте усі файли із PyTorch/Safetensor-моделлю. Далі конвертуємо модель: вказуємо теку, туди ж буде збережено результат, та указуємо тип виводу конвертації, f32. Для останнього кроку встановіть docker.

mkdir -p ~/models
huggingface-cli login
huggingface-cli download mistralai/Mistral-7B-Instruct-v0.3 --local-dir "~/models" --include "*"
#Convert to GGUF
docker run --rm -v "~/models":/repo ghcr.io/ggerganov/llama.cpp:full --convert "/repo" --outtype f32
ls ~/models | grep .gguf
#> ggml-model-f32.gguf
#Quantize from F32.gguf to Q4_K_M.bin
docker run --rm -v "~/models":/repo ghcr.io/ggerganov/llama.cpp:full --quantize "/repo/ggml-model-f32.gguf" "/repo/ggml-model-Q4_K_M.bin" "Q4_K_M"
ls ~/models | grep .bin
#> ggml-model-Q4_K_M.bin

На виході ви отримали ggml-model-f32.gguf файл. Це все!

Ollama App

Як варіант, використовуйте ollama --quantize. Підтримуються GGUF моделі у F16 F32 чи Safetensors форматі:

#GGUF to q6_K
echo "FROM hf.co/bartowski/Llama-3.2-3B-Instruct-GGUF:F16" > ~/models/modelfile
ollama create hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF:q6_K —quantize q6_K —file ~/models/modelfile
ollama list
#Safetensors
model=sentence-transformers-testing/stsb-bert-tiny-safetensors
modelname=hf.co/${model}
modeldir=${PWD}/${model}
mkdir -p "${modeldir}" && huggingface-cli download "${model}" --local-dir "${modeldir}" --include "*"
echo "FROM ${modeldir}" > "${modeldir}/modelfile"
ollama create $modelname -f ${modeldir}/modelfile
ollama list | grep $modelname

Для ollama/llama.cpp F16 вважається Full Precession, для комп’ютерів споживчого класу.

Brew та macOS

На macOS ви можете використовувати brew, щоб встановити llama.cpp, хоча він іноді може бути ненадійним через залежності.

brew install llama.cpp
ls /opt/homebrew/bin | grep llama
mkdir -p ~/models
huggingface-cli login
huggingface-cli download "mistralai/Mistral-7B-Instruct-v0.3" --local-dir "~/models" --include "*"#Convert to GGUF
llama-gguf "mistralai/Mistral-7B-Instruct-v0.3" --outtype f32#Quantize GGUF
llama-quantize "mistralai/Mistral-7B-Instruct-v0.3/ggml-model-f32.gguf" "mistralai/Mistral-7B-Instruct-v0.3/Q4_K_M.bin" "Q4_K_M"

Найважчий спосіб

Це найскладніший спосіб зробити збірку з коду. Хоча часто складний через різноманітні залежності та налаштування, які вам доведеться вручну підлаштовувати під ваше середовище, ОС, обладнання графічного процесора тощо:

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

Залежності

  1. Docker або Docker Desktop.
  2. Встановлення та вхід: huggingface-cli login.
  3. На картці моделі HugginFace може вимагати прийняття умов використання.

Available options

Тлумачення назв моделей: Що означає Q#_K_M у квантованих моделях?

У контексті llama.cpp, Q4_K_M позначає певний тип методу квантування. Правила позначення такі:

  • Q означає квантування;
  • 4 вказує на кількість бітів, що використовуються у процесі квантування. Чим менше число, тим гірша якість. 32 найкраща якість;
  • K вказує на використання кластеризації за методом k-середніх при квантуванні;
  • M позначає розмір моделі після квантування. (S = мала, M = середня, L = велика). L більше займатиме простору, але матиме меншу втрату якості моделі;
  • I = Importance Matrix (imatrix).

Що таке матриця важливості (Importance Matrix)?

Матриця важливості (imatrix) призначає оцінку важливості кожній вазі або активації в нейронній мережі. Ця оцінка важливості зазвичай розраховується на основі чутливості виходу моделі до змін у цій конкретній вазі або активації.

Матриця важливості дозволяє здійснювати цілеспрямоване квантування, коли найбільш важливі компоненти зберігаються з більшою точністю, тоді як менш важливі квантуються для економії пам’яті та обчислювальних ресурсів.

Такий цільовий підхід особливо важливий при квантуванні з дуже низькою точністю (наприклад, 4-бітовій або нижчій), оскільки він допомагає зберегти корисність моделі.

Приклад: IQ3_M це квантизація 3 біт, з використанням imatrix середньої величини.

Imatrix дозволяє зменшити розмір моделі мінімізуючи втрату якості що більш важливо у випадку найбільшої компресії. Lllama.cpp підтримує imatrix для Q1, Q2, Q3 та Q4 компресії. Ollama/quantize на разі не підтримує imatrix.

llama.cpp

usage: ./llama-quantize [--help] [--allow-requantize] [--leave-output-tensor] [--pure] [--imatrix] [--include-weights] [--exclude-weights] [--output-tensor-type] [--token-embedding-type] [--override-kv] model-f32.gguf [model-quant.gguf] type [nthreads]
--allow-requantize: Allows requantizing tensors that have already been quantized. Warning: This can severely reduce quality compared to quantizing from 16bit or 32bit
--leave-output-tensor: Will leave output.weight un(re)quantized. Increases model size but may also increase quality, especially when requantizing
--pure: Disable k-quant mixtures and quantize all tensors to the same type
--imatrix file_name: use data in file_name as importance matrix for quant optimizations
--include-weights tensor_name: use importance matrix for this/these tensor(s)
--exclude-weights tensor_name: use importance matrix for this/these tensor(s)
--output-tensor-type ggml_type: use this ggml_type for the output.weight tensor
--token-embedding-type ggml_type: use this ggml_type for the token embeddings tensor
--keep-split: will generate quatized model in the same shards as input --override-kv KEY=TYPE:VALUE
Advanced option to override model metadata by key in the quantized model. May be specified multiple times.
Note: --include-weights and --exclude-weights cannot be used together
Allowed quantization types:
2 or Q4_0 : 3.56G, +0.2166 ppl @ LLaMA-v1-7B
3 or Q4_1 : 3.90G, +0.1585 ppl @ LLaMA-v1-7B
8 or Q5_0 : 4.33G, +0.0683 ppl @ LLaMA-v1-7B
9 or Q5_1 : 4.70G, +0.0349 ppl @ LLaMA-v1-7B
19 or IQ2_XXS : 2.06 bpw quantization
20 or IQ2_XS : 2.31 bpw quantization
28 or IQ2_S : 2.5 bpw quantization
29 or IQ2_M : 2.7 bpw quantization
24 or IQ1_S : 1.56 bpw quantization
31 or IQ1_M : 1.75 bpw quantization
10 or Q2_K : 2.63G, +0.6717 ppl @ LLaMA-v1-7B
21 or Q2_K_S : 2.16G, +9.0634 ppl @ LLaMA-v1-7B
23 or IQ3_XXS : 3.06 bpw quantization
26 or IQ3_S : 3.44 bpw quantization
27 or IQ3_M : 3.66 bpw quantization mix
12 or Q3_K : alias for Q3_K_M
22 or IQ3_XS : 3.3 bpw quantization
11 or Q3_K_S : 2.75G, +0.5551 ppl @ LLaMA-v1-7B
12 or Q3_K_M : 3.07G, +0.2496 ppl @ LLaMA-v1-7B
13 or Q3_K_L : 3.35G, +0.1764 ppl @ LLaMA-v1-7B
25 or IQ4_NL : 4.50 bpw non-linear quantization
30 or IQ4_XS : 4.25 bpw non-linear quantization
15 or Q4_K : alias for Q4_K_M
14 or Q4_K_S : 3.59G, +0.0992 ppl @ LLaMA-v1-7B
15 or Q4_K_M : 3.80G, +0.0532 ppl @ LLaMA-v1-7B
17 or Q5_K : alias for Q5_K_M
16 or Q5_K_S : 4.33G, +0.0400 ppl @ LLaMA-v1-7B
17 or Q5_K_M : 4.45G, +0.0122 ppl @ LLaMA-v1-7B
18 or Q6_K : 5.15G, +0.0008 ppl @ LLaMA-v1-7B
7 or Q8_0 : 6.70G, +0.0004 ppl @ LLaMA-v1-7B
1 or F16 : 14.00G, -0.0020 ppl @ Mistral-7B
32 or BF16 : 14.00G, -0.0050 ppl @ Mistral-7B
0 or F32 : 26.00G @ 7B
COPY : only copy tensors, no quantizing

Ollama

ollama create mynewmodelname:q6_K —quantize q6_K —file modelfile
Supported Quantizations
q4_0
q4_1
q5_0
q5_1
q8_0
K-means Quantizations
q3_K_S
q3_K_M
q3_K_L
q4_K_S
q4_K_M
q5_K_S
q5_K_M
q6_K

Hugging Face GGUF Quants Q2-Q8

huggingface.co/...​ces/ggml-org/gguf-my-repo

BitNet b1.58

Цікавий момент як різні сили і думки формують архітектуру сучасних LLM знаходячи баланс між декількома силами та ідеями та як швидко усе змінюється в ШІ галузі. С початку ми прийшли до ідеї чим більше тим краще: більше даних, більше параметрів більше модель. Потім ми зрозуміли що моделі виросли до якихось мега-монстрозних розмірів і вирішили їх зменшити методом квантизації. І дійшовши до крайності стиснення якості у 1 біт, ми раптом зрозуміли що можна із самого початку робити моделі не із плаваючою точкою а 1-бітові, при тому не стискаючи її а зразу навчаючи так що із одного боку дасть нам зберігати все ті ж самі данні, як і f32, але що цікаво на практиці показує набагато менший розмір, через те що раніше навіть круглий 0 у f32 форматі все-одно займав би 32 біта, а от у 1-бітовому форматі 0 займатиме все-одно 1 біт, і теж саме якщо 8-розрядне число в двоїчній формі в 1-бітовій моделі займатиме 8 штук по одному біту, а в f32 всеодно усі 32 біти. Тож кожна окрема вага f32 формату в залежності від її довжини може якщо навчена в 1-бітовому форматі займати різну кількість памʼяті, а не завжди статично 32 біти. Що із одного боку дає вбудоване стиснення «by design», а із іншого зберігає повну якість. 1-бітові моделі ще відомі як BitNet b1.58. Також виявляється, що 1-розрядні моделі легше обробляти, оскільки відпадає необхідність у деяких важких обчислювальних операціях над числами з плаваючою комою.

Приклад: 1bitLLM/bitnet_b1_58-3B

Висновки

Найпростіший спосіб конвертувати PyTorch та Safetensor у GGUF та квантизувати — це використати офіційний docker-контейнер. Не використовуйте PyTorch-моделі із неперевірених джерел, вони можуть їсти ваші ресурси для виконання чужих зловмисних завдань. Квантизація дозволяє запускати великі моделі на персональних компʼютерах.

Слідуючи крокам в статті ви можете стиснути великі моделі до розміру що дозволить запускати їх на персональних компʼютерах. Для найбільшої якості моделі необхідно підібрати параметри квантизації для максимального збереження якості. Доступні варіанти квантизації дозволяють знайти баланс між якістю моделі і стисненням її розміру.

В недалекому майбутньому навчені нові b1.58 моделі займатимуть набагато менше простору у памʼяті та процесорних ресурсів що має дати значний поштовх у розвитку ШІ, так як ми зможемо або ж отримати ту саму якість використовуючи менше ресурсів компʼютера або навпаки використовувати усе ті самі ресурси на повну як і попередні моделі, але ці моделі будуть мати більше вбудованих знань і як результат будуть потенційно значно якісніші.

Підтримка

Якщо вам сподобалася ця стаття і ви хочете підтримати мене:

  1. Натисніть «Подобається 👍» та додайте «До обраного ⭐️» мою статтю; це допоможе мені. Також слідкуйте за мною на DOU щоб отримувати останні статті.
  2. Дайте відгук у коментарях нижче, навіть якщо це просте «дякую» — це допоможе мені розуміти, що моя робота була не марною. Якщо є помилки, скажіть де, а найголовніше як виправити, не претендую на роль всезнайки.
  3. Шукаю ентузіастів та однодумців, що знаються на Python і хотіли б втілити описані ідеї в моїх статтях у життя, і, можливо, навіть зробити сумісний проєкт: Напишіть мені в LinkedIn. На разі працю над PoC, який використовує описані принципи у моїх статтях. Буду радий поділитись своїми напрацюваннями і знаннями.
  4. Я готую статтю яка по великому рахунку використовує NLP для побудувати графу знань із вільного тексту, який зберігається у БД для того щоб потім бути використаним в Agentic RAG чатботі. Чи було би вам цікаво стати соовтором? Треба вичитати перевірити, виправити де не правильно, може оновити якщо щось застаріло чи додати нове. Це буде продовженням до цієї та попередньої статті. Прошу написати мені персональне повідомлення LinkedIn / Discord якщо ви хочете по співпрацювати на цю тему.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось17
До обраногоВ обраному13
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Шукаю співавтора: Knowledge Graph, NLP, NER
Це буде продовженням моєї попередньої статті.

Деталі
dou.ua/forums/topic/49809

Дякую за статтю
Чи працювали ви з Multi-modal LLM?
Розробляю PoC для відеоаналітики з використанням LLaVA 1.6. Цю модель можливо запускати з 1 FPS, але хочеться більше.

Вітаю. Дякую!
Особисто я із відео не працював.

FYI multi-modal це не обовʼязково саме про відео. Це про те що у моделі є декілька здібностей. На приклад коли є і декодер і енкодер із текста у відео і при тому ще й навпаки. Але може бути і відео + фото, або фото + текст в одну і іншу сторону, те саме із аудіо. Але це на справді не тільки про мультімедіа: може бути модель яка працює із декільками мовами, і на приклад може як працювати із табличними даними так і звичайним текстом.

Теж вирішив у своєму проєкті вибрати GGUF файл щоб на етапі розробки не сильно заморочуватись з тонкими налаштуваннями LLM.

Але потроху приглядаюсь до Safetensor, щоб краще контролювати свій ШІ.

Який практичний сенс конвертації в gguf крім запуску LLM на телефоні? Наскільки швидший inference у порівнянні з PyTorch (при однаковій квантизації)? Як там з підтримкою GPU? В PyTorch є багато додаткових модулів і біблотек, які скоріш за все не конвертовуються в gguf. Краще вже використовувати ONNX для інференсу.

Ну запуск на Linux, macOS або Windows за допомогою llama.cpp/LocalAI/Ollama. До речі якщо треба на телефоні Android, то тут треба не GGUF а TensorFlow, якщо на iOS/iPad то тут треба тоді CoreML package format, його і macOS теж підтримує нативно.

Ще один практичний спосіб це QLoRA зробити модель і до навчити щоб вона швидко працювала над вашим датасетом.

QLoRA є і для PyTorch (та інших бібліотек також)

ONNX виглядає як колись популярний, нині вже не так часто використовуємий. Для продакшн Inference більш популярний kserve.github.io але цих inference двіжків їх багато, серед них багато які працюють тільки із своїм власним форматом упаковки моделі.

GGUF формат більш популярний для платформ користувацького класу: персональні компʼютери. Його плюс у відносно широкій популярності.

ONNX виглядає як колись популярний, нині вже не так часто використовуємий

Я не знаю звідки ви це взяли, бо ONNX це лише спроба уніфікувати (і на мою думку вдала) формат представлення моделі, щоб можна було комбінувати різні фрейморки тренування моделей та інфенерс движків

  • Багато фрейморків мають вбудовану підтримку конвертації в ONNX
  • ONNX формат постійно оновлюється, додають нові оператори та типи даних
  • Багато інференс движків, які підтримують ONNX

onnx.ai/...​ted-tools.html#buildModel

На фоні ONNX, GGUF виглядає як вузьконаправлене рішення для запуску LLM на кавовій машині

Ну може помиляюсь. Було враження що їх реплзиторії на гітхабі якось не дуже часто оновлюються.

Найближче до того що ви хочете я думаю називається QLoRA.
LoRA це процесс навчання моделі шляхом створення додаткового рівня в нейронній мережі, плюс того що це реально зробити на персональному компʼютері.
Q це квантизація.
QLoRA дозволяє зменшити (квантизувати модель) і заодно довчити її своєму датасету, QLoRA переконується щоб втрати на квантизації мінімально вплинули на якість навчання.

One interesting framework is RAFT which takes an input document and creates a dataset, consisting of synthetically generated `{ question, answer, documents }` triplets. The dataset is used to fine-tune models for improved question-answering and retrieval.

github.com/...​rilla/tree/build2024/raft

У вас цікаві теми публікацій. Добре, що це зʼявляється на доу.

Дякую. До речі прям щойно відредагував цю статтю і додав трохи про однобітні моделі відомі як BitNet b1.58.

Підписатись на коментарі