简体   繁体   English

gcloud ml-engine 在大文件上返回错误

[英]gcloud ml-engine returns error on large files

I have a trained model that takes in a somewhat large input.我有一个接受过大输入的训练模型。 I generally do this as a numpy array of the shape (1,473,473,3).我通常将其作为形状 (1,473,473,3) 的 numpy 数组来执行。 When I put that to JSON I end up getting about a 9.2MB file.当我把它放到 JSON 中时,我最终得到了一个大约 9.2MB 的文件。 Even if I convert that to a base64 encoding for the JSON file the input is still rather large.即使我将其转换为 JSON 文件的 base64 编码,输入仍然相当大。

ml-engine predict rejects my request when sending the JSON file with the following error: ml-engine predict 在发送 JSON 文件时拒绝我的请求,并出现以下错误:

(gcloud.ml-engine.predict) HTTP request failed. Response: {
"error": {
    "code": 400,
    "message": "Request payload size exceeds the limit: 1572864 bytes.",
    "status": "INVALID_ARGUMENT"
  }
}

It looks like I can't send anything over about 1.5MB in size to ML-engine.看起来我无法向 ML-engine 发送大小超过 1.5MB 的任何内容。 Is this for sure a thing?这确定是一回事吗? How do others get around doing online predictions for large data?其他人如何绕过对大数据进行在线预测? Do I have to spin up a compute-engine or will I run into the same issue there?我必须启动计算引擎还是会遇到同样的问题?

Edit:编辑:

I am starting from a Keras model and trying to export to tensorflow serving.我从 Keras 模型开始并尝试导出到 tensorflow 服务。 I load my Keras model into a variable named 'model' and have a defined directory "export_path".我将我的 Keras 模型加载到一个名为“model”的变量中,并定义了一个目录“export_path”。 I build the tensorflow serving model like this:我像这样构建 tensorflow 服务模型:

signature = predict_signature_def(inputs={'input': model.input},
                                outputs={'output': model.output})
builder = saved_model_builder.SavedModelBuilder(export_path)
builder.add_meta_graph_and_variables(
    sess=sess,
    tags=[tag_constants.SERVING],
    signature_def_map={
        signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: signature
    }
)
builder.save()

How would the input look for this signature_def?输入将如何查找此 signature_def? Would the JSON just be something like {'input': ' https://storage.googleapis.com/projectid/bucket/filename '} where the file is the (1,473,473,3) numpy array? JSON 会像 {'input': ' https://storage.googleapis.com/projectid/bucket/filename '} 这样的文件是 (1,473,473,3) numpy 数组吗?

2nd Edit: Looking at the code posted by Lak Lakshmanan, I have tried a few different variations without success to read an image url and attempt to parse the file that way.第二次编辑:查看 Lak Lakshmanan 发布的代码,我尝试了一些不同的变体,但没有成功读取图像 url 并尝试以这种方式解析文件。 I have tried the following without success:我尝试了以下但没有成功:

inputs = {'imageurl': tf.placeholder(tf.string, shape=[None])}
filename = tf.squeeze(inputs['imageurl']) 
image = read_and_preprocess(filename)#custom preprocessing function
image = tf.placeholder_with_default(image, shape=[None, HEIGHT, WIDTH, NUM_CHANNELS])
features = {'image' : image}
inputs.update(features)
signature = predict_signature_def(inputs= inputs,
                                outputs={'output': model.output})


with K.get_session() as session:
    """Convert the Keras HDF5 model into TensorFlow SavedModel."""
    builder = saved_model_builder.SavedModelBuilder(export_path)
    builder.add_meta_graph_and_variables(
        sess=session,
        tags=[tag_constants.SERVING],
        signature_def_map={
            signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: signature
        }
    )
    builder.save()

I believe the problem is with getting a mapping from the imageurl placeholder towards building the features.我相信问题在于从 imageurl 占位符获取映射到构建功能。 Thoughts on what I am doing wrong?关于我做错了什么的想法?

What I typically do is to have the json refer to a file in Google Cloud Storage.我通常做的是让 json 引用 Google Cloud Storage 中的文件。 Users would first have to upload their file to gcs and then invoke prediction.用户首先必须将他们的文件上传到 gcs,然后调用预测。 But this approach has other advantages, since the storage utilities allow for parallel and multithreaded uploads.但这种方法还有其他优点,因为存储实用程序允许并行和多线程上传。

Keras/TensorFlow 2.0 Keras/TensorFlow 2.0

In TensorFlow 2.0, this is what the serving function will look like:在 TensorFlow 2.0 中,服务功能如下所示:

