注意
转到末尾 下载完整的示例代码。
将onnx节点附加到转换后的模型¶
本示例展示了如何将一些onnx节点附加到转换后的模型以生成所需的输出。在这种情况下,它删除了输出概率的第二列。
为了完全准确,大部分代码都是使用LLM生成的,并进行了修改以适应最新变化。
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnx
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y)
clr = LogisticRegression(max_iter=500)
clr.fit(X_train, y_train)
model_to_convert 指要转换的scikit-learn分类器。
model_to_convert = clr # model to convert
X_test = X_test[:1] # data used to test or train, one row is enough
设置修改后的ONNX模型的输出文件名
output_filename = "output_file.onnx" # Replace with your desired output filename
步骤 1:将模型转换为ONNX格式,禁用标签输出。定义ONNX模型的输入类型。输入类型是具有形状[None, X_test.shape[1]]的浮点张量,其中None表示输入样本的数量可以是灵活的,而X_test.shape[1]是每个输入样本的特征数量。“张量”本质上是多维数组,在机器学习中常用于表示数据。“浮点张量”专门包含浮点数,即带小数的数字。
initial_type = [("float_input", FloatTensorType([None, X_test.shape[1]]))]
将模型转换为ONNX格式。- target_opset=18 指定要使用的ONNX算子的版本。- options={…} 设置转换的参数
“zipmap”: False 确保输出是原始数组
而是概率而不是字典。
“output_class_labels”: False 确保输出仅包含概率,而不包含类标签。
ONNX(Open Neural Network Exchange)是一种表示机器学习模型的开放格式。它允许多种机器学习框架之间的互操作性,从而可以在各种平台上使用模型。
onx = convert_sklearn(
model_to_convert,
initial_types=initial_type,
target_opset={"": 18, "ai.onnx.ml": 3},
options={
id(model_to_convert): {"zipmap": False, "output_class_labels": False}
}, # Ensures the output is only probabilities, not labels
)
步骤 2:加载ONNX模型以进行进一步修改(如果需要)。从序列化的字符串表示加载ONNX模型。ONNX文件本质上是机器学习模型的序列化表示,可以在不同系统之间共享和使用。
onnx_model = onnx.load_model_from_string(onx.SerializeToString())
假设模型中的第一个输出应该是概率张量。提取表示概率的输出张量的名称。如果有多个输出,则选择第二个,否则选择第一个。
prob_output_name = (
onnx_model.graph.output[1].name
if len(onnx_model.graph.output) > 1
else onnx_model.graph.output[0].name
)
添加一个Gather节点来仅提取正类(索引1)的概率。创建一个张量来指定要收集的索引(索引1),它代表正类。
indices = onnx.helper.make_tensor(
"indices", onnx.TensorProto.INT64, (1,), [1]
) # Index 1 to gather positive class
在ONNX图中创建一个“Gather”节点来提取正类的概率。- inputs: [prob_output_name, “indices”] 指定输入
到此节点(概率张量和索引张量)。
outputs: [“positive_class_prob”] 指定此节点的输出名称。
axis=1 表示沿概率张量的列(特征)进行收集。
“Gather”节点用于从张量中提取特定元素。在这里,它提取正类的概率。
gather_node = onnx.helper.make_node(
"Gather",
inputs=[prob_output_name, "indices"],
outputs=["positive_class_prob"],
axis=1, # Gather along columns (axis 1)
)
将Gather节点添加到ONNX图中
onnx_model.graph.node.append(gather_node)
input: "probabilities"
input: "indices"
output: "positive_class_prob"
op_type: "Gather"
attribute {
name: "axis"
i: 1
type: INT
}
为索引添加张量初始化器(Gather节点需要)ONNX中的初始化器用于定义计算中使用的常量张量。
onnx_model.graph.initializer.append(indices)
dims: 1
data_type: 7
int64_data: 1
name: "indices"
删除现有输出,仅添加正类概率的新输出。清除现有输出定义,用新的输出替换它们。
del onnx_model.graph.output[:]
为正类概率定义新输出。创建一个名为“positive_class_prob”的新输出张量规范。
positive_class_output = onnx.helper.make_tensor_value_info(
"positive_class_prob", onnx.TensorProto.FLOAT, [None, 1]
)
onnx_model.graph.output.append(positive_class_output)
name: "positive_class_prob"
type {
tensor_type {
elem_type: 1
shape {
dim {
}
dim {
dim_value: 1
}
}
}
}
步骤 3:保存修改后的ONNX模型。将修改后的ONNX模型保存到指定的输出文件名。然后,可以在支持ONNX的不同环境(如推理服务器或其他机器学习框架)中加载和使用生成的ONNX文件。
onnx.save(onnx_model, output_filename)
模型可以按如下方式打印。
print(onnx.printer.to_text(onnx_model))
<
ir_version: 8,
opset_import: ["ai.onnx.ml" : 1, "" : 18, "" : 18],
producer_name: "skl2onnx",
producer_version: "1.19.1",
domain: "ai.onnx",
model_version: 0,
doc_string: ""
>
"05f01d3ce40e4d9d969b78b0be9e706d" (float[?,4] float_input) => (float[?,1] positive_class_prob)
<int64[1] indices = {1}>
{
[LinearClassifier] label, probability_tensor = ai.onnx.ml.LinearClassifier <classlabels_ints: ints = [0, 1, 2], coefficients: floats = [-0.426998, 0.909799, -2.30715, -1.00512, 0.559776, -0.434449, -0.268645, -0.704307, -0.132778, -0.47535, 2.5758, 1.70943], intercepts: floats = [9.22076, 2.16403, -11.3848], multi_class: int = 1, post_transform: string = "SOFTMAX"> (float_input)
[Normalizer] probabilities = ai.onnx.ml.Normalizer <norm: string = "L1"> (probability_tensor)
positive_class_prob = Gather <axis: int = 1> (probabilities, indices)
}
脚本总运行时间: (0 分钟 0.059 秒)