Cannot use predict_generator on loaded model - keras

I am trying to load a Keras model for prediction only (i.e. I do not have to compile the model, per Pepslee's post here).
When I try to use model.predict_generator(), I get:
Using TensorFlow backend.
Exception in thread Thread-1:
Traceback (most recent call last):
File "/user/pkgs/anaconda2/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/user/pkgs/anaconda2/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "/user/pkgs/anaconda2/lib/python2.7/site-packages/keras/utils/data_utils.py", line 559, in _run
sequence = list(range(len(self.sequence)))
ValueError: __len__() should return >= 0
I am working with Tensorflow version 1.12.0, Keras version 2.2.4. I need to use these versions to ensure compatibility with my cuDNN version, which I have no control over.
How can I get around this error?
EDIT
I was asked for an example. Unfortunately there's too much proprietary info here for me to give much detail, but here are the bare bones (note the model is not actually an LSTM):
class LSTMmodel():
def __init__(self, hid1 = 10, batch_size=32, mode='test'):
self.hid_dim_1 = hid1
self.t_per_e, self.test_generator = self.read_data()
#Load the entire fitted model
model_name = ''.join(glob.glob('*model.h5'))
self.__model = load_model(model_name, compile=False)
def read_data(self):
num_test_minibatches = 10
test_IDs = range(111, 111+10)
params = {'list_IDs': test_IDs, 'batch_size': self.batch_size, 'n_vars': 354}
test_generator = DataGenerator(test_IDs, **params)
t_per_e = int(len(test_IDs) - self.batch_size + 1)
return t_per_e, test_generator
def lstm_model():
#Model building here. Not needed, since not compiling the model
return 0
def lstm_predict(self):
pred = self.__model.predict_generator(self.test_generator, self.t_per_e)
return pred
class DataGenerator(keras.utils.Sequence):
#Other methods in here as necessary
def __len__(self):
'Denotes the number of batches per epoch'
batches_per_epoch = int(np.floor(len(self.list_IDs) - self.batch_size + 1))
return batches_per_epoch
def __data_generation(self, other_params_here):
'Generates data containing batch_size samples'
return preprocessed_data
def test_lstm():
test_inst = LSTMmodel(hid1=10) #hid1 is a hyperparameter
test_prediction = test_inst.lstm_predict()
return test_prediction
if __name__ == '__main__':
testvals = test_lstm()
Basically, the workflow is:
1) test_lstm() creates an instance of the LSTMmodel class, and then calls lstm_predict.
2) lstm_predict uses predict_generator which takes in the generator for the test set and the number of examples to generate (steps from here).
3) The generator for the test set is created as an instance of class DataGenerator() in the read_data() method of class LSTMmodel(). Importantly, the test data generator is created in the same way as the training data generator and the validation data generator.
4) self.__model is created by loading a fully trained model in the init method of class LSTMmodel().
How can I get rid of the error?

Related

Multiple Keras.Sequence.on_epoch_end() calls

