Make predictions using a tensorflow graph from a keras model

Question:

I have a model trained using Keras with Tensorflow as my backend, but now I need to turn my model into a tensorflow graph for a certain application. I attempted to do this and make predictions to insure that it is working correctly, but when comparing to the results gathered from model.predict() I get very different values. For instance:

from keras.models import load_model
import tensorflow as tf

model = load_model('model_file.h5')

x_placeholder = tf.placeholder(tf.float32, shape=(None,7214,1))
y = model(x_placeholder)

x = np.ones((1,7214,1))


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print("Predictions from:ntf graph:      "+str(sess.run(y, feed_dict={x_placeholder:x})))
    print("keras predict: "+str(model.predict(x)))

returns:

Predictions from:
tf graph:      [[-0.1015993   0.07432419  0.0592984 ]]
keras predict: [[ 0.39339241  0.57949686 -3.67846966]]

The values from keras predict are correct, but the tf graph results are not.

If it helps to know the final intended application, I am creating a jacobian matrix with the tf.gradients() function, but currently it does not return the correct results when comparing to theano’s jacobian function, which gives the correct jacobian. Here is my tensorflow jacobian code:

x = tf.placeholder(tf.float32, shape=(None,7214,1))
y = tf.reshape(model(x)[0],[-1])
y_list = tf.unstack(y)

jacobian_list = [tf.gradients(y_, x)[0] for y_ in y_list]
jacobian = tf.stack(jacobian_list)

EDIT: Model code

import numpy as np

from keras.models import Sequential
from keras.layers import Dense, InputLayer, Flatten
from keras.layers.convolutional import Conv1D
from keras.layers.convolutional import MaxPooling1D
from keras.optimizers import Adam
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

# activation function used following every layer except for the output layers
activation = 'relu'

# model weight initializer
initializer = 'he_normal'

# shape of input data that is fed into the input layer
input_shape = (None,7214,1)

# number of filters used in the convolutional layers
num_filters = [4,16]

# length of the filters in the convolutional layers
filter_length = 8

# length of the maxpooling window 
pool_length = 4

# number of nodes in each of the hidden fully connected layers
num_hidden_nodes = [256,128]

# number of samples fed into model at once during training
batch_size = 64

# maximum number of interations for model training
max_epochs = 30

# initial learning rate for optimization algorithm
lr = 0.0007

# exponential decay rate for the 1st moment estimates for optimization algorithm
beta_1 = 0.9

# exponential decay rate for the 2nd moment estimates for optimization algorithm
beta_2 = 0.999

# a small constant for numerical stability for optimization algorithm
optimizer_epsilon = 1e-08

model = Sequential([

    InputLayer(batch_input_shape=input_shape),

    Conv1D(kernel_initializer=initializer, activation=activation, padding="same", filters=num_filters[0], kernel_size=filter_length),

    Conv1D(kernel_initializer=initializer, activation=activation, padding="same", filters=num_filters[1], kernel_size=filter_length),

    MaxPooling1D(pool_size=pool_length),

    Flatten(),

    Dense(units=num_hidden_nodes[0], kernel_initializer=initializer, activation=activation),

    Dense(units=num_hidden_nodes[1], kernel_initializer=initializer, activation=activation),

    Dense(units=3, activation="linear", input_dim=num_hidden_nodes[1]),
]) 

# compile model
loss_function = mean squared error
early_stopping_min_delta = 0.0001
early_stopping_patience = 4
reduce_lr_factor = 0.5
reuce_lr_epsilon = 0.0009
reduce_lr_patience = 2
reduce_lr_min = 0.00008

optimizer = Adam(lr=lr, beta_1=beta_1, beta_2=beta_2, epsilon=optimizer_epsilon, decay=0.0)

early_stopping = EarlyStopping(monitor='val_loss',     min_delta=early_stopping_min_delta, 
                                   patience=early_stopping_patience, verbose=2, mode='min')

reduce_lr = ReduceLROnPlateau(monitor='loss', factor=0.5, epsilon=reuce_lr_epsilon, 
                              patience=reduce_lr_patience,     min_lr=reduce_lr_min, mode='min', verbose=2)

model.compile(optimizer=optimizer, loss=loss_function)

model.fit(train_x, train_y, validation_data=(cv_x, cv_y),
      epochs=max_epochs, batch_size=batch_size, verbose=2,
      callbacks=[reduce_lr,early_stopping])

