使用BentoML部署含分类特征的CatBoostClassifier遇报错求助
解决CatBoost + BentoML服务的分类特征类型不匹配问题
问题根源
直接加载模型预测正常,但BentoML服务中报错,核心原因是服务端接收的输入数据类型与训练时不匹配:
- 传字符串时,BentoML可能将其转为字节格式(
b'Tertiary'),被CatBoost误判为数值特征尝试转float失败; - 传数字时,CatBoost识别到该特征在模型中是分类类型,但输入被标记为数值类型,触发兼容性校验报错。
可行解决方案
方案1:在BentoML服务中显式处理输入,用CatBoost Pool包装数据
在服务代码中,将输入数据转为DataFrame,并明确指定分类特征列,再用catboost.Pool包装后传入模型,确保特征类型与训练时一致:
import bentoml import pandas as pd from catboost import CatBoostClassifier, Pool # 加载保存的CatBoost模型 catboost_model = bentoml.catboost.load_model("catboost_classifier:latest") @bentoml.service class CatBoostPredictionService: @bentoml.api(input=bentoml.io.JSON(), output=bentoml.io.JSON()) def predict(self, input_data: dict): # 将输入转为DataFrame,保证road_type为object类型 df = pd.DataFrame([input_data]) # 明确指定分类特征列,和训练时一致 categorical_features = ["road_type"] # 用Pool包装数据 pool = Pool(df, cat_features=categorical_features) # 预测 result = catboost_model.predict(pool) return {"prediction": result.tolist()}
方案2:将预处理逻辑与模型打包为Pipeline
用sklearn.pipeline.Pipeline把「分类特征类型转换」和CatBoost模型绑定,再保存整个Pipeline到BentoML,确保服务端自动执行一致的预处理:
import bentoml import pandas as pd from sklearn.pipeline import Pipeline from sklearn.preprocessing import FunctionTransformer from catboost import CatBoostClassifier # 定义预处理函数:确保road_type为object类型 def ensure_categorical_type(df): df["road_type"] = df["road_type"].astype(object) return df # 创建Pipeline preprocessor = FunctionTransformer(ensure_categorical_type) model = CatBoostClassifier(cat_features=["road_type"]) # 假设已经完成模型训练 # model.fit(X_train, y_train) pipeline = Pipeline([ ("preprocess", preprocessor), ("classifier", model) ]) # 保存Pipeline到BentoML bentoml.sklearn.save_model("catboost_pipeline", pipeline) # 服务端加载Pipeline并预测 @bentoml.service class CatBoostPipelineService: @bentoml.api(input=bentoml.io.JSON(), output=bentoml.io.JSON()) def predict(self, input_data: dict): df = pd.DataFrame([input_data]) result = self.model.predict(df) return {"prediction": result.tolist()} def __init__(self): self.model = bentoml.sklearn.load_model("catboost_pipeline:latest")
方案3:调整BentoML的输入格式,直接接收DataFrame类型
使用bentoml.io.PandasDataFrame作为输入类型,避免JSON转义导致的类型问题:
import bentoml from catboost import CatBoostClassifier catboost_model = bentoml.catboost.load_model("catboost_classifier:latest") @bentoml.service class CatBoostPredictionService: @bentoml.api(input=bentoml.io.PandasDataFrame(), output=bentoml.io.JSON()) def predict(self, input_df): # 直接用DataFrame预测,训练时指定的cat_features会生效 result = catboost_model.predict(input_df) return {"prediction": result.tolist()}
调用服务时,直接以DataFrame的格式(比如CSV或JSON数组)传入,确保road_type列的类型为字符串。
内容的提问来源于stack exchange,提问作者andreigeorgiu
相关产品推荐
相关产品推荐

