Reputation: 81
I am trying to create a tensorflow model using Keras that is compatible with Google’s Machine Learning Engine. I have an existing trained Keras model which takes a vector float input. I am introducing a string vector input layer to the front of the existing model. This would pass the string to be preprocessed. I am trying to preprocess image data using a Lambda layer. While preprocessing, in order to decode the string jpeg data, I would need to remove the batch dimension from the tensor. After preprocessing, I would need to reintroduce the “None” batch dimension. This is where I’m facing the issue. There seems to be no way to reintroduce “None” as the batch dimension. Google ML Engine requires that the batch dimension should be unknown all the way through the entire model.
Tensorflow version: 1.12 Keras version: 2.2.4 OS: Debian Linux (VM instance) Python version: 2.7
I have tried: 1. Reshape() with both [None,299,299,3] as well as with [-1,299,299,3]. Both don’t work as required
img_height=299
img_width=299
inputs = Input(shape=[1],dtype=tf.string)
inputs_inter1 = Lambda(preprocess_input, output_shape=(img_height,img_width,3))(inputs)
print(inputs_inter1.shape)
print("Combining with string vector input")
combine_out = trainedmodel(inputs_inter1)
Combinedmodel = Model(inputs,combine_out)
input_tensor = Combinedmodel.inputs[0]
output_tensor = Combinedmodel.outputs[0]
print("Inputs: "+str(input_tensor))
print("Outputs: "+str(output_tensor))
def preprocess_input(x):
import tensorflow as tf
x=tf.reshape(x,())
x = tf.image.decode_jpeg(x,channels=3)
x = tf.image.resize_images(x,(299,299))
x = tf.cast(x, tf.float32)
x = tf.math.divide(x, 255.0)
x = tf.math.subtract(x, 0.5)
x = tf.math.multiply(x, 2.0)
x = tf.expand_dims(x,0)
return x
Expected result:
Inputs: Tensor("input_1_1:0", shape=(?, 1), dtype=string)
Outputs: Tensor("model_2/model_1/dense_2/Softmax:0", shape=(?, 8), dtype=float32)
Actual result:
Inputs: Tensor("input_1_1:0", shape=(?, 1), dtype=string)
Outputs: Tensor("model_2/model_1/dense_2/Softmax:0", shape=(1, 8), dtype=float32)
Upvotes: 2
Views: 3725
Reputation: 81
Answering my own question.
The trick is to create a new placeholder with the required dimensions [None,299,299,3], copy the preprocessed tensor into it and return that placeholder from the Lambda function/layer.
def preprocess_input(x):
import tensorflow as tf
x=tf.reshape(x,())
x = tf.image.decode_jpeg(x,channels=3)
x = tf.image.resize_images(x,(299,299))
x = tf.cast(x, tf.float32)
x = tf.math.divide(x, 255.0)
x = tf.math.subtract(x, 0.5)
x = tf.math.multiply(x, 2.0)
x = tf.placeholder_with_default(x,[None,299,299,3])
return x
The usage of tf.placeholder_with_default can be found here: https://www.tensorflow.org/api_docs/python/tf/placeholder_with_default
ETA: Latest Tensorflow 2.0 has a backwards compatible placeholder with default function. Can be used in the short-term.
tf.compat.v1.placeholder_with_default
Upvotes: 4