Я бы рекомендовал не использовать 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, который вы отправляете в службу, будет выглядеть как задокументированный (см. «Экземпляры строки 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}
# ....
Одно особое примечание: как указал Джереми Леви, имя этого входного псевдонима должен заканчиваться на _bytes
(image_bytes
). Это связано с тем, что JSON не имеет способа отличить текст от двоичных данных.
Обратите внимание, что тот же трюк можно применить к данным с плавающей запятой, а не только к данным uint8.
Ваш клиент будет отвечать за создание строки байтов uint8. Вот как вы могли бы сделать это в 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. Это показано в этом примере, который я здесь не повторится. Клиенту просто нужно отправить необработанные байты JPEG. Здесь применяется то же примечание о суффиксе _bytes
.
person
rhaertel80
schedule
14.09.2017