Sagemaker 预测本地实例,JSON 错误
Sagemaker Predict on local instance, JSON Error
我正在尝试在 Sagemaker 实例上的 MXNet 上制作迁移学习方法。训练和服务在本地开始没有任何问题,我正在使用 python 代码来预测:
def predict_mx(net, fname):
with open(fname, 'rb') as f:
img = image.imdecode(f.read())
plt.imshow(img.asnumpy())
plt.show()
data = transform(img, -1, test_augs)
plt.imshow(data.transpose((1,2,0)).asnumpy()/255)
plt.show()
data = data.expand_dims(axis=0)
return net.predict(data.asnumpy().tolist())
我检查了 data.asnumpy().tolist()
没问题,然后 pyplot 绘制图像(第一个是原始图像,第二个是调整大小的图像)。但是 net.predict
引发错误:
---------------------------------------------------------------------------
JSONDecodeError Traceback (most recent call last)
<ipython-input-171-ea0f1f5bdc72> in <module>()
----> 1 predict_mx(predictor.predict, './data2/burgers-imgnet/00103785.jpg')
<ipython-input-170-150a72b14997> in predict_mx(net, fname)
30 plt.show()
31 data = data.expand_dims(axis=0)
---> 32 return net(data.asnumpy().tolist())
33
~/Projects/Lab/ML/AWS/v/lib64/python3.6/site-packages/sagemaker/predictor.py in predict(self, data)
89 if self.deserializer is not None:
90 # It's the deserializer's responsibility to close the stream
---> 91 return self.deserializer(response_body, response['ContentType'])
92 data = response_body.read()
93 response_body.close()
~/Projects/Lab/ML/AWS/v/lib64/python3.6/site-packages/sagemaker/predictor.py in __call__(self, stream, content_type)
290 """
291 try:
--> 292 return json.load(codecs.getreader('utf-8')(stream))
293 finally:
294 stream.close()
/usr/lib64/python3.6/json/__init__.py in load(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
297 cls=cls, object_hook=object_hook,
298 parse_float=parse_float, parse_int=parse_int,
--> 299 parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
300
301
/usr/lib64/python3.6/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
352 parse_int is None and parse_float is None and
353 parse_constant is None and object_pairs_hook is None and not kw):
--> 354 return _default_decoder.decode(s)
355 if cls is None:
356 cls = JSONDecoder
/usr/lib64/python3.6/json/decoder.py in decode(self, s, _w)
337
338 """
--> 339 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
340 end = _w(s, end).end()
341 if end != len(s):
/usr/lib64/python3.6/json/decoder.py in raw_decode(self, s, idx)
355 obj, end = self.scan_once(s, idx)
356 except StopIteration as err:
--> 357 raise JSONDecodeError("Expecting value", s, err.value) from None
358 return obj, end
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
我尝试 json.dumps 我的数据,没有问题。
请注意,我还没有在 AWS 上部署该服务,我希望能够在本地测试模型和预测,然后再制作更大的火车并稍后提供服务。
感谢您的帮助
您对从笔记本传递到预测环境(在 docker 中)的数据进行反序列化时遇到问题,但我无法根据提供的代码重现此问题。使用 MXNet 估计器(例如 from sagemaker.mxnet import MXNet
)时,您可以在入口点脚本中实现 transform_fn
以反序列化数据并使用模型进行预测。在函数的开头使用 json.loads
,如下例所示;
def transform_fn(net, data, input_content_type, output_content_type):
"""
Transform a request using the Gluon model. Called once per request.
:param net: The Gluon model.
:param data: The request payload.
:param input_content_type: The request content type.
:param output_content_type: The (desired) response content type.
:return: response payload and content type.
"""
# we can use content types to vary input/output handling, but
# here we just assume json for both
parsed = json.loads(data)
nda = mx.nd.array(parsed)
output = net(nda)
prediction = mx.nd.argmax(output, axis=1)
response_body = json.dumps(prediction.asnumpy().tolist()[0])
return response_body, output_content_type
如果您在使用 json.loads
命令时仍有问题,您应该检查 data
的值,并仔细查找与编码相关的问题(即以 \
开头的字符串)这是无效的)。
注意:您在函数和堆栈跟踪中也有不同的代码,因此您可能想要确认自己 运行 与您认为的 运行 一样。你提到你还没有部署(本地或实例),但这是预测所必需的。
对 net.predict 的调用工作正常。
您似乎正在使用 SageMaker Python SDK predict_fn 进行托管。调用 predict_fn 后,MXNet 容器将尝试将您的预测序列化为 JSON,然后再将其发送回客户端。您可以在此处查看执行此操作的代码:https://github.com/aws/sagemaker-mxnet-container/blob/master/src/mxnet_container/serve/transformer.py#L132
容器无法序列化,因为 net.predict 不是 return 可序列化的对象。您可以通过 returning 列表来解决此问题:
return net.predict(data.asnumpy().tolist()).asnumpy().tolist()
另一种方法是使用 transform_fn 而不是 prediction_fn 这样您就可以处理输出序列化你自己。您可以在此处 https://github.com/aws/sagemaker-python-sdk/blob/e93eff66626c0ab1f292048451c4c3ac7c39a121/examples/cli/host/script.py#L41
查看 transform_fn 的示例
我正在尝试在 Sagemaker 实例上的 MXNet 上制作迁移学习方法。训练和服务在本地开始没有任何问题,我正在使用 python 代码来预测:
def predict_mx(net, fname):
with open(fname, 'rb') as f:
img = image.imdecode(f.read())
plt.imshow(img.asnumpy())
plt.show()
data = transform(img, -1, test_augs)
plt.imshow(data.transpose((1,2,0)).asnumpy()/255)
plt.show()
data = data.expand_dims(axis=0)
return net.predict(data.asnumpy().tolist())
我检查了 data.asnumpy().tolist()
没问题,然后 pyplot 绘制图像(第一个是原始图像,第二个是调整大小的图像)。但是 net.predict
引发错误:
---------------------------------------------------------------------------
JSONDecodeError Traceback (most recent call last)
<ipython-input-171-ea0f1f5bdc72> in <module>()
----> 1 predict_mx(predictor.predict, './data2/burgers-imgnet/00103785.jpg')
<ipython-input-170-150a72b14997> in predict_mx(net, fname)
30 plt.show()
31 data = data.expand_dims(axis=0)
---> 32 return net(data.asnumpy().tolist())
33
~/Projects/Lab/ML/AWS/v/lib64/python3.6/site-packages/sagemaker/predictor.py in predict(self, data)
89 if self.deserializer is not None:
90 # It's the deserializer's responsibility to close the stream
---> 91 return self.deserializer(response_body, response['ContentType'])
92 data = response_body.read()
93 response_body.close()
~/Projects/Lab/ML/AWS/v/lib64/python3.6/site-packages/sagemaker/predictor.py in __call__(self, stream, content_type)
290 """
291 try:
--> 292 return json.load(codecs.getreader('utf-8')(stream))
293 finally:
294 stream.close()
/usr/lib64/python3.6/json/__init__.py in load(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
297 cls=cls, object_hook=object_hook,
298 parse_float=parse_float, parse_int=parse_int,
--> 299 parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
300
301
/usr/lib64/python3.6/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
352 parse_int is None and parse_float is None and
353 parse_constant is None and object_pairs_hook is None and not kw):
--> 354 return _default_decoder.decode(s)
355 if cls is None:
356 cls = JSONDecoder
/usr/lib64/python3.6/json/decoder.py in decode(self, s, _w)
337
338 """
--> 339 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
340 end = _w(s, end).end()
341 if end != len(s):
/usr/lib64/python3.6/json/decoder.py in raw_decode(self, s, idx)
355 obj, end = self.scan_once(s, idx)
356 except StopIteration as err:
--> 357 raise JSONDecodeError("Expecting value", s, err.value) from None
358 return obj, end
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
我尝试 json.dumps 我的数据,没有问题。
请注意,我还没有在 AWS 上部署该服务,我希望能够在本地测试模型和预测,然后再制作更大的火车并稍后提供服务。
感谢您的帮助
您对从笔记本传递到预测环境(在 docker 中)的数据进行反序列化时遇到问题,但我无法根据提供的代码重现此问题。使用 MXNet 估计器(例如 from sagemaker.mxnet import MXNet
)时,您可以在入口点脚本中实现 transform_fn
以反序列化数据并使用模型进行预测。在函数的开头使用 json.loads
,如下例所示;
def transform_fn(net, data, input_content_type, output_content_type):
"""
Transform a request using the Gluon model. Called once per request.
:param net: The Gluon model.
:param data: The request payload.
:param input_content_type: The request content type.
:param output_content_type: The (desired) response content type.
:return: response payload and content type.
"""
# we can use content types to vary input/output handling, but
# here we just assume json for both
parsed = json.loads(data)
nda = mx.nd.array(parsed)
output = net(nda)
prediction = mx.nd.argmax(output, axis=1)
response_body = json.dumps(prediction.asnumpy().tolist()[0])
return response_body, output_content_type
如果您在使用 json.loads
命令时仍有问题,您应该检查 data
的值,并仔细查找与编码相关的问题(即以 \
开头的字符串)这是无效的)。
注意:您在函数和堆栈跟踪中也有不同的代码,因此您可能想要确认自己 运行 与您认为的 运行 一样。你提到你还没有部署(本地或实例),但这是预测所必需的。
对 net.predict 的调用工作正常。
您似乎正在使用 SageMaker Python SDK predict_fn 进行托管。调用 predict_fn 后,MXNet 容器将尝试将您的预测序列化为 JSON,然后再将其发送回客户端。您可以在此处查看执行此操作的代码:https://github.com/aws/sagemaker-mxnet-container/blob/master/src/mxnet_container/serve/transformer.py#L132
容器无法序列化,因为 net.predict 不是 return 可序列化的对象。您可以通过 returning 列表来解决此问题:
return net.predict(data.asnumpy().tolist()).asnumpy().tolist()
另一种方法是使用 transform_fn 而不是 prediction_fn 这样您就可以处理输出序列化你自己。您可以在此处 https://github.com/aws/sagemaker-python-sdk/blob/e93eff66626c0ab1f292048451c4c3ac7c39a121/examples/cli/host/script.py#L41
查看 transform_fn 的示例