TensorFlow offers two modes of execution, the Graph mode, and the Eager mode. The main difference between these two modes is the way they build and execute the computational graph.
In Graph mode, the user first defines a static computational graph that represents the operations and data dependencies of the model. The graph is then compiled and optimized for execution, which allows for efficient parallelism and distributed execution across devices and servers. The Graph mode is the default mode in TensorFlow 1.x, and it is still available in TensorFlow 2.x for backward compatibility.
In Eager mode, the user can execute TensorFlow operations immediately as they are called, without the need to define a static computational graph. Eager mode provides a more interactive and intuitive programming interface, similar to other deep learning frameworks such as PyTorch and Chainer. Eager mode also supports dynamic control flow and Python control structures, which makes it easier to implement custom training loops and other advanced functionalities. Eager mode is the default mode in TensorFlow 2.x.
Here is an example of how to use both modes to build and train a simple neural network:
import tensorflow as tf
# Graph mode
tf.compat.v1.disable_eager_execution()
# Define the computational graph
x = tf.compat.v1.placeholder(tf.float32, shape=(None, 784))
y = tf.compat.v1.placeholder(tf.float32, shape=(None, 10))
w = tf.Variable(tf.random.normal((784, 10)), name='weights')
b = tf.Variable(tf.zeros((10,)), name='biases')
logits = tf.matmul(x, w) + b
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits))
optimizer = tf.compat.v1.train.GradientDescentOptimizer(0.01).minimize(loss)
# Execute the graph
with tf.compat.v1.Session() as sess:
sess.run(tf.compat.v1.global_variables_initializer())
for i in range(1000):
batch_x, batch_y = get_next_batch()
sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})
if i % 100 == 0:
print('Loss at step {}: {}'.format(i, sess.run(loss, feed_dict={x: batch_x, y: batch_y})))
# Eager mode
tf.compat.v1.enable_eager_execution()
# Define the model and optimizer
class SimpleModel(tf.keras.Model):
def __init__(self):
super(SimpleModel, self).__init__()
self.w = tf.Variable(tf.random.normal((784, 10)), name='weights')
self.b = tf.Variable(tf.zeros((10,)), name='biases')
def call(self, inputs):
logits = tf.matmul(inputs, self.w) + self.b
return logits
model = SimpleModel()
optimizer = tf.keras.optimizers.SGD(0.01)
# Train the model
for i in range(1000):
batch_x, batch_y = get_next_batch()
with tf.GradientTape() as tape:
logits = model(batch_x)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=batch_y, logits=logits))
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
if i % 100 == 0:
print('Loss at step {}: {}'.format(i, loss))
As shown in the example, the Graph mode uses placeholders to define the input and output tensors of the model, and variables to store the model parameters. The user then defines the loss function and the optimizer, and uses a session to execute the graph and update the variables using the optimizer.