つれづれなる備忘録

日々の発見をあるがままに綴る

Google Colabでpython2 ~ GPUの利用

 前回ブラウザ上で実行できるPython環境として、Google Colaboratory (Colab)を紹介した。メリットの1つとしてGPUが使用できることを取り上げたが、今回はGoole Colab上でのGPUの使用方法と効果について紹介する。

atatat.hatenablog.com

1. ColabノートブックでのGPU設定

 基本的にはGoogle Colabのトップページの下のアクセラレターの使用:TensorFlow と GPUのページ(英語)に従って、注釈を入れる形で使用方法やGPUの効果を確認するサンプルコードについて紹介する。

まず最初にノートブックのメニューバー上の"編集"から"ノートブックの設定"をクリックすると、以下のアクセラレータを選択するポップアップがあらわれるのでGPUを選択して保存する。

"ノートブックのアクセラレータ設定"
ノートブックのアクセラレータ設定

これでノートブック上でGPUが使用できる状態になる。GPUの設定ができているかどうかはtf.test.gpu_device_name()GPU名を取得する以下のコードで確認することができる。

import tensorflow as tf
device_name = tf.test.gpu_device_name()
if device_name != '/device:GPU:0':
  raise SystemError('GPU device not found')
print('Found GPU at: {}'.format(device_name))

正しく設定できていれば

Found GPU at: /device:GPU:0

となる。

2. GPU効果計測のためのサンプルコード

以上でGPUで処理することができるが、効果の確認として以下の処理でCPUとGPUの演算時間を比較する。

def cpu():
  with tf.device('/cpu:0'):
    random_image_cpu = tf.random.normal((100, 100, 100, 3))
    net_cpu = tf.keras.layers.Conv2D(32, 7)(random_image_cpu)
    return tf.math.reduce_sum(net_cpu)

def gpu():
  with tf.device('/device:GPU:0'):
    random_image_gpu = tf.random.normal((100, 100, 100, 3))
    net_gpu = tf.keras.layers.Conv2D(32, 7)(random_image_gpu)
    return tf.math.reduce_sum(net_gpu)

cpu()はcpuでの処理を実行する関数、gpu()GPUでの処理を実行する関数を定義している。 with tf.device()とすることで処理するデバイスを指定する。(詳しくはtf.device  |  TensorFlow Core v2.7.0) 次にtf.random.normal((100, 100, 100, 3))では指定したshape(上記は(100,100,100,3))の形式で正規分布乱数を出力する。例えばshapeに(2,2,2,3)を指定すると以下のように出力される。

import tensorflow as tf
tf.random.normal((2, 2, 2, 3))

実行結果は以下の通り。

<tf.Tensor: shape=(2, 2, 2, 3), dtype=float32, numpy=
array([[[[ 0.24025539,  1.32085   , -1.6566725 ],
         [-1.3553022 , -1.4656491 ,  0.06768529]],

        [[-0.6647642 ,  0.9501496 ,  0.13946538],
         [-0.9395935 ,  0.08838586,  0.7459039 ]]],


       [[[-0.17912869,  0.6915636 , -0.13298476],
         [-0.19780236, -0.8404351 ,  0.15334088]],

        [[-0.13912152,  2.172381  ,  0.5304954 ],
         [ 0.5558663 , -0.4010124 ,  1.9473423 ]]]], dtype=float32)>

なお他にも細かく指定できるので、詳細は公式リファレンスtf.random.normal  |  TensorFlow Core v2.7.0を参照。

random_cpu_imageの意味としては100x100,RGB(3)のイメージ(画像化すると砂嵐ノイズ)100セットということになる。 次にtf.keras.layers.Conv2D(32, 7)(random_image_cpu)は画像認識でお馴染みのコンボリューション処理を行う。 最後に配列(テンソル)の各要素の総和をとるtf.math.reduce_sum(net_gpu)を関数としての返り値とする。

tf.math.reduce_sum()の実行例のコードは以下のようになる。

import numpy as np
arr = np.array([[0, 1, 2], [3, 4, 5]])
tf.math.reduce_sum(arr)

実行すると各要素の総和が返ってくるがオブジェクト形式(下`numpy=15'が総和)になる。数値だけ取り出す場合はtf.math.reduce_sum(arr).numpy()とする。

<tf.Tensor: shape=(), dtype=int64, numpy=15>

以上cpu()およびgpu()の処理をまとめると、CPUまたはGPUを選択し、100x100,RGB(3)のイメージ(画像化すると砂嵐ノイズ)100セット生成し、 生成したイメージをコンボリューションした後、配列要素の総和を返す。

Tensorflowの初期化処理をあらかじめ実行しておくことで、関数内の処理時間のみを評価できるようにするため、それぞれの関数cpu()およびgpu()を一度実行する。

cpu()
gpu()

正しく実行されれば以下のような出力になる。

<tf.Tensor: shape=(), dtype=float32, numpy=1180.4795>

3. CPUとGPU処理時間の比較

 定義した関数cpu()gpu()の処理時間を比較する。この例ではtimeitを使用してそれぞれの処理時間を評価している。 timeit --- 小さなコード断片の実行時間計測 — Python 3.10.0b2 ドキュメント

以下のコードは関数cpu()およびgpu()を10回実行したときに要した時間を表示とCPUに対してGPUが何倍速いかを表示する。

import timeit
print('Time (s) to convolve 32x7x7x3 filter over random 100x100x100x3 images '
      '(batch x height x width x channel). Sum of ten runs.')
print('CPU (s):')
cpu_time = timeit.timeit('cpu()', number=10, setup="from __main__ import cpu")
print(cpu_time)
print('GPU (s):')
gpu_time = timeit.timeit('gpu()', number=10, setup="from __main__ import gpu")
print(gpu_time)
print('GPU speedup over CPU: {}x'.format(int(cpu_time/gpu_time)))

実行結果は以下のようになり、GPUの方がCPUよりも18倍速いという結果になった。

Time (s) to convolve 32x7x7x3 filter over random 100x100x100x3 images (batch x height x width x channel). Sum of ten runs.
CPU (s):
3.630094464000024
GPU (s):
0.19144165500000554
GPU speedup over CPU: 18x

4. まとめ

 今回はGoogle Colab上でGPUを利用するための設定と、GPUによる処理速度向上を確認するためのサンプルコード、実行例を紹介した。基本的にはノートブックの設定でアクセレレータの選択をGPUとするだけで使用可能で、自前のPCでGPUの設定をするよりかはるかに楽だということがわかると思う。