I have a complex keras model in which one of the layers is a custom pretrained layer which expects "int32" as inputs. This model is implemented as a class that inherits from Model and it is implemented like this:
class MyModel(tf.keras.models.Model):
def __init__(self, size, input_shape):
super(MyModel, self).__init__()
self.layer = My_Layer()
self.build(input_shape)
def call(self, inputs):
return self.layer(inputs)
But when it reaches the self.build method, it throws the next error:
ValueError: You cannot build your model by calling `build` if your layers do not support float type inputs. Instead, in order to instantiate and build your model, `call` your model on real tensor data (of the correct dtype).
How can I fix it?
The exception is thrown when building a model with model.build.
model.build function build a model based on given input shape.
The error is raised because when we trying to build a model, it first calls a model with x argument depending on input shape type in the following code
if (isinstance(input_shape, list) and
all(d is None or isinstance(d, int) for d in input_shape)):
input_shape = tuple(input_shape)
if isinstance(input_shape, list):
x = [base_layer_utils.generate_placeholders_from_shape(shape)
for shape in input_shape]
elif isinstance(input_shape, dict):
x = {
k: base_layer_utils.generate_placeholders_from_shape(shape)
for k, shape in input_shape.items()
}
else:
x = base_layer_utils.generate_placeholders_from_shape(input_shape)
x is a TensorFlow placeholder here. So when trying to call a model with x as an input it will pop a TypeError and the result except for block will work and give an error.
I assume your input shape is 16x16. Instead of using self.build([(16,16)]) this, call the model based on real tensor
inputs = tf.keras.Input(shape=(16,))
self.call(inputs)
Workaround
I've encountered the same problem when trying to export model with multiple Int-typed input tensor as SavedModel. I worked around by overriding the build method and manually specifying self._build_input_shape. So you solution would look like:
class MyModel(tf.keras.models.Model):
def __init__(self, size, input_shape):
super(MyModel, self).__init__()
self.layer = My_Layer()
self.build(input_shape)
def call(self, inputs):
return self.layer(inputs)
def build(self, input_shapes):
super(tf.keras.Model, self).build(input_shapes)
What happened in the original code
The default build method of tf.keras.Model object will treat by default input tensors as float tensors, which ends up throwing the exception.
Such behavior of tf.keras.Model is defined here, where inputs for your model are created by base_layer_utils.generate_placeholders_from_shape, which will specify dtype as float.
What would happen with the workaround
As tf.keras.Model.build would finally invoke it's super class's build function tf.keras.layer.Layer.build, the workaround skips tf.keras.Model.build logic that causes the problem, but you may have to add complemental code after that in case you rely on other logics in defined in tf.keras.Model.build
Related
i built and trained my LSTM model for a regression task and everything works fine. i would like to use the fast_gradient_method function from cleverhans (or any other cleverhans function as the issue stands for any other attack).
i don't understand how am i supposed to pass the model to the function. from cleverhans:
:param model_fn: a callable that takes an input tensor and returns the model logits
whatever input i give to the function (the model itself, the weights i get with get_weights, the weights of the "stage" right before the dense layer...), i get this error:
TypeError: 'module' object is not callable
what would be the correct input to make it work?
in the only working example i found, the following line of code is used to define logits_model and then pass it as :param model_fn:, but i still get the error above
logits_model = tf.keras.Model(model.input,model.layers[-1].output)
to pass a valid model, it should be defined in the following way:
(it is just an example)
"make" is only needed for model.summary() to work, I found the code in another SO post that I can't seem to find right now
class modSubclass(Model):
def __init__(self):
super(modSubclass, self).__init__()
self.lstm1 = GRU(hidden_size1, activation='relu',return_sequences=True,input_shape=(input_size,1))
self.lstm2 = GRU(hidden_size2, activation='relu')
self.dense1 = Dense(K, activation='relu')
def call(self,x):
x = self.lstm1(x)
x = self.lstm2(x)
x = self.dense1(x)
return x
def make(self, input_shape):
'''
This method makes the command "model.summary()" work.
input_shape: (H,W,C), do not specify batch B
'''
x = tf.keras.layers.Input(shape=input_shape)
model = tf.keras.Model(inputs=[x], outputs=self.call(x), name='actor')
print(model.summary())
return model
I created a custom layer (e.g. from Dense), to which I want to pass a non trainable Variable (custom_input) of constant size (custom_input_shape). I'll leave out some of the details to keep it short.
class CustomLayer(tf.keras.layers.Dense):
def __init__(self, custom_input_shape, **kwargs):
super().__init__(**kwargs)
self.input_spec = [
self.input_spec,
tf.keras.layers.InputSpec(shape=([self.custom_input_shape])),
]
def build(self, input_shape):
super().build(
self.input_spec = [
self.input_spec,
tf.keras.layers.InputSpec(shape=([self.custom_input_shape])),
]
def call(self, inputs: Tuple[tf.Tensor, tf.Tensor]):
x, custom_input = inputs
...
return x
I adapted the input_spec, and pass in the regular inputs including the custom_input as a tuple (inputs, custom_input).
The custom_input is calculated once in the call() method of my custom model before each layer gets called, and gets passed to each custom layer that needs the custom_input.
Training a model with a Layer like this in it works, but I am not sure if this is the recommended way to go about this.
Additionally, if I want to save a custom Model with this layer, it fails. model.save() tries to call the model with some generic input, and fails some custom calculations in call() because it assumes the custom_input is dependent on the batch size, and passes in an empty Tensor because of it, while it should actually be of fixed size.
I would be glad for any recommendations on how to solve this according to Tensorflow 'rules'.
I'm trying to use a subclassed model to decode binary data, thus my inputs are tensors of booleans/bits. I began by using TensorFlow's functional API to build a model and everything worked as expected. This was (the relevant part of) my code:
def build_decoder(bitrate):
input_layer = layers.Input(shape=(bitrate,))
hidden = tf.expand_dims(input_layer, -1)
hidden = layers.Conv1D(filters=128, kernel_size=2, padding="same", activation="elu")(hidden)
hidden = layers.AvgPool1D(pool_size=2)(hidden)
hidden = layers.Conv1D(filters=128, kernel_size=2, padding="same", activation="elu")(hidden)
hidden = layers.AvgPool1D(pool_size=2)(hidden)
hidden = layers.Bidirectional(
layers.GRU(units=128,
activation="tanh",
recurrent_activation="sigmoid",
reset_after=True,
return_sequences=True))(hidden)
[...]
This was working fine, but for some unimportant reasons I wanted to use subclassing to build the model instead. This is my approach so far.
class Decoder(tf.keras.Model):
def __init__(self, config: SplitDecoderConfig or int or str):
super(Decoder, self).__init__()
[...]
self.upper = []
for i in range(config.conv_layers):
self.upper.append(layers.Conv1D(filters=config.conv_filters[i],
kernel_size=config.conv_kernel_sizes[i],
padding="same", activation="elu"))
self.upper.append(layers.AvgPool1D(pool_size=config.conv_pool_sizes[i]))
[...]
print("building")
self.build([None, config.bitrate])
print("calling")
self.call(tf.random.uniform([8, config.bitrate]) < .5)
def call(self, inputs, *args, **kwargs):
# inputs = tf.cast(inputs, tf.half) # un-commenting this works, but is very slow during training
upper = tf.expand_dims(inputs, -1)
for layer in self.upper:
upper = layer(upper) # crashes here when iterating over the first Conv1D layer
[...]
return self.output_layer(combined)
Building the model works fine, using self.build() (which uses a tensor of float32 values) does work as well, but as soon as I call the model (see the function call at the end of _ init_()) with bools the following error is raised:
tensorflow.python.framework.errors_impl.InvalidArgumentError: Value for attr 'T' of bool is not in the list of allowed values: half, bfloat16, float, double, int32
; NodeDef: {{node Conv2D}}; Op<name=Conv2D; signature=input:T, filter:T -> output:T; attr=T:type,allowed=[DT_HALF, DT_BFLOAT16, DT_FLOAT, DT_DOUBLE, DT_INT32]; attr=strides:list(int); attr=use_cudnn_on_gpu:bool,default=true; attr=padding:string,allowed=["SAME", "VALID", "EXPLICIT"]; attr=explicit_paddings:list(int),default=[]; attr=data_format:string,default="NHWC",allowed=["NHWC", "NCHW"]; attr=dilations:list(int),default=[1, 1, 1, 1]> [Op:Conv2D]
Note that the operation where it crashes is a 2D-convolution, while I dont use such layers at all... is this a backend thing?
Casting the inputs at the beginning of call() would fix the problem, but generates huge storage overhead and slows down training by a factor of almost 50 (at least I would think that there lies the problem... I tried to add an Input-wrapper like I did in the functional example, but without any positive results...
Looking forward to your help, thanks!
====== EDIT ======
I continued debugging and found out, that the layers within upper do not save any information about the output_shape or anything related, thus after building (or even calling my model with data) I cannot use model.summary() as it will crash with the errormessage that my layers were not built and to not have a known output_shape (even though I can compute the shape i.e. with compute_output_shape())...
Maybe the problem lies in the way I am subclassing Model?
Additionally model.layers() is empty which i find weird...
I am trying to implement a custom PCA layer for my model being developed using Model Subclassing API. This is how I have defined the layer.
class PCALayer(tf.keras.layers.Layer):
def __init__(self):
super(PCALayer, self).__init__()
self.pc = pca
def call(self, input_tensor, training=False):
x = K.constant(self.pc.transform(input_tensor))
return x
The pca itself is from sklearn.decomposition.PCA and has been fit with the needed data and not transformed.
Now, this is how I have added the layer to my model
class ModelSubClassing(tf.keras.Model):
def __init__(self, initizlizer):
super(ModelSubClassing, self).__init__()
# define all layers in init
# Layer of Block 1
self.pca_layer = PCALayer()
self.dense1 = tf.keras.layers.Dense(...)
self.dense2 = tf.keras.layers.Dense(...)
self.dense3 = tf.keras.layers.Dense(...)
def call(self, input_tensor, training=False):
# forward pass: block 1
x = self.pca_layer(input_tensor)
x = self.dense1(x)
x = self.dense2(x)
return self.dense3(x)
When I compile the model there is no error. However, when I fit the model, I get the following error:
NotImplementedError: Cannot convert a symbolic Tensor (model_sub_classing_1/Cast:0) to a numpy array. This error may indicate that you're trying to pass a Tensor to a NumPy call, which is not supported
Can anyone help me please...
self.pc.transform which comes from sklearn is expecting a numpy array, but you provide a tf tensor. When the layer is built, it passes a symbolic tensor to build the graph etc, and this tensor cannot be converted to a numpy array. The answer is in error :
you're trying to pass a Tensor to a NumPy call, which is not supported
Compare the following code snippets. I implemented a simple keras model like this
inp = layers.Input((10,2))
x = layers.Flatten()(inp)
x = layers.Dense(5)(x)
m = models.Model(inputs=inp, outputs=x)
For one reason or another, I need to have my model in an objective way. So no problem, it's easy to reimplement that into:
class MyModel(tf.keras.Model):
def __init__(self, inp_shape, out_size = 5):
super(MyModel, self).__init__()
self.inp = layers.InputLayer(input_shape=inp_shape)
self.flatten = layers.Flatten()
self.dense = layers.Dense(out_size)
def call(self, a):
x = self.inp(a)
x = self.flatten(x)
x = self.dense(x)
return x
However in the second case when I try to run:
m = MyModel((10,2))
m.summary()
I get:
ValueError: This model has not yet been built. Build the model first by calling `build()` or calling `fit()` with some data, or specify an `input_shape` argument in the first layer(s) for automatic build.
I don't quite get why? Shouldn't the above be equivalent?
The reason for this is that when you create an object of this model you are just creating its layers and not its graph. So in short the output from layer 1 is not going in layer 2 cause those are entirely separate attributes of the class but when you call the model those separate attributes combines and form the graph.
When you define a model in tf. keras with subclassed API, you need to build the model first by calling build or run the model on some data.
m = MyModel((10,2))
m.build(input_shape=(10, 2)) # < -- build the model
m.summary()
That said, you don't also need to define self.inp while building the model with subclassed API. The .summary() may not look right to you for the subclassed model, you may need to check this instead.