TensorFlow for Machine Intelligence


In [ ]:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

In [ ]:
a = tf.random_normal([2, 20])

with tf.Session() as sess:
    out = sess.run(a)

In [ ]:
print out  # a 2x20 random matrix

In [ ]:
x, y = out

In [ ]:
plt.scatter(x, y)
plt.show()

Computation Graph

Each Tensorflow node is an Operation or Op. To create an operation, you call its associated Python operation or constructor. For example, "constant" takes a tensor input, and output several tensors the same as the input. Note that this simply add Ops to a graph behind the scenes, but no computation is actually taking place. Operations can be zero-input and zero-output. The operation in Tensorflow is more than just mathematical operations like add or sub. They can include tasks such as initializing state.


In [ ]:
# define first Tensorflow graph
a = tf.constant(5, name='input_a')   # constant is an Op
b = tf.constant(3, name='input_b')
c = tf.multiply(a, b, name='mul_c')
d = tf.add(a, b, name='add_d')
e = tf.add(c, d, name='add_e')
# run the graph
with tf.Session() as sess:
    print "e = %d" % sess.run(e)
    writer = tf.summary.FileWriter('./my_graph/computation_graph/example_1', sess.graph)
    writer.close()

In [ ]:
# define an equal graph with Tensor
a = tf.constant([5, 3], name='input_a')
b = tf.reduce_prod(a, name='prod_b')
c = tf.reduce_sum(a, name='sum_c')
d = tf.add(b, c, name='add_d')
with tf.Session() as sess:
    print "d = %d" % sess.run(d)
    writer = tf.summary.FileWriter('./my_graph/computation_graph/example_2', sess.graph)
    writer.close()

Python Native Types and Numpy Arrays

  1. We can pass in Python native types, single values will be converted to 0-D Tensor (scalar), lists of values will be converted to a 1-D Tensor (vector), lists of lists of values will be converted to a 2-D Tensor (matrix) and so on.
  2. Numpy arrays can be directly passed into any TensorFlow Op.
  3. It really is best to start getting in the habit of being explicit about the numeric properties you want your Tensor objects to have.

In [ ]:
import tensorflow as tf

In [ ]:
# TensorFlow shape, can either be list or tuple
s_3_flex = [2, None, None]
a = tf.constant([5, 3], name='input_a')
b = tf.reduce_prod(a, name='prod_b')
c = tf.reduce_sum(a, name='sum_c')
d = tf.add(b, c, name='add_d')
shape = tf.shape(a, name='shape_d')
with tf.Session() as sess:
    print sess.run(shape)  # tf.shape is also an Operation

Overloaded operations

Technically, the == operator is overloaded as well, but it will not return a Tensor of boolean values. Instead, it will return True if the two tensors being compared are the same object, and False otherwise. This is mainly used for internal purposes. If you’d like to check for equality or inequality, check out tf.equal() and tf.not_equal, respectively.

TensorFlow graphs

As a convenience, TensorFlow automatically creates a Graph when the library is loaded and assigns it to be the default. Thus, any Operations, tensors, etc. defined outside of a Graph.as_default() context manager will automatically be placed in the default graph.
When defining multiple graphs in one file, it's best practice to either not use the default graph or immediately assign a handle to it.
Additionally, it is possible to load in previously defined models from other TensorFlow scripts and assign them to Graph objects using a combination of the Graph.as_graph_def() and tf.import_graph_def functions. Thus, a user can compute and use the output of several separate models in the same Python file.


In [ ]:
# multiple graph example
import tensorflow as tf
g1 = tf.Graph()
g2 = tf.Graph()
# or we use get a handle to default graph like g2 = tf.get_default_graph()
with g1.as_default():
    pass

with g2.as_default():
    pass

TensorFlow sessions

tf.Session(target=None, graph=default_graph, config=default)

  1. target specifies the execution engine to use. For most applications, this will be left at its default empty string value. When using sessions in a distributed setting, this parameter is used to connect to tf.train.Server instances (covered in the later chapters of this book).
  2. graph specifies the Graph object that will be launched in the Session. The default value is None, which indicates that the current default graph should be used. When using multiple graphs, it’s best to explicitly pass in the Graph you’d like to run (instead of creating the Session inside of a with block).
  3. config allows users to specify options to configure the session, such as limiting the number of CPUs or GPUs to use, setting optimization parameters for graphs, and logging options.

tf.Session.run(fetches, feed_dict=None, options="", run_metadata="")

  1. fetches is a required argument, which can be any graph element including Operations or Tensor Object. If the requested object is a Tensor, then the output of run() will be a NumPy array. If the object is an Operation, then the output will be None. When fetches is a list, the output of run() will be a list with values corresponding to the output of the requested elements. "Operations" example: tf.initialize_all_variables(), that is a useful side-effect when run.
  2. The parameter feed_dict is used to override Tensor values in the graph, and it expects a Python dictionary object as input. It is very useful when you have a large graph and want to test out part of it with dummy values, TensorFlow won’t waste time with unnecessary computations.

In [ ]:
# use session as context manager
import tensorflow as tf
g1 = tf.Graph()
with g1.as_default():
    a = tf.random_normal((2, 20))
    sess = tf.Session()
    print a.eval(session=sess)
    sess.close()

