rahullak
rahullak

Reputation: 81

How to reintroduce (None, ) batch dimension to tensor in Keras / Tensorflow?

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

  1. tf.reshape as above. Does not work.
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

Answers (1)

rahullak
rahullak

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

Related Questions