我有一个google-cloud-ml模型,我可以通过传递float32的3维数组运行预测......
{ 'instances' [ { 'input' : '[ [ [ 0.0 ], [ 0.5 ], [ 0.8 ] ] ... ] ]' } ] }
然而,这不是传输图像的有效格式,因此我想传递base64编码的png或jpeg。 This document讨论了这样做,但不清楚的是整个json对象是什么样的。 { 'b64' : 'x0welkja...' }
取代'[ [ [ 0.0 ], [ 0.5 ], [ 0.8 ] ] ... ] ]'
,留下封闭的'实例'和'输入'相同?还是其他一些结构?或者,tensorflow模型是否必须在base64上训练?
答案 0 :(得分:2)
TensorFlow模型不必对base64数据进行训练。保留您的训练图表。但是,在导出模型时,您需要导出一个可以接受png或jpeg(或者可能是原始的,如果它很小)数据的模型。然后,在导出模型时,您需要确保使用以_bytes
结尾的输出的名称。这向CloudML Engine发出信号,表示您将发送base64编码数据。把它们放在一起就像这样:
from tensorflow.contrib.saved_model.python.saved_model import utils
# Shape of [None] means we can have a batch of images.
image = tf.placeholder(shape=[None], dtype=tf.string)
# Decode the image.
decoded = tf.image.decode_jpeg(image, channels=3)
# Do the rest of the processing.
scores = build_model(decoded)
# The input name needs to have "_bytes" suffix.
inputs = {'image_bytes': image}
outputs = {'scores': scores}
utils.simple_save(session, export_dir, inputs, outputs)
您发送的请求将如下所示:
{"instances": [{"b64": "x0welkja..."}]}
答案 1 :(得分:2)
如果您只想要一种有效的方式将图像发送到模型(而不一定是base-64编码),我建议您将图像上传到Google云端存储,然后让您的模型读取GCS。这样,您不受图像大小的限制,您可以利用GCS API提供的多部分,多线程,可恢复上传等。
TensorFlow的tf.read_file将直接关闭GCS。这是一个服务input_fn的例子,它将执行此操作。您对CMLE的请求会向其发送图像URL(gs://bucket/some/path/to/image.jpg)
def read_and_preprocess(filename, augment=False):
# decode the image file starting from the filename
# end up with pixel values that are in the -1, 1 range
image_contents = tf.read_file(filename)
image = tf.image.decode_jpeg(image_contents, channels=NUM_CHANNELS)
image = tf.image.convert_image_dtype(image, dtype=tf.float32) # 0-1
image = tf.expand_dims(image, 0) # resize_bilinear needs batches
image = tf.image.resize_bilinear(image, [HEIGHT, WIDTH], align_corners=False)
#image = tf.image.per_image_whitening(image) # useful if mean not important
image = tf.subtract(image, 0.5)
image = tf.multiply(image, 2.0) # -1 to 1
return image
def serving_input_fn():
inputs = {'imageurl': tf.placeholder(tf.string, shape=())}
filename = tf.squeeze(inputs['imageurl']) # make it a scalar
image = read_and_preprocess(filename)
# make the outer dimension unknown (and not 1)
image = tf.placeholder_with_default(image, shape=[None, HEIGHT, WIDTH, NUM_CHANNELS])
features = {'image' : image}
return tf.estimator.export.ServingInputReceiver(features, inputs)
您的训练代码将训练实际图像,就像上面的rhaertel80建议一样。有关培训/评估输入功能的信息,请参阅https://github.com/GoogleCloudPlatform/training-data-analyst/blob/master/courses/machine_learning/deepdive/08_image/flowersmodel/trainer/task.py#L27。
答案 2 :(得分:1)
我试图使用@Lak的答案(感谢Lak)在一个json文件中获得多个实例的在线预测,但是一直出现以下错误(我的测试json中有两个实例,因此形状为[2]) :
输入文件名张量必须为标量,但形状为[2]
问题是ML引擎显然将所有实例批处理在一起,然后将它们传递给服务的inpur接收器函数,但是@Lak的示例代码假定输入是单个实例(如果您的单个实例确实可以正常工作json)。我更改了代码,以便它可以处理一批输入。我希望它可以帮助某人:
def read_and_preprocess(filename):
image_contents = tf.read_file(filename)
image = tf.image.decode_image(image_contents, channels=NUM_CHANNELS)
image = tf.image.convert_image_dtype(image, dtype=tf.float32) # 0-1
return image
def serving_input_fn():
inputs = {'imageurl': tf.placeholder(tf.string, shape=(None))}
filename = inputs['imageurl']
image = tf.map_fn(read_and_preprocess, filename, dtype=tf.float32)
# make the outer dimension unknown (and not 1)
image = tf.placeholder_with_default(image, shape=[None, HEIGHT, WIDTH, NUM_CHANNELS])
features = {'image': image}
return tf.estimator.export.ServingInputReceiver(features, inputs)
主要变化是:1)您没有squeeze
输入张量(在特殊情况下,当您的json仅包含一个实例时,这会造成麻烦),以及2)使用tf.map_fn
来将read_and_preprocess
函数应用于一批输入的图片网址。