Gemma-2-27b-itを使うのに苦戦した話(Mac + llama.cpp)
はじめに
どんな人向けの記事?
- ローカルLLMに興味がある方
- Gemma-2-27bの性能に興味がある方
- Gemma-2-27bがうまく動かせない方
内容
- Gemma-2-27b-itのollamaモデルがなぜか機能しない
- 解決策
- Gemma-2-27b-it-bf16の出力遅すぎでは?
- Gemma-2-27b-it-f16の出力例
- まとめ
Mac Studio(M2 Ultra 128GB)
M2 Ultra MacでGoogleが数日前に公開したGemma-2-27b-itを使って、いつもどおり記事を作ろうと思ったら大苦戦しました。
今回は、Gemma-2-27b-itが問題なく使えるようになるまでの過程を記事にしようと思います。
Gemma-2-27b-itのollamaモデルがなぜか機能しない
ollamaモデルの入手
gemma2はメジャーなLLMモデルということもあり、すぐにOllamaのlibraryに追加されていました。
今回はこちらのf16モデルを使ってみました。
ollama run gemma2:27b-instruct-fp16
早速、いつものプロンプトを入力します。
下記の設定で、2000字程度の日本語短編小説を作成してください。
# 設定
## 主人公
* 知性を持った金のニワトリ。
* 名前は「ゴスラム」
* 毎日一つだけ金の卵を産む。
* 逆境を糧に成長する。
## 世界観
22世紀初頭。人智を超えたAIの登場により、あらゆるモノ・サービスの価値が目まぐるしく変化する時代。
## イントロ:
主人公ゴスラムは、自分の産んだ金の卵を売ることで生計を立てていた。
ところが、AIが低コストで金を生成する方法を見つけてからは、金の価値が暴落してしまった。
危機感を覚えたゴスラムは、起死回生のあるビジネスを始めることを決意する。
すると、下記のように最初は問題なく出力されていたかと思っていたら、次第に意味のわからない文章が増えてきて、最後は全く無意味な文章を生成するだけになってしまいました。
gemma2:27b-instruct-fp16の出力
22世紀の初頭、黄金のニワトリと称される「ゴスラム」は、街で最も尊敬される存在
だった。彼は、卵から生まれたばかりの頃から、周りの人々から「奇跡の鳥」と呼ば
れ、人々は彼の産む金色の卵を求めて遠方からやって来た。
しかし、それはもう過去の話だ。
〜中略〜
21世紀の人間たちが
彼は、
「彼らに」提供する情報源は、
「彼は…」と、
「彼らは」の言葉で、
「彼は…」
"They” の「21世紀の人間たち」を表現していた。
解決策
結論から言うと、Ollamaでの利用は諦めてllama.cppのwebサーバを使うことで解決しました。
原因について理解できているわけではないですが、下記のポストが参考になりました。
本記事では原因の究明はせずに、Gemma-2-27b-itを使う方法だけを解説します。
以下にその手順を記載します。
- ggufモデルのダウンロード
私は少しでも精度を出したかったので、gemma-2-27b-it-bf16のモデルをダウンロードしました。
-
llama.cppの更新&make
今更ですが、ディレクトリ構造を書き留めておきます。
* 作業ディレクトリ
- llama.cpp
- models
- gemma-2-27b-it-bf16
- venv
作業ディレクトリで下記のコマンドによりllama.cppの更新とmakeをします。
cd llama.cpp
git pull
make
- llama-serverの起動
作業ディレクトリにserver.shを作成します。
#!/bin/bash
LISTEN=0.0.0.0
PORT=8080
SERVER=./llama.cpp/llama-server
MODEL=./models/gemma-2-27b-it-bf16/gemma-2-27b-it-bf16-00001-of-00002.gguf
$SERVER --host $LISTEN --port $PORT -ngl 200 -m $MODEL --chat-template gemma
nglは何を入力すべきかわからなかったので、GPUを使うように大きめの値を入力しておきました。次に、上記スクリプトを実行します。
bash server.sh
これで、ブラウザからhttp://[llama.cppサーバーのIPアドレス]:8080
でllama.cppサービスにアクセスできるようになります。下記はブラウザでアクセスしたときの画面です(New UIを用いています)。
Gemma-2-27b-it-bf16の出力遅すぎでは?
上記で問題なく出力することはできたものの、とにかく生成速度が遅い(0.53 tokens per second)!Mac特有の問題なのか理由はわからないですが、f16に変換したら出力も破綻せずに生成速度も早くなった(11.00 tokens per second)ので、結局gemma-2-27b-it-f16を用いることにしました。
- f16モデルへの変換
./llama.cpp/llama-quantize ./models/gemma-2-27b-it-bf16/gemma-2-27b-it-bf16-00001-of-00002.gguf ./models/gemma-2-27b-it-f16.gguf f16
- server.shの修正
#!/bin/bash
LISTEN=0.0.0.0
PORT=8080
SERVER=./llama.cpp/llama-server
MODEL=./models/gemma-2-27b-it-f16.gguf
$SERVER --host $LISTEN --port $PORT -ngl 200 -m $MODEL --chat-template gemma
これでようやくgemma-2-27b-itを動かせる環境が整いました!
ちなみに、Q5_K_Mを用いたときの生成速度は14.57 tokens/sでした。
gemma-2-27b-it-f16の出力(996文字)
黄金の卵
22世紀初頭。空を覆うドローン、街を走る自動運転車。人智を超えたAIがもたらした未来は、便利さと同時に、予測不能な変化をもたらしていた。
ゴスラムは、そんな時代の波に揉まれながら、今日も静かに金の卵を産んでいた。彼は知性を備えた金のニワトリであり、毎日一つだけ、輝きを放つ金の卵を産むことができる。かつては、その卵は莫大な価値を誇り、ゴスラムは裕福な生活を送っていた。
しかし、時代は容赦なく変化した。AIが低コストで金を生成する技術を開発したのだ。金の価値は暴落し、ゴスラムの生活は一変した。かつては高級レストランの食材として扱われた金の卵は、今では市場に出回ることもなく、ゴスラムの納屋の隅に積み上げられるだけになった。
「このままではいけない」
ゴスラムは、危機感に駆られた。彼は自分の存在意義を見出すために、必死に頭を働かせた。金の卵の価値がなくなったとしても、彼には他に何かできることがあるはずだ。
ある日、ゴスラムは街の広場を散歩していると、一人の老人が困っている様子に気がついた。老人は、AIの進化で失業し、生活に困っていたのだ。ゴスラムは、老人に金の卵をプレゼントしようと考えた。
「この卵を売って、生活の足しにしてください」
老人は、ゴスラムの申し出に驚き、涙を流した。金の卵はもはや価値がないと言われているが、老人の心には温かい光を灯してくれた。
その日から、ゴスラムは金の卵を、困っている人々に配り始めた。彼は卵を売るのではなく、人々の心を豊かにするために、卵を贈ることにした。
彼の行為は、人々の心に響き、やがて街中に広がっていった。ゴスラムの金の卵は、再び人々に希望を与える存在となった。
ゴスラムは、金の卵を産むことに誇りを感じた。金の価値がなくなったとしても、彼の卵は人々の心を豊かにする力を持っていた。
「金の価値は、人々の心を動かす力にある」
ゴスラムは、そう悟った。
彼のビジネスは、従来の価値観を覆す、新しい時代のビジネスだった。それは、AIの進化によって失われたものを取り戻す、希望の光を灯すビジネスだった。
ゴスラムは、金のニワトリとして、新たな時代を切り開いていった。
彼は、金の卵を産み続けるだけでなく、人々の心を豊かにするビジネスを展開していくことを決意した。彼の未来は、希望に満ち溢れていた。
-
GPT-4oの作成した一枚絵
所感・まとめ
今回は、gemma-2-27b-itをMacで使ってみた、という内容で記事を書きましたが、とにかくまともに動かせるようになるまでに数日かかりました。
出力された物語もクオリティが高く、満足のいくものでした。ただ、この物語では「人々の心を豊かにする」ことが価値であることに気づいたものの、具体的にどのようなビジネスを展開したかまでは描かれておらず、続きが気になる展開で物語を終えていますね。
ここまで見ていただきありがとうございました。次回もぜひ、よろしくお願いします。
Discussion
Gemma 2にはSliding Window Attentionという機構があり、これは前4096トークンに限ってAttentionを計算する少々特殊なAttentionです。ところが、(当初の)llama.cppにAttentionの距離制限という概念はなく、前のトークン全てにAttentionを計算していました。
文章が短い最初のうちは、4096トークン制限と制限なしは等価です。しかし文章が4096トークン以上になると、llama.cppは本来Attention計算してはいけないところまでAttentionを計算してしまう。
これが、最初は順風満帆なのに途中で唐突に文章が崩壊するメカニズムです。
また、bf16の生成が遅い問題ですが、Windows & NVIDIA GPU環境で私も再現できました。
断言はできませんが、llama.cppがGPUでのbf16推論に対応していないことがこの問題の背景にある気がします。
(ちなみに、タスクマネージャーを監視しているとCPU使用率が急速に上昇していました。推測ですが、非対応の演算ということでCPU実行にフォールバックされてしまったのでしょう)
非常に丁寧にご解説いただき、感謝いたします!とても勉強になります。
なるほど、Sliding Windowについてはほとんど理解できていませんでしたが、そのような仕組みになっていたのですね。
bf16の生成が遅い問題についても、確かに私の環境でもGPUがほとんど動いておらず、CPU使用率が上昇していました。NVIDIA GPU環境でも同じだったのは意外でしたが、llama.cpp側が対応していなかったということなんですね。
基本は取り回しが楽なollamaでローカルLLMを使う予定ですが、今後llama.cppを使う際は参考にさせていただきます。改めて、参考になるコメントをいただきありがとうございました!