能否用TensorFlow Serving实现双向流式RPC分类?实现或扩展方案问询
我来帮你理清这个问题——首先明确一点:截至2024年,TensorFlow Serving并没有原生实现双向流式gRPC服务。你看到官方文档里提到的“streaming results”属于未来规划的改进方向,还没落地到正式发布的稳定版本中。目前TF Serving仅支持普通的请求-响应式Unary RPC,以及服务器单向推送结果的Server-side streaming,但没法处理像Google Cloud Speech API那样的双向流式场景(客户端持续发数据、服务器实时返回结果)。
接下来针对你的需求,分享几个最实用的落地方案:
一、最省心:在TF Serving之上封装自定义流式层
这个方案不用改动TF Serving本身,只需要在它外面套一层自己的双向流式gRPC服务,负责对接客户端的流式请求、分片处理数据,再调用TF Serving的标准接口完成推理,最后实时把结果推回去。具体步骤大概是这样:
- 定义自定义流式proto:写一个自己的gRPC proto文件,定义流式的输入(比如你的数据流分片)和输出(分类结果)结构。
- 编写流式服务端:
- 持续接收客户端发来的数据流分片,攒到一定量(比如每10个分片,或者达到模型要求的输入长度)就触发一次推理
- 把攒好的数据打包成TF Serving要求的
PredictRequest,调用它的gRPC接口 - 拿到推理结果后,立刻推送给客户端
- 客户端适配:编写对应的流式请求逻辑,持续发数据并接收实时结果
给你一段简化的Python伪代码参考(服务端核心逻辑):
import grpc import tensorflow as tf from tensorflow_serving.apis import predict_pb2, prediction_service_pb2_grpc # 导入你自己定义的流式proto生成的代码 from custom_streaming_proto import streaming_classification_pb2, streaming_classification_pb2_grpc class StreamingClassifier(streaming_classification_pb2_grpc.StreamingClassificationServicer): def __init__(self): # 连接到TF Serving的gRPC端口 self.tf_serving_stub = prediction_service_pb2_grpc.PredictionServiceStub( grpc.insecure_channel("tf-serving:8500") ) self.data_buffer = [] self.batch_size = 10 # 每攒10个分片做一次推理 def ClassifyStream(self, request_iterator, context): for req in request_iterator: # 把收到的分片加入缓冲区 self.data_buffer.extend(req.data_chunk) # 达到批量阈值就推理 if len(self.data_buffer) >= self.batch_size: # 构造TF Serving的请求 predict_req = predict_pb2.PredictRequest() predict_req.model_spec.name = "your_classification_model" predict_req.inputs["input_data"].CopyFrom( tf.make_tensor_proto(self.data_buffer, dtype=tf.float32) ) # 调用TF Serving predict_resp = self.tf_serving_stub.Predict(predict_req, timeout=10) # 解析结果并返回给客户端 pred_result = predict_resp.outputs["prediction"].float_val yield streaming_classification_pb2.ClassificationResponse(prediction=pred_result) # 清空缓冲区(如果是滑动窗口推理,可以只保留最后几个分片) self.data_buffer = [] # 处理最后一批不足batch_size的数据 if self.data_buffer: predict_req = predict_pb2.PredictRequest() predict_req.model_spec.name = "your_classification_model" predict_req.inputs["input_data"].CopyFrom( tf.make_tensor_proto(self.data_buffer, dtype=tf.float32) ) predict_resp = self.tf_serving_stub.Predict(predict_req, timeout=10) pred_result = predict_resp.outputs["prediction"].float_val yield streaming_classification_pb2.ClassificationResponse(prediction=pred_result)
二、换框架:直接用原生支持流式的推理服务
如果不想自己写封装层,也可以考虑切换到原生支持双向流式的推理框架,省掉很多开发工作:
- Triton Inference Server:NVIDIA做的通用推理框架,支持TensorFlow、PyTorch等多种模型格式,原生支持双向流式gRPC,只需要配置好模型的流式推理参数就能用
- TorchServe:PyTorch官方的推理服务,同样支持双向流式gRPC和HTTP/2流式,配置简单,对PyTorch模型友好(如果你的模型可以转成PyTorch格式的话)
- FastAPI + WebSockets:如果对gRPC没有硬性要求,用FastAPI的WebSocket实现双向流式通信,后端调用TF Serving完成推理,开发成本极低,适合快速迭代
三、进阶玩法:自定义TF Serving的Servable
如果你有C++开发经验,并且追求极致性能,可以直接修改TF Serving的源码,扩展它的Servable接口,实现支持双向流式的自定义Servable。不过这个方案门槛很高,需要对TF Serving的源码结构有深入了解,维护成本也大,一般只推荐给有特殊性能需求的场景。
总结
目前TF Serving原生不支持双向流式gRPC,最实用的方案是在它上面套一层自定义的流式gRPC服务,或者直接切换到Triton这类原生支持流式的框架。如果追求极致性能且有C++能力,可以考虑自定义Servable。
内容的提问来源于stack exchange,提问作者naktinis