Data for a Keras generator is being randomly fetched from a DB at the end of each epoch using on_epoch_end() and once during initialization. During training with multiple workers I've noticed multiple calls to the on_epoch_end() function at the end of each epoch instead of the expected single call.
Using traceback I've noticed the extra calls caused by multiple workers are all made by threading.py:
[custom_generator.py] on_epoch_end called
File "/opt/conda/lib/python3.9/threading.py", line 930, in _bootstrap
self._bootstrap_inner()
File "/opt/conda/lib/python3.9/threading.py", line 973, in _bootstrap_inner
self.run()
File "/opt/conda/lib/python3.9/threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "/opt/conda/lib/python3.9/site-packages/keras/utils/data_utils.py", line 761, in _run
self.sequence.on_epoch_end()
File "/home/user/custom_generator.py", line 110, in on_epoch_end
traceback.print_stack()
Generator
class CustomGenerator(tf.keras.utils.Sequence):
def __init__(self, sampler, processor, batch_size, steps_per_epoch):
# Input size: (512,512,3) RGB Images
self.samples = sampler.fetch(batch_size*steps_per_epoch)
self.batch_size = batch_size
self.steps_per_epoch = steps_per_epoch
def __len__(self):
return self.steps_per_epoch
def __getitem__(self, index):
return processor(
self.samples[index * self.batch_size:(index+1) * self.batch_size]
)
def on_epoch_end(self):
self.samples = sampler.fetch(self.batch_size*self.steps_per_epoch)
traceback.print_stack()
gen = CustomGenerator(Sampler(), Processor(), batch_size=1, steps_per_epoch=1500)
Im using Tensorflow 2.8.0, same issue happened at TF 2.3.0 as well. Is there any way to reduce the number of calls to one without reducing the number of workers? Is this behaviour documented somewhere? Strangely, I am unable to reproduce the issue with dummy data.
EDIT
I've managed to reproduce the problem. It happens only when both training and validation generators are supplied to the model.fit(). The validation generator has the appropriate number of calls made to the on_epoch_end() function. The training generator, however, has at least twice the expected calls.
Reproducible code
class Generator(tf.keras.utils.Sequence):
def __init__(self, steps_per_epoch, batch_size):
self.oee_counter = 0
self.steps_per_epoch = steps_per_epoch
self.batch_size = batch_size
def __getitem__(self, idx):
self.X = np.random.random((self.batch_size,512))
self.y = np.random.randint(low=0, high=2, size=self.batch_size)
return self.X, self.y
def on_epoch_end(self):
self.oee_counter += 1
print('Called OEE')
def __len__(self):
return self.steps_per_epoch
gen1 = Generator(1500,1)
gen2 = Generator(2000,1)
inp = tf.keras.layers.Input((512))
out = tf.keras.layers.Dense(1,activation='sigmoid')(inp)
m = tf.keras.Model(inp, out)
m.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.BinaryCrossentropy())
m.fit(
x=gen1,
validation_data=gen2,
validation_freq=1,
epochs=3,
workers=10,
max_queue_size=50,
use_multiprocessing=False,
)
print(gen1.oee_counter) # 6 calls (expected 3)
print(gen2.oee_counter) # 3 calls (correct)

Tensorflow feed_dict dimension miss match with the neural network input and training input

