TensorFlow Serving是独立C++服务进程,不可用import导入;必须将模型保存为SavedModel格式(如./model/1),通过Docker启动并严格匹配挂载路径、MODEL_NAME与端口配置,再用REST或gRPC调用。

tensorflow_model_server 不是 Python 库,不能用 import 导入;它是一个独立的 C++ 服务进程。你在 Python 中能做的,是「准备模型」和「调用服务」——不是运行 Serving 本身。
模型必须保存为 SavedModel 格式才能被 TensorFlow Serving 加载
TensorFlow Serving 只认 SavedModel 目录结构,不支持 HDF5(.h5)、checkpoint 或自定义序列化格式。
常见错误现象:
- 启动时提示
Failed to load servable或No versions of servable found - 目录里只有
model.h5,但 Serving 一直报错找不到版本
正确做法:
- 用
model.save(export_path, save_format='tf')(TF 2.x 推荐) -
export_path必须是形如./my_model/1的路径,末尾数字是版本号(正整数) - 该路径下必须包含
saved_model.pb和variables/子目录 - 不要手动改名或压缩这个目录;Serving 会扫描子目录名是否为纯数字来识别版本
示例:
import tensorflow as tf
from tensorflow.keras.applications import ResNet50
<p>model = ResNet50(weights='imagenet')
model.save('./resnet50/1', save_format='tf') # 注意:末尾是 '1',不是 'v1' 或 'version1'
</p>
Docker 启动时挂载路径和环境变量必须严格匹配
错误配置导致最常见的问题是 404 Not Found 或 Connection refused,其实服务根本没起来,或者模型压根没加载。
关键点:
-
--mount type=bind,source=$(pwd)/resnet50,target=/models/resnet50:宿主机路径要绝对或相对于当前 shell,target必须是/models/xxx,其中xxx是你的模型名 -
-e MODEL_NAME=resnet50:必须与target中的模型名一致(即/models/resnet50的最后一段) -
-p 8501:8501:REST API 默认端口;若改了--rest_api_port,客户端也要同步改 - 不要漏掉
tensorflow/serving镜像 tag;生产建议显式指定版本,如tensorflow/serving:2.18.0
启动命令示例:
docker run -p 8501:8501 \ --mount type=bind,source=$(pwd)/resnet50,target=/models/resnet50 \ -e MODEL_NAME=resnet50 \ -t tensorflow/serving:2.18.0
验证是否加载成功:查看容器日志中是否有类似 Running gRPC ModelServer at 0.0.0.0:8500 ... 和 Exporting HTTP/REST API at: localhost:8501,以及 Successfully loaded servable。
Python 客户端发 REST 请求要注意输入张量名和 shape
TensorFlow Serving 的 REST API 不接受任意 JSON,必须按模型签名(signature_def)组织请求体。很多失败源于 inputs 字段名写错,或数据 shape 不匹配。
常见错误现象:
-
400 Bad Request提示JSON Parse error或Expected string for input -
500 Internal Server Error报Invalid argument: Input to reshape is a tensor with 3 values, but the requested shape has 4
解决方法:
- 先查签名:
curl http://localhost:8501/v1/models/resnet50看signature_def中的inputs键名(通常是input_1或serving_default下的具体名) - 图像模型通常要求
uint8、[1, H, W, 3]的 batched 形状;用tf.io.encode_jpeg或np.expand_dims(..., axis=0)处理 - 发送时用
"instances"(非"inputs")包裹 list of dict,每个 dict key 是张量名,value 是嵌套 list(不是 numpy array)
示例(ResNet50):
import json
import numpy as np
import requests
<h1>假设 img_array 是 (224, 224, 3) uint8 numpy 数组</h1><p>instances = [img_array.tolist()] # 注意:tolist() 转成 Python list,且外层包一层 list 表示 batch=1</p><p>data = json.dumps({"instances": instances})
headers = {"content-type": "application/json"}
response = requests.post(
'<a href="https://www.php.cn/link/7cf64721b76a6355fe9ee5a3ba6b72d6">https://www.php.cn/link/7cf64721b76a6355fe9ee5a3ba6b72d6</a>',
data=data,
headers=headers
)
</p>
注意::predict 后缀不能省;如果模型有多个 signature,需在 URL 中指定,如 /v1/models/resnet50/signatures/classify:predict。
gRPC 比 REST 更快,但 Python 客户端需要额外生成 stub
如果你对延迟敏感(比如毫秒级响应),gRPC 是更优选择,但它不像 REST 那样开箱即用。
关键差异:
- REST 使用 HTTP/JSON,调试方便,但序列化/解析开销大;gRPC 使用 Protocol Buffers + HTTP/2,二进制传输,性能高 2–5 倍
- Python 客户端必须先用
protoc编译tensorflow_serving/apis/prediction_service.proto生成 Python stub(prediction_service_pb2_grpc.py) - 你需要手动构造
predict_pb2.PredictRequest,设置model_spec.name、inputs['input_1'].CopyFrom(tf.make_ndarray(...)),比 REST 繁琐得多 - 依赖
grpcio和tensorflow-serving-api(注意:这个 PyPI 包仅含 proto stub,不含服务端)
真正容易被忽略的一点:Serving 默认只监听 0.0.0.0:8500(gRPC)和 0.0.0.0:8501(REST)。如果你在容器外访问,确保 Docker 的 -p 映射正确,且宿主机防火墙没拦 8500 端口。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