model.save('model_file.h5')
Asked By: Starnetter

||

Answers:

@frankyjuang linked me to here

https://github.com/amir-abdi/keras_to_tensorflow

and combining this with code from

https://github.com/metaflow-ai/blog/blob/master/tf-freeze/load.py

and

https://github.com/tensorflow/tensorflow/issues/675

I have found a solution to both predicting using a tf graph and creating the jacobian function:

import tensorflow as tf
import numpy as np

# Create function to convert saved keras model to tensorflow graph
def convert_to_pb(weight_file,input_fld='',output_fld=''):

    import os
    import os.path as osp
    from tensorflow.python.framework import graph_util
    from tensorflow.python.framework import graph_io
    from keras.models import load_model
    from keras import backend as K


    # weight_file is a .h5 keras model file
    output_node_names_of_input_network = ["pred0"] 
    output_node_names_of_final_network = 'output_node'

    # change filename to a .pb tensorflow file
    output_graph_name = weight_file[:-2]+'pb'
    weight_file_path = osp.join(input_fld, weight_file)

    net_model = load_model(weight_file_path)

    num_output = len(output_node_names_of_input_network)
    pred = [None]*num_output
    pred_node_names = [None]*num_output

    for i in range(num_output):
        pred_node_names[i] = output_node_names_of_final_network+str(i)
        pred[i] = tf.identity(net_model.output[i], name=pred_node_names[i])

    sess = K.get_session()

    constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph.as_graph_def(), pred_node_names)
    graph_io.write_graph(constant_graph, output_fld, output_graph_name, as_text=False)
    print('saved the constant graph (ready for inference) at: ', osp.join(output_fld, output_graph_name))

    return output_fld+output_graph_name

Call:

tf_model_path = convert_to_pb('model_file.h5','/model_dir/','/model_dir/')

Create function to load the tf model as a graph:

def load_graph(frozen_graph_filename):
    # We load the protobuf file from the disk and parse it to retrieve the 
    # unserialized graph_def
    with tf.gfile.GFile(frozen_graph_filename, "rb") as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())

    # Then, we can use again a convenient built-in function to import a graph_def into the 
    # current default Graph
    with tf.Graph().as_default() as graph:
        tf.import_graph_def(
            graph_def, 
            input_map=None, 
            return_elements=None, 
            name="prefix", 
            op_dict=None, 
            producer_op_list=None
        )

    input_name = graph.get_operations()[0].name+':0'
    output_name = graph.get_operations()[-1].name+':0'

    return graph, input_name, output_name

Create a function to make model predictions using the tf graph

def predict(model_path, input_data):
    # load tf graph
    tf_model,tf_input,tf_output = load_graph(model_path)

    # Create tensors for model input and output
    x = tf_model.get_tensor_by_name(tf_input)
    y = tf_model.get_tensor_by_name(tf_output) 

    # Number of model outputs
    num_outputs = y.shape.as_list()[0]
    predictions = np.zeros((input_data.shape[0],num_outputs))
    for i in range(input_data.shape[0]):        
        with tf.Session(graph=tf_model) as sess:
            y_out = sess.run(y, feed_dict={x: input_data[i:i+1]})
            predictions[i] = y_out

    return predictions

Make predictions:

tf_predictions = predict(tf_model_path,test_data)

Jacobian function:

def compute_jacobian(model_path,input_data):

    tf_model,tf_input,tf_output = load_graph(model_path)    

    x = tf_model.get_tensor_by_name(tf_input)
    y = tf_model.get_tensor_by_name(tf_output)
    y_list = tf.unstack(y)
    num_outputs = y.shape.as_list()[0]
    jacobian = np.zeros((num_outputs,input_data.shape[0],input_data.shape[1]))
    for i in range(input_data.shape[0]):
        with tf.Session(graph=tf_model) as sess:
            y_out = sess.run([tf.gradients(y_, x)[0] for y_ in y_list], feed_dict={x: input_data[i:i+1]})
            jac_temp = np.asarray(y_out)
        jacobian[:,i:i+1,:]=jac_temp[:,:,:,0]
    return jacobian

Compute Jacobian Matrix:

jacobians = compute_jacobian(tf_model_path,test_data)
Answered By: Starnetter