言語モデルをFPGA上で動作させる - takgto/utokyo-chipathon2023 GitHub Wiki
このページではswanという言語モデルをVitisとVivadoを使ってKV260に実装する方法を説明します。
言語モデルを高位合成でFPGAに実装してみた
このサイトのやり方で、KV260上で言語モデルを動作させます。授業用PCの全てにVitis 2022.1がインストールされています。
TAに「KV260上でswanを動かしたい」と伝えてもらえたら、次のファイルをUSBからPCのDownloadフォルダにコピーします。
kv260_custom_pkgディレクトリ(kv260_custom,sysroots,pl.dtbo(デバイスツリー)が入っています)
次に、これらフォルダとファイルをWSL側にコピーする。 WSLのターミナルから
cp -r kv260_custom_pkg /mnt/c/Users/x-nics-kuroda
sysrootはkv260_custom_pkgの中のkv260_sysroot.tar.gzを解凍して取り出します。
tar -xvzf kv260_sysroot.tar.gz
解凍してできた、kv260_sysroot/sysrootsの下のcortexa72-cortexa53-xilinx-linuxをsysrootsとして後で出てくるVitis applicationで指定します。
以下、次の手順で言語モデルを作成してください。
1. swanをgit cloneする。
swanというディレクトリができます。その下にsrcフォルダがあり、swanのソースコードが入っています(上の参考サイトにコードの中身や解説が書かれています。)
git clone https://github.com/turingmotors/swan.git
2. Vitisの起動
mkdir kv260_swan
cd kv260_swan
vitis&
Vitis IDE Launcherが立ち上がるので、Worksapceの最後がkv260_swanであることを確認して右下のLaunchをクリックする。
次の画面でCreate Application Projectをクリックする。
次の画面ではそのままNextをクリックする。
次の画面ではVitis Application Platformを選択する。図の番号の準に渡したkv260_custom_pkgの中のkv260_cutomディレクトリを指定してOpenをクリック。
kv260が新たなプラットフォームとして加わったことを確認してNextをクリック。
次の画面ではApplication project nameにswanとだけ記入してNextをクリック。
次の画面では、番号に従ってsysrootの下のcortexa72-cortexa53-xilinx-linuxディレクトリを入力してください。Root FS: と Kernel Imageは空欄のままで構いません。
次の画面ではEmpty Applicationを選択して(defaultでEmpty Applicaitonです)、Finishをクリック。
次の画面に切り替わるはずです。
次にPL(FPGA)側のソースコードをimportします。まず次の画面の左上の Explorer から swan_kernels/src を右クリックし、Import Sources を選択します。 この時、Active build configuarationをHardwareにします。
次の画面のFrom directoryでBrowseを選択し、git cloneしてできたswanの下のsrcを選択してOpenします。次の画面が現れるはずです。ここで、Kernel_と先頭についてたファイル(計6つ)を選択してFinishをクリックします。Kernel_がつくとFPGA側の高位合成C program(HLSC)であることを意味します。
ファイルを追加できたら、右上のExplorerから swan_kernels/swan_kernels.prj を選択し、丸いアイコンの Add Hardware Functionsをクリック
kernel_と先頭についたファイルを選択してOKをクリック
次の図はKV260の構成を示したものです。図のPL側とPS側のビルドを次に行います。
3. PL(FPGA)側Programのビルド
エクスプローラの左側のswan_system_hw_linkを選択して上のメニューの下にある金づちマークをクリックするとビルドが始まります。約50分かかります。
TargetがHardwareであることを確認すること。ビルドが終了するとHardwareのフォルダができ、そこにbinary_container_1.xclbinが生成されます。
4. PS(ホスト側)Programのビルド
PL側と同様に、今度はswan/srcを右クリックしてimport sourcesを選択、swan リポジトリのsrcディレクトリにあるホストプログラム(kernel_*以外全て)を追加します。
swan.prjを選択して、メニューの金づちマークをクリックします。こちらのビルドは直ぐに終了します。swan/Hardwareの下にswanという実行ファイルができます。
[注意点]
- 「error while loading shared libraries: libxilinxopencl.so.2: cannot open shared object file: No such file or directory」のようなエラーが出る場合は、KV260 のデフォルトの rootfs に XRT がインストールされていないことが原因です。しかし、
sudo apt install xrtではなく以下のコマンドを使用してください。
--> 次のコマンドを実行するにはKV260とPCをネットワーク共有して、KV260からインターネットサイトが見えるようにしないとなりません。行う前にTAに相談ください。
$ sudo apt install zocl-202210.2.13.479-r0.0.xilinx_k26_kv
$ sudo apt install xrt-202210.2.13.479-r0.0.cortexa72_cortexa53
$ sudo apt install packagegroup-petalinux-opencv
xrtに含まれるzoclのバージョンが新しいと正常に動作しないようです。
5. KV260へのファイル転送
次の3つのファイルはKV260のホームディレクトリ(/home/root)に置きます。 WSL2において、
- ~/kv260_swan/swan_system_hw_link/Hardware/binary_container_1.xclbin をbinary_container_1.bin にリネームしたもの
- ~/kv260_swan/swan/Hardware/swan
- ~/swan/model (TAから)
/lib/firmware/xilinx/swanディレクトリを作成しそこに置く
- kv260_swan/swan_system_hw_link/Hardware/binary_container_1.xclbin をbinary_container_1.bit.bin にリネームしたもの
- pl.dtbo (TAから)
- shell.json (下の内容のテキストファイル. 自分で作成する)
{
"shell_type" : "XRT_FLAT",
"num_slots": "1"
}
6. SWANの実行
まず、xmutilコマンドを用いてPLにハードウェアを生成します。 KV260上で、
sudo xmutil listapps
sudo xmutil unloadapp
sudo xmutil loadapp swan
Loaded to Slot 0と出れば成功です。
これで、ホームディレクトリにある swanを実行すると、KV260上でLLMが動き出します。
お世辞にも早いとは言い難いですが、わずか~4GBメモリのFPGAボード上で小型LLMが動きます。
先の参考資料には、PCだけでSWANを実行する方法が載ってます。直ぐにできますのでやってみてください。
7. 改良するためには、
主に応答速度を改良するには、次の方法があると思います。
- HLSプラグマ最適化
- #pragma HLS PIPELINE:ループのパイプライン化
- #pragma HLS UNROLL:ループ展開で並列度向上
- #pragma HLS ARRAY_PARTITION:BRAMの並列アクセス
- II(Initiation Interval)の改善
- カーネル統合 + Dataflow化 現在は各カーネルが完全に終わってから次のカーネルが開始、中間データは毎回DRAMに書き戻しているので効率いいとは言えません。
- 各処理が重なって動作(パイプライン)
- 中間データはFIFO経由(DRAM不要)
- タイリング + オンチップバッファ 大きな行列を小さなタイル(ブロック)に分割し、タイル単位で処理する。 行列演算を小ブロックに分割し、BRAMにタイルをキャッシュしてDRAMアクセス回数を削減。 これは、
- より小さなモデルへの変更
- TinyLlama、SmolLM等の軽量モデル
- 層数・hidden sizeの削減
- 量子化
- モデル自体をfloat32からINT8等に量子化
- メモリ転送量が1/4〜1/8に削減
- DSPの利用効率も向上