serving a tensorflow classifier - python

I have been fighting with tensorflow's builder to be able to serve my model, I am trying to feed data to my classifier after serving the model
My question is how would i feed the input to the model?
I have seen the code used by google's inception tutorial
and have tried to implement it
classify_inputs_tensor_info = utils.build_tensor_info(
serialized_tf_example)
classes_output_tensor_info = utils.build_tensor_info(classes)
scores_output_tensor_info = utils.build_tensor_info(values)
classification_signature = signature_def_utils.build_signature_def(
inputs={
signature_constants.CLASSIFY_INPUTS: classify_inputs_tensor_info
},
outputs={
signature_constants.CLASSIFY_OUTPUT_CLASSES:
classes_output_tensor_info,
signature_constants.CLASSIFY_OUTPUT_SCORES:
scores_output_tensor_info
},
method_name=signature_constants.CLASSIFY_METHOD_NAME)
and from what i understand the input is passed to a tensor called serialized_tf_example which as the name suggests serializes the input to string but then they use tf.FixedLenFeature which i don't understand and then parses the serialized_tf_example with tf.parse_example and assigns it to x which is used within the model, but i would like to parse it to a classifier that accepts arrays as inputs but don't know how to go around this.
while trying to implement this i wrote this
serialized_tf_example = tf.placeholder(tf.string, name='tf_example')
feature_configs = { 'audio/encoded': tf.FixedLenFeature( shape=[193], dtype=tf.float32, default_value=input_x),}
tf_example = tf.parse_example(serialized_tf_example, feature_configs)
x = tf_example['audio/encoded']
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
# Define the dimensions in the feature columns
feature_columns = [tf.contrib.layers.real_valued_column("", dimension=5)]
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
dnn_feature_columns=feature_columns, dnn_hidden_units=[200,300], n_classes=10,
dnn_optimizer=tf.train.GradientDescentOptimizer(
learning_rate=0.01
)
)
#run training
classifier.fit(input_fn=get_train_inputs, steps=100)
#testing
accuracy_score = classifier.evaluate(input_fn=get_test_inputs, steps=10)["accuracy"]
print('Test accuracy : ', format(accuracy_score))
prediction = format(list(classifier.predict_classes(x, as_iterable=True)))
but x is a tensor and so is not able to be read. when i try use run or .eval() it asks me to feed a value to serialized_tf_example
InvalidArgumentError (see above for traceback): You must feed a value
for placeholder tensor 'tf_example' with dtype string [[Node:
tf_example = Placeholderdtype=DT_STRING, shape=[],
_device="/job:localhost/replica:0/task:0/cpu:0"]]
when i use prediction = format(list(classifier.predict_classes(np.array(x), as_iterable=True))
I get
InvalidArgumentError (see above for traceback): Shape in
shape_and_slice spec [1,200] does not match the shape stored in
checkpoint: [193,200] [[Node: save/RestoreV2_1 =
RestoreV2[dtypes=[DT_FLOAT],
_device="/job:localhost/replica:0/task:0/cpu:0"](_recv_save/Const_0, save/RestoreV2_1/tensor_names, save/RestoreV2_1/shape_and_slices)]]

You can/should use classifier.predict without tf.Example.Your input_fn in train and eval returns x, y. you can write a predict_input_fn similar to other input functions.
predictoin = next(classifier.predict_classes(input_fn=predict_input_fn))
Please note that, if you get all predictions with list function should end by an exception. You can check tf.estimator.inputs.numpy_input_fn

Related

Pretrained Tensorflow Model invalid argument error

I'm doing my project using tensorflow with pre-trained mobilenet_v2 model which can be found on https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md
I wanted to get hidden layer values so I implemented this source code and I got an invalidargumenterror
if __name__ == '__main__':
im = Image.open('./sample/maltiz.png')
im3 = im.resize((300, 300))
image = np.asarray(im)[:,:,:3]
model_path = 'models/ssd_mobilenet_v2_coco_2018_03_29/'
meta_path = os.path.join(model_path, 'model.ckpt.meta')
model = tf.train.import_meta_graph(meta_path)
sess = tf.Session()
model.restore(sess, tf.train.latest_checkpoint(model_path))
data = np.array([image])
data = data.astype(np.uint8)
X = tf.placeholder(tf.uint8, shape=[None, None, None, 3])
graph = tf.get_default_graph()
for i in graph.get_operations():
if "Relu" in i.name:
print(sess.run(i.values(), feed_dict = { X : data}))
I got this error message
File "load_model.py", line 42, in <module>
print(sess.run(i.values(), feed_dict = { X : data}))
InvalidArgumentError: You must feed a value for placeholder tensor 'image_tensor' with dtype uint8 and shape [?,?,?,3]
[[node image_tensor (defined at load_model.py:24) ]]
I printed out the placeholder and the shape of data.
placeholder was uint8 typed [?,?,?,3]
and image had a shape with [1,300,300,3]
I don't know what is the problem.
It looks like just perfect matching with the type on the error message.
Please let me know what is the problem.
When you load the predefined graph and restore the graph to the latest checkpoint, the graph is already defined. But when you do
X = tf.placeholder(tf.uint8, shape=[None, None, None, 3])
You are creating an extra node in the graph. and this node has nothing to do with the nodes you want to evaluate, nodes from graph.get_operations() don't depend on this extra node but some other node, and since this other node does not get fed with values, the error says invalid arguments.
The correct way is to get the tensor that the nodes to be evaluated depend upon from the predefined graph.
im = Image.open('./sample/maltiz.png')
im3 = im.resize((300, 300))
image = np.asarray(im)[:,:,:3]
model_path = 'models/ssd_mobilenet_v2_coco_2018_03_29/'
meta_path = os.path.join(model_path, 'model.ckpt.meta')
model = tf.train.import_meta_graph(meta_path)
sess = tf.Session()
model.restore(sess, tf.train.latest_checkpoint(model_path))
data = np.array([image])
data = data.astype(np.uint8)
graph = tf.get_default_graph()
X = graph.get_tensor_by_name('image_tensor:0')
for i in graph.get_operations():
if "Relu" in i.name:
print(sess.run(i.values(), feed_dict = { X : data}))
PS: I did try the above approach myself but there is some tensorflow (version 1.13.1) internal bug which stops me from evaluating all the nodes that have Relu in their names. But still some nodes can be evaluated this way.

Keras model.fit() with tf.dataset fails while using tf.train works fine

Summary: according to the documentation, Keras model.fit() should accept tf.dataset as input (I am using TF version 1.12.0). I can train my model if I manually do the training steps but using model.fit() on the same model, I get an error I cannot resolve.
Here is a sketch of what I did: my dataset, which is too big to fit in the memory, consists of many files each with different number of rows of (100 features, label). I'd like to use tf.data to build my data pipeline:
def data_loader(filename):
'''load a single data file with many rows'''
features, labels = load_hdf5(filename)
...
return features, labels
def make_dataset(filenames, batch_size):
'''read files one by one, pick individual rows, batch them and repeat'''
dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.map( # Problem here! See edit for solution
lambda filename: tuple(tf.py_func(data_loader, [filename], [float32, tf.float32])))
dataset = dataset.flat_map(
lambda features, labels: tf.data.Dataset.from_tensor_slices((features, labels)))
dataset = dataset.batch(batch_size)
dataset = dataset.repeat()
dataset = dataset.prefetch(1000)
return dataset
_BATCH_SIZE = 128
training_set = make_dataset(training_files, batch_size=_BATCH_SIZE)
I'd like to try a very basic logistic regression model:
inputs = tf.keras.layers.Input(shape=(100,))
outputs = tf.keras.layers.Dense(1, activation='softmax')(inputs)
model = tf.keras.Model(inputs, outputs)
If I train it manually everything works fine, e.g.:
labels = tf.placeholder(tf.float32)
loss = tf.reduce_mean(tf.keras.backend.categorical_crossentropy(labels, outputs))
train_step = tf.train.GradientDescentOptimizer(.05).minimize(loss)
iterator = training_set.make_one_shot_iterator()
next_element = iterator.get_next()
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
for i in range(training_size // _BATCH_SIZE):
x, y = sess.run(next_element)
train_step.run(feed_dict={inputs: x, labels: y})
However, if I instead try to use model.fit like this:
model.compile('adam', 'categorical_crossentropy', metrics=['acc'])
model.fit(training_set.make_one_shot_iterator(),
steps_per_epoch=training_size // _BATCH_SIZE,
epochs=1,
verbose=1)
I get an error message ValueError: Cannot take the length of Shape with unknown rank. inside the keras'es _standardize_user_data function.
I have tried quite a few things but could not resolve the issue. Any ideas?
Edit: based on #kvish's answer, the solution was to change the map from a lambda to a function that would specify the correct tensor dimensions, e.g.:
def data_loader(filename):
def loader_impl(filename):
features, labels, _ = load_hdf5(filename)
...
return features, labels
features, labels = tf.py_func(loader_impl, [filename], [tf.float32, tf.float32])
features.set_shape((None, 100))
labels.set_shape((None, 1))
return features, labels
and now, all needed to do is to call this function from map:
dataset = dataset.map(data_loader)
Probably tf.py_func produces an unknown shape which Keras cannot infer. We can set the shape of the tensor returned by it using set_shape(your_shape) method and that would help Keras infer the shape of the result.

keras custom loss function call hidden layer dense operations

I am trying to define a custom loss function in keras that uses an intermediary layer output, manipulate it (let's say multiply by 2( and then and back into the model to produce the final output. So assuming a model
input_dim = X_train.shape[1]
encoding_dim = 14
#encoder
input_tensor = Input(shape=(input_dim, ))
encoderOut = Dense(encoding_dim, activation="tanh",
activity_regularizer=regularizers.l1(10e-5))(input_tensor)
encoderOut = Dense(int(encoding_dim / 2), activation="relu")(encoderOut)
encoder = Model(input_tensor, encoderOut)
#decoder
decoder_input = Input(shape=(int(encoding_dim / 2),))
decoderOut = Dense(int(encoding_dim / 2), activation='tanh',name='decoder_input')(decoder_input)
decoderOut = Dense(input_dim, activation='relu',name='decoder_output')(decoderOut)
decoder = Model(decoder_input, decoderOut)
#autoencoder
autoInput = Input(shape=(input_dim, ))
encoderOut = encoder(autoInput)
decoderOut = decoder(encoderOut)
autoencoder = Model(inputs=autoInput, outputs=decoderOut)
My loss function is
def L2Loss(y_true,y_pred):
get_layer_output_enc = K.function([encoder.layers[0].input, K.learning_phase()], [encoder.layers[2].output])
out= get_layer_output_enc([y_true])[0]*10
Unfortunately when I run it I got:
517 None, None,
518 compat.as_text(c_api.TF_Message(self.status.status)),
--> 519 c_api.TF_GetCode(self.status.status))
520 # Delete the underlying status object from memory otherwise it stays alive
521 # as there is a reference to status from this from the traceback due to
InvalidArgumentError: You must feed a value for placeholder tensor 'model_89_target_28' with dtype float and shape [?,?]
[[Node: model_89_target_28 = Placeholder[dtype=DT_FLOAT, shape=[?,?], _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]
Alternatively I tried to reproduce a dense layer operation extracting the weights:
layer_output_enc = encoder.layers[2].output#get_layer_output_enc([y_true])[0]*10
w_dec0 = decoder.layers[1].get_weights()[0]
b_dec0 = decoder.layers[1].get_weights()[1]
print type(layer_output_enc),'--',layer_output_enc.shape
layer_output_enc = backend.cast(layer_output_enc,'float64')#tf.convert_to_tensor(layer_output_enc)
out_dec0 = K.dot(layer_output_enc,w_dec0)+b_dec0
print out_dec0.shape
out2 = K.tanh(out_dec0)
But again I got the error:
AttributeError: 'numpy.ndarray' object has no attribute 'get_shape'
which is weird because I now 'layer_output_enc' is of type :
Any help appreciated.
You can't call your model within the loss function of Keras model, you can only use the input tensors y_true and y_pred. So the loss function cannot access intermediate layers. I had the same need and the tricky solution I found was to concatenate the output tensor with the intermediate layer as a new output of the model. It may be much simpler working directly with tensorflow though.

How to save and restore a lstm trained model in Tensorflow using Saver?

I have saved a trained LSTM model and I want to restore the prediction to use it in testing. I was trying to follow this post. But I am getting errors. Here is what I tried:
x = tf.placeholder('tf.float32', [None, input_vec_size, 1])
y = tf.placeholder('tf.float32')
def recurrent_neural_network(x):
layer = {'weights': tf.Variable(tf.random_normal([n_hidden, n_classes])),
'biases': tf.Variable(tf.random_normal([n_classes]))}
x = tf.transpose(x, [1, 0, 2])
x = tf.reshape(x, [-1, 1])
x = tf.split(x, input_vec_size, 0)
lstm_cell = rnn.BasicLSTMCell(n_hidden, state_is_tuple=True)
outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)
output = tf.add(tf.matmul(outputs[-1], layer['weights']), layer['biases'])
return output
def train_neural_network(x):
prediction = recurrent_neural_network(x)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
Training ...
saver.save(sess, os.path.join(os.getcwd(), 'my_test_model'))
After that, in the training phase I am trying
def test_neural_network(input_data):
with tf.Session() as sess:
#sess.run(tf.global_variables_initializer())
new_saver = tf.train.import_meta_graph('my_test_model.meta')
new_saver.restore(sess, tf.train.latest_checkpoint('./'))
prediction = tf.get_default_graph().get_tensor_by_name("prediction:0")
Calculate features from input_data ...
result = sess.run(tf.argmax(prediction.eval(feed_dict={x: features}), 1))
But this throws the following error:
KeyError: "The name 'prediction:0' refers to a Tensor which does not exist. The operation, 'prediction', does not exist in the graph."
Then I tried adding :
tf.add_to_collection('prediction', prediction) before saving and replacing by prediction = tf.get_collection('prediction')[0] after restoring. But this gives me the following error:
InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'Placeholder_2' with dtype float and shape [?,34,1]
[[Node: Placeholder_2 = Placeholderdtype=DT_FLOAT, shape=[?,34,1], _device="/job:localhost/replica:0/task:0/cpu:0"]]
I know for the first error, I am supposed to assign a name in order to restore but prediction is not a tensorflow variable. I went through few previous posts and articles but unable to come up with a working solution. So, my questions are:
Am I doing something conceptually wrong? If so, what?
If not, is there an implementation error? And how do I solve it?
Thanks.
I could save my trained model at last and so posting an answer in case anyone comes across this question. I did not get a solution for the exact problem but I could build and save my model using tflearn. In order to train and store:
model = tflearn.DNN(lstm_model(n_classes, input_vec_size))
model.fit(train_x, train_y, validation_set=(test_x, test_y), n_epoch=20,
show_metric=True, snapshot_epoch=True, run_id='lstm_model')
model.save("../Models/lstm_model")
And later, to restore:
model.load(filepath+"lstm_model")
This seemed to be a far easier way to work with the model, and provides a compact and novel way to do the same task which I posted in the question.

Restoring and use multiple tensorflow model in the same time

I'm quiet new to tensorflow and I struggle to understand how to us it. I'm am currently trying to use it to identify numbers so I used the code providing in the mnist tutorial ( https://www.tensorflow.org/get_started/mnist/pros ) with few modification. I used my own sources rather that the sources given in mnist and I change few part of the code so that I can creat model with sources of different sizes. (28x28 and 56x56)
The, I saved the model as follow :
def save_progression(sess, id_collec, x, y_conv, y_, accuracy, keep_prob, train_step, i, modelDir):
saver = tf.train.Saver()
print(modelDir)
modelNamePrefix=os.path.join(modelDir, "step%s" % str(i))
if (os.path.isdir(modelNamePrefix) == False):
os.makedirs(modelNamePrefix)
if (len(tf.get_collection(id_collec)) > 0):
tf.get_collection_ref(id_collec)[0] = x
tf.get_collection_ref(id_collec)[1] = y_conv
tf.get_collection_ref(id_collec)[2] = y_
tf.get_collection_ref(id_collec)[3] = accuracy
tf.get_collection_ref(id_collec)[4] = keep_prob
tf.get_collection_ref(id_collec)[5] = train_step
else:
tf.add_to_collection(id_collec, x)
tf.add_to_collection(id_collec, y_conv)
tf.add_to_collection(id_collec, y_)
tf.add_to_collection(id_collec, accuracy)
tf.add_to_collection(id_collec, keep_prob)
tf.add_to_collection(id_collec, train_step)
saver.save(sess, os.path.join(modelNamePrefix, "myModel"));
with
sess beign the tf.InteractiveSession()
id_collec is '28x28' or '56x56'
x being the placeholder for input imagies
y_conv the result of a tf.matmul
accuracy beign the result of tf.reduce_mean
y_ the placeholder that defined the number of class
keep_prob a placeholder for a float
train_step = the result of tf.train.AdamOptimizer
i is just a number to change the out directory for the model
modelDir = where the model directory will be created
Then in another program I restore the model as follow:
self._sess = tf.Session()
print("import meta graph %s.meta" % (os.path.join(modelDir, modelName)))
saver = tf.train.import_meta_graph("%s.meta" % (os.path.join(modelDir, modelName)))
print("restoring %s" % (os.path.join(modelDir, modelName)))
saver.restore(self._sess, "%s" % (os.path.join(modelDir, modelName)));
self._placeHolder_x, self._predictNode, _, _, self._placeHolder_keep_prob, _ = tf.get_collection('%dx%d' % (dim, dim))
When I load one model it's ok, but when I load two different model (one base on 28x28 images and one base on 56x56 images) I got an error on the second tf.restore.
[...]
tensorflow.python.framework.errors_impl.InvalidArgumentError: Assign requires shapes of both tensors to match. lhs shape= [3136,1024] rhs shape= [5,5,64,128] [[Node: save/Assign_14 = Assign[T=DT_FLOAT,
_class=["loc:#Variable_4"], use_locking=true, validate_shape=true, _device="/job:localhost/replica:0/task:0/cpu:0"](Variable_4/Adam_1, save/RestoreV2_14)]]
Caused by op u'save/Assign_14'
[...]
InvalidArgumentError (see above for traceback): Assign requires shapes of both tensors to match. lhs shape= [3136,1024] rhs shape= [5,5,64,128] [[Node: save/Assign_14 = Assign[T=DT_FLOAT, _class=["loc:#Variable_4"], use_locking=true, validate_shape=true,
_device="/job:localhost/replica:0/task:0/cpu:0"](Variable_4/Adam_1, save/RestoreV2_14)]]
What do I do wrong ? clearly, the two model use some variables or something.
I first though it was because I use the same id for the collection so I made it different. But the error is in the restore itself not even the get collection.
I heard there is a way somehow to make a scope of somekind allowing to avoid the two model to share things together but I'm don't understabd how that work.
When I seek answer to the web I found many informations but being new to tensorflow I failed to apply those information tu my code.
any idea ?
Ps: If I put those value in colelction if because I need them, either to continue training in a later date if I want two, or to launch the sess.run.
Ok, I found a solution, I added
dim = int(sys.argv[5])
with tf.variable_scope('%dx%d' % (dim, dim)):
before the call to my function that defined the graph entire graph and I added the same line before restoring the graph as well and it run without crashing
The problem might be that you're restoring both models into the same Graph. You might want to initialize separate graphs for each of your models:
graph1 = tf.Graph()
graph2 = tf.Graph()
with tf.Session(graph = graph1) as sess1:
saver.restore(.....)
with tf.Session(graph = graph2) as sess2:
saver.restore(...)

Categories

Resources