Intel環境でLLMを動かす（NPU編）

# はじめに
　IntelでLLMを動かす際の手順についてまとめました。なお、[GPU環境](https://qiita.com/ishikaha/items/ec74ac8cb0c3eb4bb1e2)との同時起動は考慮されていません。
# 使用環境

- AtomMan X7 Ti 185H
- CPU: Intel Core Ultra9 processor 185H
- NPU: Intel AI Boost
- Memory: 96GB
- OS: Ubuntu 24.04.1 LTS
# 手順
## ドライバをインストールする
　まず、Intelのサイトを参考にドライバをインストールします。

https://github.com/intel/linux-npu-driver/releases

　古いドライバを削除します。
```bash
sudo dpkg --purge --force-remove-reinstreq intel-driver-compiler-npu intel-fw-npu intel-level-zero-npu
```
（GPU環境でこれを実行すると、Level-Zeroドライバが削除されて、にっちもさっちもいかなくなります。）

　新しいドライバをダウンロードしてきます。
```bash
wget https://github.com/intel/linux-npu-driver/releases/download/v1.10.0/intel-driver-compiler-npu_1.10.0.20241107-11729849322_ubuntu24.04_amd64.deb
wget https://github.com/intel/linux-npu-driver/releases/download/v1.10.0/intel-fw-npu_1.10.0.20241107-11729849322_ubuntu24.04_amd64.deb
wget https://github.com/intel/linux-npu-driver/releases/download/v1.10.0/intel-level-zero-npu_1.10.0.20241107-11729849322_ubuntu24.04_amd64.deb
```

　ドライバを放置したまま、libtbb12をインストールします。放置する理由はよくわかりません。

```bash
sudo apt update
sudo apt install libtbb12
```
　放置していたドライバをインストールします。

```bash
sudo dpkg -i *.deb
```

　Level-Zeroドライバをダウンロードして、インストールします。

```bash
wget https://github.com/oneapi-src/level-zero/releases/download/v1.17.44/level-zero_1.17.44+u22.04_amd64.deb
sudo dpkg -i level-zero*.deb
```
　インストールされたかどうか確認します。
```bash
dpkg -l level-zero
```

　このように出ればOK。
```
要望=(U)不明/(I)インストール/(R)削除/(P)完全削除/(H)保持
| 状態=(N)無/(I)インストール済/(C)設定/(U)展開/(F)設定失敗/(H)半インストール/(W>
|/ エラー?=(空欄)無/(R)要再インストール (状態,エラーの大文字=異常)
||/ 名前           バージョン   アーキテクチ 説明
+++-==============-============-============-=================================
ii  level-zero     1.17.44      amd64        oneAPI Level Zero
```

　ここで再起動します。

　再起動して、`ls /dev/accel/accel0`が通ればOKです。

　デバイスをroot以外のユーザでも使えるように、以下の設定を施します。
```bash
sudo usermod -a -G render <ユーザ名> #<ユーザ名>は適宜置換え 
sudo bash -c "echo 'SUBSYSTEM==\"accel\", KERNEL==\"accel*\", GROUP=\"render\", MODE=\"0660\"' > /etc/udev/rules.d/10-intel-vpu.rules"
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=accel
reboot
```
## NPU用ライブラリをインストールする。
　まず、cmakeをインストールしておきます。
 
 ```bash
 sudo apt install cmake
 ```
　ここで、間違えても`pip install cmake`を実行してはいけません。ここ、結構ハマりました。

　以下は例によって、必要であれば仮想環境下で操作します。

 ```bash
pip install intel-npu-acceleration-library
```
　同時にPytorchやTransformersもインストールされるようです。その他にも、matplotlibとかnumpyとかpandasとか、定番のライブラリを拾ってくれるので、一から入れる場合はお得感で少し幸せになれるかもしれません。

　これで準備は完了です。

 # LLMを使ってみる
　今回もtanuki8Bを試してみます。前回のファイルを少し改変します。また、float32で処理できないようなので、float16で処理します（bfloat16もだめな模様）。

 ```python:tanuki_NPU.py
import datetime
from intel_npu_acceleration_library import NPUModelForCausalLM, float16
from intel_npu_acceleration_library.compiler import CompilerConfig
from transformers import AutoTokenizer, TextStreamer
import torch

st = datetime.datetime.now()
print("開始時刻", end=": ")
print(st)

compiler_conf = CompilerConfig(dtype=float16)
model = NPUModelForCausalLM.from_pretrained("weblab-GENIAC/Tanuki-8B-dpo-v1.0", use_cache=True, config=compiler_conf).eval()
tokenizer = AutoTokenizer.from_pretrained("weblab-GENIAC/Tanuki-8B-dpo-v1.0")
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

messages = [
    {"role": "system", "content": "以下は、タスクを説明する指示です。要求を適切に満たす応答を書きなさい。"},
    {"role": "user", "content": "たぬきに純粋理性批判は理解できますか？"}
]

input_ids = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
output_ids = model.generate(input_ids,
                            max_new_tokens=1024,
                            temperature=0.5,
                            streamer=streamer)

et = datetime.datetime.now()
print("終了時刻", end=": ")
print(et)

t = et - st
print("所要時間", end=": ")
print(t)
```
　だいたいこのくらいの時間になりました。

```bash
所要時間: 0:06:10.993427
```

　GPUより若干遅めです。int4にすると少しだけ速くなりました。