Keras merge/concatenate models outputs as a new layers - python

I want to use pretrained models' convolutionnal feature maps as input features for a master model.
inputs = layers.Input(shape=(100, 100, 12))
sub_models = get_model_ensemble(inputs)
sub_models_outputs = [m.layers[-1] for m in sub_models]
inputs_augmented = layers.concatenate([inputs] + sub_models_outputs, axis=-1)
Here is the key part of what I do in get_model_ensemble():
for i in range(len(models)):
model = models[i]
for lay in model.layers:
lay.name = lay.name + "_" + str(i)
# Remove the last classification layer to rather get the underlying convolutional embeddings
model.layers.pop()
# while "conv2d" not in model.layers[-1].name.lower():
# model.layers.pop()
model.layers[0] = new_input_layer
return models
All this gives:
Traceback (most recent call last):
File "model_ensemble.py", line 151, in <module>
model = get_mini_ensemble_net()
File "model_ensemble.py", line 116, in get_mini_ensemble_net
inputs_augmented = layers.concatenate([inputs] + sub_models_outputs, axis=-1)
File "/usr/local/lib/python3.4/dist-packages/keras/layers/merge.py", line 508, in concatenate
return Concatenate(axis=axis, **kwargs)(inputs)
File "/usr/local/lib/python3.4/dist-packages/keras/engine/topology.py", line 549, in __call__
input_shapes.append(K.int_shape(x_elem))
File "/usr/local/lib/python3.4/dist-packages/keras/backend/tensorflow_backend.py", line 451, in int_shape
shape = x.get_shape()
AttributeError: 'BatchNormalization' object has no attribute 'get_shape'
Here is type info:
print(type(inputs))
print(type(sub_models[0]))
print(type(sub_models_outputs[0]))
<class 'tensorflow.python.framework.ops.Tensor'>
<class 'keras.engine.training.Model'>
<class 'keras.layers.normalization.BatchNormalization'>
Note: the models I get from get_model_ensemble() have got their compile() function already called. So, how should I concatenate my models properly? Why wont it work? I guess that maybe that has something to do with how would the inputs be fed to the sub-models and how I hot-swapped their input layers.
Thanks for the help!

The thing works if we do:
sub_models_outputs = [m(inputs) for m in sub_models]
rather than:
sub_models_outputs = [m.layers[-1] for m in sub_models]
TLDR: models needs to be called as a layer.

Related

What is the ideal way, in tensorflow, of feeding the output of a model back into itself, for predicting data that changes over time?

I am working on a model that trains on simulation data, which should ideally be able to predict N timesteps forward from a given state in a simulation. I have attempted to model this by feeding the output of the model back into itself N times, where N is a hyperparameter of the model. I have done this in the call function of the tensorflow.keras.Model() class.
The relevant code:
def call(self, inputs):
x = inputs[0]
outputs = tf.TensorArray(
dtype=tf.float32, size=0, dynamic_size=True, infer_shape=False
)
window = inputs[1]
for i in tf.range(window):
x = self.model(x)
outputs = outputs.write(i, x)
outputs = tf.transpose(outputs.stack(), [1, 2, 3, 0, 4])
return outputs
This works, and the model trains, but i want to save the model using the tensorflow.keras.Model.save() function. Trying this leads to the following error:
Traceback (most recent call last):
File "/zhome/22/4/118839/Masters_Thesis/Model_files/Unet.py", line 562, in <module>
model_.save(savepath + "/saved_model/Model")
File "/zhome/22/4/118839/Masters_Thesis/Menv/lib/python3.9/site-packages/keras/utils/traceback_utils.py", line 70, in error_handler
raise e.with_traceback(filtered_tb) from None
File "/appl/python/3.9.11/lib/python3.9/contextlib.py", line 126, in __exit__
next(self.gen)
File "/zhome/22/4/118839/Masters_Thesis/Model_files/Unet.py", line 485, in call
for i in tf.range(4):
tensorflow.python.framework.errors_impl.OperatorNotAllowedInGraphError: Iterating over a symbolic `tf.Tensor` is not allowed: AutoGraph did convert this function. This might indicate you are trying to use an unsupported feature.
Is there a better way of doing what I'm trying to do? Any other threads I have found recommend using the tf.map_fn() function, but this does not work for me due to the sequential nature of the model. Any help is appreciated!

