tf.image.decode_jpeg - 内容必须是标量,形状为 [1]
tf.image.decode_jpeg - contents must be scalar, got shape [1]
我已经构建了一个 server/client 演示,用于通过 tensorflow 服务进行图像分类,遵循本教程
https://github.com/tmlabonte/tendies/blob/master/minimum_working_example/tendies-basic-tutorial.ipynb
客户
它接受图像作为输入,将其转换为 Base64,使用 JSON
将其传递给服务器
input_image = open(image, "rb").read()
print("Raw bitstring: " + str(input_image[:10]) + " ... " + str(input_image[-10:]))
# Encode image in b64
encoded_input_string = base64.b64encode(input_image)
input_string = encoded_input_string.decode("utf-8")
print("Base64 encoded string: " + input_string[:10] + " ... " + input_string[-10:])
# Wrap bitstring in JSON
instance = [{"images": input_string}]
data = json.dumps({"instances": instance})
print(data[:30] + " ... " + data[-10:])
r = requests.post('http://localhost:9000/v1/models/cnn:predict', data=data)
#json.loads(r.content)
print(r.text)
服务器
将模型加载为 .h5 后,服务器必须另存为 SavedModel。
图像必须作为 Base64 编码字符串从客户端传递到服务器。
model=tf.keras.models.load_model('./model.h5')
input_bytes = tf.placeholder(tf.string, shape=[], name="input_bytes")
# input_bytes = tf.reshape(input_bytes, [])
# Transform bitstring to uint8 tensor
input_tensor = tf.image.decode_jpeg(input_bytes, channels=3)
# Convert to float32 tensor
input_tensor = tf.image.convert_image_dtype(input_tensor, dtype=tf.float32)
input_tensor = input_tensor / 127.5 - 1.0
# Ensure tensor has correct shape
input_tensor = tf.reshape(input_tensor, [64, 64, 3])
# CycleGAN's inference function accepts a batch of images
# So expand the single tensor into a batch of 1
input_tensor = tf.expand_dims(input_tensor, 0)
# x = model.input
y = model(input_tensor)
然后 input_bytes 成为 SavedModel
中 predition_signature 的输入
tensor_info_x = tf.saved_model.utils.build_tensor_info(input_bytes)
最后服务器结果如下:
§ saved_model_cli show --dir ./ --all
signature_def['predict']:
The given SavedModel SignatureDef contains the following input(s):
inputs['images'] tensor_info:
dtype: DT_STRING
shape: ()
name: input_bytes:0
The given SavedModel SignatureDef contains the following output(s):
outputs['scores'] tensor_info:
dtype: DT_FLOAT
shape: (1, 4)
name: sequential_1/dense_2/Softmax:0
Method name is: tensorflow/serving/predict
发送图片
当我发送图像 base64 时,我收到来自服务器的 运行 次错误,关于输入的形状似乎不是标量:
Using TensorFlow backend.
Raw bitstring: b'\xff\xd8\xff\xe0\x00\x10JFIF' ... b'0;s\xcfJ(\xa0h\xff\xd9'
Base64 encoded string: /9j/4AAQSk ... 9KKKBo/9k=
{"instances": [{"images": "/9j ... Bo/9k="}]}
{ "error": "contents must be scalar, got shape [1]\n\t [[{{node DecodeJpeg}} = DecodeJpeg[_output_shapes=[[?,?,3]], acceptable_fraction=1, channels=3, dct_method=\"\", fancy_upscaling=true, ratio=1, try_recover_truncated=false, _device=\"/job:localhost/replica:0/task:0/device:CPU:0\"](_arg_input_bytes_0_0)]]" }
正如您从服务器看到的那样,input_bytes
与 shape=[]
一样是标量,我也尝试用 tf.reshape(input_bytes, [])
重塑它,但没办法,我总是得到同样的错误.
我没有在互联网上和 Whosebug 中找到有关此错误的任何解决方案。你能建议如何解决它吗?
谢谢!
我解决了这个问题,我想评论一下如何让您从解决方案中受益!
当您像这样发送 json 时:
{"instances": [{"images": "/9j ... Bo/9k="}]}
实际上你在发送 [] 时发送了一个大小为 1 的数组
如果您想发送 2 张图片,您应该这样写
{"instances": [{"images": "/9j ... Bo/9k="}, {"images": "/9j ... Bo/9k="}]}
这里的尺寸是 2 (shape = [2])
所以解决方案是在占位符中声明接受任何类型的 shape=[None]
input_bytes = tf.placeholder(tf.string, shape=[None], name="input_bytes")
那么如果您只发送 1 张图像,则矢量 1 可以通过以下方式转换为标量:
input_scalar = tf.reshape(input_bytes, [])
我的代码中还有另一个错误,我没有考虑到 tensorflow/serving 中有通过在 json 中明确说明 'b64' 来解码 base64 的功能,请参阅到 RESTful API Encoding binary values,所以如果你发送
{"instances": [{"images": {"b64": "/9j ... Bo/9k="}}]}
服务器将自动解码 base64 输入,正确的比特流将到达 tf.image.decode_jpeg
我已经构建了一个 server/client 演示,用于通过 tensorflow 服务进行图像分类,遵循本教程 https://github.com/tmlabonte/tendies/blob/master/minimum_working_example/tendies-basic-tutorial.ipynb
客户
它接受图像作为输入,将其转换为 Base64,使用 JSON
将其传递给服务器input_image = open(image, "rb").read()
print("Raw bitstring: " + str(input_image[:10]) + " ... " + str(input_image[-10:]))
# Encode image in b64
encoded_input_string = base64.b64encode(input_image)
input_string = encoded_input_string.decode("utf-8")
print("Base64 encoded string: " + input_string[:10] + " ... " + input_string[-10:])
# Wrap bitstring in JSON
instance = [{"images": input_string}]
data = json.dumps({"instances": instance})
print(data[:30] + " ... " + data[-10:])
r = requests.post('http://localhost:9000/v1/models/cnn:predict', data=data)
#json.loads(r.content)
print(r.text)
服务器
将模型加载为 .h5 后,服务器必须另存为 SavedModel。 图像必须作为 Base64 编码字符串从客户端传递到服务器。
model=tf.keras.models.load_model('./model.h5')
input_bytes = tf.placeholder(tf.string, shape=[], name="input_bytes")
# input_bytes = tf.reshape(input_bytes, [])
# Transform bitstring to uint8 tensor
input_tensor = tf.image.decode_jpeg(input_bytes, channels=3)
# Convert to float32 tensor
input_tensor = tf.image.convert_image_dtype(input_tensor, dtype=tf.float32)
input_tensor = input_tensor / 127.5 - 1.0
# Ensure tensor has correct shape
input_tensor = tf.reshape(input_tensor, [64, 64, 3])
# CycleGAN's inference function accepts a batch of images
# So expand the single tensor into a batch of 1
input_tensor = tf.expand_dims(input_tensor, 0)
# x = model.input
y = model(input_tensor)
然后 input_bytes 成为 SavedModel
中 predition_signature 的输入 tensor_info_x = tf.saved_model.utils.build_tensor_info(input_bytes)
最后服务器结果如下:
§ saved_model_cli show --dir ./ --all
signature_def['predict']:
The given SavedModel SignatureDef contains the following input(s):
inputs['images'] tensor_info:
dtype: DT_STRING
shape: ()
name: input_bytes:0
The given SavedModel SignatureDef contains the following output(s):
outputs['scores'] tensor_info:
dtype: DT_FLOAT
shape: (1, 4)
name: sequential_1/dense_2/Softmax:0
Method name is: tensorflow/serving/predict
发送图片
当我发送图像 base64 时,我收到来自服务器的 运行 次错误,关于输入的形状似乎不是标量:
Using TensorFlow backend.
Raw bitstring: b'\xff\xd8\xff\xe0\x00\x10JFIF' ... b'0;s\xcfJ(\xa0h\xff\xd9'
Base64 encoded string: /9j/4AAQSk ... 9KKKBo/9k=
{"instances": [{"images": "/9j ... Bo/9k="}]}
{ "error": "contents must be scalar, got shape [1]\n\t [[{{node DecodeJpeg}} = DecodeJpeg[_output_shapes=[[?,?,3]], acceptable_fraction=1, channels=3, dct_method=\"\", fancy_upscaling=true, ratio=1, try_recover_truncated=false, _device=\"/job:localhost/replica:0/task:0/device:CPU:0\"](_arg_input_bytes_0_0)]]" }
正如您从服务器看到的那样,input_bytes
与 shape=[]
一样是标量,我也尝试用 tf.reshape(input_bytes, [])
重塑它,但没办法,我总是得到同样的错误.
我没有在互联网上和 Whosebug 中找到有关此错误的任何解决方案。你能建议如何解决它吗?
谢谢!
我解决了这个问题,我想评论一下如何让您从解决方案中受益!
当您像这样发送 json 时:
{"instances": [{"images": "/9j ... Bo/9k="}]}
实际上你在发送 [] 时发送了一个大小为 1 的数组 如果您想发送 2 张图片,您应该这样写
{"instances": [{"images": "/9j ... Bo/9k="}, {"images": "/9j ... Bo/9k="}]}
这里的尺寸是 2 (shape = [2])
所以解决方案是在占位符中声明接受任何类型的 shape=[None]
input_bytes = tf.placeholder(tf.string, shape=[None], name="input_bytes")
那么如果您只发送 1 张图像,则矢量 1 可以通过以下方式转换为标量:
input_scalar = tf.reshape(input_bytes, [])
我的代码中还有另一个错误,我没有考虑到 tensorflow/serving 中有通过在 json 中明确说明 'b64' 来解码 base64 的功能,请参阅到 RESTful API Encoding binary values,所以如果你发送
{"instances": [{"images": {"b64": "/9j ... Bo/9k="}}]}
服务器将自动解码 base64 输入,正确的比特流将到达 tf.image.decode_jpeg