
2026/02/22 5:57
**HN掲示:NVMe→GPU バイパスでCPUを経由せず、単一のRTX 3090上でLlama 3.1 70B を動作させる**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
NTransformer は、依存関係のない軽量 C++/CUDA エンジンであり、ユーザーが PCIe 上でモデル層をストリーミングし、オプションで高速直接 I/O 用に NVMe を使用することで、70 B 変種を含むフルサイズ Llama モデルをコンシューマ GPU 上で直接実行できるようにします。
- Resident mode(レジデントモード):Llama 3.1‑8 B Q8_0 は 10 GB の VRAM だけで 48.9 トークン/秒を達成し、tiered‑auto モードは 10.3 GB を使用して 48.8 トークン/秒を提供します。
- 70 B model(70 B モデル):ストリーミング(mmap)のみでは非常に遅く (0.006 トークン/秒、7.3 GB)、tiered auto はスループットを 0.2 トークン/秒まで向上させ、23.1 GB を消費します。Q4_K_M のレイヤー・スキップを使用すると速度が 0.5 トークン/秒に上昇し、わずか 22.9 GB で済みます。これは単一 RTX 3090 + 48 GB RAM システムでのプレーン mmap に対して 83 倍速です。
- Bandwidth bottleneck(帯域幅ボトルネック):PCIe Gen3 x8 (~6.5 GB/s) がデータ転送を制限します。Q4_K_M は VRAM に 10 層多く収容でき (36 層対 26 層)、tier‑B 転送が削減され、スループットが向上します。
- Layer‑skip(レイヤー・スキップ):コサイン類似度キャリブレーションを使用して、1 トークンあたり 20–80 層を最小限の品質低下でスキップし、大規模モデルの推論速度を向上させます。
- Architecture(アーキテクチャ):3 タイヤの適応型キャッシュが VRAM‑resident、ピン留め RAM、および NVMe/mmap タイヤを自動的にサイズ決定します。エンジンはすべての GGUF 量子化 (Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16, F32) をサポートし、レジデント、tiered‑auto、layer‑skip、および self‑speculative decoding の 4 種類の自動選択データパスを提供します。
- System requirements(システム要件):Linux (Ubuntu kernel 6.17+)、CUDA 13.1、gcc‑14/g++‑14、CMake 3.24+、NVIDIA GPU CC 8.0+ (RTX 3090 テスト済み)。直接 I/O 用に別の PCIe スロットに NVMe SSD が必要です。セットアップスクリプトはカーネルモジュールをパッチし、AMD IOMMU を無効化し、NVMe を VFIO にバインドします(DMA 分離について注意)。
- NVMe‑direct pipeline(NVMe 直接パイプライン):各層 (~670 MB for 70 B Q6_K) は約 202 ms の NVMe コマンドで CUDA‑ピン留めステージングメモリに読み込まれ、非同期 DMA により GPU バッファへ転送され、デュアルバッファ間で計算と重ね合わせて実行されます。
- Roadmap(ロードマップ):完成済みフェーズ—基盤、SLEP ストリーミング、最適化、NVMe direct。今後の作業には speculative decoding の仕上げと公開 C API の追加が含まれます。
NTransformer は、大規模モデルをコストの高いサーバーインフラなしでコンシューマ GPU 上にローカル実行できるようにすることで、推論コストを低減し、オンプレミス AI サービスのレイテンシを削減し、研究・産業界全体での採用拡大を促進します。
本文
NTransformer
高効率なC++/CUDA LLM推論エンジン – PCIe経由でGPUメモリへモデル層をストリーミングし、CPUを完全にバイパスするNVMeダイレクトI/Oオプション付きで、RTX 3090(24 GB VRAM)単体でLlama 70Bを実行します。
主な成果
| モデル | 実行モード | デコード速度 | 使用VRAM | 備考 |
|---|---|---|---|---|
| Llama 3.1 8B Q8_0 | Resident | 48.9 tok/s | 10.0 GB | 全層がVRAMに収まる |
| Llama 3.1 8B Q8_0 | Tiered (auto) | 48.8 tok/s | 10.3 GB | 32/32層が自動でVRAMへ昇格 |
| Llama 3.1 70B Q6_K | Streaming (mmap) | 0.006 tok/s | 7.3 GB | ページキャッシュのスラッシング(53 GB > 48 GB RAM) |
| Llama 3.1 70B Q6_K | Tiered (auto) | 0.2 tok/s | 23.1 GB | 26VRAM + 54RAM + 0NVMe |
| Llama 3.1 70B Q4_K_M | Tiered (auto) | 0.3 tok/s | 22.9 GB | 36VRAM + 44RAM(50 %高速) |
| Llama 3.1 70B Q4_K_M | Tiered + layer skip | 0.5 tok/s | 22.9 GB | 36VRAM + 44RAM、20層スキップ |
*三階層適応キャッシュはハードウェアに合わせて自動調整されます:
- VRAMに常駐(I/Oゼロ)
- ピン留め済みRAM(H2Dのみ)
- NVMe/mmapフォールバック*
RTX 3090 + 48 GB RAMの消費者向けハードウェアで、mmapベースより83倍速を実現。
ボトルネック: Gen3 ×8 PCIe H2D帯域(約6.5 GB/s)
Q4_K_MはVRAMに10層多く収める(36 vs 26)、Tier‑B転送が減少。
Layer skip(コサイン類似度調整)は1トークンあたり20/80層を除外し、品質低下を最小化。
主な機能
- CUDA Toolkit以外に依存せず、PyTorchやcuBLASは不要。
- GGUFモデルフォーマット:Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16, F32量子化。
- 3‑Tier適応キャッシュ:VRAM常駐 + ピン留めRAM + NVMe/mmap階層。
- SLEPストリーミング:ダブルバッファリングによりNVMe読み込み、PCIe DMA、GPU計算を重ね合わせる。
- gpu‑nvme‑directバックエンド:ユーザースペースNVMeドライバーでモデルウェイトを直接ピン留めGPUアクセスメモリへ読込む。
- Layer skip:コサイン類似度調整により冗長層(20/80)をスキップ。
- Self‑speculative decoding:VRAM常駐層をドラフトモデルとして使用し、追加モデル不要。
- 4種類のデータパス(自動選択)
- VRAM常駐 → GPU計算
- ピン留めRAM H2D
- Mmapピン留め
- CPUワーカー memcpy
- Llamaアーキテクチャ:RoPE, GQA, SwiGLU, RMSNorm, KVキャッシュ。
要件
| 項目 | バージョン |
|---|---|
| Linux(Ubuntu、カーネル 6.17+で検証) | – |
| CUDA Toolkit | 13.1 |
| GCC/G++ | 14 |
| NVIDIA GPU | Compute Capability 8.0+(RTX 3090をテスト) |
| CMake | ≥3.24 |
| 任意 | 別PCIeスロットにNVMe SSD + gpu‑nvme‑directライブラリ |
クイックスタート
# ビルド mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=gcc-14 \ -DCMAKE_CXX_COMPILER=g++-14 \ -DCMAKE_CUDA_COMPILER=/usr/local/cuda-13.1/bin/nvcc cmake --build . -j # Residentモード(モデルがVRAMに収まる場合) ./ntransformer -m /path/to/llama-8b-q8_0.gguf -p "Hello" -n 128 # Streamingモード(モデルがVRAMを超える場合) ./ntransformer -m /path/to/llama-70b-q6_k.gguf -p "Hello" -n 32 --streaming # Layer skip(70Bで最速) ./ntransformer -m /path/to/llama-70b-q4_k_m.gguf \ -p "Hello" -n 32 --streaming --skip-threshold 0.98 # Self‑speculative decoding ./ntransformer -m /path/to/llama-70b-q6_k.gguf \ -p "Hello" -n 32 --self-spec --draft-k 3 # チャットモード ./ntransformer -m /path/to/model.gguf --chat # ベンチマーク ./ntransformer -m /path/to/model.gguf --benchmark -n 64
NVMeダイレクトI/Oのシステム設定
nvme direct を動作させるにはシステムレベルでいくつか変更が必要です。
自動セットアップスクリプトがすべてを処理します。
# 初回完全セットアップ(対話形式、バックアップ作成) sudo ./scripts/setup_system.sh # 現在の状態確認(変更なし) sudo ./scripts/setup_system.sh --check # NVMeのみ(再起動後に実行) sudo ./scripts/setup_system.sh --nvme-only
スクリプトが変更する項目と理由
| フェーズ | 何を変更 | 理由 | リスク | 復元 |
|---|---|---|---|---|
| 1 | gcc‑14、cmake、カーネルヘッダーのインストール | CUDA 13.1はgcc‑15(Ubuntu 25.10のデフォルト)と非互換 | 低 – 標準パッケージ | |
| 2 | GRUBに を追加 | AMDルートコンプレックスがIOMMUオン時にGPU→NVMe P2P読み込みをブロックする。無効化でPCIe書き込み(ドアベル)が可能になる | 中 – 全PCIeデバイス間のDMA隔離が解除される。マルチテナント/サーバー環境では使用しないこと | から削除、、再起動 |
| 3 | NVIDIA DKMS () をパッチ | がカーネル 6.12+で削除。修正が無ければ が失敗しGPUがNVMe BAR0をMMIO書き込みできない | 高 – パッチ不備でGPUドライバーがロードされず、再起動時にブラックスクリーンになる。 バックアップ自動作成 | をDKMSソースディレクトリへ、 |
| 3b | CUDAヘッダー () をパッチ | glibc 2.42+ が を 宣言。CUDA 13.1 は非宣言で、ビルド失敗になる | 低 – 一つのヘッダーのみ影響。バックアップ作成 | |
| 4 | VFIOモジュール (, ) をロード | NVMeをVFIOにバインドしてユーザースペースアクセスを可能にする。GeForce GPUは が必要 | 低 – モジュールは再起動時にアンロードされる。「Unsafe noiommu」=VFIOデバイスのIOMMU DMA保護が無効 | 再起動または |
| 5 | NVMeをカーネルからunbindし、VFIOへbind | は生RAW PCIeアクセスを必要とする。NVMeはVFIOにバインドされることで に表示されなくなる | 高 – 誤ったデバイスを操作するとブートディスクが失われる可能性あり。スクリプトは自動検出し、ブートデバイスへの適用は拒否 | |
BIOS設定(手動:スクリプト実行前に)
| 設定 | 値 |
|---|---|
| Above 4 GB Decoding | ON(64‑bit BARマッピングが必要) |
| IOMMU | OFF(またはオンでもスクリプトでパラメータ追加) |
| Secure Boot | OFF(署名/パッチ済みカーネルモジュールのロードに必須) |
ハードウェア注意事項
本プロジェクトは低レベルPCIe操作(GPU MMIO書き込みによるNVMeコントローラレジスタ制御、ユーザースペースNVMeコマンド送信、VFIOデバイスパススルー)を行います。RTX 3090 + WD SN740で十分にテスト済みですが、誤設定やハードウェア互換性の不備により以下が発生する可能性があります:
- NVMeリンク障害(GPU読み込み時に電源サイクルが必要)
- RAWブロックストレージでデータ損失
- IOMMU無効化やカーネルモジュールパッチによるシステム不安定
決してブートドライブをNVMeダイレクトI/Oに使用しないでください。専用のセカンダリNVMeを常に使用してください。
著者はハードウェア損傷やデータ喪失について責任を負いません。自己責任でご利用ください。
スクリプト一覧
| スクリプト | 目的 | 実行タイミング |
|---|---|---|
| システム全体設定(7フェーズ) | 初回セットアップ |
| VFIO + NVMeバインドのみ | 再起動後に実行 |
| 状態確認 | デバッグ時 |
| 単一NVMeをVFIOへバインド | スタンドアロン、再起動後 |
| NVMeをカーネルデバイスに戻す | NVMeダイレクト終了時 |
NVMeダイレクトストリーミング
VRAMに収まらないモデルでは、NVMeバックエンドがCPUを完全に排除します。
NVMe SSD → (DMA) → ピン留めステージング → (PCIe H2D) → GPUバッファ → 計算
設定手順
# NVMeサポート付きでビルド(gpu‑nvme‑directライブラリが必要) cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_GPUNVME=ON \ -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 \ -DCMAKE_CUDA_COMPILER=/usr/local/cuda-13.1/bin/nvcc cmake --build . -j # GGUFモデルをNVMe生RAWデバイスへ書き込む sudo ./scripts/restore_nvme.sh # カーネルドライバーがbindされていること確認 sudo dd if=model.gguf of=/dev/nvme0n1 bs=1M oflag=direct status=progress # NVMeをVFIOへバインドしてユーザースペースアクセス可能にする sudo ./scripts/setup_nvme.sh # VFIOロード、D0パワー状態強制、BusMaster有効化 # NVMeバックエンドで実行 sudo GPUNVME_PCI_BDF=0000:01:00.0 GPUNVME_GGUF_LBA=0 \ ./build/ntransformer -m /path/to/model.gguf -p "Hello" -n 32 --streaming # NVMeをカーネルドライバーへ戻す sudo ./scripts/restore_nvme.sh
動作原理
でGGUFファイルをNVMeブロックに書き込み。dd
がNVMeをVFIOにバインドし、PCIe D0状態とBusMasterを有効化。setup_nvme.sh
がユーザースペースからNVMeコントローラを初期化(admin/IOキュー)。gpu‑nvme‑direct- 推論時には各層(70B Q6_Kは約670 MB)を約670のNVMeコマンドで~202 msに読み込み。
- データはCUDAピン留めステージングへ入り、非同期DMAでGPU計算バッファへ転送される。
- ダブルバッファリングによりNVMe読込・H2D DMA・GPU計算を重ね合わせ、スループットを最大化。
アーキテクチャ概要
src/ ├── core/ # テンソル、アロケータ、GPUデバイス管理 ├── cuda/ # CUDAカーネル:GEMV, RMSNorm, RoPE, SwiGLU, softmax ├── memory/ # SLEP層ストリーミングエンジン(NVMe + mmap) ├── model/ # Transformer:設定、GGUFローダー、注意機構、FFN、正規化 ├── inference/ # トークナイザ、サンプラー、エンジン ├── utils/ # タイマー、ロガー └── main.cpp # CLI入り口 scripts/ ├── setup_system.sh # システム全体設定(GRUB, NVIDIAパッチ, CUDAパッチ, VFIO, NVMe) ├── setup_nvme.sh # NVMeをVFIOへバインド、gpu‑nvme‑direct用に構成 └── restore_nvme.sh # NVMeをカーネルデバイスへ戻す tests/ # ユニットテスト(テンソル, GEMMカーネル, NVMe層ローダ)
3‑Tier適応キャッシュ – forward_tiered()
forward_tiered()| 階層 | 内容 | 備考 |
|---|---|---|
| Tier A | VRAM常駐(層0–28) | GPU計算はI/Oゼロで永続的に保持。 |
| Tier B | ピン留めRAM(層29–79、ダブルバッファ) | H2D DMAとGPU計算を重ね合わせる。 |
| Tier C | NVMe/mmapフォールバック | 必要時のみ使用。 |
Tierサイズは
cudaMemGetInfo() と /proc/meminfo MemAvailable から自動算出。
量子化形式
| フォーマット | 重みビット数 | ブロックサイズ | 対応 |
|---|---|---|---|
| Q4_0 | 4.5 | 32 | はい |
| Q8_0 | 8.5 | 32 | はい |
| Q4_K_M | 4.5 | 256 | はい(Q4_K + Q5_K + Q6_Kの混合) |
| Q5_K | 5.5 | 256 | はい |
| Q6_K | 6.6 | 256 | はい |
| F16 | 16 | 1 | はい |
| F32 | 32 | 1 | はい |
フェーズロードマップ
| フェーズ | ステータス | ハイライト |
|---|---|---|
| 1 – 基盤 | 完了 | Llama 8B Q8_0、カスタムCUDAカーネル、48.9 tok/s |
| 2 – SLEPストリーミング | 完了 | 70Bを単一GPUで実行、3階層キャッシュ、33×速度向上 |
| 3 – 最適化 | 完了 | Q4_K_M/Q5_Kサポート、Layer skip(0.5 tok/s)、self‑speculative decoding、F16 KVキャッシュ |
| 4 – NVMe Direct | 完了 | バックエンド(GPU主導NVMe読込、3.35 GB/s) |
| 5 – ポリッシュ | 計画中 | ドラフトモデルを用いた推測デコーディング、ベンチマーク、公開C API |
ライセンス
BSD‑2‑Clause