【问题标题】:How to read a utf-8 encoded binary string in tensorflow?如何在 tensorflow 中读取 utf-8 编码的二进制字符串?
【发布时间】:2018-08-01 08:22:58
【问题描述】:

我正在尝试将编码的字节字符串转换回张量流图中的原始数组(使用张量流操作),以便在张量流模型中进行预测。数组到字节的转换基于this answer,它是谷歌云机器学习引擎上张量流模型预测的建议输入。

def array_request_example(input_array):
    input_array = input_array.astype(np.float32)
    byte_string = input_array.tostring()
    string_encoded_contents = base64.b64encode(byte_string)
    return string_encoded_contents.decode('utf-8')}

张量流代码

byte_string = tf.placeholder(dtype=tf.string)
audio_samples = tf.decode_raw(byte_string, tf.float32)

audio_array = np.array([1, 2, 3, 4])
bstring = array_request_example(audio_array)
fdict = {byte_string: bstring}
with tf.Session() as sess:
    [tf_samples] = sess.run([audio_samples], feed_dict=fdict)

我尝试过使用decode_rawdecode_base64,但都没有返回原始值。

我已尝试将 decode raw 的 out_type 设置为不同的可能数据类型,并尝试更改将原始数组转换为的数据类型。

那么,我将如何在 tensorflow 中读取字节数组?谢谢:)

额外信息

这背后的目的是为自定义 Estimator 创建服务输入函数,以使用 gcloud ml-engine local predict(用于测试)和对存储在云上的模型使用 REST API 进行预测。

Estimator 的服务输入函数是

def serving_input_fn():
    feature_placeholders = {'b64': tf.placeholder(dtype=tf.string,
                                                  shape=[None],
                                                  name='source')}
    audio_samples = tf.decode_raw(feature_placeholders['b64'], tf.float32)
    # Dummy function to save space
    power_spectrogram = create_spectrogram_from_audio(audio_samples)
    inputs = {'spectrogram': power_spectrogram}
    return tf.estimator.export.ServingInputReceiver(inputs, feature_placeholders)

Json 请求

我使用 .decode('utf-8') 是因为在尝试 json 转储 base64 编码的字节字符串时,我收到此错误

raise TypeError(repr(o) + " is not JSON serializable")
TypeError: b'longbytestring'

预测错误

使用 gcloud local 传递 json 请求 {'audio_bytes': 'b64': bytestring} 时出现错误

PredictionError: Invalid inputs: Expected tensor name: b64, got tensor name: [u'audio_bytes']

那么也许 google cloud local predict 不会自动处理音频字节和 base64 转换?或者我的 Estimator 设置可能有问题。

而对 REST API 的请求 {'instances': [{'audio_bytes': 'b64': bytestring}]} 给出了

{'error': 'Prediction failed: Error during model execution: AbortionError(code=StatusCode.INVALID_ARGUMENT, details="Input to DecodeRaw has length 793713 that is not a multiple of 4, the size of float\n\t [[Node: DecodeRaw = DecodeRaw[_output_shapes=[[?,?]], little_endian=true, out_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_source_0_0)]]")'}

这让我很困惑,因为我明确地将请求定义为浮点数并在服务输入接收器中执行相同操作。

从请求中删除 audio_bytes 并对字节字符串进行 utf-8 编码可以让我得到预测,但在本地测试解码时,我认为音频从字节字符串转换不正确。

【问题讨论】:

    标签: tensorflow google-cloud-platform byte google-cloud-ml


    【解决方案1】:

    您引用的answer 是在假设您在 CloudML Engine 的服务上运行模型的情况下编写的。该服务实际上负责 JSON(包括 UTF-8)和 base64 编码。

    要让您的代码在本地或其他环境中运行,您需要进行以下更改:

    def array_request_example(input_array):
        input_array = input_array.astype(np.float32)
        return input_array.tostring()
    
    byte_string = tf.placeholder(dtype=tf.string)
    audio_samples = tf.decode_raw(byte_string, tf.float32)
    
    audio_array = np.array([1, 2, 3, 4])
    bstring = array_request_example(audio_array)
    fdict = {byte_string: bstring}
    with tf.Session() as sess:
        tf_samples = sess.run([audio_samples], feed_dict=fdict)
    

    也就是说,根据您的代码,我怀疑您希望以 JSON 格式发送数据;你可以使用gcloud local predict来模拟CloudML Engine的服务。或者,如果您更喜欢编写自己的代码,可能是这样的:

    def array_request_examples,(input_arrays):
      """input_arrays is a list (batch) of np_arrays)"""
      input_arrays = (a.astype(np.float32) for a in input_arrays)
      # Convert each image to byte strings
      bytes_strings = (a.tostring() for a in input_arrays)
      # 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 = [{'audio_bytes': {'b64': e}} for e in encoded]
      # Create a JSON request
      return json.dumps({'instances': instances})
    
    def parse_request(request):
      # non-TF to simulate the CloudML Service which does not expect
      # this to be in the submitted graphs.
      instances = json.loads(request)['instances']
      return [base64.b64decode(i['audio_bytes']['b64']) for i in instances]
    
    byte_strings = tf.placeholder(dtype=tf.string, shape=[None])
    decode = lambda raw_byte_str: tf.decode_raw(raw_byte_str, tf.float32)
    audio_samples = tf.map_fn(decode, byte_strings, dtype=tf.float32)
    
    audio_array = np.array([1, 2, 3, 4])
    request = array_request_examples([audio_array])
    fdict = {byte_strings: parse_request(request)}
    with tf.Session() as sess:
      tf_samples = sess.run([audio_samples], feed_dict=fdict)
    

    【讨论】:

    • 谢谢 :),你说得对,我正在发送 JSON 来进行预测。您建议的内容可以在本地读取字节字符串(一旦我添加了 decode(utf-8)),但不适用于我的 Estimator 的服务输入函数。我已经更新了 OP 来解释原因。从我看到的解析 gcloud 应该自动执行(如果我理解你的答案正确的话)没有按预期发生。
    猜你喜欢
    • 1970-01-01
    • 2013-01-31
    • 2016-07-01
    • 2016-11-12
    • 2017-02-04
    • 2011-07-02
    • 2017-06-14
    • 2015-03-28
    • 1970-01-01
    相关资源
    最近更新 更多