sklearn-onnx只支持scikit-learn的模型转换.而 onnxmltools 可用于 libsvm , lightgbm , _xgboost_的模型转换.
其它的ONNX模型转换工具:github/onnx , torch.onnx , ONNX-MXNet API , Microsoft.ML.Onnx …
支持的模型 Supported scikit-learn Models - sklearn-onnx 1.18.0 documentation
安装 1 mamba install skl2onnx onnxruntime
入门 1 2 3 4 5 6 7 8 9 10 11 12 # 训练模型 import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier iris = load_iris() X, y = iris.data, iris.target X = X.astype(np.float32) X_train, X_test, y_train, y_test = train_test_split(X, y) clr = RandomForestClassifier() clr.fit(X_train, y_train)
将模型转为ONNX类型 1 2 3 4 5 6 7 8 from skl2onnx import to_onnx # 将clr这个模型转为onnx模型,并用X的第一行进行类型推断 onx = to_onnx(clr, X[:1]) # 打开并保存文件 with open("rf_iris.onnx", "wb") as f: f.write(onx.SerializeToString())
加载模型,推理 1 2 3 4 5 6 7 8 9 import onnxruntime as rt # 加载rf_iris.onnx这个路径的模型,推理后端设置为CPU sess = rt.InferenceSession("rf_iris.onnx", providers=["CPUExecutionProvider"]) # 获取输入和输出节点名称 input_name = sess.get_inputs()[0].name label_name = sess.get_outputs()[0].name # 推理X_test,设置列名 pred_onx = sess.run([label_name], {input_name: X_test.astype(np.float32)})[0]
convert_sklearn和to_onnx convert_sklearn是原来的函数,需要手动指定输入类型和大小;而to_onnx自动从dataframe或ndarray推断 大小和类型. convert_sklearn的用法:
1 2 3 4 5 6 7 8 from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType # 输入叫'float_input',类型为FloatTensorType,行数为None,即未知需要推断多少行,列数为4(特征维度) initial_type = [('float_input', FloatTensorType([None, 4]))] onx = convert_sklearn(clr, initial_types=initial_type) with open("logreg_iris.onnx", "wb") as f: f.write(onx.SerializeToString())
查看支持的硬件 硬件在此指示:sess = rt.InferenceSession(“rf_iris.onnx”, providers=[“CPUExecutionProvider”]),查看providers:
1 2 print(f'所有的硬件:{rt.get_all_providers()}') print(f'可用的硬件:{rt.get_available_providers()}')
如果你在providers
列表中指定了多个提供者,ONNX Runtime会尝试按照列表中的顺序使用这些提供者来执行模型。
具体来说,当你有多个提供者时,ONNX Runtime会逐个尝试使用它们:
首先,ONNX Runtime会尝试使用列表中指定的第一个提供者来加载和执行模型。如果这个提供者可用(即相应的硬件或软件环境已就绪),并且模型可以成功在该提供者上执行,那么ONNX Runtime就会使用这个提供者来运行模型的推理。
如果第一个提供者不可用(比如因为硬件不支持、驱动未安装等原因),ONNX Runtime会尝试列表中的下一个提供者。这个过程会一直继续,直到找到一个可用的提供者或者列表中所有的提供者都尝试过了。
使用sklearn.pipeline创建流程,从三个分类器投票获得结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import numpy from onnxruntime import InferenceSession from sklearn.datasets import load_diabetes from sklearn.ensemble import ( GradientBoostingRegressor, RandomForestRegressor, VotingRegressor, ) from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.pipeline import Pipeline from skl2onnx import to_onnx from onnx.reference import ReferenceEvaluator X, y = load_diabetes(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split(X, y) # Train classifiers reg1 = GradientBoostingRegressor(random_state=1, n_estimators=5) reg2 = RandomForestRegressor(random_state=1, n_estimators=5) reg3 = LinearRegression() ereg = Pipeline( steps=[ ("voting", VotingRegressor([("gb", reg1), ("rf", reg2), ("lr", reg3)])), ] ) ereg.fit(X_train, y_train)
1 2 3 4 5 6 7 8 9 10 # 保存ONNX模型 onx = to_onnx(ereg, X_train[:1].astype(numpy.float32), target_opset=12) sess = InferenceSession(onx.SerializeToString(), providers=["CPUExecutionProvider"]) # 使用ONNX预测 pred_ort = sess.run(None, {"X": X_test.astype(numpy.float32)})[0] # 使用sklearn pipeline预测 pred_skl = ereg.predict(X_test.astype(numpy.float32)) print("Onnx Runtime prediction:\n", pred_ort[:5]) print("Sklearn rediction:\n", pred_skl[:5])
撰写diff函数对比结果 1 2 3 4 5 6 7 def diff(p1, p2):# 返回最大绝对值误差,和使用原始序列的绝对值归一化后的最大误差 p1 = p1.ravel() p2 = p2.ravel() d = numpy.abs(p2 - p1) return d.max(), (d / numpy.abs(p1)).max() print(diff(pred_skl, pred_ort))
可以直接使用ReferenceEvaluator从一个onnx对象创建参考评估器,从而对比推理精度 1 2 3 oinf = ReferenceEvaluator(onx) pred_pyrt = oinf.run(None, {"X": X_test.astype(numpy.float32)})[0] print(diff(pred_skl, pred_pyrt))
当输入是Dataframe类型时 管道通常接收矩阵格式的数据(ndarray),如果所有数据共享相同的类型,则可以在矩阵中使用数据。但df中保存的数据通常有多种类型,float、integer或字符串表示类别。ONNX也支持df。