AI」カテゴリーアーカイブ

VRAM 8GB の GPU 3枚で 30B 前後の LLM を動かす。Ollama でマルチ GPU 速度の比較

PC 上でローカル LLM を実行する場合、VRAM 容量が足りなくてもビデオカードを複数枚集めれば GPU 上で動作することがわかったので、色々組み合わせて速度を比較してみました。

家に眠っていた古いビデオカードを集めて 30B 前後のモデルが動いています。流石にパフォーマンスでは GeForce RTX 4090 等の上位モデルに敵わないと思いますが、13 tps ほど出ていますので動かすだけなら十分かと思います。

以下その結果です。速度は変動があるので数値はあくまで参考程度にお願いします。

27B gemma2:27b

VRAM 8GB のビデオカード 3枚で動作させることができました。使用したのは GeForce RTX 2070 Super (8GB)、GeForce GTX 1080 (8GB)、GeForce GTX 1070 (8GB) といった組み合わせです。GTX 1000 世代は TensorCore がありませんが、それでも CPU よりずっと高速です。

種類GPU合計VRAMメモリ使用量容量の割合速度
CPU のみRyzen 7 9700X19GB100% CPU1.97 tps
3 GPU2070S + 1080 + 10708+8+8=24GB23GB100% GPU12.89 tps
2 GPU4060Ti + 2070S16+8=24GB23GB100% GPU15.94 tps

うまく動いたので、あとから他の PC で使っていた RTX 4060ti (16GB) も持ってきました。「メモリ容量」と「容量の割合」は「ollama ps」コマンドで表示される値です。

32B qwen2.5:32b

32B はギリギリ入りませんでした。同じ 24GB でも GeForce RTX 4060 Ti (16GB) + GeForce RTX 2070 Super (8GB) の場合はメモリに載ります。やはり分割は少ない方がメモリの利用効率が上がるようです。

種類GPU合計VRAMメモリ使用量容量の割合速度
CPU のみRyzen 7 9700X22GB100% CPU1.77 tps
3 GPU2070S + 1080 + 10708+8+8=24GB25GB3% CPU + 97% GPU7.69 tps
2 GPU4060Ti + 2070S16+8=24GB23GB100% GPU13.56 tps

14B phi4:14b

14B はもちろん動きます。4060Ti (16GB) の場合は一枚に収まりました。8GB 2枚でも動くかもしれませんが残念ながら未確認です。余裕があれば後ほど試したいと思っています。

種類GPU合計VRAMメモリ使用量容量の割合速度
CPU のみRyzen 7 9700X11GB100% CPU3.06 tps
3 GPU2070S + 1080 + 10708+8+8=24GB16GB100% GPU17.38 tps
1 GPU4060Ti16GB14GB100% GPU37.38 tps

70B llama3.3:70b

70B はさすがに大きく、手持ちのビデオカード 4枚全部繋いでもメモリに入りませんでした。

種類GPU合計VRAMメモリ使用量容量の割合速度
CPU のみRyzen 7 9700X46GB100% CPU0.88 tps
3 GPU2070S + 1080 + 10708+8+8=24GB50GB52% CPU + 48% GPU1.09 tps
2 GPU4060Ti + 2070S16+8=24GB48GB49% CPU + 51% GPU1.46 tps
3 GPU4060Ti + 2070S + 108016+8+8=32GB49GB35% CPU + 65% GPU1.69 tps
4 GPU4060Ti + 2070S + 1080 + 107016+8+8+8=40GB51GB21% CPU + 79% GPU2.22 tps

データ

より詳しい結果を以下のページにまとめました。

使用した環境など

Proxmox VE 上の VM に Ubuntu 22.04 をインストールし、その上で ollama を走らせています。GPU は最大 4枚を VM にパススルーしています。ビデオカードはそれぞれ以下の方法で接続しています。

  • マザーボード上の PCIe x16 スロット 1 (PCIe 3.0 x16 で RTX 2070Super)
  • マザーボード上の PCIe x16 スロット 2 (PCIe 4.0 x4 で RTX 4060Ti)
  • M.2 スロット + Oculink 経由で外部の DEG1 に接続 (PCIe 3.0 x4 で GTX1080)
  • マザーボード上の PCIe x1 スロットからライザーケーブル (PCIe 3.0 x1 で GTX1070)