Connecting BatchDataset with Keras VGG16 preprocess_input

I am using tf.keras.preprocessing.image_dataset_from_directory to get a BatchDataset, where the dataset has 10 classes.
I am trying to integrate this BatchDataset with a Keras VGG16 (docs) network. From the docs:
Note: each Keras Application expects a specific kind of input preprocessing. For VGG16, call tf.keras.applications.vgg16.preprocess_input on your inputs before passing them to the model.
However, I am struggling to get this preprocess_input working with a BatchDataset. Can you please help me figure out how to connect these two dots?
Please see the below code:
train_ds = tf.keras.preprocessing.image_dataset_from_directory(train_data_dir, image_size=(224, 224))
train_ds = tf.keras.applications.vgg16.preprocess_input(train_ds)
This will throw TypeError: 'BatchDataset' object is not subscriptable:
Traceback (most recent call last):
...
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/vgg16.py", line 232, in preprocess_input
return imagenet_utils.preprocess_input(
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/imagenet_utils.py", line 117, in preprocess_input
return _preprocess_symbolic_input(
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/imagenet_utils.py", line 278, in _preprocess_symbolic_input
x = x[..., ::-1]
TypeError: 'BatchDataset' object is not subscriptable
From TypeError: 'DatasetV1Adapter' object is not subscriptable (from BatchDataset not subscriptable when trying to format Python dictionary as table) the suggestion was to use:
train_ds = tf.keras.applications.vgg16.preprocess_input(
list(train_ds.as_numpy_iterator())
)
However, this also fails:
Traceback (most recent call last):
...
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/vgg16.py", line 232, in preprocess_input
return imagenet_utils.preprocess_input(
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/imagenet_utils.py", line 117, in preprocess_input
return _preprocess_symbolic_input(
File "/path/to/venv/lib/python3.10/site-packages/keras/applications/imagenet_utils.py", line 278, in _preprocess_symbolic_input
x = x[..., ::-1]
TypeError: list indices must be integers or slices, not tuple
This is all using Python==3.10.3 with tensorflow==2.8.0.
How can I get this working? Thank you in advance.
Okay I figured it out. I needed to pass a tf.Tensor, not a tf.data.Dataset. One can get a Tensor out by iterating over the Dataset.
This can be done in a few ways:
train_ds = tf.keras.preprocessing.image_dataset_from_directory(...)
# Option 1
batch_images = next(iter(train_ds))[0]
preprocessed_images = tf.keras.applications.vgg16.preprocess_input(batch_images)
# Option 2:
for batch_images, batch_labels in train_ds:
preprocessed_images = tf.keras.applications.vgg16.preprocess_input(batch_images)
If you convert option 2 into a generator, it can be directly passed into the downstream model.fit. Cheers!

How to average a layer's output in tensorflow?

This is a toy model I am trying to implement with tensorflow. The input is a set (10) of real number pairs. And the underlying function I want to approximate is . The implemented model should look like this:
I also need to mention that "Hidden Layer" is the same layer (same parameters) for all X_i.
What I implemented so far:
import tensorflow as tf
import numpy as np
def tf_model():
# Define the inputs
inputs = tf.keras.Input(shape=[10, 2])
# Define common hidden layer
hidden_layer = tf.keras.layers.Dense(64, activation="relu")(inputs)
# Propagate and average
outputs = tf.keras.layers.Dense(1, activation="sigmoid")(hidden_layer)
outputs = tf.keras.layers.Average()(outputs)
return tf.keras.Model(inputs=inputs, outputs=output)
X = np.random.rand(1000,10,2) * 100
y = 1 / (1 + X[...,0]**2 + X[...,1]**4)
y = np.average(y, axis=1)
model = tf_model()
model.fit(X, y)
What I get from running this:
Traceback (most recent call last):
File "model_test.py", line 21, in <module>
model = tf_model()
File "model_test.py", line 13, in tf_model
outputs = tf.keras.layers.Average()(outputs)
File "/home/redbull/.local/lib/python3.8/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
raise e.with_traceback(filtered_tb) from None
File "/home/redbull/.local/lib/python3.8/site-packages/keras/layers/merge.py", line 88, in build
raise ValueError(
ValueError: A merge layer should be called on a list of inputs. Received: input_shape=(None, 10, 1) (not a list of shapes)
I think the issue is that tf.keras.layers.Average() only works with a list of inputs, but not a tf layer/ tensor.
Since tf.keras.layers.Average() does not seem to be suitable in this scenario, how can I implement the wished functionality?
You can use tf.reduce_mean as below.
outputs = tf.reduce_mean(outputs, axis=1)

IndexError when trying to get output of layer in Keras model

I am trying to see what my data looks like after going through a convolutional layer in my Keras model. I am using the Theano backend. The code I have has been cobbled together from the Keras Github:
def get_layer0_outputs(model, test_data):
output = model.layers[0].output
inputs = [K.learning_phase()] + model.inputs
func = K.function(inputs, [output])
return func([0] + [test_data])
What I'm trying to do here is compile a function for the first layer (a Conv2D layer) in my network. The test_data argument is an np.ndarray. My model is loaded correctly, and I have already trained it with decent accuracy.
However, when I call this function, I get a cryptic stacktrace:
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/theano/compile/function_module.py", line 884, in __call__
self.fn() if output_subset is None else\
File "/usr/local/lib/python3.5/dist-packages/theano/gof/op.py", line 872, in rval
r = p(n, [x[0] for x in i], o)
File "/usr/local/lib/python3.5/dist-packages/theano/tensor/nnet/abstract_conv.py", line 1626, in perform
conv_out = self.conv(img, kern, mode="valid", dilation=self.filter_dilation)
File "/usr/local/lib/python3.5/dist-packages/theano/tensor/nnet/abstract_conv.py", line 1531, in conv
dilated_kern[n, im0, ...],
IndexError: index 1 is out of bounds for axis 1 with size 1
What does this mean? Am I calling my function incorrectly?
Your function works for me using the following model:
a = Input(shape=(224,224,3))
b = Conv2D(8, 3, strides=(2,2))(a)
model = Model(inputs=a, outputs=b)
model.compile(optimizer='sgd', loss='mse')
def get_layer0_outputs(model, test_data):
output = model.layers[0].output
inputs = [K.learning_phase()] + model.inputs
func = K.function(inputs, [output])
return func([0] + [test_data])
print get_layer0_outputs(model, np.zeros((1, 224, 224, 3)))[0].shape
Note that layer 0 is an Input layer not a Conv2D, but the code also works for layer 1. I'm using the tensorflow backend so I don't know if the difference is your model or the theano backend.

CNTK python API: How to get predictions from the trained model?

I have a trained model which I am loading using CNTK.load_model() function. I was looking at the MNIST Tutorial on the CNTK git repo as reference for model evaluation code. I have created a data reader (which is a MinibatchSource object) and trying to run model.eval(mb) where mb = minibatch_source.next_minibatch(...) (Similar to this answer)
But, I'm getting the following error message
Traceback (most recent call last):
File "LID_test.py", line 162, in <module>
test_and_evaluate()
File "LID_test.py", line 159, in test_and_evaluate
predictions = model.eval(mb)
File "/home/t-asbahe/anaconda3/envs/cntk-py35/lib/python3.5/site-packages/cntk/ops/functions.py", line 228, in eval
_, output_map = self.forward(arguments, self.outputs, device=device, as_numpy=as_numpy)
File "/home/t-asbahe/anaconda3/envs/cntk-py35/lib/python3.5/site-packages/cntk/utils/swig_helper.py", line 62, in wrapper
result = f(*args, **kwds)
File "/home/t-asbahe/anaconda3/envs/cntk-py35/lib/python3.5/site-packages/cntk/ops/functions.py", line 354, in forward
None, device)
File "/home/t-asbahe/anaconda3/envs/cntk-py35/lib/python3.5/site-packages/cntk/utils/__init__.py", line 393, in sanitize_var_map
if len(arguments) < len(op_arguments):
TypeError: object of type 'Variable' has no len()
I have no input_variable named 'Variable' in my model and I don't see any reason to get this error.
P.S.: My inputs are sparse inputs (one-hots)
You have a few options:
Pass a set of data as numpy array (instance in CNTK 202 tutorial) where onehot data is passed in as a numpy array.
pred = model.eval({model.arguments[0]:[onehot]})
Read the minibatch data and pass it to the eval function
eval_input_map = { input : reader_eval.streams.features }
eval_data = reader_eval.next_minibatch(eval_minibatch_size,
input_map = eval_input_map)
mydata = eval_data[input].value
predicted= model.eval(mydata)

Categories

Resources