我想创建一个返回命名Tensor的模型签名(使用Keras),这就是我的意思。当模型部署到TF-Serving时,我希望它返回如下JSON:
{
"predictions": [
{
"t3": 19,
"t1": 76.975174,
"t2": "cat3"
},
{
"t3": 17,
"t1": 77.7983246,
"t2": "cat3"
}
]
}
最重要的是t1
,t2
,t3
,这是我命名的,如果我不命名,返回的JSON是这样的:
{
"predictions": [
{
"output_0": 77.5714188,
"output_1": "cat3",
"output_2": 17
},
{
"output_0": 80.7243729,
"output_1": "cat4",
"output_2": 17
}
]
}
output_0
、output_1
和output_2
是由某个组件自动生成的(不确定是哪一个,但我猜是TF或Keras)。
这是我目前掌握的情况:
from tensorflow.keras import layers
class OutputWithNames(layers.Layer):
def __init__(self):
super(OutputWithNames, self).__init__()
def call(self, x):
return {"t1": x[0], "t2": x[1], "t3": x[2]}
添加这个自定义层作为模型签名中的最后一个层,我得到了我所提到的内容:一个JSON对象,具有所需的属性名t1
、t2
和t3
。
使用saved_model_cli
工具检查保存的模型,当生成的模型按预期工作时,我得到的输出签名如下:
The given SavedModel SignatureDef contains the following output(s):
outputs['t1'] tensor_info:
dtype: DT_FLOAT
shape: (-1)
name: StatefulPartitionedCall_1:0
outputs['t2'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: StatefulPartitionedCall_1:1
outputs['t3'] tensor_info:
dtype: DT_INT32
shape: (-1)
name: StatefulPartitionedCall_1:2
再说一次,到目前为止一切都很好。但是当我只有一个输出时:
from tensorflow.keras import layers
class OutputWithNames(layers.Layer):
def __init__(self):
super(OutputWithNames, self).__init__()
def call(self, x):
return {"t1": x}
注:在第一个代码块中,x
是一个Tensor列表,因为我有多个输出。这就是为什么我可以/必须使用x[0]
。但在第二个代码块中,x
只是一个Tensor,因为只有一个输出。这就是为什么在x
前面没有[]
。
这一次,TF-Serving将为我生成这个JSON:
{
"predictions": [
67.2723083,
68.9468231
]
}
虽然这是我期待看到的:
{
"predictions": [
{
"t1": 67.2723083
},
{
"t1": 68.9468231
}
]
}
下面是saved_model_cli
工具返回的结果:
The given SavedModel SignatureDef contains the following output(s):
outputs['t1'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: StatefulPartitionedCall:0
基本上,保存的模型已经为输出正确设置了名称,但是由于某种原因,TF-Serving将其剥离,并且它只返回值,而不是返回对象数组。
我的问题是,当只有一个输出时,如何强制TF-Serving返回一个对象列表?
1条答案
按热度按时间tjrkku2a1#
答案是,如果不改变TF Serving的实现方式,就无法实现。TF Serving文档中指出:
...如果模型的输出只包含一个命名的Tensor,我们忽略名称和
predictions
键Map到标量或列表值的列表。如果模型输出多个命名的Tensor,我们输出对象的列表,类似于上面提到的行格式的请求。如果您事先不知道要使用什么模型(以及预期输出),我的建议是:
1.解析返回的JSON
predictions
对象。1.检查JSON数组是否包含值或对象。
1.如果它返回值,就知道所用模型的输出只包含一个命名Tensor,因此可以为
"t1"
单独制定任何想要使用的逻辑。1.如果它返回对象,那么您就知道所用模型的输出包含多个命名Tensor,每个Tensor都具有您已经设置的名称(例如
"t3"
、"t1"
、"t2"
)。或者,如果您可以向输出添加一个额外的(任意的)Tensor,例如,通过定义一个特定的Predict SignatureDef,这可能会允许您强制TF Serving返回一个对象列表,但显然其中一个对象将是任意的,您可以忽略其名称。
预测SignatureDefs还允许您向输出添加可选的附加Tensor,您可以显式查询这些Tensor。假设除了下面的scores输出键之外,您还希望获取池层以用于调试或其他目的。在这种情况下,您只需添加一个具有类似pool的键和适当值的附加Tensor。
我对定义或实现这样的签名并不熟悉,但如果前面提到的基本解析方法在您的情况下不可行,希望这能提供另一个方向。