【PyTorch】Windows10にPyTorchを導入してGPUの演算性能を評価する

自分用のメモ。
LinuxマシンとかAWSとかではやっているのをよく見かけるPyTorchのGPU利用ですが、Windows10の場合はどうするんだろう、と調べて実際にやってみた記録。

参考にしたのはこちら。

goldfish-man.hatenablog.com

環境

5年前位に買ったWindows10マシンで、当時はスペックが良い方だったのだけれど、今となってはやや見劣りする感じ。

実行環境はこんな感じ。

  • Anaconda
  • Python 3.7.1
  • Jupyter Lab

準備

Visual Studio Community2019をインストール

まずはVisual Studioが必要とのこと。インストールは下記より。

visualstudio.microsoft.com

Visual Studioそのものを使う、というよりはそのなかのコンポーネントがCUDAを動かすのに必要、ということらしい。

CUDAをインストール

developer.nvidia.com

上記リンクからCUDAの最新版をインストールする。
たぶん最新版のが良いのじゃないかな、と思う。ちなみに現時点での最新版は10.1 update 2になっている。下の画像のように自分の環境をポチポチしていってダウンロードすれば良い。

CUDAダウンロード時の設定

自分はnetworkにしました。localにするとかなり巨大な.exeをダウンロードするので。networkでも大して時間はかからず。10分かからないくらいだったかな?

PyTorchをインストール

pytorch.org

PyTorchのインストール方法を上記から選択する。

PyTorchのインストール方法の選択

今回はPython3.7、CUDA10.1、condaでのインストールなので上のような設定になる。するとRun This commandのところに良い感じにインストール用のコマンドが表示されるので、これを実行すれば良い。

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

pipだろうがcondaだろうが、インストールできればOKなのだけれど、すでにCUDA対応でないPyTorchをインストールしている場合はやり直した方が良い。

性能評価

チュートリアルのサンプルコードを実行する

pytorch.org

チュートリアルにある2番目のコードで試してみた。
コードにある通り、バッチサイズ64、入力層のノード数1000、隠れ層のノード数100、出力層のノード数10、活性化関数にReLUを使うシンプルなネットワーク。
なお、実行時間を計測するため、timeライブラリを使い、forループの前後で時間を計測した。

まずはCPUの結果から。

99 350.2883605957031
199 1.6243224143981934
299 0.015767984092235565
399 0.0004199870745651424
499 6.515638960991055e-05
elapsed_time:0.3560447692871094[sec]

実行時間は0.36秒程度。
次に、コードの一部を変更してGPUで実行する。

99 339.7377014160156
199 0.7344891428947449
299 0.003484970424324274
399 0.00013160801609046757
499 3.048904000024777e-05
elapsed_time:1.5827696323394775[sec]

ん?CPUの方が速い?

GPUの演算性能に影響を与える因子

codeday.me

結論から言うと、上のURLにあるように、並列計算できる分量が多ければ多いほど、GPUの性能が際立ってくる。逆に一回当たりの演算の並列化量が少なく、forループなどの並列化できない箇所が多いと、CPUの方が演算速度が速くなる。
上記のテストコードの場合、入力層から隠れ層への行列演算が

(64×1000)(1000×100)

のサイズの行列の積であった。人間が計算するには大きな行列だけれど、GPUから見たらこのサイズは小さくて十分に並列化できない、ということらしい。
なので、テストコードをいじって、行列演算のサイズを変えてみた。

  • 入力ノードを増やす

N, D_in, H, D_out = 64, 3500, 100, 10として入力ノードのサイズを変え、積を計算する行列を大きくしてみた。

CPUの結果

99 2738.1865234375
199 1301.2371826171875
299 940.7708129882812
399 786.500732421875
499 706.3295288085938
elapsed_time:1.023407220840454[sec]

GPUの結果

99 14849.46875
199 3840.01416015625
299 1686.515625
399 968.605224609375
499 664.8519287109375
elapsed_time:0.963533878326416[sec]

わずかにGPUの方が速い結果となった。

  • バッチ数を減らし、入力ノードと隠れ層のノードを増やす

N, D_in, H, D_out = 8, 10000, 200, 10とした。バッチサイズ64のままで入力ノードを10000にするとうまく実行できなかったのでこの設置としている。

CPUの結果

99 840.8685302734375
199 198.62562561035156
299 103.77583312988281
399 74.15234375
499 61.467132568359375
elapsed_time:3.577970504760742[sec]

GPUの結果

99 241.82785034179688
199 86.19084930419922
299 82.44027709960938
399 82.34451293945312
499 82.33955383300781
elapsed_time:1.187114953994751[sec]

GPUの方が速くなった。やはり行列のサイズがGPUの恩恵を受けるのに必要な因子であるようだ。

まとめ

  • Windows10にGPU対応のPyTorchを導入した
  • CPUとGPUの演算性能を比較すると、チュートリアルのサンプルコードではCPUの方が速い結果となった
  • これは並列化できる箇所の大きさ、特に行列演算の大きさに依存するため、GPUの恩恵を受けるには並列化できるサイズに注意する