映射TF2 keras模型的最佳实践是什么;TFX管道中TF服务分类/预测/回归API的签名?
我们正在建立一个基于气流的自动TFX管道,并以我们的模型为基础。我们将keras模型保存如下:映射TF2 keras模型的最佳实践是什么;TFX管道中TF服务分类/预测/回归API的签名?,keras,tensorflow2.0,tfx,Keras,Tensorflow2.0,Tfx,我们正在建立一个基于气流的自动TFX管道,并以我们的模型为基础。我们将keras模型保存如下: model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures, ) 签名是: signatures = { 'serving_default': _get_serve_tf_examples_fn(model, tf_transfo
model.save(fn_args.serving_model_dir, save_format='tf',
signatures=signatures,
)
签名是:
signatures = {
'serving_default':
_get_serve_tf_examples_fn(model, tf_transform_output) \
.get_concrete_function(
tf.TensorSpec(
shape=[None],
dtype=tf.string,
name='examples'
)
),
'prediction':
get_request_url_fn(model, tf_transform_output) \
.get_concrete_function(
tf.TensorSpec(
shape=[None],
dtype=tf.string,
name='prediction_examples'
)
),
}
_get_serve_tf_examples_fn用于为TFX评估器组件提供额外的张量,这些张量不用于模型评估目的。如上面的Keras TFX教程所示:
def _get_serve_tf_examples_fn(model, tf_transform_output):
model.tft_layer = tf_transform_output.transform_features_layer()
@tf.function
def serve_tf_examples_fn(serialized_tf_examples):
feature_spec = tf_transform_output.raw_feature_spec()
feature_spec.pop(_LABEL_KEY)
parsed_features = tf.io.parse_example(serialized_tf_examples, feature_spec)
transformed_features = model.tft_layer(parsed_features)
transformed_features.pop(_transformed_name(_LABEL_KEY))
return model(transformed_features)
return serve_tf_examples_fn
上述模型“接口”接受TFX评估器组件(TFMA)所需的TF.Examples
然而,对于TF服务,我们希望能够向TF服务预测REST API发送1个原始字符串(只是一个url),并获得预测分数。目前,get\u request\u url\u fn
是:
def get_request_url_fn(model, tf_transform_output):
model.tft_layer = tf_transform_output.transform_features_layer()
@tf.function
def serve_request_url_fn(request_url):
feature_spec = tf_transform_output.raw_feature_spec()
# Model requires just one of the features made available to other TFX components
# Throw away the rest and leave just 'request_url'
feature_spec = {'request_url': feature_spec['request_url']}
parsed_features = tf.io.parse_example(request_url, feature_spec)
transformed_features = model.tft_layer(parsed_features)
transformed_features.pop(_transformed_name(_LABEL_KEY))
return model(transformed_features)
return serve_request_url_fn
这种方法仍然需要以TF的形式输入。这需要代表客户承担相当数量的管理费用。即,导入tensorflow
。但该代码确实有效:
url = f'http://{server}:8501/v1/models/wrcv3:predict'
headers = {"content-type": "application/json"}
url_request = b'index'
example = tf.train.Example(
features=tf.train.Features(
feature={"request_url":
tf.train.Feature(bytes_list=tf.train.BytesList(value=[url_request]))
}
)
)
print(example)
data = {
"signature_name":"prediction",
"instances":[
{
"prediction_examples":{"b64": base64.b64encode(example.SerializeToString()).decode('utf-8')}
}
]
}
data = json.dumps(data)
print(data)
json_response = requests.post(url, data=data, headers=headers)
print(json_response.content)
print(json_response.json)
结果是:
features {
feature {
key: "request_url"
value {
bytes_list {
value: "index"
}
}
}
}
{"signature_name": "prediction", "instances": [{"prediction_examples": {"b64": "ChoKGAoLcmVxdWVzdF91cmwSCQoHCgVpbmRleA=="}}]}
b'{\n "predictions": [[0.897708654]\n ]\n}'
<bound method Response.json of <Response [200]>>
返回:
{"signature_name": "prediction", "instances": [{"prediction_examples": {"b64": "aW5kZXguaHRtbA=="}}]}
b'{ "error": "Could not parse example input, value: \\\'index.html\\\'\\n\\t [[{{node ParseExample/ParseExampleV2}}]]" }'
<bound method Response.json of <Response [400]>>
{“signature_name”:“prediction”,“instances”:[{“prediction_examples”:{“b64”:“aW5kZXguaHRtbA==”}}]}
b“{”错误“:“无法分析示例输入,值:\\\\'index.html\\\\\\\\\n\\t[{{node ParseExample/ParseExampleV2}}]]””
问题是:要接受原始字符串,signaturedef/签名应该是什么样子?如果不喜欢get\u request\u url\u fn
。当然,客户端不应该仅仅为了发出请求而加载TF
TFX网站本身详细记录了分类/预测/回归的3个protobuf,但(对我来说)如何使用这3个protobuf进行我们需要的映射并不直观
提前深表感谢。根据您的代码,函数SERVICE\u request\u url\u fn的输入是一个密集张量,但您的变换图的输入可能是一个稀疏张量
函数tf.io.parse_example知道如何将tf.example反序列化为稀疏张量,但如果要发送张量而不序列化,则应手动将其转换为稀疏张量,并停止使用tf.io.parse函数
例如:
@tf.function(input_signature=[tf.TensorSpec(shape=(None),dtype=tf.string,name='examples'))
def SERVICE_request_url_fn(自我,请求url):
请求\u url\u sp\u tensor=tf.sparse.SparseTensor(
指数=[[0,0]],
值=请求\ url,
密集_形=(1,1)
)
已解析的_特征={
“请求url”:请求url张量,
}
转换的\u功能=self.model.tft\u示例\u层(解析的\u功能)
转换的\u要素.pop(\u转换的\u名称(\u标签\u键))
返回self.model(转换的特征)
Hi@Crinela,谢谢你的评论,当我尝试上面的功能时,它只在一个数据输入上工作,如果我有多个数据输入怎么办。我应该如何调整函数?谢谢你应该把所有的绳子都放进SparseTensor里。我有一个可能的建议:def serve_raw_list_fn(self,request_url):v=tf.where(tf.not_equal(request_url,“”)z=tf.zeros(tf.shape(v),dtype=tf.dtypes.int64)idx=tf.concat([v,z],axis=1)request_url_sp_tensor=tf.SparseTensor(idx,request\u url,(tf.shape(request\u url,out\u type=tf.int64)[0],1])解析的\u特性={'request\u url':request\u url\u sp\u tensor,}
{"signature_name": "prediction", "instances": [{"prediction_examples": {"b64": "aW5kZXguaHRtbA=="}}]}
b'{ "error": "Could not parse example input, value: \\\'index.html\\\'\\n\\t [[{{node ParseExample/ParseExampleV2}}]]" }'
<bound method Response.json of <Response [400]>>