轉換具有精簡運算子列表的模型

某些專用於 ONNX 的執行階段並未實作所有運算子,如果可用的運算子列表中缺少其中一個運算子,則轉換後的模型可能無法執行。如果使用者想要將某些運算子列入黑名單,某些轉換器可能會以不同的方式轉換模型。

GaussianMixture

第一個會根據運算子黑名單變更其行為的轉換器是針對模型 GaussianMixture

import onnxruntime
import onnx
import numpy
import os
from timeit import timeit
import numpy as np
import matplotlib.pyplot as plt
from onnx.tools.net_drawer import GetPydotGraph, GetOpNodeProducer
from onnxruntime import InferenceSession
from sklearn.mixture import GaussianMixture
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from skl2onnx import to_onnx

data = load_iris()
X_train, X_test = train_test_split(data.data)
model = GaussianMixture()
model.fit(X_train)
GaussianMixture()
在 Jupyter 環境中,請重新執行此儲存格以顯示 HTML 表示法,或信任筆記本。
在 GitHub 上,HTML 表示法無法呈現,請嘗試使用 nbviewer.org 載入此頁面。


預設轉換

model_onnx = to_onnx(
    model,
    X_train[:1].astype(np.float32),
    options={id(model): {"score_samples": True}},
    target_opset=12,
)
sess = InferenceSession(
    model_onnx.SerializeToString(), providers=["CPUExecutionProvider"]
)

xt = X_test[:5].astype(np.float32)
print(model.score_samples(xt))
print(sess.run(None, {"X": xt})[2])
[-1.55507181 -1.88300778 -3.57222331 -1.67405519 -1.85984688]
[[-1.5550716]
 [-1.8830082]
 [-3.572221 ]
 [-1.6740558]
 [-1.8598464]]

顯示 ONNX 圖形。

pydot_graph = GetPydotGraph(
    model_onnx.graph,
    name=model_onnx.graph.name,
    rankdir="TB",
    node_producer=GetOpNodeProducer(
        "docstring", color="yellow", fillcolor="yellow", style="filled"
    ),
)
pydot_graph.write_dot("mixture.dot")

os.system("dot -O -Gdpi=300 -Tpng mixture.dot")

image = plt.imread("mixture.dot.png")
fig, ax = plt.subplots(figsize=(40, 20))
ax.imshow(image)
ax.axis("off")
plot black op
(-0.5, 4796.5, 8425.5, -0.5)

不使用 ReduceLogSumExp 的轉換

參數 black_op 用於告知轉換器不要使用此運算子。讓我們看看在這種情況下轉換器會產生什麼。

model_onnx2 = to_onnx(
    model,
    X_train[:1].astype(np.float32),
    options={id(model): {"score_samples": True}},
    black_op={"ReduceLogSumExp"},
    target_opset=12,
)
sess2 = InferenceSession(
    model_onnx2.SerializeToString(), providers=["CPUExecutionProvider"]
)

xt = X_test[:5].astype(np.float32)
print(model.score_samples(xt))
print(sess2.run(None, {"X": xt})[2])
[-1.55507181 -1.88300778 -3.57222331 -1.67405519 -1.85984688]
[[-1.5550716]
 [-1.8830082]
 [-3.5722215]
 [-1.6740558]
 [-1.8598464]]

顯示 ONNX 圖形。

pydot_graph = GetPydotGraph(
    model_onnx2.graph,
    name=model_onnx2.graph.name,
    rankdir="TB",
    node_producer=GetOpNodeProducer(
        "docstring", color="yellow", fillcolor="yellow", style="filled"
    ),
)
pydot_graph.write_dot("mixture2.dot")

os.system("dot -O -Gdpi=300 -Tpng mixture2.dot")

image = plt.imread("mixture2.dot.png")
fig, ax = plt.subplots(figsize=(40, 20))
ax.imshow(image)
ax.axis("off")
plot black op
(-0.5, 4921.5, 13264.5, -0.5)

處理時間

print(
    timeit(
        stmt="sess.run(None, {'X': xt})", number=10000, globals={"sess": sess, "xt": xt}
    )
)

print(
    timeit(
        stmt="sess2.run(None, {'X': xt})",
        number=10000,
        globals={"sess2": sess2, "xt": xt},
    )
)
0.4618227000000843
0.5505055000000993

使用 ReduceLogSumExp 的模型速度快得多。

如果轉換器無法在沒有的情況下轉換...

許多轉換器不考慮運算子的白名單和黑名單。如果轉換器無法在不使用列入黑名單的運算子(或僅使用列入白名單的運算子)的情況下進行轉換,skl2onnx 會引發錯誤。

try:
    to_onnx(
        model,
        X_train[:1].astype(np.float32),
        options={id(model): {"score_samples": True}},
        black_op={"ReduceLogSumExp", "Add"},
        target_opset=12,
    )
except RuntimeError as e:
    print("Error:", e)
Error: Operator 'Add' is black listed.

此範例使用的版本

import sklearn  # noqa

print("numpy:", numpy.__version__)
print("scikit-learn:", sklearn.__version__)
import skl2onnx  # noqa

print("onnx: ", onnx.__version__)
print("onnxruntime: ", onnxruntime.__version__)
print("skl2onnx: ", skl2onnx.__version__)
numpy: 1.23.5
scikit-learn: 1.4.dev0
onnx:  1.15.0
onnxruntime:  1.16.0+cu118
skl2onnx:  1.15.0

指令碼總執行時間: (0 分鐘 31.602 秒)

由 Sphinx-Gallery 產生的展示