OculinkでRX 9070 XTを2枚繋いでLocal LLM

OculinkでRX 9070 XTを2枚繋いでLocal LLM

我が家ではMinisforum N5 ProなるAI NASを利用しているAMD Ryzen AI 9 HX PRO 370というかっこいい名前のAI向けを謳うSoCを搭載していて、GPUはモバイル版のRadeon 890Mに、XDNA 2世代の50TOPSのNPUが積まれている。初期搭載のMiniscloud OSにはこれらをAI活用するツールがいくつか搭載されているらしい。

SSDごとそのOSは葬ってしまったので使い勝手は知る由もないが、Proxmox VEを構築している今の環境でもGPU/NPUを活用してAI機能、すなわちLocal LLMを利用している。 初めは小さなモデルを動かしてはチャットを楽しんで「ヾ(´∀`)ノキャッキャ」と喜ぶだけの使い方だったが、人間は欲に弱い生き物。大きなモデルを動かしてAIに雑務をやらせたくなってくる。HX PRO 370はiGPUにシステムメモリを共有しているので、たくさんGPUに割り当てて大きなモデルを動かしたりして暫くは満足していた。しかし人間は欲に弱い生き物。大きなモデルがいい感じに動くとわかったら、それをより高速に動かしたくなってくる。

そんな時に目をつけたのがN5 ProのI/OポートにあるOculink。PCIe 4x4が外に出ているこのOculinkにGPUを繋いでAIを動かしたい気持ちが湧いてきた。 この記事はそんな欲に向かって進んだ結果、2枚のGPUを外付けしたモンスターNASが誕生するまでの顛末を綴ったここ一年間の記録である。

Note

この記事では生成AIを扱っていますが、記事の本文は全て人間が書いています(AI生成物であると明記してある箇所を除く)。AI生成記事を好んで読まれご所望されている方々のご期待に添えないこと、あらかじめご了承ください。

目次

Open 目次

  1. Day1 - iGPUでLLM
    1. コンテナ設定
  2. Day2 - NPUも使いたい
    1. XDNA2ドライバの導入
    2. Lemonade導入
    3. NPU性能
  3. Day3 - 大きなモデルを動かしたい
    1. メモリの節約とzramの導入
    2. Qwen3.6 35B-A3B iGPU性能
  4. Day4 - 外付けGPUを繋げたい
    1. LLM向きなGPU
    2. Oculink PCIe変換カード
    3. 不安定なOculink接続と問題解決
      1. 症状
      2. 調査結果
        1. パラメータの意味
  5. Day5 - やっぱり32GB VRAM欲しい
    1. 2枚目のGPUとeGPUボックス化
      1. MasterBox NR200P
      2. 玄人思考 RD-RX9070XT-E16GB/TP
      3. Oculinkカード
      4. PCIe to Oculinkカード
      5. その他
        1. Oculinkケーブル
        2. 850W GOLD ATX電源
        3. GPU電源分岐ケーブル
        4. GPU高さ調整具
        5. ファンコントローラー
    2. 外付けデュアルGPUボックスの完成
  6. 性能比較ベンチ
    1. RX 9070 XT 🆚 Oculink
      1. 考察
    2. 1枚のR9700 🆚 2枚のRX 9070 XT
      1. 考察
  7. まとめ

Day1 - iGPUでLLM

ローカルLLMを動かしたい気持ちが湧いてきたのは約一年前、N5 Proを購入した当初にはすでにあった。パーツ選定で96GBのDDR5を購入したのも、LLMに使うことを見越してのことだ。 Proxmox VEで構築しているので、LXCコンテナの中で動かすことになるのだが、単にGPUのデバイスパススルーするだけでは動かなかったのを覚えている。

コンテナ設定

GPUで演算をするだけなら、デバイスパススルーで /dev/dri/renderD128 をコンテナに追加するだけでいけると思っていたのだが、なぜか画面出力のcard0も渡してあげないといけなかった。加えてGPUがシステムメモリを共有するという特性上、confファイルを直接編集してlxc.prlimit.memlockを追加し、メモリロックに関する設定を緩和させる必要があった。 何度か試行錯誤して次の設定でうまく起動し、llama.cppでgemma-3-4b-it:Q4_K_M20~25TPSで動いてくれていた。

arch: amd64
cores: 4
dev0: /dev/dri/renderD128,gid=993
dev1: /dev/dri/card0,gid=44
features: nesting=1,keyctl=1
hostname: llm
memory: 8192
net0: name=eth0,bridge=vnet0,hwaddr=BC:24:11:C6:FA:F5,ip=dhcp,ip6=auto,type=veth
onboot: 1
ostype: ubuntu
rootfs: local-zfs:subvol-131-disk-0,size=64G
swap: 2048
timezone: Asia/Tokyo
unprivileged: 1
lxc.prlimit.memlock: unlimited

Day2 - NPUも使いたい

せっかく高性能なNPUが搭載されているので使いたい気持ちはすごいあったのだが、2025年はLinuxサポートが壊滅的だった。 今年3月になり、カーネルドライバの成熟とFastFlow LMでLinuxサポートが追加されたので、NPUでのLLM構築をして遊んでいた。

XDNA2ドライバの導入

当時はProxmox 9.1/Linux 6.17で、まだカーネルでXDNA2のドライバが無効化されていたため、DKMSでxdna-driverを導入するところからスタート。xdna-driverはタグを切る運用ではないようだが、唯一存在した2.21.75のDKMSでの導入をセットアップした。 おそらくProxmox 9.2の7系からか、原稿執筆時の最新版7.0.14-12-pveにはカーネルモジュールとしてamdxdnaが同梱されるようになっている。しかし自動復旧などのサポートがまだ取り込まれていないのもあって、未だにDKMSでの導入を続けている。

ドライバが正常に読まれると、/dev/kfd/dev/accel/accel0が登場するので、これらをコンテナにパススルーして準備は完了。

dev0: /dev/kfd,gid=993
dev1: /dev/accel/accel0,gid=993
dev2: /dev/dri/renderD128,gid=993
dev3: /dev/dri/card0,gid=44

Lemonade導入

コンテナにFastflow LMを導入して動作確認しつつ少し遊んだ後は、GPUとNPUとをLLMで使うのに便利なオールインワンツールのLemonadeを導入。バックエンドの管理からモデルの追加やロード、OpenAI互換APIの集約までをこれひとつで実現でき、さらに便利になった。

LemonadeでFastflowLM

NPU性能

肝心のNPUの性能はというと、gemma4-it-e2b-FLMで短文のキャッチボールでは20~25TPSと、簡単な作業にはストレスなく使える感じである。RAGから単純に情報を取ってきてもらったり、AIチャットのタイトル考案など、軽量な処理にはNPUモデルを常用する運用となった。

Day3 - 大きなモデルを動かしたい

Lemonadeでいろんなモデルを動かして試した結果、GPUの性能的に4Bや9Bが実用速度で動かせるモデルだという感覚に落ち着いていた。大きくてもファイルサイズにして8GBもいかないくらいのモデルを動かして遊ぶ日々だった。 しかし巷ではQwen3.6 35B-A3Bのファインチューニングが大流行りし、Q4量子化でも20GBを超える様々な特徴を持ったモデルが次々と登場することとなる。DistillationやUncensoredは当たり前になり、さらに特徴を持たせるなどして派生モデルは数えきれないほどに。MoEのアクティブ推論3Bなので、4Bが実用的な890Mでもモデルが読み込めさえすれば十分に使える可能性を秘めている。

メモリの節約とzramの導入

派生モデルは一体どういったキャラ付けをされているのか、好奇心を掻き立てられこれらを動かしたくなってしまう。ただ、そのままではGPUに割り当てられるメモリが足りないので、空き容量の確保に奔走した。 常駐不要なコンテナを停止し、使うときだけ起動するようにSablierでオンデマンド起動を構成して10GB以上のメモリを回収。 さらにzramでメモリ圧縮を効かせて見かけ上のメモリ空き容量を増やした。 UEFIで32GBのメモリをiGPUの890Mに固定して割り当て、VRAMから溢れたモデルやKVキャッシュが配置されるGTTはブート引数に amdgpu.gttsize=16384 として16GBを確保し、48GB相当のVRAMとして十分に大きなモデルを動かせるようにした。

Qwen3.6 35B-A3B iGPU性能

30B超の巨大なモデルでも、MTPでトークン予測が走るActive 3Bであれば890Mでも速度としては20~25TPSが出ていた。Qwen3.6 35B-A3B派生+MTPでもQ4量子化であれば、128Kのコンテキスト長でVRAMは29.8GBで収まっていた。Hermes Agentで定期タスクを回す使い方では、この速度が出ていれば雑務をこなすには十分だ。

Day4 - 外付けGPUを繋げたい

様々なモデルを大小色々と動かしていくうちに、思考中の時間が気になってきた。即答するInstructモデルであれば、長い会話が積み上がって20TPSに落ち込んでもまだ会話にストレスがないが、ぶつぶつと考え込むタイプのモデルが一向に回答しないThinkingを同じ速度で巡らせているとイライラが溜まってくる。コーディングモデルで対話して決定を下す作業をしている時だと、人間が書いた方が早いだろと感じることもしばしばあった。

内蔵GPUの限界を感じたので、ちゃんとしたGPUを導入しようと考え始めた。

LLM向きなGPU

今よりLLMが早く動いて欲しい気持ちだけでゲームに使う考えはなく、これと言ってこだわりもないためGPU選びをするところから始めた。半導体市場の先が読めないので長く使えるGPUがいい。LLMに使うのに8GB VRAMでは論外なので、最新GPUのうち16GB以上のVRAMを積むものをざっと並べて考えてみた。LLM性能はVRAM帯域やベンチ結果から捻り出した独自の評価で、価格は値上げもあって今では参考にならないが、どちらも相対的な指標としてみてほしい。

メーカー型番VRAMLLM性能価格(万円)
NVIDIARTX 509032GB★★★★★60~
AMDAI PRO R970032GB★★★25~
IntelArc Pro B7032GB★★★25~
NVIDIARTX 508016GB★★★★★20〜25
NVIDIARTX 5070 Ti16GB★★★★15〜20
NVIDIARTX 5060 Ti (16GB)16GB★★★10-15
AMDRX 9070 XT16GB★★★8~10
AMDRX 907016GB★★7〜10
AMDRX 9060 XT (16GB)16GB★★6〜8

32GB搭載品を狙いたいところだが、RTX 5090はAIバブルの餌食となっていてコスパがかなり悪い。AMDとIntelの32GBモデルは同じ価格帯でVRAM比でコスパはいいが、LLM性能はベンチマーク結果が振るわずまずまずのようだ。 「まずまず」の理由を深掘りしてみると、どちらもソフトウェア最適化がCUDAほど成熟していないがために、ハードの性能を生かしきれていない様子だった。 今は星3つでも、今後4つに化ける可能性は大いにある。

ここで注目したいのが、R9700とRX 9070 XT。これらは共通のアーキテクチャで同じコアを持ち、VRAMだけが違うという仕様のため、実質R9700はRX 9070 XTのVRAM倍増版なのだ。 VRAMがR9700の半分であるRX 9070 XTは価格が3分の1ほどで買える(2026年7月時点)ので、RX 9070 XTのお買い得さが際立っている。

Oculinkの速度制約による性能低下も懸念されるので、星5つを買って大怪我するより星3つで体調不良くらいの方がマシと考え、RX 9070 XTを購入することにした。

Amazon | ASRock AMD Radeon RX 9070 XT Steel Legend Dark 16GB GDDR6 256ビット、2970MHzブースト、PCIe 5.0、3xDP2.1+HDMI2.1、トリプルファン、メタルバックプレート、RGB同期、DirectX12 Ultimate、RDNA4、2x8ピン。 | ASRock | グラフィックボード 通販

OculinkでGPUを繋げるには、PCIeスロットの形に変換しないといけない。Minisforum DEG1AOOSTAR EG01が有名どころだが、どちらも1万円以上する。Oculinkの信号はPCIeそのものなので、そこまで大袈裟なことをしていないものに1万円はかなり割高と感じたため、AliExpressで探すこととした。

DEG1やEG01に似たGPUスタンド一体型のものはAliでも高価だったため、GPUの固定方法はあとで考えるとして3000円台でケーブル付きのこちらを購入した。

高速安定拡張 Oculink SFF-8612 から PCI-E 4.0 X16 アダプターライザーカード、ケーブル付き 24 ピン電源供給、GPU 用 - AliExpress

不安定なOculink接続と問題解決

GPUと変換カードが届いていざ接続。手持ちの450W SFX電源を繋いで起動し、コンテナにパススルーしてLemonadeで動作させることに成功した。しかし長くは続かなかった。

チャットでの動作確認では、モデルのロードが完了し、最初の会話を返すところまではうまくいくのだが、何回か会話を続けていると接続を見失ってしまうことがあった。Fableに解析を依頼すると、立派な調査レポートと解決案を得られた。実際にpcie_aspm=off amdgpu.aspm=0 amdgpu.runpm=0をブート引数に設定してみたところ、以降はずっと安定して稼働し続けている。省電力モードを切ってもアイドル時で3Wなので、安定性のトレードオフとして無視できるコストだ。

以下、AI生成調査レポートのコピペ(抜粋)。


症状

  • Vulkan (RADV) バックエンドで llama-server が、何回目かのチャットのタイミングで不定期に vk::Queue::submit: ErrorDeviceLost でクラッシュ
  • モデル非依存 (MoE の Qwen3.6 系でも dense の 13B でも発生)
  • ホスト側 dmesg には毎回同じパターン:
[drm:gfx_v12_0_bad_op_irq [amdgpu]] *ERROR* Illegal opcode in command stream
amdgpu 0000:c9:00.0: [gfxhub] page fault (src_id:0 ring:222 ...)
amdgpu 0000:c9:00.0:   in page starting at address 0x000080010002b000 from client 10
amdgpu 0000:c9:00.0:          Faulty UTCL2 client ID: CPF (0x4)
amdgpu 0000:c9:00.0:          WALKER_ERROR: 0x6 / PERMISSION_FAULTS: 0xb / MAPPING_ERROR: 0x1
amdgpu 0000:c9:00.0: ring gfx_0.0.0 timeout ...
amdgpu 0000:c9:00.0: [drm] device wedged, but recovered through reset
  • 加えて、推論が成功した直後のアイドル中ring sdma0 timeout が単発で出ていた

調査結果

  • 真因は アイドル時の PCIe 省電力遷移 (ASPM L1 / runtime PM) からの復帰で、OcuLink 区間越しの GART (GPU→ホスト RAM の DMA 窓) アクセスが壊れること
  • kernel cmdline に pcie_aspm=off amdgpu.aspm=0 amdgpu.runpm=0 を追加して解消見込み
パラメータの意味
パラメータレイヤー効果
pcie_aspm=offPCIe リンク層 (全体)アイドル時のリンク省電力ステート (L0s/L1) を禁止、常時 L0
amdgpu.aspm=0PCIe リンク層 (GPU)amdgpu ドライバが自前で行う ASPM 有効化を抑止 (両方入れるのが定番)
amdgpu.runpm=0デバイス電源アイドル時に GPU を D3/BACO に落とすランタイム PM を無効化、常時オン

Day5 - やっぱり32GB VRAM欲しい

Oculinkでも16GBに収まるモデルであれば、かなり高速に動作することがわかった。例えばmmnga-o/GPT-OSS-Swallow-20B-RL-v0.1-ggufのQ4_K_M量子化では、iGPUの890Mでは24TPSだった回答が、RX 9070 XTでは同じ質問で140TPSにまで高速化した。長考するタイプのモデルでも全くといっていいほどストレスを感じなくなった。

ただ、やはり16GBのVRAMは少ない。モデルとKVキャッシュの合計が少しでもVRAMの容量を超えてしまうと、システムRAMに配置されたGTTにデータが溢れ、それを毎トークンOculinkを行き来し参照することになる。推論速度は5分の一にまで低下することもあった。ならばと精度を犠牲にファイルサイズを小さくしたIQ2モデルを動かしてみたものの、量子化サイズを落とすと想像以上におバカになってしまう。もうRX 9070 XTでは満たされない。1枚だけでは。

実は最初からRX 9070 XTを2枚買うつもりで考えていた。というのも、性能が少し劣るがllama.cppではモデルを分割して複数のGPUに分けてロードできるので、2枚買って実質32GB VRAMとしてLLMを動かそうと企んでいたのだ。しかも2枚買っても1枚のR9700より価格は安いのに、活かせるコアは2枚分というお得さもある。消費電力も2倍になるが、暖房機能が無料で付いてきたと考えればお得だ。

2枚目のGPUとeGPUボックス化

1枚目は固定も何もない裸の状態で動作させていたが、2枚目とともにケースに収めることにした。

MasterBox NR200P

nr200p

昔買って押し入れに眠っていたCooler MasterのMasterBox NR200Pを引っ張り出してきた。 このNR200P V1はMini-ITX向けにも関わらず、GPUなどPCIe拡張カードの搭載箇所が2つあるという、他に類を見ない変態ケースだ。写真ではすでにGPUを搭載した後だが、縦位置の2スロットと横位置の3スロットが目を引くだろう。メッシュパネルは全面外せてメンテナンス性に優れ、GPU2枚を組み込んで補助電源やOculinkカードの配置がしやすく、さらにATX電源も(力技で)内蔵できてしまう。まさにデュアルeGPUボックス作りにはぴったりだ。このケースありきで構成を考えていく。

玄人思考 RD-RX9070XT-E16GB/TP

2枚目のGPUは玄人思考のRX 9070 XTを購入した。ちょうど底値だったのと、NR200Pの下部に収めるために2スロット厚である必要があったため。1枚目のOculinkカードの位置からして3スロットある一番上を開けないと干渉してしまうのだ。

Amazon | 玄人志向 AMD Radeon RX 9070 XT 搭載 グラフィックボード 16GB トリプルファン 【国内正規品】 RD-RX9070XT-E16GB/TP | 玄人志向 | グラフィックボード 通販

Oculinkカード

2枚目向けのOculinkカードは、6ピン電源で給電できるこちらを購入した。1枚目のOculinkカードでATX24ピンを使っているので、同じカードを買ってもATX電源に繋げられないためである。なおOculinkケーブルは付属しない。

トップ評価のOculink SFF-8612 to Pcie X4 X16スロットアダプターカードDC 12V GPU電源PCメインボードグラフィックカード用 - AliExpress

PCIe to Oculinkカード

Minisforum N5 ProにはOculinkポートが1つしかないため、2つ目のOculinkを増設するための拡張カードを追加する。PCI Expressに装着して信号をそのまま外に出す形のもの。

ADTLINK PCIe 4.0 X4 - OCuLink SFF-8611/8612 アダプター (ハーフハイトおよびフルハイトブラケット付き) OCuLink グラフィックスカード外部接続用 - AliExpress

その他

Oculinkケーブル

2まいめのOculinkカードはPCIeスロットに対して横向きにOculinkポートがあるが、ケース背面から引き回したいので、L字に曲がったケーブルを購入。L字側の端子部分に厚みがあって差し込めなかったので、干渉しないよう少し削って高さを抑える加工をした。

JULONGFENGBAO 1/2 個 6 ピン 8 ピン PCI Express からデュアル PCIE 8 (6+2) ピン電源ケーブルグラフィックスカード PCI-E GPU データスプリッタ - AliExpress

850W GOLD ATX電源

TGP 304WのGPUを2枚載せるだけなので700W級でも動作させることは可能だが、余裕を持って850Wを選択した。

Amazon | Cooler Master ELITE Gold 850 FM A/JP cord 80PLUS GOLD認証取得 ATX 3.1対応 850W電源ユニット [MPX-8505-AFAG-BJP] | Cooler Master | 電源ユニット 通販

GPU電源分岐ケーブル

先のATX電源にはPCIe電源が分岐型の8+8と単独の8ピンの3口あるが、GPU1枚あたり2口、なので2枚で4口と、Oculinkカードで1口の計5口必要なため、2本の分岐ケーブルを購入。安価なのに18AWGの太めのケーブルで大電流を流しても安心感がある。

JULONGFENGBAO 1/2 個 6 ピン 8 ピン PCI Express からデュアル PCIE 8 (6+2) ピン電源ケーブルグラフィックスカード PCI-E GPU データスプリッタ - AliExpress

GPU高さ調整具

寝かせて取り付ける方のGPUの固定されない側が垂れ下がってしまうので、高さをいい感じに調整し支えるために購入。

コンピュータグラフィックスカードホルダーシャーシファンサポート固定金属ブラケット6-96mm調整可能なGPUホルダー - AliExpress

ファンコントローラー

NR200Pの天面から排気するケースファンを動かすためのもの。SATA電源を繋いでファンを固定の速度で動かす形となる。

1 に 8 3Pin ファンハブ Pwm Sata Molex スプリッタ PC マイニングケーブル 12V 電源クーラー冷却速度コントローラ 4PIN アダプタ - AliExpress

外付けデュアルGPUボックスの完成

購入したパーツを全て組み込み、完成したデュアルeGPUボックスがこちら!

box-side-a

box-side-b

box-top

box

N5 Proの方にもOculink拡張カードを取り付けたら、2本のOculinkケーブルで繋ぐだけでデュアルeGPUをNASに追加できる。

pcie-oculink dual-oculink

gpu-monitor

性能比較ベンチ

デュアルOculinkによる性能低下が許容できるものであるかを、公開されているベンチマーク結果と照らし合わせて比較して考察していく。

まずは単体GPUだけでOculinkに起因する性能低下を計測する。いくつか見つかったベンチ結果の中で、一番「同じベンチマーク環境に近いものを再現できそう」な結果がこちら。この結果を比較対象として、Oculinkでどれだけ低下するかを観測した。

https://github.com/ggml-org/llama.cpp/discussions/15396#discussioncomment-14989283

項目投稿結果の構成手元のOculinkの環境差分備考
PCIePCIe 5.0x16 64GB/sPCIe 4x4 8GB/s-87.5%投稿の方は記載のRyzen 7 7700Xから推測
Power上限317 Wsysfsのpower1_capで317Wに変更0%投稿結果はOCモデル?
llama-cppb7083b7083なしreleaseバイナリを利用
モデルgpt-oss-20b-GGUF/gpt-oss-20b-MXFP4.ggufggml-org/gpt-oss-20b-GGUF:MXFP4若干違うモデルファイルの更新が入っている

llama-benchの実行時引数も投稿に書かれていたものと揃えてベンチマークを回し、結果の値部分を次の表にまとめた。

n_ubatchtest投稿ベンチ結果 t/sOculinkベンチ結果 t/sdiff
2048pp20482753.99 ± 3.512871.56 ± 5.06+4.27%
2048pp81922359.88 ± 4.742382.36 ± 4.48+0.95%
2048pp163841942.51 ± 1.231890.34 ± 1.41-2.69%
2048pp327681417.87 ± 0.441162.06 ± 0.59-18.04%
2048tg128174.16 ± 0.42167.67 ± 0.40-3.73%

考察

pp2048など、なぜかOculinkの結果がPCIe直結の結果より上回るものも現れているが、トークンサイズの小ささによってPCIeの転送速度の影響よりも揺らぎの方が大きく影響をもたらした可能性が考えられる。

pp32768で大きく低下して見えるのは、サーマルスロットリングが発動したと見当を付けている。というのも、この時のGPUのjunction温度を観測したところ 105℃ を示しており、動作抑制が働くには十分すぎるくらい熱を持っていたからだ。OCモデルではない通常の9070 XTを317W(+13W)で長時間のプロンプト処理をさせ続けていたら、設計限界を超えていてもおかしくない。

トークン生成の結果は -3.73% という結果となり、これがまさにOculinkによる性能低下を示している。tgではGPUからの転送速度がそのまま出力結果に反映されるためだ。想像以上に良い結果となり、Oculink運用でも十分にLocal LLMは使えるものと確認できた。

ベンチ結果全体
root@lemonade:/var/lib/lemonade/.cache/huggingface/hub# GGML_VK_VISIBLE_DEVICES=0 /tmp/tmp.7r808fAdJL/build/bin/llama-bench -m models--ggml-org--gpt-oss-20b-GGUF/snapshots/ef9b12f2ff56c69cf32153a02784e7a3c88bf524/gpt-oss-20b-MXFP4.gguf -ngl 99 -t 1 -fa 1 -b 4096 -ub 2048,4096 -p 2048,8192,16384,32768
load_backend: loaded RPC backend from /tmp/tmp.7r808fAdJL/build/bin/libggml-rpc.so
WARNING: radv is not a conformant Vulkan implementation, testing use only.
WARNING: radv is not a conformant Vulkan implementation, testing use only.
ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = AMD Radeon RX 9070 XT (RADV GFX1201) (radv) | uma: 0 | fp16: 1 | bf16: 1 | warp size: 64 | shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
load_backend: loaded Vulkan backend from /tmp/tmp.7r808fAdJL/build/bin/libggml-vulkan.so
load_backend: loaded CPU backend from /tmp/tmp.7r808fAdJL/build/bin/libggml-cpu-icelake.so
| model                          |       size |     params | backend    | ngl | threads | n_batch | n_ubatch | fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | ------: | ------: | -------: | -: | --------------: | -------------------: |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     2048 |  1 |          pp2048 |       2871.56 ± 5.06 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     2048 |  1 |          pp8192 |       2382.36 ± 4.48 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     2048 |  1 |         pp16384 |       1890.34 ± 1.41 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     2048 |  1 |         pp32768 |       1162.06 ± 0.59 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     2048 |  1 |           tg128 |        167.67 ± 0.40 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     4096 |  1 |          pp2048 |       2823.90 ± 6.14 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     4096 |  1 |          pp8192 |       1866.95 ± 1.81 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     4096 |  1 |         pp16384 |       1519.25 ± 2.50 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     4096 |  1 |         pp32768 |        990.56 ± 0.43 |
| gpt-oss 20B MXFP4 MoE          |  11.27 GiB |    20.91 B | Vulkan     |  99 |       1 |    4096 |     4096 |  1 |           tg128 |        167.81 ± 0.19 |

build: 2376b7758 (7083)

1枚のR9700 🆚 2枚のRX 9070 XT

OculinkのPCIe 4x4と理論的に同じ速度であるPCIe 3x8でR9700を接続しているベンチマーク結果を見つけた。 この結果を用いて、PCIeバスの速度に引っ張られない単純なGPU2枚構成による影響を反映した比較を行う。

https://github.com/ggml-org/llama.cpp/discussions/21043#discussioncomment-16956724

項目投稿結果の構成手元のOculinkの環境差分備考
PCIePCIe 3x8 8GB/sPCIe 4x4 8GB/s0%pcie gen 3 at x8との発言コメント
Power上限300W304W+1.33%R9700のTBPは300W
llama-cppb9203b9203なしreleaseバイナリを利用
モデルQwen3.6-27B-UD-Q4_K_XL (MPT付き)unsloth/Qwen3.6-27B-GGUF:UD-Q4_K_XL若干違うMTPの比較はしないのでMTPなしモデルを利用

llama-benchのコマンドはDiscusstion先頭にあるStock benchmarkを参考に、KV Q4_0の引数を加えてベンチマークを実施。次の表のとおりとなった。

testSingle R9700 t/sDual RX 9070 XT t/sdiff
pp128736.8511.79 ± 26.15-30.54%
pp2048924.21375.25 ± 1.57+48.80%
pp8192888.91263.51 ± 24.08+42.14%
pp16384825.61160.00 ± 8.60+40.50%
tg12828.223.66 ± 0.19-16.31%
tg204829.623.49 ± 0.06-20.95%
tg819229.923.14 ± 0.10-22.74%
tg1638429.823.11 ± 0.09-22.48%

考察

小さなプロンプト処理では2つのGPUに分けて処理する効率より、そのためのオーバーヘッドの方が勝って性能が負けていると考えられる。 コンテキストの長い大きな処理においては、R9700単体よりRX 9070 XT2枚の方が +40%以上のスコアを叩き出していて、2つのGPUで処理をすることによる恩恵が明確に現れている。

トークン生成の結果は -16%〜-23% と軒並み悪化しており、2枚のGPU間の同期などがボトルネックとなっていると考えられる。コンテキスト長が長くなると結果が悪化していくのを見るに、2つのGPUが相互参照するKVキャッシュ周りが詰まっているのだろう。

ベンチ結果全体
root@lemonade:/var/lib/lemonade/.cache/huggingface/hub# /tmp/tmp.7r808fAdJL/llama-b9203/llama-bench -m models--unsloth--Qwen3.6-27B-GGUF/snapshots/82d411acf4a06cfb8d9b073a5211bf410bfc29bf/Qwen3.6-27B-UD-Q4_K_XL.gguf -t 1 -ngl 99 -fa 1 -p 128,2048,8192,16384 -n 128,2048,8192,16384 -r 3 -ctk q4_0 -ctv q4_0
load_backend: loaded RPC backend from /tmp/tmp.7r808fAdJL/llama-b9203/libggml-rpc.so
WARNING: radv is not a conformant Vulkan implementation, testing use only.
WARNING: radv is not a conformant Vulkan implementation, testing use only.
ggml_vulkan: Found 2 Vulkan devices:
ggml_vulkan: 0 = AMD Radeon RX 9070 XT (RADV GFX1201) (radv) | uma: 0 | fp16: 1 | bf16: 1 | warp size: 64 | shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
ggml_vulkan: 1 = AMD Radeon RX 9070 XT (RADV GFX1201) (radv) | uma: 0 | fp16: 1 | bf16: 1 | warp size: 64 | shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
load_backend: loaded Vulkan backend from /tmp/tmp.7r808fAdJL/llama-b9203/libggml-vulkan.so
load_backend: loaded CPU backend from /tmp/tmp.7r808fAdJL/llama-b9203/libggml-cpu-zen4.so
| model                          |       size |     params | backend    | ngl | threads | type_k | type_v | fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | ------: | -----: | -----: | -: | --------------: | -------------------: |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |           pp128 |       511.79 ± 26.15 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |          pp2048 |       1375.25 ± 1.57 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |          pp8192 |      1263.51 ± 24.08 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |         pp16384 |       1160.00 ± 8.60 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |           tg128 |         23.66 ± 0.19 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |          tg2048 |         23.49 ± 0.06 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |          tg8192 |         23.14 ± 0.10 |
| qwen35 27B Q4_K - Medium       |  16.39 GiB |    26.90 B | Vulkan     |  99 |       1 |   q4_0 |   q4_0 |  1 |         tg16384 |         23.11 ± 0.09 |

build: 87589042c (9203)

まとめ

nas-egpu

デュアルRX 9070 XTはLocal LLMにおいて、R9700の8割程度の性能は発揮できる結果となった。25万円の8割なので20万円相当の性能となるが、RX 9070 XTが底値だったのもあって、それを下回る金額で実現できた。 この8割の性能というは2026年8月現在での話で、ROCmドライバのP2P機能をllama.cppで活用する挑戦デュアルRX 9070 XTに特化して高速化をする挑戦が実れば、より高い性能を発揮できるようになるだろう。

Qwen3.8-27B-GGUF:Q6_Kに128kコンテキストを載せてOh My Piでリポジトリの理解から実装の変更までの長時間タスクを動かしたりしているが、長いコンテキストになっても30TPS前後で動いてくれている。どうやら同じような構成でR9700単体では50TPS出るらしいので、もう一踏ん張り欲しいところだ。 まあ人間は欲に弱い生き物なので、いずれR9700を導入しているかもしれないが、今のところデュアルRX 9070 XTに大変満足している。

しかし暑い。デュアルeGPUボックスが熱い。部屋があつい。エアコンつけててもぬるい風が棚から吹いてくる。夏にGPUを増やすもんじゃない。

Related Posts

NAS4FreeでTime Machineの設定するメモ

NAS4FreeでTime Machineの設定するメモ

Mavericksの登場で手元のMacBook Airをクリーンインストールしました。 その際、バックアップから復元するような手段は取らず、必要なデータのみを移して環境を再構築しました。 というのも、 ...

read more
自宅サーバーを増やした

自宅サーバーを増やした

増税前のPCパーツ買いだめイベントに便乗して、3月中に自宅サーバーを増設しました。 どんな構成で組み立てたのかの紹介になります。 目次 構成目標 サーバー増設にあたって、次に挙げる構 ...

read more
サーバーの発熱でこたつを温める

サーバーの発熱でこたつを温める

この記事はcoins Advent Calendarの一部です。 寒い日が続きますね。昨夜の外気温は摂氏2度でした ...

read more
GTX 1070とKaby Lake i5で新しくメインPC組んだ

GTX 1070とKaby Lake i5で新しくメインPC組んだ

4Kの広大なモニタを生かすためにも、Kaby Lake世代のCPUとNVIDIA Pascal™アーキテクチャのGPUを搭載したマシンを組みたくなったので組んでみました。 小さなPCしか ...

read more
宅内WebサービスをCaddyとPocket IDでまるごとPasskey認証に

宅内WebサービスをCaddyとPocket IDでまるごとPasskey認証に

Synologyを辞めてProxmox VE+Rockstorに移行してからというもの、LXCコンテナでOSS ...

read more