Reputation: 8277
After doing a simple minimisation task (fitting optimal parameter for a hard sigmoid approximation) with tensorflow, I decided to translate it from graph mode to eager mode. My surprise was that it takes a lot longer to run in eager mode.
Here are the codes.
Graph mode code:
import tensorflow as tf
from time import time
beg = time()
a = tf.Variable(-10, name='a', dtype=tf.float32)
b = tf.Variable(10, name='b', dtype=tf.float32)
def g(x):
return tf.clip_by_value( (x-a)/(b-a), 0, 1)
X = tf.lin_space(-20., 20., 2000)
loss = tf.reduce_sum( tf.square( tf.math.sigmoid(X) - g(X)))
opt = tf.train.AdamOptimizer(learning_rate=1e-3)
train_op = opt.minimize( loss)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
for _ in range( int(1e4)):
sess.run( train_op)
print( 'Non-eager run in %.1f seconds' %(time()-beg))
printing Non-eager run in 3.5 seconds
Eager mode code:
import tensorflow as tf
from time import time
tf.enable_eager_execution()
beg = time()
a = tf.Variable(-10, name='a', dtype=tf.float32)
b = tf.Variable(10, name='b', dtype=tf.float32)
def g(x):
return tf.clip_by_value( (x-a)/(b-a), 0, 1)
X = tf.lin_space(-20., 20., 2000)
opt = tf.train.AdamOptimizer(learning_rate=1e-3)
for _ in range( int(1e4)):
with tf.GradientTape() as tape:
loss = tf.reduce_sum( tf.square( tf.math.sigmoid(X) - g(X)))
grads = tape.gradient(loss, [a,b])
opt.apply_gradients(zip(grads, [a,b]), global_step=tf.train.get_or_create_global_step())
print( 'Eager run in %.1f seconds' %(time()-beg))
printing Eager run in 20.9 seconds
My bet is that my eager code is sub-optimal, and as tensorflow
seems to be shifting to eager execution in its next big release I would like to know how to optimise this code to performances at least matching the first version.
Upvotes: 1
Views: 677
Reputation: 27050
Your code, in tensorflow 2.0 will look something like (please note you can already try the nightly build of tensorflow 2.0 (https://pypi.org/project/tf-nightly-2.0-preview/))
import tensorflow as tf
from time import time
tf.enable_eager_execution()
beg = time()
@tf.function
def train():
a = tf.Variable(-10, name='a', dtype=tf.float32)
b = tf.Variable(10, name='b', dtype=tf.float32)
def g(x):
return tf.clip_by_value((x - a) / (b - a), 0, 1)
X = tf.lin_space(-20., 20., 2000)
opt = tf.train.AdamOptimizer(learning_rate=1e-3)
for _ in range(int(1e4)):
with tf.GradientTape() as tape:
loss = tf.reduce_sum(tf.square(tf.math.sigmoid(X) - g(X)))
grads = tape.gradient(loss, [a, b])
opt.apply_gradients(
zip(grads, [a, b]),
global_step=tf.train.get_or_create_global_step())
train()
print('Eager run in %.1f seconds' % (time() - beg))
Please note that tf.contrib.eager.defun
and Autograph
(available in 1.12 and above), that are the base of @tf.session
are still under active development and are experimental, hence implementation is a little bit buggy right now; so if it fails to run or it is slower probably is worth opening an issue on Github.
In 2.0 @tf.session
will merge the pros of both defun
and autograd
Upvotes: 2