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

将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:17:34