I have two classes of diseases A and B. My training data has 28 images including both classes.
I have created resize function using opencv.
def resize_cv(x,width,height):
new_image=cv.resize(x,(width,height))
return new_image
X contains list of 28 images.
xx=[]
for i in X:
xx.append(resize_cv(i,196,196)) #resizing happens here
print("__Resized the images__")
def scaling (X):
new=[]
for i in X:
for j in i:
new.append(j/255)
break
return new
def label_encode(y):
from sklearn.preprocessing import LabelBinarizer
ff=LabelBinarizer()
return ff.fit_transform(y)
X=scaling(xx)
y=label_encode(y)
Now I split the data into training and testing and create our step size
X_train,X_test, y_train, y_test=split_data(X,y,0.2)
#creating smaller batches
step_size=7
steps = len(X_train)
remaining = steps % step_size
I have created a neural network now when I feed into the network I am getting an dimensional error.
layer_conv1 = create_convolutional_layer(input=x,num_input_channels=num_channels,conv_filter_size=filter_size_conv1,num_filters=num_filters_conv1,name="conv1")
layer_conv1_1 = create_convolutional_layer(input=layer_conv1,num_input_channels=num_filters_conv1,conv_filter_size=filter_size_conv1,num_filters=num_filters_conv1,name="conv2")
layer_conv1_1_1 = create_convolutional_layer(input=layer_conv1_1,num_input_channels=num_filters_conv1,conv_filter_size=filter_size_conv1,num_filters=num_filters_conv1,name="conv3")
max_pool_1=maxpool2d(layer_conv1_1_1,2,name="maxpool_1")
drop_out_1=dropout(max_pool_1,name="dropout_1")
flatten_layer=create_flatten_layer(drop_out_3)
layer_fc2 = create_fc_layer(input=flatten_layer,num_inputs=fc_layer_size,num_outputs=num_classes,use_relu=True)
y_pred = tf.nn.softmax(layer_fc2,name="y_pred")
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y,logits=y_pred))
#Defining objective
train = tf.train.AdamOptimizer(learning_rate=0.00001).minimize(cost)
print ("_____Neural Network Architecture Created Succefully_____")
epochs=10
matches = tf.equal(tf.argmax(y_pred,axis=1),tf.argmax(y,axis=1))
acc = tf.reduce_mean(tf.cast(matches,tf.float32))
#Initializing weights
init = tf.global_variables_initializer()
with tf.Session() as sess:
#writing output to the logs for tensorboard
writer=tf.summary.FileWriter("./logs",sess.graph)
sess.run(init)
for i in range(epochs):
#creating smaller batches
for j in range(0,steps-remaining,step_size):
sess.run([acc,train,cost],feed_dict={x:X_train[j:j+step_size],y:y_train[j:j+step_size]})
Error Trace:
Traceback (most recent call last):
File "/home/centura/gitlab/moles_model/moles_model/modelversion1.py", line 313, in <module>
sess.run([acc,train,cost],feed_dict={x:X_train,y:y_train})
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/client/session.py", line 900, in run
run_metadata_ptr)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/client/session.py", line 1111, in _run
str(subfeed_t.get_shape())))
ValueError: Cannot feed value of shape (22, 196, 3) for Tensor 'x:0', which has shape '(?, 196, 196, 3)'
I have checked images dimension in the X array.
Each image maintain the dimension (196,196,3) but,
when I checked the dimension of the image in X_train the dimension of each image is (196,3).
I am not getting where the missing 196 goes.
I am using tensorflow-gpu=1.9.0, python 3.6 , pycharm IDE.
The answer was simple the reason the Conversion of (196,196,3) happened due to the extra for loop in the scaling function.
Instead of using this code
def scaling (X):
new=[]
for i in X:
for j in i:
new.append(j/255)
break
return new
I should have avoided the second loop an the function will look something like this:
def scaling (X):
new=[]
for i in X:
new.append(i/255)
return new

Unable to load keras model with lambda function using a custom distance function

