古めの環境ですがRyzen 7 1700とRX 480の環境があったのでROCmで機械学習ができないかと思ったので実験してみます。
環境は以下の自作PCにRocky Linux9.4をMinimumインストールしました。
CPU:Ryzen 7 1700
MB:TUF B450M-PLUS GAMING
RAM:16GB×2枚 2666 MHz
SSD:Intel 670p 1TB
Radeonのドライバをインストールするツールをインストールします。現時点(2024/6/1)の最新版はROCm6系ですが、RX480を動かす都合で5系の最新版だった5.7.3をインストールします。
# dnf install https://repo.radeon.com/amdgpu-install/5.7.3/rhel/9.2/amdgpu-install-5.7.50703-1.el9.noarch.rpm -y
EPELリポジトリとCodeReady Linux Builderリポジトリが必要なので有効にしてから、amdgpu-installを実行します。5系の対応バージョンが9.2までみたいなので、amdgpudistroをセットしておきます。
(最初は9.2をインストールしたんですが、dnf updateしたらバージョンが上がってしまいました)
# echo "9.2" > /etc/yum/vars/amdgpudistro # dnf install epel-release -y # crb enable # amdgpu-install --usecase=rocm
ダウンロードに2.4G程度、ディスクも17G程度要求されたので、しばらく待ちます。
dkmsでモジュールを確認するとaddedとなっており、rocminfoで確認してもROCk module is loadedとなっているので、インストールはできたようです。
# dkms status
amdgpu/6.2.4-1697730.el9: added
# rocminfo
ROCk module is loaded
=====================
HSA System Attributes
=====================
Runtime Version: 1.1
System Timestamp Freq.: 1000.000000MHz
Sig. Max Wait Duration: 18446744073709551615 (0xFFFFFFFFFFFFFFFF) (timestamp count)
Machine Model: LARGE
System Endianness: LITTLE
Mwaitx: DISABLED
DMAbuf Support: YES
==========
HSA Agents
==========
*******
Agent 1
*******
Name: AMD Ryzen 7 1700 Eight-Core Processor
Uuid: CPU-XX
Marketing Name: AMD Ryzen 7 1700 Eight-Core Processor
Vendor Name: CPU
Feature: None specified
Profile: FULL_PROFILE
Float Round Mode: NEAR
Max Queue Number: 0(0x0)
Queue Min Size: 0(0x0)
Queue Max Size: 0(0x0)
Queue Type: MULTI
Node: 0
Device Type: CPU
Cache Info:
L1: 32768(0x8000) KB
Chip ID: 0(0x0)
ASIC Revision: 0(0x0)
Cacheline Size: 64(0x40)
Max Clock Freq. (MHz): 3000
BDFID: 0
Internal Node ID: 0
Compute Unit: 16
SIMDs per CU: 0
Shader Engines: 0
Shader Arrs. per Eng.: 0
WatchPts on Addr. Ranges:1
Features: None
Pool Info:
Pool 1
Segment: GLOBAL; FLAGS: FINE GRAINED
Size: 32508848(0x1f00bb0) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 2
Segment: GLOBAL; FLAGS: KERNARG, FINE GRAINED
Size: 32508848(0x1f00bb0) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
Pool 3
Segment: GLOBAL; FLAGS: COARSE GRAINED
Size: 32508848(0x1f00bb0) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Alignment: 4KB
Accessible by all: TRUE
ISA Info:
*******
Agent 2
*******
Name: gfx803
Uuid: GPU-XX
Marketing Name: AMD Radeon (TM) RX 480 Graphics
Vendor Name: AMD
Feature: KERNEL_DISPATCH
Profile: BASE_PROFILE
Float Round Mode: NEAR
Max Queue Number: 128(0x80)
Queue Min Size: 64(0x40)
Queue Max Size: 131072(0x20000)
Queue Type: MULTI
Node: 1
Device Type: GPU
Cache Info:
L1: 16(0x10) KB
Chip ID: 26591(0x67df)
ASIC Revision: 1(0x1)
Cacheline Size: 64(0x40)
Max Clock Freq. (MHz): 1266
BDFID: 1792
Internal Node ID: 1
Compute Unit: 36
SIMDs per CU: 4
Shader Engines: 4
Shader Arrs. per Eng.: 1
WatchPts on Addr. Ranges:4
Features: KERNEL_DISPATCH
Fast F16 Operation: TRUE
Wavefront Size: 64(0x40)
Workgroup Max Size: 1024(0x400)
Workgroup Max Size per Dimension:
x 1024(0x400)
y 1024(0x400)
z 1024(0x400)
Max Waves Per CU: 40(0x28)
Max Work-item Per CU: 2560(0xa00)
Grid Max Size: 4294967295(0xffffffff)
Grid Max Size per Dimension:
x 4294967295(0xffffffff)
y 4294967295(0xffffffff)
z 4294967295(0xffffffff)
Max fbarriers/Workgrp: 32
Packet Processor uCode:: 730
SDMA engine uCode:: 58
IOMMU Support:: None
Pool Info:
Pool 1
Segment: GLOBAL; FLAGS: COARSE GRAINED
Size: 8388608(0x800000) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Alignment: 4KB
Accessible by all: FALSE
Pool 2
Segment: GLOBAL; FLAGS:
Size: 8388608(0x800000) KB
Allocatable: TRUE
Alloc Granule: 4KB
Alloc Alignment: 4KB
Accessible by all: FALSE
Pool 3
Segment: GROUP
Size: 64(0x40) KB
Allocatable: FALSE
Alloc Granule: 0KB
Alloc Alignment: 0KB
Accessible by all: FALSE
ISA Info:
ISA 1
Name: amdgcn-amd-amdhsa--gfx803
Machine Models: HSA_MACHINE_MODEL_LARGE
Profiles: HSA_PROFILE_BASE
Default Rounding Mode: NEAR
Default Rounding Mode: NEAR
Fast f16: TRUE
Workgroup Max Size: 1024(0x400)
Workgroup Max Size per Dimension:
x 1024(0x400)
y 1024(0x400)
z 1024(0x400)
Grid Max Size: 4294967295(0xffffffff)
Grid Max Size per Dimension:
x 4294967295(0xffffffff)
y 4294967295(0xffffffff)
z 4294967295(0xffffffff)
FBarrier Max Size: 32
*** Done ***
上記の出力のAgent 2がRX480(gfx803)になります。GPUも認識できているようですね。
次にLLMを動かすために、llama.cppをコンパイルします。LLAMA_HIPBLAS=1を指定してROCmを有効にします。
# dnf install git make wget -y # cd /work # git clone https://github.com/ggerganov/llama.cpp # cd /work/llama.cpp # export CC=/opt/rocm/llvm/bin/clang # export CXX=/opt/rocm/llvm/bin/clang++ # make LLAMA_HIPBLAS=1 -j
GGUF形式のモデルをダウンロードします。今回は以下を使わせていただきました。
https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-fast-instruct-gguf/
llama2の13bを量子化したモデルです。8GB弱のモデルなのでほぼGPUに乗せることができるのではないかと思いました。
# mkdir /work/model # cd /work/model # wget https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-fast-instruct-gguf/resolve/main/ELYZA-japanese-Llama-2-13b-fast-instruct-q4_K_M.gguf
41layerをGPUオフロードしようとするとOut of Memoryになって落ちたので39指定にしました。
# /work/llama.cpp/main -ngl 39 -m /work/model/ELYZA-japanese-Llama-2-13b-fast-instruct-q4_K_M.gguf -p '[INST] <<SYS>>あなたは誠実で優秀な日本人のアシスタントです。<</SYS>>Pythonでmysqlからselectするサンプルを実装して[/INST]'
~~~~~~~~~~~~省略~~~~~~~~~~~~
ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no
ggml_cuda_init: CUDA_USE_TENSOR_CORES: yes
ggml_cuda_init: found 1 ROCm devices:
Device 0: AMD Radeon (TM) RX 480 Graphics, compute capability 8.0, VMM: no
llm_load_tensors: ggml ctx size = 0.37 MiB
llm_load_tensors: offloading 39 repeating layers to GPU
llm_load_tensors: offloaded 39/41 layers to GPU
llm_load_tensors: ROCm0 buffer size = 7090.72 MiB
llm_load_tensors: CPU buffer size = 7585.80 MiB
~~~~~~~~~~~~省略~~~~~~~~~~~~
[INST] <<SYS>>あなたは誠実で優秀な日本人のアシスタントです。<</SYS>>Pythonでmysqlからselectするサンプルを実装して[/INST] mysql-connector-pythonをpipでインスト ールしたら、次のように実装することができます。
```
import mysql.connector
cnx = mysql.connector.connect(host='localhost', user='username', password='password')
cursor = cnx.cursor()
query = "SELECT * FROM table_name"
cursor.execute(query)
results = cursor.fetchall()
for row in results:
print(row)
``` [end of text]
llama_print_timings: load time = 5032.17 ms
llama_print_timings: sample time = 4.97 ms / 102 runs ( 0.05 ms per token, 20539.67 tokens per second)
llama_print_timings: prompt eval time = 31577.39 ms / 37 tokens ( 853.44 ms per token, 1.17 tokens per second)
llama_print_timings: eval time = 8256.41 ms / 101 runs ( 81.75 ms per token, 12.23 tokens per second)
llama_print_timings: total time = 39857.12 ms / 138 tokens
Log end
プロンプトの表示は12.23 tokens per secondなので、実用的な速度だと感じました。
Ryzen 2400Gで同様のモデルでCPUで実行した場合、3.86 tokens per secondだったので、RX480はは3倍速いです。ただ、load timeはGPUを使うケースでは長くなるようです。
せっかくなので、全部VRAMに乗せられるのが期待できる7Bのモデルも試してみます。
# cd /work/model
# wget https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-7b-instruct-gguf/resolve/main/ELYZA-japanese-Llama-2-7b-instruct-q4_K_M.gguf
# /work/llama.cpp/main -ngl 33 -m /work/model/ELYZA-japanese-Llama-2-7b-instruct-q4_K_M.gguf -p '[INST] <<SYS>>あなたは誠実で優秀な日本人のアシスタントです。<</SYS>>Pythonでmysqlからselectするサンプルを実装して[/INST]'
~~~~~~~~~~~~省略~~~~~~~~~~~~
ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no
ggml_cuda_init: CUDA_USE_TENSOR_CORES: yes
ggml_cuda_init: found 1 ROCm devices:
Device 0: AMD Radeon (TM) RX 480 Graphics, compute capability 8.0, VMM: no
llm_load_tensors: ggml ctx size = 0.30 MiB
llm_load_tensors: offloading 32 repeating layers to GPU
llm_load_tensors: offloading non-repeating layers to GPU
llm_load_tensors: offloaded 33/33 layers to GPU
llm_load_tensors: ROCm0 buffer size = 3820.94 MiB
llm_load_tensors: CPU buffer size = 70.31 MiB
~~~~~~~~~~~~省略~~~~~~~~~~~~
[INST] <<SYS>>あなたは誠実で優秀な日本人のアシスタントです。<</SYS>>Pythonでmysqlからselectするサンプルを実装して[/INST] ```python
import mysql.connector
# クライアントライブラリのインストール
mysql.connector/connectors/pandas-mysql.pyx
# 接続情報の設定
host = 'localhost'
username = 'root'
password = ''
dbname = 'test'
# 接続
cnx = mysql.connector.connect(host=host, user=username, passwd=password,
database=dbname)
# データの取得
cursor = cnx.cursor()
# ステートメント
cursor.execute("SELECT * FROM table1")
# データを読み込む
df = pd.io.sql(cursor, index_col=None)
# クローズ
cnx.close()
# データを表示
print(df)
``` [end of text]
llama_print_timings: load time = 3086.38 ms
llama_print_timings: sample time = 7.60 ms / 228 runs ( 0.03 ms per token, 30000.00 tokens per second)
llama_print_timings: prompt eval time = 15435.83 ms / 61 tokens ( 253.05 ms per token, 3.95 tokens per second)
llama_print_timings: eval time = 10469.52 ms / 227 runs ( 46.12 ms per token, 21.68 tokens per second)
llama_print_timings: total time = 25941.17 ms / 288 tokens
Log end
RX480で21.68 tokens per secondでした。WebのAI系のサービスでの速度と遜色ないです。
Ryzen 2400Gでは7.01 tokens per secondだったのでこちらも3倍ですね。
残り1layerならすべてVRAMに載せきってもそこまで実行速度には影響でないようです。
第一世代のRyzenはWindows11にアップグレードできないので、どうするかと思っていましたが、これならローカルのAIChat環境として余生が送れそうです。
RX480がFP16で5.834 TFLOPS メモリ帯域256GB/sとそこまでハイスペックではない環境でこれなので、中古で安くに入手できるVEGA56(FP16 21.09 TFLOPS メモリ帯域409.6GB/s)あたりを入手すれば高速化も狙えそうです。