LoginSignup
7

More than 5 years have passed since last update.

Jetson TX1におけるGPU性能調査 その1

Last updated at Posted at 2016-09-21

はじめに

Jetson TX1のGPUを使用した効能を調査します。
第一回として、Pythonでもお手軽にGPU環境が使用できるCuPyを使用してみました。
(C/C++よりPythonの方がサクッと試せそうだったのでPythonを選択しています)
(ゴリゴリにCUDAやGPGPUを活用したい場合はC/C++を選択すべきかも?)

CuPyとは

Chainerをインストールすることで使用できるPython用ライブラリ。
NumPyと同じ構文・感覚で使用でき、うまく使えばNumPyとCuPy配列を手軽に切り替えられる。

switch_numpy_cupy.py
import numpy
import cupy

#xp = numpy
xp = cupy

a = xp.arange( 25 ).reshape( 5 , 5 )
a = a.dot( a )

参考リンク: Preferred Networks社のスライドシェア
参考リンク: ChainerとCuPyについて

GPUの効能調査

CPU代表としてNumPyに、GPU代表としてCuPyに頑張ってもらいます。

比較方法

  • 配列の内積を求めるプログラムで計算時間を比較する。
    • 配列の準備やGPUのデバイスオープンの時間は除き、純粋に内積の計算時間のみ比較する。
  • 下記プログラム内の「xp = ○○」をコメントアウトで切り替えることで、CPUのみとGPUを使用した場合を切り替える
  • 下記プログラム内の「N」を10~1000変えてみて、CPUのみとGPUを使用した場合の計算時間を求める
  • ターミナルにて「python gpu_test.py」を実行し処理時間を出力させる
gpu_test.py
import time
import numpy
import cupy

#xp = numpy
xp = cupy

#配列の次元
N = 10
N2 = N * N

#配列のセット
a = xp.arange( N2 ).reshape( N , N )
start = time.time()
#内積の計算
a = a.dot( a )
end = time.time()
#内積の計算時間を出力する
print ( end - start )

結果

  • 500×500配列の内積計算まではCPUの方が高速、700×700配列以降はGPUの圧勝
  • 配列の次元が増加するに連れ、
    • CPUのみの場合はは指数関数的に計算時間が伸びている
    • GPUを使用すると計算時間は微増するだけ

結果をまとめた表とグラフ
numpy_cupy.png numpy_cupy_1.png

横軸の範囲を0~1200 -> 0~700、縦軸の範囲を0~40 -> 0~3.5に変更したグラフ
numpy_cupy_2.png

GPUの効能調査(追加確認)

chachayさんのナイスなコメントをいただきましたので、CuPyに関して追加で確認を実施しました。
(chachayさん、ありがとうございますm(_ _)m)
CuPyで内積を計算する前に、CuPyを用いた適当な計算を行うことにしました。

追加確認の内容

追加確認では下記の2種のプログラムを使用します。

  • gpu_test_1.py:
    • 上のテストとやってることは変わらない
    • 1回プログラムを実行(ターミナルで「python gpu_test_1.py」)すればN=10~1000まで全部計算してくれる
  • gpu_test_2.py:
    • 計算時間を計測したい内積計算の前にCuPyを用いた適当な計算を行い、CUDAのコンパイルを先に完了させる
    • 1回プログラムを実行(ターミナルで「python gpu_test_2.py」)すればN=10~1000まで全部計算してくれる
gpu_test_1.py
import time
import numpy
import cupy

#xp = numpy
xp = cupy

N = [10,100,200,300,400,500,600,700,800,900,1000]

#if xp == cupy: 
#   z = xp.arange(4).reshape( 2 , 2 )
#   z.dot( z )

for N in N:
    N2 = N * N
    a = xp.arange(N2).reshape(N, N)
    start = time.time()
    a.dot(a)
    end = time.time()
    print str(N) + " * " + str(N) + " => " + str(end - start)
gpu_test_2.py
import time
import numpy
import cupy


#xp = numpy
xp = cupy

N = [10,100,200,300,400,500,600,700,800,900,1000]

# CuPyを用いた適当な計算を実行し、CUDAのコンパイルを先に完了させる
if xp == cupy:  
    z = xp.arange(4).reshape( 2 , 2 )
    z.dot( z )

for N in N:
    N2 = N * N
    a = xp.arange(N2).reshape(N, N)
    start = time.time()
    a.dot(a)
    end = time.time()
    print str(N) + " * " + str(N) + " => " + str(end - start)

追加確認の結果

先にCUDAのコンパイルを完了させるのとさせないのでは、1回目の内積計算で大きな差(約0.6sec)が出ました。

結果をまとめた表とグラフ
numpy_cupy.png numpy_cupy_3.png
縦軸の範囲を0~0.7 -> 0~0.18に変更したグラフ
numpy_cupy_4.png

CPU(NumPy)とGPU(CuPy)の計算時間 決定版

Jetson TX1の場合の計算時間です
(他のGPUボード等では結果に差が出る可能性があります)

  • 10×10配列など配列の次元が小さい場合はCPUの方が高速だが、200×200配列以降はGPUの方が速くなる
  • 配列の次元が増加するに連れ、
    • CPUのみの場合はは指数関数的に計算時間が伸びている
    • GPUを使用すると計算時間は微増するだけ

結果をまとめた表とグラフ
numpy_cupy.png numpy_cupy_5.png

横軸の範囲を0~1200 -> 0~700、縦軸の範囲を0~40 -> 0~0.1に変更したグラフ
numpy_cupy_6.png

終わりに

配列の次元が小さく並列度が小さい場合は、GPUの効果があまり感じられないことが分かりました(いまさら感)。
ただ、内積計算だけで言えば、700×700配列を使用しなければGPUの効果が得られないのは意外でした。
CPUからGPUへのメモリアクセスによる遅延だけが問題なのか、それ以外に問題があるのか深堀したいですね。

(2016/09/23追記)
Jetson TX1において、内積の計算は200×200配列以降でGPUの方が速く計算できることがわかりました。
関数自体を並列化するなどすれば、配列の次元が小さくてもGPUの方が速く計算できそうな気がします。
(CuPyで関数の並列化できるのかなど、今後の調査課題も見つかりました)
また、追加確認の結果、最初にCuPy実行時にCUDAのコンパイルが実行されるということがわかりました。

コメントでご指摘をくださったchachayさん、ありがとうございます!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7