I'm trying to build a system to check sentence similarities using a siamese LSTM model using Manhattan distance as the distance function while merging two layers.
I'm using the code found in this article
https://medium.com/mlreview/implementing-malstm-on-kaggles-quora-question-pairs-competition-8b31b0b16a07
The issue is that after I've built and saved the model in a json file I'm unable to load the model as an error gets thrown saying
name 'exponent_neg_manhattan_distance' is not defined
Here's the code:
# Model variables
n_hidden = 50
gradient_clipping_norm = 1.25
batch_size = 64
n_epoch = 5
def exponent_neg_manhattan_distance(left, right):
''' Helper function for the similarity estimate of the LSTMs outputs'''
return K.exp(-K.sum(K.abs(left-right), axis=1, keepdims=True))
# The visible layer
left_input = Input(shape=(max_seq_length,), dtype='int32')
right_input = Input(shape=(max_seq_length,), dtype='int32')
embedding_layer = Embedding(len(embeddings), embedding_dim, weights=[embeddings], input_length=max_seq_length, trainable=False)
# Embedded version of the inputs
encoded_left = embedding_layer(left_input)
encoded_right = embedding_layer(right_input)
# Since this is a siamese network, both sides share the same LSTM
shared_lstm = LSTM(n_hidden)
left_output = shared_lstm(encoded_left)
right_output = shared_lstm(encoded_right)
# Calculates the distance as defined by the MaLSTM model
malstm_distance = Merge(mode=lambda x: exponent_neg_manhattan_distance(x[0], x[1]), output_shape=lambda x: (x[0][0], 1))([left_output, right_output])
# Pack it all up into a model
malstm = Model([left_input, right_input], [malstm_distance])
# Adadelta optimizer, with gradient clipping by norm
optimizer = Adadelta(clipnorm=gradient_clipping_norm)
malstm.compile(loss='mean_squared_error', optimizer=optimizer, metrics=['accuracy'])
# Start training
training_start_time = time()
malstm_trained = malstm.fit([X_train['left'], X_train['right']], Y_train, batch_size=batch_size, nb_epoch=n_epoch,
validation_data=([X_validation['left'], X_validation['right']], Y_validation))
print("Training time finished.\n{} epochs in {}".format(n_epoch, datetime.timedelta(seconds=time()-training_start_time)))
malstm.save('malstm.h5')
model_json = malstm.to_json()
with open ('malstm.json', 'w') as file:
file.write(model_json)
malstm.save_weights('malst_w.h5')
Now when I try to load the model I get the following error:
model = model_from_json(open('malstm.json').read(), custom_objects = {"exponent_neg_manhattan_distance":exponent_neg_manhattan_distance})
C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py:1271: UserWarning: The `Merge` layer is deprecated and will be removed after 08/2017. Use instead layers from `keras.layers.merge`, e.g. `add`, `concatenate`, etc.
return cls(**config)
Traceback (most recent call last):
File "<ipython-input-12-4c72a4db6c29>", line 1, in <module>
model = model_from_json(open('malstm.json').read(), custom_objects = {"exponent_neg_manhattan_distance":exponent_neg_manhattan_distance})
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\models.py", line 349, in model_from_json
return layer_module.deserialize(config, custom_objects=custom_objects)
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\layers\__init__.py", line 55, in deserialize
printable_module_name='layer')
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\utils\generic_utils.py", line 144, in deserialize_keras_object
list(custom_objects.items())))
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 2524, in from_config
process_node(layer, node_data)
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 2483, in process_node
layer(input_tensors, **kwargs)
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 619, in __call__
output = self.call(inputs, **kwargs)
File "C:\Users\archi\Miniconda3\lib\site-packages\keras\legacy\layers.py", line 209, in call
return self.mode(inputs, **arguments)
File "<ipython-input-19-913812c640b3>", line 28, in <lambda>
NameError: name 'exponent_neg_manhattan_distance' is not defined
I've searched online and the issue is probably because of the use of the lambda function. Is there any way I could load this model because it took a crazy amount of time to train. Any help would be appreciated!
First save your model with model.save
Then load with with custom objects
model.save("model_path")
from keras.models import load_model
# Returns a compiled model identical to the previous one model =
load_model('model_path',
custom_objects={
'RAdam':RAdam,
'exponent_neg_manhattan_distance':exponent_neg_manhattan_distance})
Converting comment into answer: you can salvage the weights of the network if you just create it yourself in code again. The error is about creating the network from JSON, but let's follow from:
# ...
# Pack it all up into a model
malstm = Model([left_input, right_input], [malstm_distance])
# ... you don't need compile for only predict
# ... skip training and model saving
# malstm.save_weights('malst_w.h5')
malstm.load_weights('malst_w.h5')
malstm.predict(...)
now, the weights are loaded into the existing model which you created in code.

Sequential Model: TypeError: call() takes at least 3 arguments (2 given)