Placeholders, as the name implies, act as if they are Tensor objects, but they do not have their values specified when created. Instead, they hold the place for a Tensor that will be fed at runtime, in effect becoming an “input” node.


In [ ]:
import tensorflow as tf
import numpy as np
# Creates a placeholder vector of length 2 with data type int32
a = tf.placeholder(tf.int32, shape=[2], name="my_input")
# Use the placeholder as if it were any other Tensor object
b = tf.reduce_prod(a, name="prod_b")
c = tf.reduce_sum(a, name="sum_c")
# Finish off the graph
d = tf.add(b, c, name="add_d")

# Open a TensorFlow Session
sess = tf.Session()
# Create a dictionary to pass into `feed_dict`
# Key: `a`, the handle to the placeholder's output Tensor
# Value: A vector with value [5, 3] and int32 data type
input_dict = {a: np.array([5, 3], dtype=np.int32)}
# Fetch the value of `d`, feeding the values of `input_vector` into `a`
result = sess.run(d, feed_dict=input_dict)
print result
sess.close()

Variables objects, which contain mutable tensor values that persist across multiple calls to Session.run(). Note that Tensor and Operations are immutable objects.
Variable Initialization Variables have an extra step involved in order to use them- you must initialize the Variable within a Session.


In [ ]:
# 2x2 matrix of  zeros
zeros = tf.zeros([2, 2])
# vector of length 6 of ones
ones = tf.ones([6])
# 3x3x3 Tensor of random uniform  values between 0 and 10
uniform = tf.random_uniform([3, 3, 3], minval=0, maxval=10)
# 3x3x3 Tensor of normally distributed numbers; mean 0 and standard deviation 2
normal = tf.random_normal([3, 3, 3], mean=0.0, stddev=2.0)
# No values below 3.0 or above 7.0 will be returned in this Tensor
trunc = tf.truncated_normal([2, 2], mean=5.0, stddev=1.0)
# pass Operations to tf Variable
# Default value of mean=0.0
 # Default value of stddev=1.0
random_var = tf.Variable(tf.truncated_normal([2, 2]))

In [ ]:
# variable initialization
var1 = tf.Variable(0, name="initialize_me")
var2 = tf.Variable(1, name="no_initialization")
init = tf.variables_initializer([var1], name="init_var1")
sess = tf.Session()
sess.run(init)

In [ ]:
# changing variables
# Create variable with starting value of 1
my_var = tf.Variable(1)
# Create an operation that multiplies the variable by 2 each time it is run
my_var_times_two = my_var.assign(my_var * 2)
# Initialization operation
init = tf.global_variables_initializer()
# Start a session
sess = tf.Session()
# Initialize variable
sess.run(init)

In [ ]:
# Multiply variable by two and return it
sess.run(my_var_times_two)
## OUT: 2

In [ ]:
# Multiply again
sess.run(my_var_times_two)
## OUT: 4

In [ ]:
# Multiply again
sess.run(my_var_times_two)
## OUT: 8

In [ ]:
# reset my_var
sess.run(my_var.initializer)  # only reset my_var instead of global reset all the variables
sess.run(my_var)

Trainable: variables are created with trainable features, that can be automatically changed by tf.optimizer object. In some cases, we want to set trainable to False. e.g. step counters or transfer learning and finetuning models.

Organizing your graph with name scopes

To manage complexity and hierarchy of large graphs, ensorFlow currently offers a mechanism to help organize your graphs: name scopes. Essentially, name scopes allow you to group Operations into larger, named blocks. Then, when you launch your graph with TensorBoard, each name scope will encapsulate its own Ops, making the visualization much more digestible.
Separating a huge graph into meaningful clusters can make understanding and debugging your model a much more approachable task.
tf.constant objects don’t behave quite the same way as other Tensors or Operations when displayed in TensorBoard. Even though we declared static_value outside of any name scope, it still gets placed inside them. The basic idea for this is that constants can be used at any time and don’t necessarily need to be used in any particular order. To prevent arrows flying all over the graph from a single point, it just makes a little small impression whenever a constant is used.


In [1]:
import tensorflow as tf
with tf.name_scope("Scope_A"):
    a = tf.add(1, 2, name="A_add")
    b = tf.multiply(a, 3, name="A_mul")
with tf.name_scope("Scope_B"):
    c = tf.add(4, 5, name="B_add")
    d = tf.multiply(c, 6, name="B_mul")
e = tf.add(b, d, name="output")
writer = tf.summary.FileWriter('./my_graph/computation_graph/name_scope', graph=tf.get_default_graph())
writer.close()

In [7]:
# use fft to compute conv2d
import tensorflow as tf
X = tf.Variable(tf.truncated_normal([128, 32, 32, 3]))
kernel = tf.Variable(tf.truncated_normal([3, 3, 3, 32]))
bias = tf.Variable(tf.truncated_normal([32]))
output = tf.nn.conv2d(X, kernel, strides=[1, 1, 1, 1], padding="SAME") + bias
dX, dKernel, dBias = tf.gradients(output, [X, kernel, bias])
sess = tf.Session()
sess.run(tf.global_variables_initializer())
dX_value, dKernel_value, dBias_value = sess.run([dX, dKernel, dBias])

In [8]:
dX_value.shape


Out[8]:
(128, 32, 32, 3)

In [9]:
dKernel_value.shape


Out[9]:
(3, 3, 3, 32)

In [ ]: