如何在tensorflow中读取utf-8编码的二进制字符串?

How to read a utf-8 encoded binary string in tensorflow?

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

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')}

Tensorflow 代码

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_raw and decode_base64 但都没有 return 原始值。

我尝试将 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云本地预测不会自动处理音频字节和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 编码可以让我得到预测结果,尽管在本地测试解码时,我认为音频是从字节字符串错误地转换而来的。

您引用的 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)