iPX社員によるブログ

iPX社員が"社の動向"から"自身の知見や趣味"、"セミナーなどのおすすめ情報"に至るまで幅広い話題を投下していくブログ。社の雰囲気を感じ取っていただけたら幸いです。

TensorFlowの未来に触れてみた

TCDの堀田です。
最近体調を崩してしまいました。季節の変わり目なので、見てくださっている皆様は体調にお気をつけください。

さて、今回のテーマですが、TensorFlow 2.0のプレビュー版を触ってみました。
新しい物好きなところがあるので、機械学習の勉強がてら動かしてみた次第です。

TensorFlow 2.0

TensorFlow 2.0は現行のTensorFlow 1.xに改良を加えた新バージョンで、先日Beta版がリリースされました。
TensorFlow 2.0の変更点は既に公式サイトを始め詳しく説明されているサイト様があります。
Effective TensorFlow 2.0  |  TensorFlow Core  |  TensorFlow
TensorFlow 2.0 α版で何が変わる? 新機能の概要 ― TensorFlow Dev Summit 2019 - Deep Insider
代表的な変更点は以下の2点です。

  • tf.kerasを始めとする標準APIが整理された
  • Eager execution (即時実行)が標準となった

Eager execution方式では、命令を呼び出した時点で実行されます。
TensorFlow 1.xではまずグラフを作成し、その後session.run()で実行するという遅延実行のような方法しかできませんでしたが、Eager executionによりデバッグ等が容易になるという利点があります。
従来のグラフモードでも実行することができ、@tf.functionというアノテーションを付けることによりPython構文の関数をグラフに変換して実行するAutoGraphという機能も追加されています。

TensorFlow公式のチュートリアルはこの恩恵が分かるようなものとなっており、今回はこのチュートリアルを写経で動作させてみました。
環境はWindowsUbuntu、それぞれのGPU版パッケージを使用しました。
TensorFlowのバージョンは2.0 Beta1を使用しました。

ソースコード

Pythonソースコードは以下の公式DCGANチュートリアルのものをベースにしています。
Deep Convolutional Generative Adversarial Network  |  TensorFlow Core  |  TensorFlow
このチュートリアルではJupyter Notebook環境で実行していますが、今回はローカルに環境を作成しているので必要なパッケージのインストールを事前に行います。

$ pip install tensorflow-gpu==2.0.0-beta1 imageio matplotlib

ちなみに上記チュートリアルソースコードですが、GeneratorとDiscriminatorの各モデルはtf.keras.Sequentialの記法でも動作しました。
Generatorはチュートリアルでは以下のように定義されています。

def make_generator_model():
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Reshape((7, 7, 256)))
    assert model.output_shape == (None, 7, 7, 256) # Note: None is the batch size

    model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    assert model.output_shape == (None, 7, 7, 128)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    assert model.output_shape == (None, 14, 14, 64)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    assert model.output_shape == (None, 28, 28, 1)

    return model

generator = make_generator_model()

Sequentialモデルの記法だと以下のように書けます。

generator = tf.keras.Sequential([
	layers.Dense(7*7*256, use_bias=False, input_shape=(100,)),
	layers.BatchNormalization(),
	layers.LeakyReLU(),
	layers.Reshape((7, 7, 256)),
	layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False),
	layers.BatchNormalization(),
	layers.LeakyReLU(),
	layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False),
	layers.BatchNormalization(),
	layers.LeakyReLU(),
    layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh')
])

generator.build()

同様に、Discriminatorは以下のように定義されていますが、

def make_discriminator_model():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same',
                                     input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Flatten())
    model.add(layers.Dense(1))

    return model

discriminator = make_discriminator_model()

以下のように定義することも可能です。

discriminator = tf.keras.Sequential([
 	layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]),
	layers.LeakyReLU(),
	layers.Dropout(0.3),
	layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'),
	layers.LeakyReLU(),
	layers.Dropout(0.3),
	layers.Flatten(),
	layers.Dense(1)
])

discriminator.build()

実行環境

PC

