話題のDeepSeekR1をJetson AGX ORINで実行してみた

# 話題のDeepSeekR1をJetson AGX ORINで実行してみた

突然降って湧いたDeep Seekの発表で、NASDAQではNvidiaと半導体関連の株価が急落し、巷では大騒ぎとなってますね。
それは置いておいて、ローカルでも実行可能らしいので、さっそく実行してみました。
 ~~意外に簡単に動きました。拍子抜けしました。~~
 CUDA関連で色々とありました。最適化オプションを追加しています。

# 環境
普通のPCで実行しても、あまり面白くないので、Jetson AGX orin 32GBで実行してみました。
llama.cppを使用します。
個人的な備忘録を兼ねて、書いてみました。

## Jetson AGX ORINについて
nvidiaのエッジ向けのHWになります。
RAMが32GBと64GBの2種類ありますが、今回使用したのは32GB版です。
https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/
開発キットや、搭載したPC的なものも発売されているようです。
https://www.adlinktech.com/Products/ROS2_Solution/ROS2_Controller/RQX-59_Series?lang=ja
（アフェリエイトではないです）

# 手順

## jetpack 6.2のインストール

USB-TypeCで接続してインストールしました。
https://developer.nvidia.com/blog/nvidia-jetpack-6-2-brings-super-mode-to-nvidia-jetson-orin-nano-and-jetson-orin-nx-modules/

## cuda-toolkit-12.6.3
https://developer.nvidia.com/cuda-toolkit-archive
CUDA Toolkit 12.6.3を選択
linux, aarch64 jetpack, Native, Ubuntu, 22.04, dep(どっちでも可)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338102/9653958e-be9c-c58b-8df5-2116da5235c9.png)

## llama.cpp

LLMを実行するためのドライバのようなもの。
https://github.com/ggerganov/llama.cpp

### build
arm版のバイナリが無いので、ビルドします。
cmakeの自動判定では、CUDAを使用しない設定になってしまうため、オプション指定が必要でした。
```bash
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DGGML_CPU_AARCH64=1 \
         -DGGML_CUDA=1 \
         -DGGML_CUDA_F16=1 \
         -DGGML_F16C=1 -DGGML_FMA=1 \
         -DCMAKE_CUDA_COMPILER=$CUDA_HOME/bin/nvcc \
         -DCUDAToolkit_ROOT=$CUDA_HOME \
         -DGGML_BLAS=1 \
         ..
         
make -j llama-server
```
しばらく待つ。
だいぶ時間はかかる。

### 実行確認
binの下にpathを通して、llama-serverが実行可能か確認
```
export PATH=./bin:$PATH
llama-server
```
実行できたらビルドは出来てます。

### モデルの取得
とりあえず、14B-Q6_Kが小さくて良いらしいというのでダウンロード。
他にもモデルが色々あるようですが、まだ試してません。
```
https://huggingface.co/bartowski/DeepSeek-R1-Distill-Qwen-14B-GGUF/blob/main/DeepSeek-R1-Distill-Qwen-14B-Q6_K.gguf
```
## 実行
```
llama-server -m DeepSeek-R1-Distill-Qwen-14B-Q6_K.gguf --host 0.0.0.0 --port 8080 --gpu-layers 49
```
--gpu-layers 49:最適値はよくわからない。とりあえず最大値としています。
--hostの指定をしないと自機以外からアクセスできません。
このように、ログが出てポート8080が開く。
```
<｜User｜>Hello<｜Assistant｜>Hi there<｜end?of?sentence｜><｜User｜>How are you?<｜Assistant｜>'
main: server is listening on http://0.0.0.0:8080 - starting the main loop
srv  update_slots: all slots are idle
```
これで、http://<ipaddress>:8080接続すればDeepSeekR1を使うことができます。
ちなみにorin上でブラウザを開くと、使用可能なメモリが減るので他のPCからアクセスしてます。
またGUIは無効にしています。
ただし空きメモリを見ると、GUIを実行する余裕は十分にありそうです。

## 実行結果

実行できました。日本語も理解してくれるようです。
ただし、1回のプロンプトの反応に30秒程度かかります。
### 「日本語は分かるか？」と質問してみた。
分かるらしい。えらい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338102/06737fce-d0ae-c707-4d69-a27fb1d00e9f.png)
### 「どんなことができる？」と質問
もちろんです！は微妙に返事が変な気もするが、概ね妥当な反応だと思う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338102/d35c3fb3-f129-a75c-4f95-6257590226f5.png)


### free -h結果
thinking中のメモリも余裕あります。
```
               total        used        free      shared  buff/cache   available
Mem:            29Gi       2.1Gi        10Gi        28Mi        17Gi        27Gi
Swap:          270Gi          0B       270Gi
```
### top結果
```
top - 22:20:03 up  2:53,  3 users,  load average: 5.87, 1.52, 0.51
Tasks: 308 total,   2 running, 306 sleeping,   0 stopped,   0 zombie
%Cpu(s): 98.4 us,  0.1 sy,  0.0 ni,  1.3 id,  0.0 wa,  0.2 hi,  0.1 si,  0.0 st
MiB Mem :  30696.8 total,  10985.4 free,   2167.5 used,  17543.9 buff/cache
MiB Swap: 277492.3 total, 277492.3 free,      0.0 used.  28099.6 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   6725 usr1      20   0   13.0g  12.1g  11.3g R  1178  40.4  12:20.37 llama-server
   1312 root      20   0       0      0      0 S   0.3   0.0   0:03.81 RTW_CMD_THREAD
   6830 usr1      20   0   13884   3636   2780 R   0.3   0.0   0:00.19 top
```

### 実行ログ
質問の度にllama.cppから出てきたログがでます。
以下が一回部のログです。
```
request: GET / 192.168.3.13 200
slot launch_slot_: id  0 | task 0 | processing task
slot update_slots: id  0 | task 0 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 15
slot update_slots: id  0 | task 0 | kv cache rm [0, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 15, n_tokens = 15, progress = 1.000000
slot update_slots: id  0 | task 0 | prompt done, n_past = 15, n_tokens = 15
slot      release: id  0 | task 0 | stop processing: n_past = 109, truncated = 0
slot print_timing: id  0 | task 0 |
prompt eval time =    4012.12 ms /    15 tokens (  267.47 ms per token,     3.74 tokens per second)
       eval time =   28221.35 ms /    95 tokens (  297.07 ms per token,     3.37 tokens per second)
      total time =   32233.47 ms /   110 tokens
srv  update_slots: all slots are idle
```
読み方は良く分かりませんが、
```
      total time =   32233.47 ms /   110 tokens
```
eval timeから見て1回の応答に30秒程度かかります。



# 感想
あまりにも意外にあっさり動いて拍子抜けしました。
突如としてChatGPTが発表されて、世界に衝撃が走りましたが。
DeepSeekも負けず劣らず更に衝撃的です。個人的には。
凄い時代になったものです。
しかしJetsonはedge向けのHWであるため、処理能力はPC搭載のGPUに比べ低く、体感的には速度はRTX3060の1/2程度です。しかしJetson AGX ORINの最大の特徴は低消費電力で最大でも60Wと、RTX3060搭載のPCに比べて1/10になります。
またORINはCPUとGPUのメモリが共用であるため、64GB版のORINなら更に大規模なllmを動かすことが出来そうです。

# 続きを書きました。

docker編とcyberagentの日本語版編
https://qiita.com/g667408/items/2c09950c481a138bde59