突然ですが、TensorFlow の Eager Mode(Eager Execution)を使っていますか?私が初めて使った時、これは便利だと思ったのですが、速度が遅いので止めました。
そんなのろまな Eager Mode(Define by Run)を Graph Mode(Define and Run)より高速にする方法を紹介します。
参考にした記事は、Tensorflow Eager vs PyTorch (強化学習編) です。jack_ama さん、ありがとうございます <(_ _)>
やり方は簡単!下記の nn99_eager.py を見てもらえればわかるように、@tf.contrib.eager.defun を一行追加するだけです。
結果は以下のようになりました。(TensorFlow 1.13.1で再度計測しました2019/3/3)
Mode | 処理時間 |
---|---|
Graph Mode | 21.501 sec |
Eager Mode(@tf.contrib.eager.defun無し) | 85.694 sec |
Eager Mode(@tf.contrib.eager.defun有り) | 17.486 sec |
なんと、Eager Mode(@tf.contrib.eager.defun有り)が、Graph Mode より約1.2倍高速になりました。
比較対象の Graph Mode 版は、TensorFlow:ニューラルネットワークによる乗算の学習 の nn99_graph.py です。
今回作成したプログラムは、以下のようになります。
OS:Ubuntu 18.04
TensorFlow 1.13.1(Eager ModeではTensorFlow 1.12.0の方が高速です)
import math
import numpy as np
import tensorflow as tf
import time
tf.enable_eager_execution()
class Model:
units1 = 2
units2 = 7
units3 = 1
epochs = 50001
def __init__(self):
self.W1 = tf.Variable(tf.random_uniform([self.units1, self.units2], -1.0, 1.0, tf.float32))
self.b1 = tf.Variable(tf.random_uniform([self.units2], -1.0, 1.0, tf.float32))
self.W2 = tf.Variable(tf.random_uniform([self.units2, self.units3], -1.0, 1.0, tf.float32))
self.b2 = tf.Variable(tf.random_uniform([self.units3], -1.0, 1.0, tf.float32))
#self.optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
self.optimizer = tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1.0e-8)
def model(self, x):
return tf.matmul(self.f(tf.matmul(x, self.W1) + self.b1), self.W2) + self.b2
def f(self, x):
return tf.tanh(x)
def loss(self, x, y):
return tf.reduce_mean(tf.square(self.model(x) - y))
def grad(self, x, y):
with tf.GradientTape() as tape:
loss = self.loss(x, y)
params = [self.W1, self.b1, self.W2, self.b2]
return tape.gradient(loss, params)
@tf.contrib.eager.defun
def optimize(self, x, y):
grads = self.grad(x, y)
params = [self.W1, self.b1, self.W2, self.b2]
self.optimizer.apply_gradients(zip(grads, params))
def train(self, x, y):
start = time.time()
for step in range(self.epochs):
self.optimize(x, y)
if step % 1000 == 0:
loss = self.loss(x, y)
print("Step={:5d}, Loss={:8.5f}".format(step, loss))
stop = time.time()
print("{:.3f}sec".format(stop - start))
def predict(self, x):
return self.model(x)[0].numpy()
model = Model()
x_train = tf.convert_to_tensor(np.array([[x1, x2] for x1 in range(1, 10, 1) for x2 in range(1, 10, 1)]), tf.float32)
y_train = tf.convert_to_tensor(np.array([[x1 * x2] for x1 in range(1, 10, 1) for x2 in range(1, 10, 1)]), tf.float32)
model.train(x_train, y_train)
for i in range(1, 21, 1):
print("{:2d} * {:2d} -> {:7.3f}".format(i, i, model.predict([[float(i), float(i)]])[0]))
Graph Mode さよ~なら~ (^o^)/~
Eager Mode だ~いすき♪(菊川怜)
最後に残念なお知らせがあります。TensorFlow 2.0 では、@tf.contrib.eager.defun がサポートされないそうです。
どうしたらいいんでしょう...