Tensorflow Saving Error (from Tensorflow Example) - tensorflow

I am trying to use the Basic Text Classification example from Tensorflow on my own dataset. Training and verification have gone well and I am to the point in the tutorial for exporting the model. The model compiles and works on an array of strings.
After that, I'd like to save the model in h5 format for use in other projects. At this point, the tutorial refers you to save and load keras models tutorial.
This second tutorial essentially says to do this:
model.save('path/saved_model.h5')
This fails with
ValueError: Weights for model sequential_X have not yet been created. Weights are created when the Model is first called on inputs or build() is called with an input_shape.
So next I attempt to do this:
model.build((None, max_features))
model.save('path/saved_model.h5')
There are several errors with this:
ValueError: Tensor conversion requested dtype string for Tensor with dtype float32: <tf.Tensor 'Placeholder:0' shape=(None, 45000) dtype=float32>
TypeError: Input 'input' of 'StringLower' Op has type float32 that does not match expected type of string.
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).
I think this essentially means the input I defined to pass into model.build defaults to float and needs to be string. I think I have two options:
Somehow define my input layer to be string, which I cannot see how to do. This feels like the correct thing to do.
Use model.call. However I am not sure how to 'call my model on real tensor data' because tensors can't be strings and that is the input to the network.
I've seen one other person with this issue here, with no solution other than to rebuild the model in functional style with mixed results. I am not sure of the point of rebuilding in the functional style since I don't fully understand the problem.
I'd prefer to have the TextVectorization layer built into the final model to simplify deployment. This is exactly the reason the docs give for doing this in the example in the first place. (The model will save without it.)
I am a novice with this so I might be making a simple mistake. How can I get this model to save?

Related

Adapting an existing keras model with multiple inputs to tensorflow federated

I'm trying to apply federated learning to an existing keras model that takes two inputs. When I call tff.learning.from_compiled_keras_model and include a dummy batch, I get this error: ValueError: Layer model_1 expects 2 inputs, but it received 1 input tensors. Inputs received: [<tf.Tensor 'packed:0' shape=(2, 20) dtype=int64>].
The model accepts two numpy arrays as inputs, so I defined my dummy_batch as:
x = tf.constant(np.random.randint(1,100, size=[20]))
collections.OrderedDict([('x', [x, x]), ('y', x)])
I dug around a little bit and saw that eventually, tf.convert_to_tensor_or_sparse_tensor gets called on the input list (in the __init__ for _KerasModel), and that returns a single tensor of shape (2,20), instead of two separate arrays or tensors. Is there some other way I can represent the list of inputs to avoid this issue?
The TFF team just pushed a commit that should contain this bugfix; this commit should be what you want. See in particular the change in tensorflow_federated/python/learning/model_utils_test.py--the added test case should have been a repro of your issue, and it now passes.
You were right to call out our call to tf.convert_to_tensor_or_sparse_tensor; now we use tf.nest.map_structure to map this function call to the leaves of the passed-in data structure. Note that Keras does some extra input normalization as well; we decided not to duplicate that logic here.
This change won't be in the pip package until the next release, but if you build from source, it will be available now.
Thanks for this catch, and pointing to the right place!

Using cleverhans with just model weights and no model class

I am using a pretrained model that someone else has created, they have only released the model weights. Currently I am importing the model weights into my graph and calling them by the tensor names. However, this seems incompatible with cleverhans' code that seems to require a model object which has the method predict.
Is there any work around for this which does not require me to rewrite most of the cleverhans attacks because I do not have the model class and predict method?
What you are describing should be possible but may be somewhat intensive on resources because it may recreate the graph several times. Basically, you can implement a CleverHans model class that takes in a graph checkpoint in the init method. The get_logits or fprop method should take an input tensor and load the graph to obtain the corresponding output tensor by performing some graph surgery to replace the checkpoint graph's input tensor with your own tensor: see the input_map argument in `tf.import_graph_de: https://www.tensorflow.org/api_docs/python/tf/graph_util/import_graph_def

Why is "step" argument necessary when predicting using data tensors? what does this error mean?

I am trying to predict() the output for a single data point d, using my trained Keras model loaded from a file. But I get a ValueError If predicting from data tensors, you should specify the 'step' argument. What does that mean?
I tried setting step=1, but then I get a different error ValueError: Cannot feed value of shape () for Tensor u'input_1:0', which has shape '(?, 600)'.
Here is my code:
d = np.concatenate((hidden[p[i]], hidden[x[i]])).resize((1,600))
hidden[p[i]] = autoencoder.predict(d,steps=)
The model is expecting (?,600) as input. I have concatenated two numpy arrays of shape (300,) each to get (600,), which is resized to (1,600). This (1,600) is my input to predict().
In my case, the input to predict was None (because I had a bug in another part of the code).
In official doc, steps refer to the total number of steps before stopping. So steps=1 means make predictions on one batch instead of making prediction on one record (single data point).
https://keras.io/models/sequential/
-> Define value of steps argument,
d = np.concatenate((hidden[p[i]],
hidden[x[i]])).resize((1,600))
hidden[p[i]] = autoencoder.predict(d,steps=1)
If you are using a test data generator, it is good practice to define the steps, as mentioned in the documentation.
If you are predicting a single instance, no need to define the steps. Just make sure the argument (i.e. instance 'd') is not None, otherwise that error will show up. Some reshaping may also be necessary.
in my case i got the same error, i just reshaped the data to predict with numpy function reshape() to the shape of the data originally used to train the model.

TensorFlow simple_save() why are input/output dicts necessary?

Since all vars/graph are loaded anyways, why am I required to provide inputs, outputs to tf.saved_model.simple_save()?
I tried loading a variable with get_tensor_by_name() that I didn't specify in inputs/outputs dictionaries and it worked! So why won't it let me have blank/None inputs/outputs and I grab my variables by their names?
When you specify the input and output tensors of your model, the inference graph is fully specified. Imagine a model that has a single input, but two outputs . For instance, the model predicts the temperature for tomorrow and whether it will rain or not. Maybe I want to save an inference graph for a model that only gives me the temperature.
When you specify the ins and outs, TensorFlow knows which layers connect them. The reason why get_tensor_by_name() worked in your case, is probably because you fetched a layer that connects your inputs to your outputs.

How to get model output from tensorflow model without knowing its name in advance?

So I frequently run models with different architectures, but have code intended to apply to all of them which runs inference off the saved models. Thus, I will be calling eval() on the last layer of this model, like this:
yhat = graph.get_tensor_by_name("name_of_my_last_layer:0")
decoded_image = yhat.eval(session=sess, feed_dict={x : X})
However, without arduous log parsing, I don't know exactly what the last layer is named, and I'm currently hand-coding it. I've considered creating a generic 'output' tensor in my graph but that seems wasteful/brittle. What is the better way?
The best way is to either making the layer you want to analyse a model output or to fix its name (by passing the name= keyword argument to the layer function when creating the layer) to be a known string.