nikkie-ftnextの日記

イベントレポートや読書メモを発信

llama.cppでLLMを量子化し、ollamaで動かせた!これで勝つる!(cyberagent/calm2-7b-chat量子化記事の再現編)

はじめに

愛衣ちゃん大勝利〜!! nikkieです。

世はまさに大規模言語モデル1時代!
ollamaを使ってLLMをもふもふ手元のPC(CPUのみ)でも動かしています2が、その秘密は量子化
今回は、今まで利用するだけだった量子化を自分でもやってみます

目次

「非力なパソコンでもLLMを動かしたい!? llama.cppの紹介」

こちらの記事を全力でパクッていきます!!

cyberagent/calm2-7b-chat3q5_k_m量子化します。
ちなみにこのモデルのライセンスは、Apache-2.0です。

M1 Mac(メモリ32GB・macOS 14.5)でllama.cppを使って量子化をしていきます。
(元記事ではUbuntuGoogle CloudのVM)です)

手順

  1. Hugging Faceに置いてあるモデルをGGUF形式に変換
  2. GGUF形式から量子化
  3. 量子化したモデルを動かす

    • llama.cpp
    • ollama

cyberagent/calm2-7b-chatをq5_k_mに量子化

環境構築

llama.cppのリポジトリをcloneします。

コミット 059031b8c40e1f4ba60586842c5b1ed3ddf61842 の時点のコードを動かしています。

(1) llama.cppをビルドします4

cd llama.cpp
make  # https://github.com/ggerganov/llama.cpp のルートでビルド

Metal Build」は無効にせずに進めました

On MacOS, Metal is enabled by default.

元記事にならってmake testしたところ、1ケース通りませんでしたが、(私に解決できる技量はないので祈りを捧げて)先に進みました

(2) Pythonの環境構築

仮想環境を作って有効化して

% pip install -r requirements/requirements-convert-hf-to-gguf-update.txt

requirements-convert-hf-to-gguf.txtと今は同内容でした

Python環境

certifi==2024.2.2
charset-normalizer==3.3.2
filelock==3.14.0
fsspec==2024.5.0
gguf==0.6.0
huggingface-hub==0.23.0
idna==3.7
Jinja2==3.1.4
MarkupSafe==2.1.5
mpmath==1.3.0
networkx==3.3
numpy==1.24.4
packaging==24.0
protobuf==4.25.3
PyYAML==6.0.1
regex==2024.5.15
requests==2.31.0
safetensors==0.4.3
sentencepiece==0.2.0
sympy==1.12
tokenizers==0.19.1
torch==2.1.2
tqdm==4.66.4
transformers==4.41.0
typing_extensions==4.11.0
urllib3==2.2.1

1. Hugging Faceに置いてあるモデルをGGUF形式に変換

今回のディレクトリ構成

llama.cpp/  # リポジトリのルート
├── .venv/  # すでに作ったPython環境
└── work/  # 作業ディレクトリ
    └── models/
        ├── hf/  # Hugging Faceからダウンロードしたモデルを置く
        └── gguf/  # llama.cppで量子化したモデルを置く

(1) Hugging Faceからモデルのダウンロード

Python環境を使います

% python -c 'import huggingface_hub; huggingface_hub.snapshot_download(repo_id="cyberagent/calm2-7b-chat", cache_dir="./work/models/hf")'

ここのダウンロードが一番時間がかかりました

% ls work/models/hf/models--cyberagent--calm2-7b-chat/snapshots/3e110c7624ff7a940badebfd5f9a91569f98cc56/
README.md               model.safetensors.index.json        special_tokens_map.json
config.json             pytorch_model-00001-of-00002.bin    tokenizer.json
generation_config.json          pytorch_model-00002-of-00002.bin    tokenizer_config.json
model-00001-of-00002.safetensors    pytorch_model.bin.index.json
model-00002-of-00002.safetensors

(2) vocab.jsonを作る

元記事より

このモデルのトークナイザ(GPTNeoXTokenizerFast)の設定をそのままの形でGGUF形式に変換することはできないからです。
そのため、トークンとIDの対応関係のみ抽出してGGUF形式に変換できるように、語彙のファイル(vocab.json)を追加します。

まずディレクトリを移動

% cd work/models/hf/models--cyberagent--calm2-7b-chat/snapshots/3e110c7624ff7a940badebfd5f9a91569f98cc56/

元記事中のコードをscript.pyとして置いて実行。
vocab.jsonができました!

(3) llama.cppが用意したconvert.pyでGGUF形式に変換