@tf.function(input_signature=[tf.TensorSpec([None,], dtype=tf.string)])
def predict_bytes(img_bytes):
    input_images = tf.map_fn(
        preprocess,
        img_bytes,
        fn_output_signature=tf.float32
    )
    batch_pred = model(input_images) # same as model.predict()
    top_prob = tf.math.reduce_max(batch_pred, axis=[1])
    pred_label_index = tf.math.argmax(batch_pred, axis=1)
    pred_label = tf.gather(tf.convert_to_tensor(CLASS_NAMES), pred_label_index)
    return {
        'probability': top_prob,
        'flower_type_int': pred_label_index,
        'flower_type_str': pred_label
    }

@tf.function(input_signature=[tf.TensorSpec([None,], dtype=tf.string)])
def predict_filename(imageurl):
    img_bytes = tf.map_fn(
        tf.io.read_file,
        filenames
    )
    result = predict_bytes(img_bytes)
    result['filename'] = filenames
    return result

shutil.rmtree('export', ignore_errors=True)
os.mkdir('export')
model.save('export/flowers_model3',
          signatures={
              'serving_default': predict_filename,
              'from_bytes': predict_bytes
          })

full code is here: https://nbviewer.jupyter.org/github/GoogleCloudPlatform/practical-ml-vision-book/blob/master/09_deploying/09d_bytes.ipynb完整代码在这里: https : //nbviewer.jupyter.org/github/GoogleCloudPlatform/practical-ml-vision-book/blob/master/09_deploying/09d_bytes.ipynb

TensorFlow 1.0 TensorFlow 1.0

In TensorFlow 1.0, the code will look like this:在 TensorFlow 1.0 中,代码将如下所示:

def serving_input_fn():
    # Note: only handles one image at a time ... 
    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)

full code here: https://github.com/GoogleCloudPlatform/training-data-analyst/blob/61ab2e175a629a968024a5d09e9f4666126f4894/courses/machine_learning/deepdive/08_image/flowersmodel/trainer/model.py#L119完整代码在这里: https : //github.com/GoogleCloudPlatform/training-data-analyst/blob/61ab2e175a629a968024a5d09e9f4666126f4666126f4894/courses/machine_learning/deepdive/08_image/flowersmodel/trainer/model.py

I encountered the same error when trying to run predictions on AI Platform with large images.我在尝试使用大图像在 AI Platform 上运行预测时遇到了同样的错误。 I solved the payload limit problem by first encoding images to PNG format before sending them to the AI Platform.我首先将图像编码为 PNG 格式,然后再将它们发送到 AI Platform,从而解决了负载限制问题。

My Keras model doesn't take PNG encoded images as an input, so I needed to convert the Keras model to a Tensorflow Estimator and define its serving input function containing the code to decode the PNG encoded images back to the format my model expects.我的 Keras 模型不接受 PNG 编码图像作为输入,因此我需要将 Keras 模型转换为 Tensorflow Estimator 并定义其服务输入函数,其中包含将 PNG 编码图像解码回我的模型期望的格式的代码。

Example code when the model expects two different grayscale images as an input:当模型需要两个不同的灰度图像作为输入时的示例代码:

import tensorflow as tf
from tensorflow.keras.estimator import model_to_estimator
from tensorflow.estimator.export import ServingInputReceiver

IMG_PNG_1 = "encoded_png_image_1"
IMG_PNG_2 = "encoded_png_image_2"


def create_serving_fn(image_height, image_width):
    def serving_input_fn():
        def preprocess_png(png_encoded_img):
            img = tf.reshape(png_encoded_img, shape=())
            img = tf.io.decode_png(img, channels=1)
            img = img / 255
            img = tf.expand_dims(img, axis=0)
            return img

        # receiver_tensors worked only when the shape parameter wasn't defined
        receiver_tensors = {
            IMG_PNG_1: tf.compat.v1.placeholder(tf.string),
            IMG_PNG_2: tf.compat.v1.placeholder(tf.string)
        }

        img_1 = preprocess_png(png_encoded_img=receiver_tensors[IMG_PNG_1])
        img_2 = preprocess_png(png_encoded_img=receiver_tensors[IMG_PNG_2])

        input_img_1 = tf.compat.v1.placeholder_with_default(img_1, shape=[None, image_height, image_width, 1])
        input_img_2 = tf.compat.v1.placeholder_with_default(img_2, shape=[None, image_height, image_width, 1])

        features = {
            "model_input_1": input_img_1,
            "model_input_2": input_img_2,
        }

        return ServingInputReceiver(features=features, receiver_tensors=receiver_tensors)

    return serving_input_fn

# Convert trained Keras model to Estimator
estimator = model_to_estimator(keras_model=model)
save_path = "location_of_the_SavedModel"
export_path = estimator.export_saved_model(
    export_dir_base=save_path,
    serving_input_receiver_fn=create_serving_fn(1000, 1000)
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM