我建议不要使用parse_example 开始。发送图像数据有多种选择,每种选择都在复杂性和有效负载大小方面进行权衡:
- 原始张量编码为 JSON
- 张量打包为字节字符串
- 压缩图像数据
在每种情况下,重要的是要注意输入占位符必须具有“无”作为其形状的外部尺寸。这是“batch_size”维度(必需,即使您打算将图像一张一张地发送到服务)。
原始张量编码为 JSON
# Dimensions represent [batch size, height width, channels]
input_images = tf.placeholder(dtype=tf.float32, shape=[None,320,240,3], name='source')
output_tensor = foo(input_images)
# Export the SavedModel
inputs = {'image': input_images}
outputs = {'output': output_tensor}
# ....
您发送到服务的 JSON 将类似于 documented(请参阅“实例 JSON 字符串”)。例如,(我建议尽可能多地删除空白;为了便于阅读,此处打印得很漂亮):
{
"instances": [
{
"image": [
[
[1,1,1], [1,1,1], ... 240 total ... [1,1,1]
],
... 320 total ...
[
[1,1,1], [1,1,1], ... 240 total ... [1,1,1]
]
]
},
{
"image": [ ... repeat if you have more than one image in the request ... ]
]
}
请注意,gcloud 从输入文件格式构建请求正文,其中每个输入位于单独的行(并且大多数打包在一行),即:
{"image": [[[1,1,1], [1,1,1], <240 of these>] ... <320 of these>]}
{"image": [[[2,2,2], [2,2,2], <240 of these>] ... <320 of these>]}
张量打包成字节串
如果您在客户端上调整大小等,我的建议是发送一个字节字符串。 JSON 可能是通过网络发送浮点数的一种相当低效的方式。即使发送整数数据也会导致膨胀。相反,您可以在客户端对字节进行编码并在 TensorFlow 中对其进行解码。我的建议是使用uint8 数据。
这是解码字节字符串的 TensorFlow 模型代码:
raw_byte_strings = tf.placeholder(dtype=tf.string, shape=[None], name='source')
# Decode the images. The shape of raw_byte_strings is [batch size]
# (were batch size is determined by how many images are sent), and
# the shape of `input_images` is [batch size, 320, 240, 3]. It's
# important that all of the images sent have the same dimensions
# or errors will result.
#
# We have to use a map_fn because decode_raw only works on a single
# image, and we need to decode a batch of images.
decode = lambda raw_byte_str: tf.decode_raw(raw_byte_str, tf.uint8)
input_images = tf.map_fn(decode, raw_byte_strings, dtype=tf.uint8)
output_tensor = foo(input_images)
# Export the SavedModel
inputs = {'image_bytes': input_images}
outputs = {'output': output_tensor}
# ....
这里需要特别注意:正如 Jeremy Lewi 所指出的,此输入别名 must 的名称以 _bytes 结尾(image_bytes)。这是因为 JSON 没有区分文本和二进制数据的方法。
请注意,同样的技巧可以应用于浮点数据,而不仅仅是 uint8 数据。
您的客户端将负责创建 uint8s 的字节字符串。以下是在 Python 中使用 numpy 的方法。
import base64
import json
import numpy as np
images = []
# In real life, this is obtained via other means, e.g. scipy.misc.imread), for now, an array of all 1s
images.append(np.array([[[2]*3]*240]*320], dtype=np.uint8))
# If we want, we can send more than one image:
images.append(np.array([[[2]*3]*240]*320], dtype=np.uint8))
# Convert each image to byte strings
bytes_strings = (i.tostring() for i in images)
# Base64 encode the data
encoded = (base64.b64encode(b) for b in bytes_strings)
# Create a list of images suitable to send to the service as JSON:
instances = [{'image_bytes': {'b64': e}} for e in encoded]
# Create a JSON request
request = json.dumps({'instances': instances})
# Or if dumping a file for gcloud:
file_data = '\n'.join(json.dumps(instances))
压缩图像数据
在 TensorFlow 中发送原始图像并进行大小调整和解码通常最方便。这在this sample中有一个例子,这里不再赘述。客户端只需要发送原始 JPEG 字节。相同的note 关于_bytes 后缀适用于此。