映射TF2 keras模型的最佳实践是什么;TFX管道中TF服务分类/预测/回归API的签名?

映射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

我们正在建立一个基于气流的自动TFX管道,并以我们的模型为基础。我们将keras模型保存如下:

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]>>