You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过gRPC获取TensorFlow Serving模型的可解析元数据?

问题描述

用户在使用TensorFlow Serving运行多个模型时,希望模型具备自描述性——让下游调用服务无需硬编码输入尺寸等信息,实现模型替换时不用更新下游系统。但通过gRPC调用元数据API获取签名定义时,返回的响应无法正常解析;而模型本身可以正常工作,使用saved_model_cli工具也能正常返回签名定义。另外用REST API调用元数据API是正常的,用户希望解决gRPC方式下的解析问题。

用户后来意识到响应数据是Protocol Buffer编码的消息,尝试用text_format.Parse解析却报错:ParseError: 2:1 : '>': Expected identifier or number, got >.

用户提供的saved_model_cli输出:

$ saved_model_cli show --dir mymodel.pb/ --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:
signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['input_data'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, -1, 286339)
        name: input:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['output/Softmax:0'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 286338)
        name: output/Softmax:0
  Method name is: tensorflow/serving/predict

用户调用gRPC元数据API的代码:

from tensorflow_serving.apis import get_model_metadata_pb2
import grpc
import tensorflow as tf
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
from tensorflow.contrib import util

MODEL_URI = '10.100.55.9:8500'
channel = grpc.insecure_channel(MODEL_URI)
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = get_model_metadata_pb2.GetModelMetadataRequest()
request.model_spec.name = 'themodel'
request.model_spec.signature_name = 'serving_default'
request.metadata_field.append('signature_def')
result = stub.GetModelMetadata(request, 1.0)

返回的result.metadata['signature_def']内容:

type_url: "type.googleapis.com/tensorflow.serving.SignatureDefMap"
value: "\n>\n\025__saved_model_init_op\022%\022#\n\025__saved_model_init_op\022\n\n\004NoOp\032\002\030\001\n\271\001\n\017serving_default\022\245\001\nJ\n\007input_1\022?\n\031serving_default_input_1:0\020\001\032 \022\013\010\377\377\377\377\377\377\377\377\377\001\022\013\010\377\377\377\377\377\377\377\377\377\001\022\004\010\224\261\021\022;\n\005dense\0222\n\031StatefulPartitionedCall:0\020\001\032\023\022\013\010\377\377\377\377\377\377\377\377\377\001\022\004\010\223\261\021\032\032tensorflow/serving/predict"
解决方法

你遇到的核心问题是用错了Protobuf的解析方式——text_format.Parse用于解析文本格式的Protobuf消息,但result.metadata['signature_def'].value是二进制编码的Protobuf数据,所以必须用ParseFromString方法来解析。

修改后的完整代码如下:

from tensorflow_serving.apis import get_model_metadata_pb2
import grpc
from tensorflow_serving.apis import prediction_service_pb2_grpc

MODEL_URI = '10.100.55.9:8500'
channel = grpc.insecure_channel(MODEL_URI)
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)

# 构建元数据请求
request = get_model_metadata_pb2.GetModelMetadataRequest()
request.model_spec.name = 'themodel'
# 不需要指定signature_name,这样可以获取所有签名定义;如果只需要特定签名可以加上
# request.model_spec.signature_name = 'serving_default'
request.metadata_field.append('signature_def')

# 获取元数据响应
result = stub.GetModelMetadata(request, 1.0)

# 解析二进制的SignatureDefMap
sig_def_map = get_model_metadata_pb2.SignatureDefMap()
sig_def_map.ParseFromString(result.metadata['signature_def'].value)

# 现在可以正常访问签名定义的结构化数据了
# 比如打印serving_default签名的输入输出信息
serving_sig = sig_def_map.signature_def['serving_default']
print("输入信息:")
for name, tensor_info in serving_sig.inputs.items():
    print(f"  名称:{name}")
    print(f"  张量名:{tensor_info.name}")
    print(f"  数据类型:{tensor_info.dtype}")
    print(f"  形状:{tensor_info.shape}")

print("\n输出信息:")
for name, tensor_info in serving_sig.outputs.items():
    print(f"  名称:{name}")
    print(f"  张量名:{tensor_info.name}")
    print(f"  数据类型:{tensor_info.dtype}")
    print(f"  形状:{tensor_info.shape}")

print(f"\n方法名:{serving_sig.method_name}")

这样处理后,你就能得到和saved_model_cli输出一致的结构化签名信息,下游系统可以直接读取输入输出的形状、类型等元数据,实现模型的自描述调用,后续替换模型时也无需修改下游代码。

内容的提问来源于stack exchange,提问作者josephkibe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:31:42