I am trying to create a multilayer bidirectional LSTM in Keras. Upon running the code below I get a TypeError raised initiating the forward model at forward_model = keras.Sequential([fw_cell])
It says the call() takes at least 3 arguments and that only two are given. I am not sure what this is referring to and therefore how to debug it. Is it saying I am not passing enough arguments to keras.Sequential()? or is it in reference to my StackedRNNCells/LSTMCell(s). Cheers!
class Model_Keras():
def __init__(self, word_dim, sentence_length, class_size):
rnn_size = 256
num_layers = 2
self.input_data = keras.Input(
shape=[sentence_length, word_dim], dtype='float32')
#self.output_data = tf.placeholder(tf.float32, [None, sentence_length, class_size])
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# Build independent forward stack of LSTM cells
fw_cell = keras.layers.LSTMCell(rnn_size, dropout=0.5)
# Stack the LSTM Cells
fw_cell = keras.layers.StackedRNNCells([fw_cell] * num_layers, input_shape=(sentence_length, word_dim), name="fwd")
# Instantiate model
forward_model = keras.Sequential([fw_cell])
# Build independent backward stack of cells
# the same way as forward stack cells.
bw_cell = keras.layers.LSTMCell(rnn_size, dropout=0.5)
bw_cell = keras.layers.StackedRNNCells([bw_cell] * num_layers, input_shape=(sentence_length, word_dim))
backward_model = keras.Sequential([bw_cell])
# Outputs of forward and backward stacks are depth-concatenated
merged_model = keras.layers.Concatenate(
[forward_model, backward_model])
# You can use TF functions to process the input
# if using a TF backend for Keras
processed_input = tf.unstack(tf.transpose(
self.input_data, perm=[1, 0, 2]))
# I don't think this is needed.
# used = tf.sign(tf.reduce_max(tf.abs(self.input_data), reduction_indices=2))
# self.length = tf.cast(tf.reduce_sum(used, reduction_indices=1), tf.int32)
# Put together inputs and merged stacked LSTM models
# apply bidirectional wrapper layer
bidirectional = keras.Sequential(
[processed_input,
merged_model,
keras.layers.Bidirectional()])
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# Process bidirectional output
model = keras.Sequential(
[tf.transpose(tf.unstack(bidirectional), perm=[1, 0, 2])])
model.add(keras.Reshape([-1, 2 * rnn_size]))
# This step replaces weight_and_bias
model.add(keras.Dense(class_size, input_dim=2 * rnn_size))
model.add(keras.Activation('softmax'))
model.add(keras.Reshape([-1, sentence_length, class_size]))
model.compile(optimizer='adam', loss='categorical_crossentropy')
return model
Full error message:
Traceback (most recent call last):
File "model.py", line 97, in <module>
epoch=10, lr=0.002, model_path="./trained_wordvec_model.pkl")
File "model.py", line 87, in train
model = Model_Keras(word_dim, sentence_length, class_size)
File "model.py", line 32, in __init__
forward_model = keras.Sequential([fw_cell])
File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 411, in __init__
self.add(layer)
File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 467, in add
layer(x)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 619, in __call__
output = self.call(inputs, **kwargs)
TypeError: call() takes at least 3 arguments (2 given)

Keras Tensorflow - Exception while predicting from multiple threads

