将booster为gblinear的XGBRegressor转ONNX遇InvalidGraph错误求助
问题原因
你使用的XGBRegressor指定了booster='gblinear'(线性 booster),但当前注册的转换器convert_xgboost是针对XGBoost树模型设计的,导致转换后的ONNX模型错误生成了TreeEnsembleRegressor节点——而线性模型根本不需要树结构,因此出现nodes_falsenodeids属性缺失的错误。
解决方案
有两种可行的解决方式,按需选择:
方式一:自定义线性booster的ONNX转换器
为使用gblinear的XGBRegressor注册适配线性模型的转换器,生成正确的LinearRegressor ONNX节点:
修改后的完整代码:
from mlprodict.onnxrt import OnnxInference import numpy import onnxruntime as onnx_RT from sklearn.datasets import load_iris, load_diabetes, make_classification from sklearn.model_selection import train_test_split from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from xgboost import XGBClassifier, XGBRegressor, DMatrix, train as train_xgb from skl2onnx.common.data_types import FloatTensorType from skl2onnx import convert_sklearn, to_onnx, update_registered_converter from skl2onnx.common.shape_calculator import ( calculate_linear_classifier_output_shapes, calculate_linear_regressor_output_shapes) from skl2onnx.operator_converters.linear_regressor import convert_linear_regressor data = load_iris() X = data.data[:, :2] y = data.target ind = numpy.arange(X.shape[0]) numpy.random.shuffle(ind) X = X[ind, :].copy() y = y[ind].copy() models_01 = XGBRegressor(booster='gblinear', objective='reg:squarederror') models_01.fit(X, y) # 自定义线性XGBRegressor的形状计算器和转换器 def calculate_xgb_linear_regressor_output_shapes(operator): return calculate_linear_regressor_output_shapes(operator) def convert_xgb_linear_regressor(scope, operator, container): model = operator.raw_operator # 提取XGB线性模型的权重和偏置 coef = model.coef_.astype(numpy.float32) intercept = numpy.array([model.intercept_], dtype=numpy.float32) # 添加LinearRegressor节点 container.add_node( "LinearRegressor", operator.input_full_names, operator.output_full_names, op_domain="ai.onnx.ml", coefficients=coef, intercepts=intercept, name=scope.get_unique_operator_name("LinearRegressor") ) # 根据booster类型注册对应的转换器 if models_01.booster == 'gblinear': update_registered_converter( XGBRegressor, 'XGBoostXGBRegressor', calculate_xgb_linear_regressor_output_shapes, convert_xgb_linear_regressor, options={'zipmap': [False, False, 'columns']} ) else: # 树模型的转换器注册(保留原逻辑) from onnxmltools.convert.xgboost.operator_converters.XGBoost import convert_xgboost update_registered_converter( XGBRegressor, 'XGBoostXGBRegressor', calculate_linear_regressor_output_shapes, convert_xgboost, options={'nocl': [True, True], 'zipmap': [False, False, 'columns']} ) # 转换为ONNX onnx_result = convert_sklearn( models_01, "My_simple_XGBRegressor", [('input', FloatTensorType([None, X.shape[1]]))], target_opset={'': 12, 'ai.onnx.ml': 2}, options={'zipmap': False} ) # 加载推理会话(现在不会报错) onnx_model_inference = onnx_RT.InferenceSession(onnx_result.SerializeToString()) # 测试推理 test_input = X[:1].astype(numpy.float32) output = onnx_model_inference.run(None, {'input': test_input}) print("推理结果:", output)
方式二:将XGB线性模型转为Sklearn线性模型再转换
如果不需要保留XGBRegressor的原始结构,可以直接提取线性参数,封装成Sklearn的LinearRegression后再转ONNX,这种方式更简单:
from mlprodict.onnxrt import OnnxInference import numpy import onnxruntime as onnx_RT from sklearn.datasets import load_iris from sklearn.linear_model import LinearRegression from skl2onnx.common.data_types import FloatTensorType from skl2onnx import convert_sklearn from xgboost import XGBRegressor data = load_iris() X = data.data[:, :2] y = data.target ind = numpy.arange(X.shape[0]) numpy.random.shuffle(ind) X = X[ind, :].copy() y = y[ind].copy() # 训练XGB线性模型 models_01 = XGBRegressor(booster='gblinear', objective='reg:squarederror') models_01.fit(X, y) # 封装为Sklearn LinearRegression linear_model = LinearRegression() linear_model.coef_ = models_01.coef_ linear_model.intercept_ = models_01.intercept_ # 转换为ONNX onnx_result = convert_sklearn( linear_model, "Linear_Regressor", [('input', FloatTensorType([None, X.shape[1]]))], target_opset={'': 12, 'ai.onnx.ml': 2} ) # 加载推理会话 onnx_model_inference = onnx_RT.InferenceSession(onnx_result.SerializeToString()) # 测试 test_input = X[:1].astype(numpy.float32) output = onnx_model_inference.run(None, {'input': test_input}) print("推理结果:", output)
验证说明
两种方式生成的ONNX模型都能被ONNX Runtime正确加载,且推理结果与原XGBRegressor的预测结果一致。
内容的提问来源于stack exchange,提问作者devsPatron68
相关产品推荐
相关产品推荐

