続編書きました:
背景
このブログを始めた2020年頃に、NVIDIA Tesla K40mを使った安価な機械学習用GPUマシンを紹介した。
その後このマシンは勉強用に色々と活用していたのだが、2020年時点でもアーキテクチャが Kepler (Compute Capability 3.5) と古く、何より計算スピードが遅すぎてKaggleなどでの活用が難しい問題があり、 結局Google Colab ProやKaggle Notebookをメインで使っていた。
更に、最近はRTX4090をメインマシンに導入したこともあり、このK40mマシンの出番はほぼなくなってしまった。
で、先日メインマシンのCPUを7950X3Dに変更したことで、AM4のCPUとマザボ、64GBのDDR4メモリなど、ほぼPC一式分のパーツが余剰となった。 売ってお金にすればよいというのに自作趣味の悪いところが出てしまい、サブマシンの更新をしたい欲が沸々と湧き上がる。
とはいえ先ほど言ったようにK40mはもう古いしなぁ……などと思いながら eBayを物色していたところ(これが良くなかった)、 Keplerより2世代新しいサーバー用GPUである Tesla P40が$200程度で売られているのを見つけてしまった。
https://www.ebay.com/itm/374377271140www.ebay.com
ちょっと調べてみると、VRAMはRTX3090/4090と同じく24GB搭載しており、FP32演算性能としてはKaggleやGoogle Colabでも使えるP100と同等と、サブマシンには適当な性能に思える。一方でP100と異なり半精度 (FP16) の演算はHW的に最適化されていないようで、近年当たり前に使われるMixed Precision 利用時の性能には不安が残るものの、このキワモノ感も検証欲をそそられる。
ということで、詳しいことは買ってから考える精神でNVIDIA Tesla P40をポチって令和最新版の格安?機械学習用マシンを組んでみたというお話。
簡単な性能検証や気になっていたMixed Precision利用時の挙動を確認してみたので興味がある方は下へどうぞ。
まとめ
P40はお手頃価格の機械学習用24GB VRAM GPUになるポテンシャルあり。3万で買えるGPUとしては破格の性能だと思う。
P100と比較すると、 P40はVRAM容量では勝るが、 VRAM帯域やFP16への対応などで劣る。 中古価格では1~2万程度の価格差でP100を買えるようなので、どっちを選ぶかは悩ましい。
懸念であった Mixed Precision 利用時の挙動であるが、確かにT4 GPUのような Mixed Precision利用を想定されているGPU(約80%高速化)に比べてトレーニング時間の削減効果は少なく、 MobileNetトレーニング時に20%程度しか計算時間を改善できなかった。
今回はeBayの中国セラーから送料込$207で購入したが、 状態は良好。 注文から10日程度で受け取れた。
- 電源供給に必要なPCIe 8pin x2→ EPS 8pin ケーブルもNVIDIA純正?らしきケーブルがついてきた
MSIのB550マザー+5800X3Dの構成にP40と映像出力用の適当なGPUを刺してUbuntuをセットアップできた。
パーツは流用したから実質タダみたいなもの……という冗談はさておき、 今P40を採用しつつコスパ重視すれば、13万くらいでそこそこの機械学習用マシンを組めると思います。
なにより、 おうちにサーバー用GPUのTeslaがあるのってロマンだよね! というところが一番大きなモチベだったりするので深く考えずに買っちゃいましたが、思ったよりも使える可能性を感じました。
昨今のLLMやDiffusion系生成モデルのようなVRAM食い機械学習モデルを動かす際にも使えるかもなので、その辺は今後使いながら検証していきたいと思います。とりあえず今回は一通りのセットアップと簡易的なベンチマークまでを記しておくつもり。
P40について
P40の基本スペックは
NVIDIA Tesla P40 Specs | TechPowerUp GPU Database
を参考に次の通りです。
- Compute Capability: 6.1
- CUDA cores: 3840
- VRAM: 24GB GDDR5, 346GB/s
- FP32演算性能: 12TFLOPS
- FP16演算性能: 183.7 GFLOPS (1:64)
- 消費電力: 250W
コンシューマ製品でいうと大体GTX1080 Tiのメモリ多い版と認識しておけば良いかもしれません。
また、ご覧の通りFP16の性能はFP32比で1/64と大きく削減されている(ちなみにP100は 2:1)。P40発売時の記事を見るとトレーニング用GPUとして発表されているものの、発売された2017年頃はまだTensorFlowやPyTorch(Chainer)などのフレームワークでも自動半精度やAuto Mixed Precisionのサポートもなかったであろうから、あまり重視されなかったのであろう。
届いたP40はちゃんとクリーニングされているのか保守在庫だったのかわかりませんが非常にきれい。 バックプレート側に"IASER"というメーカー名っぽいシールが新しく貼られているのですが、軽くググっても何を意味するのか分からず。 もしかするとサーバー用GPUのリファービッシュを販売している中国メーカーなのかもしれません。
P40は電源供給にEPS 8pin(マザボに指すCPU用の12Vコネクタと同じ)を使うのですが、PCIe 8pin x2からの変換ケーブルもNVIDIAのロゴの入ったタグの付いた純正?らしきものがついてきました。
K40mとの比較写真。Pascal世代のカードのデザインはNVIDIAぽさがあって良き。
P40はパッシブ冷却なので、前回作成したダンボールで作ったハウジングを取り付けたファンと一緒に使います。
組み立て
メインのパーツは前世代のPCから流用します。 また、我が家では床に直置きだと取り回しに問題があることが前回の経験からわかっていたので、今回は少しお金はもったいないですが所謂ベンチ台を購入してその上に組立しました。
- MB: MSI MPG B550 Gaming Plus
- CPU: Ryzen75800X3D
- CPU cooler: Deep Cool AK400
- Mem: DDR4 3200MHz 64GB (Micron, ADATA2枚ずつ混載)
- SSD: MX500 1TB SATA
- GPU (Graphics): Quadro K600
- GPU (Compute): Tesla P40
- PSU: Corsair RM1000
- Case: 2WAY ベンチテーブル SMZ-2WBT-ATX
ゲームしないのに5800X3Dはもったいないので、 これだけは売ってしまって5900Xに買い替えたいとは思っています。
ちなみにベンチ台は13000円もしたのですが、正直ただの金属フレームです。安価に作る目的に反してちょっと高すぎる印象は受けますが、工作精度はそれなりに高くねじ穴ずれなどはなかったのでまあ納得して使っています。
Amazon.co.jp: 【長尾製作所×シミラボ】 2WAY ベンチテーブル SMZ-2WBT-ATX : ホーム&キッチン
出来上がりはこんな感じ。
UEFU設定、Ubuntuインストール
UEFI設定はだいぶ苦戦しました。 最初にP40を1つ目のx16に、 K600を2つ目のx16に刺したところ、 "VGA" のPOSTチェックLEDが点灯してしまいUEFI画面が映らず。
K600だけを接続したところちゃんとUEFIが映ったので、色々いじって試したところ次の設定でうまく行きました。 必要十分条件であるとは検証できていませんが、とりあえず私の環境では動いた条件として認識ください。
- Above 4G memory/Crypto Currency mining: Enabled
- Re-Size BAR Support: Enabled
- VGA Detection: False
- Full Screen Logo Display: Disabled
このUEFI設定でP40を1つ目のx16に、K600を2つ目のx16を刺して起動を確認できました。
Ubuntuは22.04を利用。 適当なUSBメモリにEtcherでISOを焼き、 普通にインストールを実行。
その後、openssh-serverのインストール、固定IPアドレス設定、CUDAインストールをリンク先を参考に行い、ベンチを取りました。
簡易ベンチマーク
TensorFlow2からの見え方
ベンチマークではないですが、一応。
>>> from tensorflow.python.client import device_lib >>> device_lib.list_local_devices() [name: "/device:CPU:0" device_type: "CPU" memory_limit: 268435456 locality { } incarnation: 5659398530349240384 xla_global_id: -1 , name: "/device:GPU:0" device_type: "GPU" memory_limit: 23176478720 locality { bus_id: 1 links { } } incarnation: 13990392878040664411 physical_device_desc: "device: 0, name: Tesla P40, pci bus id: 0000:2b:00.0, compute capability: 6.1" xla_global_id: 416903419 ]
ai-benchmark
この記事でRTX4090の性能を測るときにも紹介した、機械学習性能を簡易的に測れるPythonパッケージ。出力全文は最後に載せます。
>>> from ai_benchmark import AIBenchmark >>> benchmark = AIBenchmark() >> AI-Benchmark-v.0.1.2 >> Let the AI Games begin.. >>> results = benchmark.run() * TF Version: 2.12.0 * Platform: Linux-5.19.0-38-generic-x86_64-with-glibc2.35 * CPU: N/A * CPU RAM: 63 GB * GPU/0: Tesla P40 * GPU RAM: 21.6 GB * CUDA Version: 11.8 * CUDA Build: V11.8.89 ~省略~ Device Inference Score: 11065 Device Training Score: 10797 Device AI Score: 21862
スコア的にはもちろんRTX4090には及ばず。公式のランキングを見ると一番近いスコアはRTX2070ですが、P40はVRAMが24GBもあるので実行できるモデルのサイズは段違い。しかもたった3万円であることを考えれば十二分なスコアではないだろうか。
MobileNetによるcats_and_dogs分類モデル
ここの記事で紹介した、TensorFlow2のチュートリアルで扱われているMobileNet V2でcats_and_dogsデータセットの画像分類モデルをトレーニングする速度を測りました。
比較対象がいないとわかりにくいと思いますので、Google ColabのT4 アクセラレータを有効化したインスタンスでも同様のコードを実行しました。もちろんCPUやディスクの性能は大きく違うので、対等な比較でないことを念頭に参考程度に見てください。
画像サイズを2種類(160x160, 512x512)、Mixed Precision有効/無効の4パターンで計測。2エポック目以降の実行時間(s/epoch)で比較します。
- 160x160
P40 | T4(Colab) | |
---|---|---|
Mixed無効 | 5.78s | 7.61s |
有効 | 5.73s | 6.84s |
倍率 | x1.01 | x1.11 |
- 512x512
P40 | T4(Colab) | |
---|---|---|
Mixed無効 | 45.71s | 54.84s |
有効 | 38.61s | 30.47s |
倍率 | x1.18 | x1.79 |
小さな画像サイズではP40のほうがT4よりも精度に関わらず速い結果に(おそらくColabのCPUかIO性能がリミットになっている?)。一方画像サイズが大きくなると、Mixed Precision無効化ではP40のほうが速いが、有効化ではT4よりも遅くなるという結果が得られた。
P40はあまりMixed Precisionによる演算速度向上の効果が得られにくいということがわかる。とは言え、やはり3万円でT4並の性能でVRAM 24GBのグラボが手に入るのは魅力的だと思う。
Mixed Precisionを利用したときの最大バッチサイズ
最後に、P40におけるMixed Precisionがどのように利用VRAM量に影響を与えるかを確かめるため、先程のMobileNet V2のモデルの入力を512x512にしたときにOOMを吐かずに動く最大バッチサイズを探ってみました。
- Mixed Precision無効: max_bs=68
- Mixed Precision無効: max_bs=112
結果、Mixed Precisionを有効にすることで、倍とまではいかないものの1.6倍以上のバッチサイズを設定できることがわかった。大きなモデルを利用するときなどには、P40であってもMixed Precisionを有効にするのが良さそうである。
ai-benchmark全文
>>> from ai_benchmark import AIBenchmark >>> benchmark = AIBenchmark() >> AI-Benchmark-v.0.1.2 >> Let the AI Games begin.. >>> results = benchmark.run() * TF Version: 2.12.0 * Platform: Linux-5.19.0-38-generic-x86_64-with-glibc2.35 * CPU: N/A * CPU RAM: 63 GB * GPU/0: Tesla P40 * GPU RAM: 21.6 GB * CUDA Version: 11.8 * CUDA Build: V11.8.89 The benchmark is running... The tests might take up to 20 minutes Please don't interrupt the script 1/19. MobileNet-V2 1.1 - inference | batch=50, size=224x224: 63.0 ± 0.8 ms 1.2 - training | batch=50, size=224x224: 191.9 ± 0.5 ms 2/19. Inception-V3 2.1 - inference | batch=20, size=346x346: 62.0 ± 1.1 ms 2.2 - training | batch=20, size=346x346: 255.4 ± 0.8 ms 3/19. Inception-V4 3.1 - inference | batch=10, size=346x346: 61.9 ± 1.0 ms 3.2 - training | batch=10, size=346x346: 255.3 ± 0.6 ms 4/19. Inception-ResNet-V2 4.1 - inference | batch=10, size=346x346: 84.6 ± 0.7 ms 4.2 - training | batch=8, size=346x346: 282.0 ± 0.6 ms 5/19. ResNet-V2-50 5.1 - inference | batch=10, size=346x346: 45.0 ± 0.6 ms 5.2 - training | batch=10, size=346x346: 166.2 ± 0.4 ms 6/19. ResNet-V2-152 6.1 - inference | batch=10, size=256x256: 60.0 ± 0.7 ms 6.2 - training | batch=10, size=256x256: 234.7 ± 0.6 ms 7/19. VGG-16 7.1 - inference | batch=20, size=224x224: 91.0 ± 1.0 ms 7.2 - training | batch=2, size=224x224: 185 ± 1 ms 8/19. SRCNN 9-5-5 8.1 - inference | batch=10, size=512x512: 87.7 ± 3.3 ms 8.2 - inference | batch=1, size=1536x1536: 74.4 ± 2.1 ms 8.3 - training | batch=10, size=512x512: 247 ± 3 ms 9/19. VGG-19 Super-Res 9.1 - inference | batch=10, size=256x256: 67.7 ± 0.5 ms 9.2 - inference | batch=1, size=1024x1024: 103.0 ± 0.7 ms 9.3 - training | batch=10, size=224x224: 251.2 ± 0.9 ms 10/19. ResNet-SRGAN 10.1 - inference | batch=10, size=512x512: 116 ± 1 ms 10.2 - inference | batch=1, size=1536x1536: 105.7 ± 0.8 ms 10.3 - training | batch=5, size=512x512: 198.5 ± 0.7 ms 11/19. ResNet-DPED 11.1 - inference | batch=10, size=256x256: 148.6 ± 0.5 ms 11.2 - inference | batch=1, size=1024x1024: 250.8 ± 0.4 ms 11.3 - training | batch=15, size=128x128: 265.1 ± 0.5 ms 12/19. U-Net 12.1 - inference | batch=4, size=512x512: 262 ± 2 ms 12.2 - inference | batch=1, size=1024x1024: 262 ± 1 ms 12.3 - training | batch=4, size=256x256: 304.0 ± 0.3 ms 13/19. Nvidia-SPADE 13.1 - inference | batch=5, size=128x128: 120.4 ± 0.6 ms 13.2 - training | batch=1, size=128x128: 214.0 ± 0.0 ms 14/19. ICNet 14.1 - inference | batch=5, size=1024x1536: 178 ± 4 ms 14.2 - training | batch=10, size=1024x1536: 507 ± 12 ms 15/19. PSPNet 15.1 - inference | batch=5, size=720x720: 513 ± 1 ms 15.2 - training | batch=1, size=512x512: 207 ± 2 ms 16/19. DeepLab 16.1 - inference | batch=2, size=512x512: 142.6 ± 0.5 ms 16.2 - training | batch=1, size=384x384: 162.8 ± 0.4 ms 17/19. Pixel-RNN 17.1 - inference | batch=50, size=64x64: 339 ± 9 ms 17.2 - training | batch=10, size=64x64: 1055 ± 33 ms 18/19. LSTM-Sentiment 18.1 - inference | batch=100, size=1024x300: 480 ± 12 ms 18.2 - training | batch=10, size=1024x300: 846 ± 19 ms 19/19. GNMT-Translation 19.1 - inference | batch=1, size=1x20: 174 ± 3 ms Device Inference Score: 11065 Device Training Score: 10797 Device AI Score: 21862