Notebook revolving around the use and concepts of Tensorflow (v1.12.0).
In [1]:
import os
import sys
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from pathlib import Path
import tensorflow as tf
%matplotlib notebook
#%matplotlib inline
models_data_folder = Path.home() / "Documents/models/"
Tensorflow operations are arranged into a computational graph. graph
is about building, session
is about running.
The graph nodes are represented by Operation
while the edges can be see as Tensor
flowing between the nodes. A Tensor
does not have values, is just a handler returned by a function.
In [5]:
# create and add up two constants
a = tf.constant(3.0, dtype=tf.float32)
b = tf.constant(4.0)
total = a + b
print(a)
print(b)
print(total)
In [9]:
# execute graph via a Session
sess = tf.Session()
print(sess.run(total))
print(sess.run({'ab': (a, b), 'total': total})) # request multiple tensors
In [19]:
# variables
x = tf.placeholder(tf.float32, name='x')
y = tf.placeholder(tf.float32, name='y')
z = x + y
sess = tf.Session()
print(sess.run(z, feed_dict={x: 3, y: 4}))
Present from Tensorflow v1.7, provides a imperative programming env that allows to evaluate operations immediately. In this env a Tensor
object actually reference concrete values that can be used in other Python contexts like debugger or Numpy.
In [2]:
tf.enable_eager_execution() # enable eager mode, need to be run at start
In [9]:
a = 3.0
b = 4.0
res = tf.multiply(a, b)
res
Out[9]:
In [8]:
np.multiply(res, res)
Out[8]:
tf.data
as a mean to build input/pre-processing pipelines. Introduces the Dataset
(sequence of elements) and Iterator
(access elements from a dataset) abstractions.
In eager mode can iterate over a dataset as done in common Python code. In a session need instead to instantiate/initialize an iterator over the dataset.
In [2]:
tf.enable_eager_execution() # enable eager mode, need to be run at start
In [4]:
dataset = tf.data.Dataset.range(10)
print(dataset.output_types)
print(dataset.output_shapes)
In [8]:
# apply custom function to each element of the dataset
dataset = dataset.map(lambda x : x + 1)
for i in dataset:
print(i)
In [18]:
# define repeatition, batching and buffers
dataset = tf.data.Dataset.range(10)
dataset = dataset.repeat(2)
dataset = dataset.batch(2)
iterator = dataset.make_one_shot_iterator()
In [19]:
for i in iterator:
print(i)
In [ ]:
# dummy variables
#v1 = tf.get_variable("v1", shape=[3], initializer=tf.zeros_initializer)
#v2 = tf.get_variablea("v2", shape=[5], initializer=tf.zeros_initializer)
v1 = tf.Variable(tf.constant(0), name='v1')
v2 = tf.Variable(tf.constant(5), name='v2')
# dummy operations
inc_v1 = v1.assign(v1+1)
dec_v2 = v2.assign(v2-1)
In [ ]:
# Save variables
# def init op and saver
init_op = tf.global_variables_initializer()
saver = tf.train.Saver()
# run some operations and save sessions
with tf.Session() as sess:
sess.run(init_op)
inc_v1.op.run()
dec_v2.op.run()
save_path = saver.save(sess,
str(models_data_folder / 'tmp' / "model.ckpt"))
print("Model saved in {}".format(save_path))
In [ ]:
# test behavior in new session (need to rerun initializer)
with tf.Session() as sess:
sess.run(init_op)
print(v1.eval())
print(inc_v1.eval())
print(v1.eval())
In [ ]:
# Restore Variables
# need to redefine the variable
v1 = tf.Variable(tf.constant(0), name='v1')
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess,
str(models_data_folder / 'tmp' / "model.ckpt"))
#now v1 should have the value we previously saved
print(v1.eval())
Uses SavedModelBuilder instead of Saver. Should this be done only for serving? In what way can I reload a model saved with the former and retrain?
In [ ]:
# directory where model will be exported
# include version info in model path as required by TF
version = 0
export_dir = str(models_data_folder / "tf_test_models_export" / str(version))
In [ ]:
# dummy model
x = tf.Variable(tf.constant(0), name='x')
y = tf.Variable(tf.constant(5), name='y')
f = tf.multiply(x, y, name='f')
In [ ]:
# save model
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
#consider difference between eval and run
#see: https://stackoverflow.com/questions/33610685/in-tensorflow-what-is-the-difference-between-session-run-and-tensor-eval
#sess.run(f, feed_dict={x:3.0, y:5.0})
fval = f.eval(feed_dict={x:3.0, y:5.0})
print(fval)
# Init builder
builder = tf.saved_model.builder.SavedModelBuilder(export_dir)
# Build info for inputs and outputs tensors
#??Is the key associated with the tensor name?
inputs = {
'x' : tf.saved_model.utils.build_tensor_info(x),
'y' : tf.saved_model.utils.build_tensor_info(y)
}
outputs = {
'f' : tf.saved_model.utils.build_tensor_info(f)
}
# Define signature (set of inputs and outputs for the graph)
prediction_signature = (
tf.saved_model.signature_def_utils.build_signature_def(
inputs=inputs,
outputs=outputs,
# method used for the inference
method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME
)
)
# Add meta-graph (dataflow graph, variables, assets, and signatures)
# to the builder
builder.add_meta_graph_and_variables(
sess=sess,
tags=[tf.saved_model.tag_constants.SERVING],
# ??
signature_def_map={
'predict' : prediction_signature
},
# ??
#legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')
)
# Finally save builder
builder.save()
In [ ]:
# Restore model
# redefine target
x = tf.Variable(tf.constant(1), name='x')
y = tf.Variable(tf.constant(5), name='y')
#f = tf.Operation(None, name='f')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
#print(f.eval())
mg = tf.saved_model.loader.load(
sess=sess,
tags=[tf.saved_model.tag_constants.SERVING],
export_dir
)
f = tf.get_default_graph().get_operation_by_name("f")
# ??Why session graph keeps getting new operations?
# isn't it clean every time we exit the "with" scope
#print(sess.graph.get_operations())
print(sess.run(f))
In [ ]:
from grpc.beta import implementations
# reference local copy of Tensorflow Serving API Files
sys.path.append(str(os.getcwd() / *[os.pardir]*2 / 'ext_libs'))
import lib.predict_pb2 as predict_pb2
import lib.prediction_service_pb2 as prediction_service_pb2
In [ ]:
host='127.0.0.1'
port=9000
channel = implementations.insecure_channel(host, int(port))
stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)
# build request
request = predict_pb2.PredictRequest()
request.model_spec.name = 'ed' # model name, as given to bazel script
request.model_spec.signature_name = 'predict' # as defined in ModelBuilder
# define inputs
x = 3
y = 4
x_tensor = tf.contrib.util.make_tensor_proto(x, dtype=tf.int32)
y_tensor = tf.contrib.util.make_tensor_proto(y, dtype=tf.int32)
request.inputs['x'].CopyFrom(x_tensor)
request.inputs['y'].CopyFrom(y_tensor)
# call prediction on the server
result = stub.Predict(request, timeout=10.0)
In [ ]:
result