GPU を接続した PC は Ryzen 9 3950X + X570 です。CPU のみの結果は別の PC (Ryzen 7 9700X) によるものです。

VM へのパススルーではなく Linux を直接インストールした場合ではもう少しパフォーマンスが上がるかもしれません。

GeForce RTX 4090 や RTX 3090 といった上位 GPU がなくても、家にあった古いビデオカードを利用して組み合わせるだけで 30B 前後のモデルが使えるようになりました。その分パフォーマンスは限られていますが、13 tps あればそれなりに使えると思いますので、アプリケーションから呼び出すテストに使ったりと色々活用できそうです。

関連エントリ

Proxmox VE の GPU パススルー設定

Proxmox VE の GPU パススルーを色々試しています。以下のページにまとめました。

GeForce の外付け GPU であれば、Proxmox 上の GUI だけで簡単に設定できることがわかりました。

AMD CPU はもともと設定不要ですし、Intel CPU でも Proxmox VE 8.2 から intel_iommu=on がデフォルトで有効化されており grub 上のカーネルオプションの設定が不要になっています。

実際に Ryzen 9 3950X + X570 にビデオカードを最大 4枚繋いでパススルーを行うことができました。

2枚はマザー上の x16 スロットに直接、もう一つは PCIe x1 からライザーケーブル経由、最後は M.2 スロットから OCulink で DEG1 に外部 GPU として接続しています。

それぞれ異なる VM に割り当ててもいいですし、全部同じ VM で使うこともできます。

例えば VRAM 8GB のビデオカードでも、3台集めれば 27b の LLM モデルを GPU で走らせることができます。GeForce RTX 2070 Super + GeForce GTX 1080 + GeForce GTX 1070 はいずれも VRAM 8GB ですが、3台使うことで ollama 上の Gemma2:27b が 13 token/s ほどになりました。CPU のみだと 1.5 token/s くらいです。

試した GPU は以下の通りです。動かなかったのは今のところ RADEON RX Vega 56 のみです。詳しくはまとめたページの方をご覧ください。

  • GeForce RTX 4060 Ti
  • GeForce RTX 2070 Super
  • GeForce GTX 1080
  • GeForce GTX 1070
  • GeForce GTX 970
  • GeForce GTX 960
  • RADEON RX 6400
  • RADEON RX 480

関連ページ

Android UserLAnd で PyTorch を使う。C++ API

Android スマートフォンの上に PyTorch の開発環境を作ってみました。かなり遅いですが、電車の中で書いたコードのビルドテストをしたり、簡単な実験をするくらいには使えそうです。

以下作業メモです。

使用した端末は Essential Phone PH-1 (Snapdragon 835, RAM 4GB, Android 10)。もちろん C++ だけでなく Python からも使えます。

●UserLAnd の準備

UserLAnd を使うと Android 上に Linux 環境を作ることができます。root 不要でただの Android アプリとして動きます。今回は最小構成にするため Ubuntu + SSH Terminal を選択しました。

●PyTorch のビルド

UserLAnd の Ubuntu を起動し Terminal で作業します。または PC 等から ssh で接続することもできます。

先に更新しておきます。

$ sudo apt update
$ sudo apt upgrade -y

必要なソフトのインストール

$ sudo apt install  git cmake g++
$ sudo apt install  libopenblas-dev

Python3 の準備

$ sudo apt install  python3-dev python3-setuptools
$ sudo apt install  python3-numpy python3-cffi
$ sudo apt install  python3-yaml python3-wheel

pytorch の準備。展開フォルダは仮に ~/pytorch とします。

$ cd
$ git clone --recursive https://github.com/pytorch/pytorch
$ cd pytorch
$ git submodule sync
$ git submodule update --init --recursive

ビルドします。複数スレッド使うとメモリ不足で落ちるので MAX_JOBS=1 を指定します。

$ cd ~/pytorch
$ USE_CUDA=0 USE_CUDNN=0 BUILD_TEST=0 USE_MKLDNN=0 USE_DISTRIBUTED=0 MAX_JOBS=1 python3 setup.py build_clib

Python 向けにビルドする場合は最後の “build_clib” を “install” にしてください。

かなり時間がかかるので電源に接続したまましばらく待ちます。

もし途中で↓のようなエラーが出た場合はコードを一部修正します。

... 8x8-dq-aarch64-neon.S:662: Error: operand mismatch -- `mov V8.4s,V9.4s'

“aten/src/ATen/native/quantized/cpu/qnnpack/src/q8gemm/8×8-dq-aarch64-neon.S” の 662行~669行あたりにある

    MOV V8.4s, V9.4s
    MOV v10.4s, v11.4s
    MOV v12.4s, V13.4s
    MOV V14.4s, V15.4s
    MOV V16.4s, V17.4s
    MOV V18.4s, V19.4s
    MOV V20.4s, V21.4s
    MOV V22.4s, V23.4s

これらの行を下のように変更します。

    MOV V8.16b, V9.16b
    MOV v10.16b, v11.16b
    MOV v12.16b, V13.16b
    MOV V14.16b, V15.16b
    MOV V16.16b, V17.16b
    MOV V18.16b, V19.16b
    MOV V20.16b, V21.16b
    MOV V22.16b, V23.16b

AArch64 の NEON にはもともとレジスタ同士の move 命令がありません。mov vdest, vsrc はアセンブラ内部で「 or vdest, vsrc, vsrc 」に置き換えられます。浮動小数点数で論理演算はできないので、アセンブラによっては 4s (単精度 32bit x4 = 128bit) の型指定がエラーになってしまうのだと考えられます。これは 16b (byte 8bit x16 = 128bit) に変更すれば OK です。

● C++ から利用する

前回も書いたように ~/pytorch/torch 以下が libtorch 相当になります。

include path に

~/pytorch/torch/include
~/pytorch/torch/include/torch/csrc/api/include

link path に

~/pytorch/torch/lib

を指定してコンパイルします。必要なライブラリは libc10 と libtorch_cpu です。コンパイルオプションの指定例は下記の通り。

$ clang -L~/pytorch/torch/lib -lc10 -ltorch_cpu  torchtest.cpp -o torchtest

実行時は LD_LIBRARY_PATH が必要です。

$ export LD_LIBRARY_PATH=~/pytorch/torch/lib

一度ビルドしておけば他の AArch64 Android の UserLAnd 上でも使えます。Raspberry Pi 4 の Ubuntu Server (AArch64) でも動きました。

● Python で使う

Python の場合は “build_clib” の代わりに “install” を使います。途中でエラーが出ますが問題ありません。(“bdist_wheel” は途中で止まるので保留中)

$ USE_CUDA=0 USE_CUDNN=0 BUILD_TEST=0 USE_MKLDNN=0 USE_DISTRIBUTED=0 MAX_JOBS=1 python3 setup.py install

これで import torch できるようになります。torchvision が必要な場合も同じようにビルドしておきます。

$ sudo apt install zlib1g-dev libjpeg-dev
$ git clone https://github.com/pytorch/vision.git
$ cd vision
$ MAX_JOBS=1 python3 setup.py install

関連ページ
HYPERでんち: Deep Learning

関連エントリ
RADEON (ROCm) で PyTorch を使う。C++ API
Jetson Nano で TensorFlow の C 言語 API を使う
Android UserLAnd の更新と VNC 画面設定
UserLAnd : Android 9.0 で Ctrl + SPACE を使えるようにする
Android Termux で日本語入力を行う / UserLAnd との併用
Android 9.0 と Bluetooth Keyboard による日本語入力
Android で動く Linux 環境 UserLAnd が XServer XSDL に対応
Oculus Go を文章書き&開発マシンにする
UserLAnd とブラウザ
Android 上の開発環境と UserLAnd
OS の中の Linux (WSL/Chrome OS/Android UserLAnd)
ARM CPU 上の開発環境とコンパイル時間の比較 (2) Pixel 3/UserLAnd

RADEON (ROCm) で PyTorch を使う。C++ API

Deep Learning フレームワークのほとんどが Python を使っています。C++ など他の言語も使えますが、Python と同じ使い方ができるものはあまり多くありません。

例えば CNTK の場合 Keras の backend として使うとこんな感じです。

# Keras
model= models.Sequential([
    layers.Dense( 64, input_shape=(784,), activation='relu' ),
    ~
  ])

CNTK の Python API を使った場合↓

# CNTK
xinput= cntk.input_variable( 784, np.float32 )
model= layers.Sequential([
    layers.Dense( 64, activation=cntk.relu ),
    ~
  ])

CNTK の C++ の場合 Parameter を確保して複数の Function に分解する必要があるのでこうなります。↓

// CNTK + C++
auto device= CNTK::DeviceDescriptor::UseDefaultDevice();
auto xinput= CNTK::InputVariable( { 784 }, CNTK::DataType::Float, L"xinput" );
auto weight= CNTK::Parameter( { 64, 784 }, CNTK::DataType::Float, CNTK::HeNormaliInitializer(), device );
auto bias= CNTK::Parameter( { 64 }, CNTK::DataType::Float, 0.0f, device );
auto x= CNTK::ReLU( CNTK::Plus( bias, CNTK::Times( weight, xinput ) ) );
~

PyTorch の場合は C++ でも Python と同じ書き方で同じ API なので覚えることが少なくて済みます。

// PyTorch C++
class ModelImpl : public torch::nn::Module {
    torch::nn::Linear  fc0;
public:
    ModelImpl()
    {
        fc0= register_module( "fc0", torch::nn::Linear( 784, 64 ) );
	~
    }
    torch::Tensor  forward( const torch::Tensor& x )
    {
        ~
        return  torch::relu( fc0( x ) );
    }
};
TORCH_MODULE(Model);

AMD RADEON を使用する場合の選択肢はいくつかあります。Python の場合は Keras + PlaidML が最も簡単で Windows/macOS でも使用できます。Linux の場合は ROCm が使えるため PlaidML 以外の選択肢が増えます。今回は C++ API を使いたいので Linux 上で ROCm を使用しました。

以下 RADEON で PyTorch (C++ API) を使うための作業メモです。

● ROCm の install

使用した環境は RADEON RX Vega 64 (gfx900) + Ubuntu 18.04 LTS です。

ROCm Documentation: Installation Guide

上のページを見ると Supported OS に 18.04.3 (Kernel 5.0) と書かれているため最初に Kernel を更新します。下記ページを参考にさせていただきました。

virtualiment: Ubuntu18.04にカーネル 5.0 をインストールする手順

カーネルの更新

$ sudo apt install --install-recommends linux-generic-hwe-18.04 xserver-xorg-hwe-18.04 
$ sudo reboot

次に手順通りに ROCm を入れます。こちらは下記のページを参考にさせていただきました。

ニートが始めるUE4開発日誌: RX470で機械学習ことはじめ その3 ~ROCmとTensorFlowのインストール~

install 前の更新とライブラリインストール

$ sudo apt update
$ sudo apt dist-upgrade
$ sudo apt install libnuma-dev
$ sudo reboot

リポジトリ追加と ROCm のインストール

$ wget http://repo.radeon.com/rocm/apt/debian/rocm.gpg.key
$ sudo apt-key add rocm.gpg.key
$ echo 'deb [arch=amd64] http://repo.radeon.com/rocm/apt/debian/ xenial main' | \
   sudo tee /etc/apt/sources.list.d/rocm.list
$ sudo apt install rocm-dkms
$ sudo usermod -a -G video $LOGNAME
$ sudo reboot

● PyTorch のビルド

PyTorch を ROCm でビルドします。ビルド手順は下記ページを参考にさせていただきました。

Lernapparat: Building PyTorch on ROCm

事前の準備

$ sudo apt install git cmake
$ sudo apt install python3-pip
$ pip3 install setuptools numpy

ビルドに必要な ROCm のパッケージを入れます。

$ sudo apt install rocm-libs miopen-hip rccl roctracer-dev

cmake のパッチのため下記のスクリプトを使います。

#!/bin/bash
for fn in $(find /opt/rocm/ -name \*.cmake ); do
  sudo sed --in-place='~' 's/find_dependency(hip)/find_dependency(HIP)/' $fn
done

上記の内容をファイル(replace_script.sh)に保存してから下記のように実行します。

$ bash ./replace_script.sh

PyTorch を checkout します。仮に展開場所を ~/pytorch とします。

$ git clone --recursive http://github.com/pytorch/pytorch

pytorch フォルダで下記のコマンドを実行します。

$ cd ~/pytorch
$ python3 tools/amd_build/build_amd.py

ビルドします。

$ cd ~/pytorch
$ RCCL_DIR=/opt/rocm/rccl/lib/cmake/rccl/ PYTORCH_ROCM_ARCH=gfx900 hip_DIR=/opt/rocm/hip/cmake/ USE_NVCC=OFF BUILD_CAFFE2_OPS=0 PATH=/usr/lib/ccache/:$PATH USE_CUDA=OFF python3 setup.py bdist_wheel

しばらくしたら Python 向けのパッケージが ~/pytorch/dist/*.whl にできます。C++ 向けの libtorch 相当が ~/pytorch/torch 以下になります。

include path は下記の通り。

~/pytorch/torch/include
~/pytorch/torch/include/torch/csrc/api/include

library は下記の場所に入るので、ビルド時の libpath と実行時の LD_LIBRARY_PATH に追加します。

~/pytorch/torch/lib

Link 時のライブラリ指定はこんな感じ。

-lc10 -ltorch -lc10_hip -ltorch_hip -ltorch_cpu -lc10

これで CUDA 向けのコードがそのまま RADEON で動くようになりました。ROCm (hip) でも PyTorch の API は cuda のままです。C++ API でも to( torch::kCUDA ) で OK。

import torch
for di in range(torch.cuda.device_count()):
    print( di, torch.cuda.get_device_name(di), torch.cuda.get_device_capability(di) )

例えば Python で↑のコードを実行すると次のように表示されます。

0 Vega 10 XT [Radeon RX Vega 64] (3, 0)

起動時に少々待たされますが起動してしまえば十分速いです。BatchSize は 64 以上がおすすめです。

関連ページ
HYPERでんち: Deep Learning

関連エントリ
Jetson Nano で TensorFlow の C 言語 API を使う

Jetson Nano で TensorFlow の C 言語 API を使う

メモです。参考にしたページは下記の通り。TensorFlow の C言語用ライブラリを作るために実機上でビルドしています。

TensorFlow: Build from source
Building Tensorflow 1.13 on Jetson Xavier
JK Jung’s blog: Building TensorFlow 1.12.2 on Jetson Nano

bazel の install ができれば、あとは PC と同じように source からビルドできます。bazel の build も上記ページのスクリプトをそのまま利用させていただきました。

(1) 予め Jetson Nano に swap を設定しておきます。

Jetson Nano関係のTIPSまとめ
Setting up Jetson Nano: The Basics

(2) bazel を install します。

bazel の version は このページ下の表 に従い TensorFlow に合わせる必要があります。TensorFlow r1.12 の場合は 0.15.2 を使用します。こちら の script をそのまま利用させていただきました。

$ git clone https://github.com/jkjung-avt/jetson_nano.git
$ cd jetson_nano
$ ./install_bazel-0.15.2.sh

(3) TensorFlow の build

TensorFlow のソースを build します。ここ の情報に従い、若干ファイルを修正する必要があるようです。こちら の script を使うとビルド時にパッチを当ててくれます。

今回は C言語用 lib が欲しいので install_tensorflow-1.12.2.sh を下記のように修正します。

・「sudo apt-get」「sudo pip3」「bazel-bin」で始まる行をすべてコメントアウト。
・「bazel build」の実行を下記のように修正

bazel build --config=opt \
	    --config=cuda \
	    --local_resources=2048.0,1.0,1.0 \
            //tensorflow/tools/pip_package:build_pip_package

bazel build --config=opt \
            --config=cuda \
	    --config=monolithic \
	    --local_resources=2048.0,1.0,1.0 \
	    //tensorflow:libtensorflow.so

あとは script を実行すると $HOME/src/tensorflow-1.12.2 以下でビルドが行われます。

$ ./install_tensorflow-1.12.2.sh

途中でエラーが出ても、$HOME/src/tensorflow-1.12.2/bazel-bin/tensorflow 以下に libtensorflow.so が出来ていれば成功です。lib とヘッダファイルは下記の場所にあるので、必要に応じて別の場所にコピーします。

lib:     $HOME/src/tensorflow-1.12.2/bazel-bin/tensorflow/libtensorflow.so
include: $HOME/src/tensorflow-1.12.2/tensorflow/c

あとは下記のような感じで使えるはずです。

#include 
~

auto* graph= TF_NewGraph();
auto* option= TF_NewSessionOptions();
auto* status= TF_NewStatus();
auto* session= TF_NewSession( graph, option, status );
~

関連ページ
HYPERでんち: NVIDIA Jetson Nano

関連エントリ
Jetson Nano / Clang の Version とコンパイル速度の比較