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

Docker部署MediaPipe Hands模型后调用MLFlow API遇400错误排查

MediaPipe Hands模型MLFlow Docker部署HTTP 400错误解决

问题背景

测试将MediaPipe Hands模型通过MLFlow部署至Docker环境,模型预期输入为{'input_1': img},其中img是形状为(1,224,224,3)的float32类型4维numpy数组。本地测试模型预测正常,但通过requests调用部署后的API时持续触发HTTP 400错误。已知MLFlow API仅支持四种输入格式,由于输入是4维数组,只能选择符合TF Serving API规范的Tensor输入,但多次尝试仍未解决。

重现步骤(已完成操作)

1. 模型转ONNX格式

因MLFlow不支持tflite模型,使用tf2onnx转换:

pip install tensorflow onnxruntime tf2onnx
import tf2onnx
tf2onnx.convert.from_tflite("hand_model/hand_landmark_full.tflite", output_path="hand_model/hand_landmark_full2.onnx");

2. MLFlow中记录模型

pip install mlflow onnx
import mlflow
import onnx
import os
from mlflow.tracking import MlflowClient

mlflow_client = MlflowClient()
EXPERIMENT_NAME = "ONNX_Hand"
experiment_details = mlflow_client.get_experiment_by_name(EXPERIMENT_NAME)

if experiment_details is not None:
    experiment_id = experiment_details.experiment_id
else:
    experiment_id = mlflow.create_experiment(EXPERIMENT_NAME)
with mlflow.start_run(experiment_id=experiment_id, run_name="handdatasetrfrun") as run:
    model = onnx.load("./onnx/hand_landmark_full2.onnx")
    mlflow.onnx.log_model(model, artifact_path="model")
run_id = run.info.run_id
print('Run ID: {}'.format(run_id))

3. 本地测试模型

处理图片并验证预测正常:

import mlflow
import numpy as np
import cv2

# 读取并处理图片
img = cv2.imread("hand.JPG")
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
resized_img = cv2.resize(RGB_img, dsize=(224,224))
image_data = cv2.flip(resized_img, 1)
float_image = image_data.astype(np.float32)
im = np.array([np.divide(float_image,255)])
print(im.shape)

logged_model = 'C:/Workspace/MLFrameworks/mpHanddetection/mlruns/1/9a44d5671a6140988fbafaa939c6f9d9/artifacts/model'
loaded_model = mlflow.pyfunc.load_model(logged_model)
data = {'input_1': im}

predictions = loaded_model.predict(data)
print(predictions)

4. 构建Docker镜像并运行

mlflow models build-docker -m "C:/Workspace/MLFrameworks/mpHanddetection/mlruns/1/9a44d5671a6140988fbafaa939c6f9d9/artifacts/model" -n "handmodel"
docker run -p 5001:8080 "handmodel"

运行时出现numpy相关警告,暂不影响服务启动。

5. API调用错误复现

import cv2
import requests
import numpy as np

img = cv2.imread("C:/Workspace/MLFrameworks/mpHanddetection/hand.JPG")
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
resized_img = cv2.resize(RGB_img, dsize=(224,224))
image_data = cv2.flip(resized_img, 1)
float_image = image_data.astype(np.float32)
im = np.divide([float_image],255)

headers = {"content-type": "application/json"}
response = requests.post(url="http://127.0.0.1:5001/invocations",   
                        data={"inputs":{'input_1': im}},
                        headers=headers)
print(response.raise_for_status())

错误日志:

requests.exceptions.HTTPError: 400 Client Error: BAD REQUEST for url: http://127.0.0.1:5001/invocations

问题原因

  1. 请求格式错误:直接将numpy数组放入字典传递给requests.post的data参数,numpy数组无法被正确序列化为JSON,且data参数传字典默认会以form-data格式发送,而非JSON格式。
  2. 未遵循TF Serving Tensor格式:MLFlow要求Tensor输入需符合TF Serving的规范,需明确指定张量的dtype和shape,并将数组转为列表。

解决方法

修改API调用代码,按照TF Serving的JSON格式构造请求体,并用json.dumps序列化后发送:

import cv2
import requests
import numpy as np
import json

# 图片处理部分不变
img = cv2.imread("C:/Workspace/MLFrameworks/mpHanddetection/hand.JPG")
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
resized_img = cv2.resize(RGB_img, dsize=(224,224))
image_data = cv2.flip(resized_img, 1)
float_image = image_data.astype(np.float32)
im = np.divide([float_image], 255)

# 构造符合TF Serving规范的请求体
input_data = {
    "inputs": {
        "input_1": {
            "dtype": "float32",
            "shape": im.shape,
            "data": im.flatten().tolist()
        }
    }
}

# 使用json参数自动序列化并发送请求
response = requests.post(
    url="http://127.0.0.1:5001/invocations",
    json=input_data
)

# 检查响应
if response.status_code == 200:
    predictions = response.json()
    print(predictions)
else:
    print(f"Error: {response.status_code}, {response.text}")

关键说明

  • 使用json参数而非data参数:requests.post的json参数会自动将字典序列化为JSON字符串,并设置正确的Content-Type头,无需手动指定headers。
  • 张量格式要求:必须包含dtype(与模型输入类型一致,此处为float32)、shape(输入数组的形状,此处为(1,224,224,3))、data(数组扁平化后的列表,因为JSON不支持多维数组)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:46:00