tensorflowkerasgoogle-cloud-platformgoogle-prediction

What is the simplest way of deploying a Keras/Tensorflow CNN available as .model .json and .h5 on Google ML Engine?


I have trouble executing predictions using a Keras CNN (VGGNet) model. It is a multi-class-classification, taking a 96x96x3 image tensor as input, yielding a probability vector of size 114 (classes). It is accepted by Google ML Engine as a valid model and the prediction input image.json is in the correct format (one line with tensor), but calling the gcloud ml-engine predict gives the following error:

"error": "Prediction failed: Error during model execution: AbortionError(code=StatusCode.INVALID_ARGUMENT, details=\"You must feed a value for placeholder tensor 'Placeholder_1' with dtype float and shape [?,114]\n\t [[Node: Placeholder_1 = Placeholderdtype=DT_FLOAT, shape=[?,114], _device=\"/job:localhost/replica:0/task:0/device:CPU:0\"]]\")"

My prediction input image.json contains

{"x": [ [ [ [ 1.0, 1.0, 1.0 ], ..., [ 1.0, 1.0, 1.0 ] ] ] ]}

and the code generating the save_model.pb file is

def build_graph(x):

  model = load_model("my-model.model")
  labels = pickle.loads(open("labels.pickle", "rb").read())

  # classify the input image
  probabilities = model.predict(x)

  outputs = tf.convert_to_tensor(probabilities)
  saver = tf.train.Saver()

  return outputs, saver

image_path = "testset/testimage.png"
# preprocess the image for classification
image = cv2.imread(image_path)
image = cv2.resize(image, (96, 96))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)

# Do training
with tf.Graph().as_default() as prediction_graph:
  x = image
  outputs = tf.placeholder(tf.float32, shape=[None, 114])
  outputs, saver = build_graph(x)

with tf.Session(graph=prediction_graph) as sess:
  sess.run([tf.local_variables_initializer(), tf.tables_initializer()])
  x = tf.placeholder(tf.float32, shape=[None, 96, 96, 3])
  sess.run(outputs, {x: image})

# export model
export_dir = "export3"
tf.saved_model.simple_save(
    sess,
    export_dir,
    inputs={"x": tf.placeholder(tf.float32, shape=[None, 96, 96, 3])},
    outputs={"y": tf.placeholder(tf.float32, shape=[None, 114])}
)

What am I missing here? Is there a simpler working way? The model is also available as .json and .h5 file generated by

# serialize model to JSON
model_json = model.to_json()
with open("my-model.json", "w") as json_file:
json_file.write(model_json)
# serialize weights to HDF5
model.save_weights("my-model.h5")

Thanks for helping!


Solution

  • Somehow, the expected output shape of [None, 114] is not fulfilled.

    I understand that after expand_dims, the shape for image is [1,96,96]. But since I don't know what do you have in your model, I can't know how do you get a probability vector of size 114.

    A vague suggestion, considering the prior clarification, is to check if you're using the tf.Variable class in your model and if you aren't changing the shape properly; since tf.Variable restricts your ability to change the shape of the variable once it has been created.

    If this isn't the case, provide more details regarding your model.