使用gcloud ml服务来拍摄大图像

时间:2017-09-14 10:00:21

标签: numpy tensorflow google-cloud-ml-engine

我在tensorflow中有一个训练有素的网络,我希望在用于预测的gcloud ml-engine中使用。

预测gcloud ml服务应接受大小为320x240x3的numpy array float32类型图像,并返回2个微小矩阵作为输出。

有谁知道我应该如何创建接受这种输入类型的输入图层?

我尝试了多种方法,例如使用base64编码的json文件,但是将字符串转换为float类型会产生一个不支持的错误:

"error": "Prediction failed: Exception during model execution: LocalError(code=StatusCode.UNIMPLEMENTED, details=\"Cast string to float is not supported\n\t [[Node: ToFloat = Cast[DstT=DT_FLOAT, SrcT=DT_STRING, _output_shapes=[[-1,320,240,3]], _device=\"/job:localhost/replica:0/task:0/cpu:0\"](ParseExample/ParseExample)]]\")"

这是创建json文件的示例(将上面的numpy数组保存为jpeg之后):

python -c 'import base64, sys, json; img = base64.b64encode(open(sys.argv[1], "rb").read()); print json.dumps({"images": {"b64": img}})' example_img.jpg &> request.json

tensorflow命令试图处理输入:

raw_str_input = tf.placeholder(tf.string, name='source')
feature_configs = {
                'image': tf.FixedLenFeature(
                    shape=[], dtype=tf.string),
            }
tf_example = tf.parse_example(raw_str_input, feature_configs)
input = tf.identity(tf.to_float(tf_example['image/encoded']), name='input')

以上是其中一个测试的示例,也尝试了多次尝试不同的tensorflow命令来处理输入,但没有一个工作...

2 个答案:

答案 0 :(得分:6)

我建议不要使用parse_example开头。有几种发送图像数据的选项,每种都有复杂性和有效载荷大小的权衡:

  1. Raw Tensor编码为JSON
  2. 作为Byte Strings打包的Tensors
  3. 压缩图像数据
  4. 在每种情况下,重要的是要注意输入占位符必须具有“无”和“无”。作为其形状的外部维度。这是" batch_size"维度(即使您打算将图像逐个发送到服务,也是必需的。)

    Raw Tensor编码为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的名称以_bytesimage_bytes)结尾。这是因为JSON没有办法区分文本形式的二进制数据。

    请注意,同样的技巧可以应用于浮动数据,而不仅仅是uint8数据。

    您的客户端将负责创建uint8s的字节字符串。以下是使用numpy在Python中执行此操作的方法。

    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后缀适用于此处。

答案 1 :(得分:1)

如果您正在使用binary data with predictions,则输入/输出别名必须以“字节”结尾。所以我认为你需要做

$(document).ready(function(){
    $("#selectAll").change(function(){
        $(".sports").prop('checked', ($(this).is(':checked')));
    });
    $(".sports").change(function(){
        $("#selectAll").prop('checked', false);
    });
});