I am using keras 2.0.8 with tensorflow 1.3.0 backend.
I am loading a model in the class init and then use it to predict multithreaded.
import tensorflow as tf
from keras import backend as K
from keras.models import load_model
class CNN:
def __init__(self, model_path):
self.cnn_model = load_model(model_path)
self.session = K.get_session()
self.graph = tf.get_default_graph()
def query_cnn(self, data):
X = self.preproccesing(data)
with self.session.as_default():
with self.graph.as_default():
return self.cnn_model.predict(X)
I initialize the CNN once and the query_cnn method happens from multiple threads.
The exception i get in my log is:
File "/home/*/Similarity/CNN.py", line 43, in query_cnn
return self.cnn_model.predict(X)
File "/usr/local/lib/python3.5/dist-packages/keras/models.py", line 913, in predict
return self.model.predict(x, batch_size=batch_size, verbose=verbose)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", line 1713, in predict
verbose=verbose, steps=steps)
File "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", line 1269, in _predict_loop
batch_outs = f(ins_batch)
File "/usr/local/lib/python3.5/dist-packages/keras/backend/tensorflow_backend.py", line 2273, in __call__
**self.session_kwargs)
File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 895, in run
run_metadata_ptr)
File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 1124, in _run
feed_dict_tensor, options, run_metadata)
File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 1321, in _do_run
options, run_metadata)
File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 1340, in _do_call
raise type(e)(node_def, op, message)
tensorflow.python.framework.errors_impl.NotFoundError: PruneForTargets: Some target nodes not found: group_deps
The code works fine most of the times, its probably some problem with the multithreading.
How can i fix it?
Make sure you finish the graph creation before creating the other threads.
Calling finalize() on the graph may help you with that.
def __init__(self, model_path):
self.cnn_model = load_model(model_path)
self.session = K.get_session()
self.graph = tf.get_default_graph()
self.graph.finalize()
Update 1: finalize() will make your graph read-only so it can be safely used in multiple threads. As a side effect, it will help you find unintentional behavior and sometimes memory leaks as it will throw an exception when you try to modify the graph.
Imagine that you have a thread that does for instance one hot encoding of your inputs. (bad example:)
def preprocessing(self, data):
one_hot_data = tf.one_hot(data, depth=self.num_classes)
return self.session.run(one_hot_data)
If you print the amount of objects in the graph you will notice that it will increase over time
# amount of nodes in tf graph
print(len(list(tf.get_default_graph().as_graph_def().node)))
But if you define the graph first that won't be the case (slightly better code):
def preprocessing(self, data):
# run pre-created operation with self.input as placeholder
return self.session.run(self.one_hot_data, feed_dict={self.input: data})
Update 2: According to this thread you need to call model._make_predict_function() on a keras model before doing multithreading.
Keras builds the GPU function the first time you call predict(). That
way, if you never call predict, you save some time and resources.
However, the first time you call predict is slightly slower than every
other time.
The updated code:
def __init__(self, model_path):
self.cnn_model = load_model(model_path)
self.cnn_model._make_predict_function() # have to initialize before threading
self.session = K.get_session()
self.graph = tf.get_default_graph()
self.graph.finalize() # make graph read-only
Update 3: I did a proof of concept of a warming up, because _make_predict_function() doesn't seems to work as expected.
First I created a dummy model:
import tensorflow as tf
from keras.layers import *
from keras.models import *
model = Sequential()
model.add(Dense(256, input_shape=(2,)))
model.add(Dense(1, activation='softmax'))
model.compile(loss='mean_squared_error', optimizer='adam')
model.save("dummymodel")
Then in another script I loaded that model and made it run on multiple threads
import tensorflow as tf
from keras import backend as K
from keras.models import load_model
import threading as t
import numpy as np
K.clear_session()
class CNN:
def __init__(self, model_path):
self.cnn_model = load_model(model_path)
self.cnn_model.predict(np.array([[0,0]])) # warmup
self.session = K.get_session()
self.graph = tf.get_default_graph()
self.graph.finalize() # finalize
def preproccesing(self, data):
# dummy
return data
def query_cnn(self, data):
X = self.preproccesing(data)
with self.session.as_default():
with self.graph.as_default():
prediction = self.cnn_model.predict(X)
print(prediction)
return prediction
cnn = CNN("dummymodel")
th = t.Thread(target=cnn.query_cnn, kwargs={"data": np.random.random((500, 2))})
th2 = t.Thread(target=cnn.query_cnn, kwargs={"data": np.random.random((500, 2))})
th3 = t.Thread(target=cnn.query_cnn, kwargs={"data": np.random.random((500, 2))})
th4 = t.Thread(target=cnn.query_cnn, kwargs={"data": np.random.random((500, 2))})
th5 = t.Thread(target=cnn.query_cnn, kwargs={"data": np.random.random((500, 2))})
th.start()
th2.start()
th3.start()
th4.start()
th5.start()
th2.join()
th.join()
th3.join()
th5.join()
th4.join()
Commenting the lines for the warmingup and finalize I was able to reproduce your first issue

Resources