WindowsUbuntuデュアルブートができる同一PCでそれぞれ動作させました。
GPUGeForce GTX 1070を搭載しています。

Windows

OSはWindows10 Homeを使用しました。
Python環境はAnacondaを使用し、Python 3.7.3の環境を作成してTensorFlow GPU版のpipパッケージをインストールしました。

TensorFlow 2.0 Alpha版のGPU版pipパッケージでは実行時にエラーが発生する場合がありましたが、Beta版のpipパッケージでは発生しなくなっているようです。

Ubuntu

OSはUbuntu 16.04.5を使用しました。
こちらもPython 3.7.3にpipパッケージでインストールしています。

共通

GPUを動かすにはCUDA Toolkit 10.0とcuDNN 7.4.1以降のインストールも必要になります。
CUDA Toolkit Archive | NVIDIA Developer
https://developer.nvidia.com/rdp/cudnn-download : cuDNNダウンロード
CUDA Toolkitの執筆時点での最新版は10.1ですが、10.0でなければ動作しません。
またcuDNNのダウンロードにはNVIDIA Developer Programへの登録が必要となります。

実行結果

Windows
2019-07-01 11:33:00.167721: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library nvcuda.dll
2019-07-01 11:33:01.206607: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties: 
name: GeForce GTX 1070 major: 6 minor: 1 memoryClockRate(GHz): 1.645
pciBusID: 0000:01:00.0
2019-07-01 11:33:01.213982: I tensorflow/stream_executor/platform/default/dlopen_checker_stub.cc:25] GPU libraries are statically linked, skip dlopen check.
2019-07-01 11:33:01.235855: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0
2019-07-01 11:33:01.250178: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2019-07-01 11:33:01.281566: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties: 
name: GeForce GTX 1070 major: 6 minor: 1 memoryClockRate(GHz): 1.645
pciBusID: 0000:01:00.0
2019-07-01 11:33:01.312795: I tensorflow/stream_executor/platform/default/dlopen_checker_stub.cc:25] GPU libraries are statically linked, skip dlopen check.
2019-07-01 11:33:01.337814: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0
2019-07-01 11:33:01.911747: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix:

...

Time for epoch 1 is 14.500241994857788 sec
Time for epoch 2 is 10.724332571029663 sec
Time for epoch 3 is 10.826036214828491 sec
Time for epoch 4 is 10.727312564849854 sec

...

Time for epoch 48 is 10.749233722686768 sec
Time for epoch 49 is 10.785157203674316 sec
Time for epoch 50 is 10.856985569000244 sec

GPUを認識して動作していることがログから読み取れます。

Ubuntu
2019-07-01 10:00:00.752139: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcuda.so.1
2019-07-01 10:00:00.773412: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1006] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2019-07-01 10:01:00.774199: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties: 
name: GeForce GTX 1070 major: 6 minor: 1 memoryClockRate(GHz): 1.645
pciBusID: 0000:01:00.0
2019-07-01 10:00:00.774418: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0
2019-07-01 10:00:00.775349: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0
2019-07-01 10:00:00.775956: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcufft.so.10.0
2019-07-01 10:00:00.776113: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcurand.so.10.0
2019-07-01 10:00:00.777022: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusolver.so.10.0
2019-07-01 10:00:00.777745: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusparse.so.10.0
2019-07-01 10:00:00.779877: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudnn.so.7

...

Time for epoch 1 is 12.890560865402222 sec.
Time for epoch 2 is 10.154475688934326 sec.
Time for epoch 3 is 10.17082405090332 sec.
Time for epoch 4 is 10.261008977890015 sec.

...

Time for epoch 48 is 10.418879270553589 sec.
Time for epoch 49 is 10.359337329864502 sec.
Time for epoch 50 is 10.389174461364746 sec.

こちらもGPUを認識して動作していることがログから読み取れます。
同じコードですがWindows版よりわずかに早く動作しているようです。

終わりに

TensorFlow 2.0を実際に実装してみたところよりとっつきやすくなった印象です。
正式リリースにはもうしばらくかかりそうですが、他のサンプルやネットワークの自前での実装についても試してみたいと思います。