% cd -  # llama.cppのルートディレクトリに戻った
% python convert.py --vocab-type bpe --outfile work/models/gguf/calm2-7b-chat.gguf work/models/hf/models--cyberagent--calm2-7b-chat/snapshots/3e110c7624ff7a940badebfd5f9a91569f98cc56

元記事は--vocabtype引数ですが、llama.cpp側のアップデートで--vocab-typeとハイフンが入っていました

できたwork/models/gguf/calm2-7b-chat.ggufは26GBでした。
Hugging Faceではtokenizerが別ファイルだったり、モデル(の重み)が複数のファイルに分かれていたりしますが、これが1つにまとまったということですかね。

2. GGUF形式から量子化

ビルドしたllama.cppを使って量子化します

./quantize work/models/gguf/calm2-7b-chat.gguf work/models/gguf/calm2-7b-chat-q5_k_m.gguf

体感1分くらいでした。
できたwork/models/gguf/calm2-7b-chat-q5_k_m.gguf4.6GBです(5分の1!)。
(小数の精度を劣後したことで)軽量化している!!

3. 量子化したモデルをllama.cppで動かす

% ./main -m work/models/gguf/calm2-7b-chat-q5_k_m.gguf -n 500 -p "USER: AIによって私達の暮らしはどのように変わりますか?
ASSISTANT: "

<|endoftext|>USER: AIによって私達の暮らしはどのように変わりますか?
ASSISTANT: 人工知能(AI)は、私たちの生活に多大な変化をもたらします。以下は、AIが私たちの生活にもたらす可能性のある変化の一例です。

1. 生産性の向上: AIは、データの分析、タスクの自動化、および予測分析などの機能を通じて、生産性を向上させます。

(省略しますが、箇条書きが5点出てきました)

流れるように文章が出てきます。
このスピードはすごい!

量子化したモデルをollamaでも動かす

以前Phi-3をollamaで動かした後、同じモデルをllama.cppでも動かしました5
この経験から、llama.cppで量子化したモデルはollamaでも動かせるのではないかと考えました。

結論を言うと、動かせています

ollamaのリポジトリを覗いたところ、
https://github.com/ollama/ollama/tree/v0.1.38?tab=readme-ov-file#import-from-gguf
ローカルにあるGGUF形式のモデルを動かす場合は、まずModelfileを作るそうです。

% cat work/Modelfile
FROM ./models/gguf/calm2-7b-chat-q5_k_m.gguf

このModelfileからollama create

% ollama create calm2:7b-chat-q5_k_m -f work/Modelfile

successすると、ollama listに出てきます

これで、もふもふ(ollama run)できるぜ!

% ollama run calm2:7b-chat-q5_k_m
>>> AIによって私達の暮らしはどのように変わりますか?

A: AI技術の進歩によって、私たちの生活は大きく変化します。例えば、医療やヘルスケアの分野では、医師の診断を助けるAI診断システムが開発され、より正確な診断が可能になることが期待されています。

(省略します)

流れるようにテキストが出てきます!
ollamaでも動かせました🙌

終わりに

cyberagent/calm2-7b-chatを例に、llama.cppで量子化して動かし、さらにollamaでも動かしました。
この手順を使えば、Hugging Faceに置いてあるどんなモデルも量子化して、ollamaで動かせるんじゃ!?6
勝ったな!
変化の激しいLLM時代ですが、この手順を掴んだことで「いいのか? こちらは量子化していつでもollamaでもふもふできるんだぞ」と余裕を持って臨んでいけそうに思います。

CyberAgentの山本さん、素晴らしい記事をありがとうございました

この記事の元ネタです

積ん読リスト

元記事、量子化命名規則部分積ん読です。
q5_k_mは

llm-course量子化の記事を見つけました。
仕組みや理論面は理解を深めたいですね。

GGUFも謎のアルファベットなので、理解していきたいところ

https://github.com/ggerganov/ggml/blob/master/docs/gguf.md:enbed


  1. 同等性能の小規模言語モデルとか出てきて、largeとかsmallの言葉選びがアホだったと思ってます(バベルの塔を立てちゃったぞ...)
  2. Phi-3をもふもふしたいなー
  3. https://github.com/ggerganov/llama.cpp/tree/059031b8c40e1f4ba60586842c5b1ed3ddf61842?tab=readme-ov-file#build
  4. この記事では既出の Apple Silicon・CPUでphi-3(Phi-3-mini-4k-instruct-gguf)を動かす - nikkie-ftnextの日記
  5. 完全に理解した段階(馬鹿の山)なので、やろうとすると色々ハマると思います