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公式のチュートリアルはこの恩恵が分かるようなものとなっており、今回はこのチュートリアルを写経で動作させてみました。
環境はWindowsとUbuntu、それぞれの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
WindowsとUbuntuのデュアルブートができる同一PCでそれぞれ動作させました。
GPUはGeForce GTX 1070を搭載しています。
共通
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を実際に実装してみたところよりとっつきやすくなった印象です。
正式リリースにはもうしばらくかかりそうですが、他のサンプルやネットワークの自前での実装についても試してみたいと思います。