<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc" style="margin-top
Step1:  Core (Low Level APIs)
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.
Step2:  Eager Execution
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.
Step3:  Dataset API
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.
Step4:  Save and Restore Variables
Step5:  Save and Restore a Model
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?
Step6:  Serving Client
Needs
pip install grpcio grpcio-tools
Plus Tensorflow Serving API files.
<ASSISTANT_TASK:>
Python Code:
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/"
Explanation: <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc" style="margin-top: 1em;"><ul class="toc-item"><li><span><a href="#Intro" data-toc-modified-id="Intro-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Intro</a></span></li><li><span><a href="#Core-(Low-Level-APIs)" data-toc-modified-id="Core-(Low-Level-APIs)-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Core (Low Level APIs)</a></span></li><li><span><a href="#Eager-Execution" data-toc-modified-id="Eager-Execution-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Eager Execution</a></span></li><li><span><a href="#Dataset-API" data-toc-modified-id="Dataset-API-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Dataset API</a></span></li><li><span><a href="#Save-and-Restore-Variables" data-toc-modified-id="Save-and-Restore-Variables-5"><span class="toc-item-num">5&nbsp;&nbsp;</span><a href="https://www.tensorflow.org/programmers_guide/saved_model" target="_blank">Save and Restore Variables</a></a></span></li><li><span><a href="#Save-and-Restore-a-Model" data-toc-modified-id="Save-and-Restore-a-Model-6"><span class="toc-item-num">6&nbsp;&nbsp;</span><a href="https://www.tensorflow.org/programmers_guide/saved_model" target="_blank">Save and Restore a Model</a></a></span></li><li><span><a href="#Serving-Client" data-toc-modified-id="Serving-Client-7"><span class="toc-item-num">7&nbsp;&nbsp;</span>Serving Client</a></span></li></ul></div>
Intro
Notebook revolving around the use and concepts of Tensorflow (v1.12.0).
End of explanation
# 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)
# execute graph via a Session
sess = tf.Session()
print(sess.run(total))
print(sess.run({'ab': (a, b), 'total': total})) # request multiple tensors
# 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}))
Explanation: Core (Low Level APIs)
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.
End of explanation
tf.enable_eager_execution() # enable eager mode, need to be run at start
a = 3.0
b = 4.0
res = tf.multiply(a, b)
res
np.multiply(res, res)
Explanation: Eager Execution
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.
End of explanation
tf.enable_eager_execution() # enable eager mode, need to be run at start
dataset = tf.data.Dataset.range(10)
print(dataset.output_types)
print(dataset.output_shapes)
# apply custom function to each element of the dataset
dataset = dataset.map(lambda x : x + 1)
for i in dataset:
    print(i)
# 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()
for i in iterator:
    print(i)
Explanation: Dataset API
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.
End of explanation
# 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)
# 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))
# 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())
# 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())
Explanation: Save and Restore Variables
End of explanation
# 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))
# 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')
# 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()
    
# 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))
Explanation: Save and Restore a Model
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?
End of explanation
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
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)
result
Explanation: Serving Client
Needs
pip install grpcio grpcio-tools
Plus Tensorflow Serving API files.
End of explanation
<END_TASK>