🦙

llama.cpp でフルの学習メモ

2023/06/25に公開

llama.cpp で CPU で LLM 学習を極め, CPU LLM 学習王になりたい.

やりましょう!

baby-llama

https://github.com/ggerganov/llama.cpp/pull/1360

まずはサイン波を学習します.
とりあえず動かせば学習してくれます.

train-text-from-scratch

https://github.com/ggerganov/llama.cpp/tree/master/examples/train-text-from-scratch

https://github.com/ggerganov/llama.cpp/pull/1652

とりあえず動かすには README にあるとおりです.
シェイクスピアのテキストを読んで学習するようです.

本家だとポインタの nullptr チェックしていないとか適当なので, 私の fork を使ったほうがいいかもしれません
(いくつか fix を取り込んでいる & セグフォしないように asan でチェック済み)

https://github.com/syoyo/llama.cpp/

../../build/bin/train-text-from-scratch \
        --vocab-model ../../models/ggml-vocab.bin \
        --ctx 64 --embd 256 --head 8 --layer 16 \
        --checkpoint-in  chk-shakespeare-256x16.bin \
        --checkpoint-out chk-shakespeare-256x16.bin \
        --model-out ggml-shakespeare-256x16-f32.bin \
        --train-data "shakespeare.txt" \
        -t 6 -b 16 -n 32 --seed 1 --adam-iter 16 \
        --print-details-interval 0 --predict 16 --use-flash

すでに llama.cpp の repo に vocab ファイル(ggml-vocab.bin)があるため, shapespeare.txt だけで学習できます!

6 threads で, i9 12900K で 20 分くらいで学習できました.

...
error_before_opt: 46.853069
error_after_opt:  38.152039
used_mem_before_opt: 988967680 bytes
used_mem_after_opt:  989736288 bytes
Generating 16 tokens.
 in hue,
Could make me any summer's story tell:
Or from their proud lap pluck them where they grew:  
Nor did I wonder at the lily's white,
Nor praise the deep vermilion in---
 veryfathered to my heart,
Which and that be
And that

なにやらシェイクスピアの片鱗は見えた! 🤩 ... 気がします...

Checkpoint は 917M, ggml model は 115 MB でした.

917M  6月 25 23:00 chk-shakespeare-256x16.bin
115M  6月 25 23:00 ggml-shakespeare-256x16-f32.bin

あとはいろいろ頑張って拡張すれば, llama.cpp(ggml) で LLM フル学習いけるはず!

発展

  • 乱数が rand() で質がよくありません. より質の高い乱数使ったほうがいいような?
  • CC-100(Commoncrawl)あたりのデータセットを用意して学習させる
    • 日本語データセットを用意して学習させる
  • CUDA/ROCm など GPU も使うようにする
  • 既存 llama pretrained の追加学習, LoRA ファインチューンなどやってみる

cgraph で graph(network op + weight) の export と import もできるようになっています.

llama 以外のネットワーク構成(gpt-neox など)で学習したい場合, C++ でゴリゴリネットワーク定義(pytorch でいう forward 定義)書いてもいいですが, Python あたりで ggml 用の cgraph を記述するのがよいかも?
(いまのところ llama.cpp での Python の converter は weight しか変換しないので, python -> ggml bin 出力の部分を書かないとであるが)

クラスタで学習

あとはデータセットを各ノードに分配したり, collective 通信やらで学習 weight をよろしく処理し, クラスタで学習でしょう.

LLM の場合は Vision 系と異なり各ノードにデータがフィットしやすい(はず)ので, ~10B くらいのネットワーク規模 + ~ 1T tokens(2~3 TB)の学習であれば高性能なネットワーク通信はいらないような... 気もします.
(最近は NVMe SSD 安価になって NVMe 2TB が 1 万円くらいなので, 各ノードに NVMe 2TB 配置も余裕でできてしまう)

HPC みたいに, CPU やネットワーク構成が均一であれば MPI(optionally with NCCL/RCCL), 不均一(CPU のスペックが違う, ノードが増えたり減ったりする)であれば async + udp ですかね. (一応 MPI も最近は動的ネットワーク構成もできるようになってきてはいますが)

幸い llama.cpp には http serve のサンプルがあるので, それを参考に http プロトコル(websocket とか)で組んでもいいかも. 動的ノード構成の場合は Redis なりをかますといいかもしれませんね.

LLaMa 学習の再現

https://github.com/Lightning-AI/lit-llama

を参考に RedPajama データセットでいける... はず!

TODO

  • ネットワーク通信あたり実装して, クラスタで学習できるようにする
  • CC-100 などのデータセットで学習させる
    • tokenize などの処理が必要
  • Chinese LLaMa https://github.com/ymcui/Chinese-LLaMA-Alpaca のように既存 LLaMa checkpoint から始めて追加学習させる
    • optimizer state などの ggml 変換が必要

Discussion