Llama2.c: 純粋なCファイルでLlama 2推論
(github.com/karpathy)- llama2.c は、PyTorchでLlama 2 LLMアーキテクチャを学習し、シンプルなCファイル
run.cで推論する「fullstack」な学習・推論ソリューション - 中心的な焦点は ミニマリズムとシンプルさ で、Llama 2アーキテクチャをハードコードし、依存関係のない純粋なC推論ファイル1つで構成した教育用実装
- ごく小さなLLMでもドメインを十分に絞れば高い性能を発揮できるという観点から、TinyStories ベースのサンプルモデルを提供
- 15Mパラメータモデルは約60MBのダウンロードで、
make run後に./run stories15M.binで実行可能 - 42M、110Mパラメータモデルも提供され、110MモデルはGPT-1と同じサイズだと明記されている
- 15Mパラメータモデルは約60MBのダウンロードで、
- MetaのLlama 2モデルもニューラルネットワークアーキテクチャが同一のため推論可能だが、チェックポイントをMetaの手順に従って入手したうえで、
export.pyでllama2.c形式に変換する必要がある- 現在の
run.cはfp32推論のみを行うため、7Bより大きいモデルを実用的にロードするのは難しい可能性が高い - 13B以上はポインタ演算のinteger overflowにより現在は動作せず、未修正の状態
- 現在の
- int8量子化 推論は
runq.cに実装されており、Q8_0方式でmatmulに参加する重みを量子化し、活性値も実行時に動的に量子化・逆量子化する- Llama 2 7Bのfp32 exportは26GBのファイルを作成し、version 2 quantized exportは6.7GBのファイルを作成する
- 作者の環境ではOpenMP 64スレッド基準でfp32は4.6 tok/s、int8は14 tok/sで実行され、チェックポイントサイズは4分の1になり、速度は約3倍向上
- 利用方法は、C推論の実行、プロンプト入力、temperatureとtop-pサンプリング制御、chatモード実行、カスタムトークナイザ指定で構成される
- 実行例は
./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth"形式 - chatモデルは
./run llama2_7b_chat.bin -m chatのように-m chatフラグで実行する - カスタムトークナイザは
tokenizer.pyで.bin形式にエクスポートした後、-zフラグで指定する
- 実行例は
- Hugging FaceでLlama 2アーキテクチャを使うモデルは、
export.pyの--hfフラグで.binファイルにエクスポートできる - 学習フローは、TinyStoriesのダウンロードと事前トークン化、
train.pyの実行、モデルのexport後にC推論へ進む流れ- デフォルトのTinyStories例が、現在提供されている唯一のデータセット例
- カスタムトークナイザの学習には
sentencepieceを使用し、例として--vocab_size=4096設定を使う
- 性能関連のビルドは
make run、make runfast、make runompに分かれ、OpenMPビルドはmatmulとattention内部の#pragma omp parallel forを有効化し、ループ処理を複数のプロセッサに分割する - プラットフォーム別ビルド手順はWindows、Centos 7、Amazon Linux 2018、Mac向けに提供される
- Windowsは
build_msvc.batまたはmake win64を使用 - Centos 7とAmazon Linux 2018は
make rungnuまたはmake runompgnuを使用 - MacのOpenMPビルドはbrewのclangをインストールした後、
make runomp CC=/opt/homebrew/opt/llvm/bin/clangを使用
- Windowsは
- テストは
pytestとCテストmake testccを提供し、test_all.pyはCとPythonで200ステップのforwardを実行して既知の期待出力と比較する - プロジェクトの目標は、読みやすい2つの学習コード
.pyファイルとC推論コードからなるシンプルな参照実装を維持することであり、複雑なフレームワークや多数のオプションは志向しない - ライセンスは MIT
1件のコメント
Hacker News のコメント
HN に上がっているのを見て面白いと思った :) もとのチェックポイントは MacBook Air M1 で
-O3コンパイルすると、予想よりずっと速い 100 tok/s で動いたので、今はさらに大きい 44M モデルを学習中それでも対話的に実行できそうで、もしかすると 7B Llama モデルも手の届くところにあるのでは、という気がする
nanoGPTを少し改造して、TinyStories の GPT-4 生成 2GB データで 12M モデルを事前学習してみたところ、結果はかなり驚くものだったその後 Wikipedia で少し適応させると、平滑化した n-gram モデルよりずっと賢く、ずっと小さい、もっともらしいデタラメ生成器になった。小さな LLM はさまざまな領域で主流になりそうで、次の目標は Llama2 7B を 10〜100M に縮小しつつ、大きく愚かにならないようにすること
Linode のようなところで GPU インスタンスを借りるのは通常の Web アプリ用サーバーよりずっと高いが、完全に無理な領域なのか、それともこうしたアプローチや別の方法が現実的な道なのかを知りたい
llama.cpp で知られる Georgi Gerganov が Emscripten でブラウザ上で動かしたバージョンがある: https://ggerganov.com/llama2.c/
進行中の Twitter スレッドはこちら: https://twitter.com/ggerganov/status/1683174252990660610
オリジナルもこの取り組みも本当に素晴らしく、ごく小さなモデルを使った概念実証に近いが、ローカルファーストの LLM は特に興味深い。ローカル推論で Web アプリを作れるという発想が良い
最適化、より小さなモデルの研究、部分ダウンロード、WebGPU 活用へとつながれば、プライベートなローカル LLM ベースのアプリを作る新しい方法の出発点になり得る。最上位 GPU の大規模クラスタでホストされる LLM と同じ能力は難しいだろうが、この方式が開くユースケースは多い
たとえば “Once upon a time...” で始まり、Lily と Timmy の話のように見えたものが、“Butterfly would pauseWhy”、“TextField”、
querySelector、HttpRequest、複数言語の断片が入り混じり、完全に壊れた出力へと変わっていく気になる人向けに Rust 版もある。リリースモードで 106 tokens/second くらい出る
https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...
Web ではない版は GPU を完全にサポートしているが、まったくミニマルではない
ときには、プロジェクト改善に向けたコミュニティの努力を分散させてしまうこともある
これがどれほど大胆な動きなのか、理解している人は多くないように思う
Andrej は OpenAI(MSFT)から高額な報酬を受け取りながらも、Apple、Facebook、そして何よりオープンソース運動を助けている。それでも彼を追い出すのは難しいはずで、そうなればすぐ Tesla や xAI に行けるからだ
Llama-2 は創作作業には使えないほど安全フィルタリングが強いと感じる: https://i.imgur.com/GFY0wSL.png
ただし、この現象は Llama2-70b-chat TGI Hugging Face で 2 通目のメッセージとして送った場合にだけある程度再現でき、プロンプト方式の側におかしな部分があってこうした挙動が生じている可能性もある。自分でモデルを動かして追加調査することはまだできていない
Chat/instruct は第三者ユーザーに配布しやすく、プロンプトが単純で、安全策が入っているという利点があるが、自分で使うには事前学習モデルより本当にかなり劣る。この点で Llama 2 は OpenAI より有利かもしれない。OpenAI は GPT-3 の事前学習モデルを廃止し、今後は chat モデルだけを提供する方向に見えるからだ
安全ハサミはいらない。自分のサーバーで動くものを制限するのは構わないが、自分のコンピュータで思いどおりに改変して使えないモデルは渡さないでほしい
Andrej がより詳しく投稿している内容はこちら: https://twitter.com/karpathy/status/1683143097604243456?s=46...
ちなみに、この方面に興味があるなら、このコードは WASI SDK できれいにビルドでき、修正なしで Wasm ランタイム上で動作する
ニューラルネットワークを実行するには、どれくらいのメモリが必要なのか気になる
ディスクから最初の2層だけを読み込み、すべてのノードの活性値を計算した後で第1層を捨て、第3層を読み込んで再び計算し、その後で第2層を捨てる、というやり方で十分なのだろうか? そうなら、メモリは2層分を保持できるだけあればよいのか気になる
要約すると、最大 RAM は量子化方式によって変わり、おおよそ 7B モデルは 4〜8GB、13B モデルは 8〜15GB、30B モデルは 13〜33GB、70B モデルは 31〜75GB の範囲になる
ふと思ったのだが、現在の LLM は確率分布を返し、乱数サンプラーがその中から1つを選んで出力に付け加え、それを繰り返している
その代わりに、乱数が分布を近似する N 個のトークンを選び、LLM に N 個の新しい分布を生成させ、それらを何らかの方法で結合して、結合分布から再び N 個のトークンを選ぶ、ということは可能だろうか?
例は https://huggingface.co/docs/transformers/internal/generation... で見られる
ただし、それをどうやるかは分からない
もちろん、トークン生成ごとにN倍の計算量が必要になる。上位 N 個を選ぶか、必要ならロジットに温度調整を適用して N 個をサンプリングできる
これは教育用なのか? llama.cpp とこのプロジェクトの成功を見ると、業界は PyTorch、TensorFlow、ONNX Runtime のような汎用フレームワークではなく、リリースされるモデルごとに別個のソースコードを持つ方向へ進んでいるように見える
そして、そうではない。名前とは違って llama.cpp は llama だけをサポートしているわけではない。完全なカスタム実装でもなく、より汎用的な
ggmlテンソルライブラリ/フレームワークの上に作られているただし、うまく機能するモデルが見つかると、その進展は次のフレームワークのバージョンに取り込まれることが多い。だから TensorFlow には CNN、GRU、TransformerEncoder のような基本要素が生まれ、同時に汎用性を犠牲にして速度を得る特定ハードウェア向け実装も作られる