mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-26 22:35:43 +00:00
### Description This PR is to update the win-ort-main branch to the tip main branch as of 2025-01-16. ### Motivation and Context This update includes the OpenVino fix for debug builds. --------- Signed-off-by: Liqun Fu <liqfu@microsoft.com> Signed-off-by: Liqun Fu <liqun.fu@microsoft.com> Signed-off-by: Junze Wu <junze.wu@intel.com> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Jianhui Dai <jianhui.j.dai@intel.com> Co-authored-by: Yueqing Zhang <yuz75@Pitt.edu> Co-authored-by: amancini-N <63410090+amancini-N@users.noreply.github.com> Co-authored-by: Adrian Lizarraga <adlizarraga@microsoft.com> Co-authored-by: liqun Fu <liqfu@microsoft.com> Co-authored-by: Guenther Schmuelling <guschmue@microsoft.com> Co-authored-by: Yifan Li <109183385+yf711@users.noreply.github.com> Co-authored-by: yf711 <yifanl@microsoft.com> Co-authored-by: Wanming Lin <wanming.lin@intel.com> Co-authored-by: wejoncy <wejoncy@163.com> Co-authored-by: wejoncy <wejoncy@.com> Co-authored-by: Scott McKay <skottmckay@gmail.com> Co-authored-by: Changming Sun <chasun@microsoft.com> Co-authored-by: Jean-Michaël Celerier <jeanmichael.celerier+github@gmail.com> Co-authored-by: Dmitry Deshevoy <mityada@gmail.com> Co-authored-by: xhcao <xinghua.cao@intel.com> Co-authored-by: Yueqing Zhang <yueqingz@amd.com> Co-authored-by: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Co-authored-by: Jiajia Qin <jiajiaqin@microsoft.com> Co-authored-by: Wu, Junze <junze.wu@intel.com> Co-authored-by: Jian Chen <cjian@microsoft.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com> Co-authored-by: Prathik Rao <prathik.rao@gmail.com> Co-authored-by: wonchung-microsoft <wonchung@microsoft.com> Co-authored-by: Vincent Wang <wangwchpku@outlook.com> Co-authored-by: PARK DongHa <luncliff@gmail.com> Co-authored-by: Hector Li <hecli@microsoft.com> Co-authored-by: Sam Webster <13457618+samwebster@users.noreply.github.com> Co-authored-by: Adrian Lizarraga <adrianlm2@gmail.com> Co-authored-by: Preetha Veeramalai <preetha.veeramalai@intel.com> Co-authored-by: jatinwadhwa921 <jatin.wadhwa@intel.com> Co-authored-by: Satya Kumar Jandhyala <satya.k.jandhyala@gmail.com> Co-authored-by: Corentin Maravat <101636442+cocotdf@users.noreply.github.com> Co-authored-by: Xiaoyu <85524621+xiaoyu-work@users.noreply.github.com> Co-authored-by: Tianlei Wu <tlwu@microsoft.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jie Chen <jie.a.chen@intel.com> Co-authored-by: Jianhui Dai <jianhui.j.dai@intel.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com> Co-authored-by: Baiju Meswani <bmeswani@microsoft.com> Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com> Co-authored-by: Justin Chu <justinchuby@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Ted Themistokleous <107195283+TedThemistokleous@users.noreply.github.com> Co-authored-by: Jeff Daily <jeff.daily@amd.com> Co-authored-by: Artur Wojcik <artur.wojcik@outlook.com> Co-authored-by: Ted Themistokleous <tedthemistokleous@amd.com> Co-authored-by: Xinya Zhang <Xinya.Zhang@amd.com> Co-authored-by: ikalinic <ilija.kalinic@amd.com> Co-authored-by: sstamenk <sstamenk@amd.com> Co-authored-by: Yi-Hong Lyu <yilyu@microsoft.com> Co-authored-by: Ti-Tai Wang <titaiwang@microsoft.com>
234 lines
6.8 KiB
Python
234 lines
6.8 KiB
Python
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
# Licensed under the MIT License.
|
|
# pylint: disable=C0411,C0412,C0413
|
|
|
|
"""
|
|
|
|
.. _l-logreg-example-speed:
|
|
|
|
Train, convert and predict with ONNX Runtime
|
|
============================================
|
|
|
|
This example demonstrates an end to end scenario
|
|
starting with the training of a machine learned model
|
|
to its use in its converted from.
|
|
|
|
Train a logistic regression
|
|
+++++++++++++++++++++++++++
|
|
|
|
The first step consists in retrieving the iris datset.
|
|
"""
|
|
|
|
from sklearn.datasets import load_iris
|
|
from sklearn.linear_model import LogisticRegression
|
|
from sklearn.model_selection import train_test_split
|
|
|
|
iris = load_iris()
|
|
X, y = iris.data, iris.target
|
|
X_train, X_test, y_train, y_test = train_test_split(X, y)
|
|
|
|
####################################
|
|
# Then we fit a model.
|
|
|
|
clr = LogisticRegression()
|
|
clr.fit(X_train, y_train)
|
|
|
|
####################################
|
|
# We compute the prediction on the test set
|
|
# and we show the confusion matrix.
|
|
from sklearn.metrics import confusion_matrix # noqa: E402
|
|
|
|
pred = clr.predict(X_test)
|
|
print(confusion_matrix(y_test, pred))
|
|
|
|
####################################
|
|
# Conversion to ONNX format
|
|
# +++++++++++++++++++++++++
|
|
#
|
|
# We use module
|
|
# `sklearn-onnx <https://github.com/onnx/sklearn-onnx>`_
|
|
# to convert the model into ONNX format.
|
|
|
|
from skl2onnx import convert_sklearn # noqa: E402
|
|
from skl2onnx.common.data_types import FloatTensorType # noqa: E402
|
|
|
|
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())
|
|
|
|
##################################
|
|
# We load the model with ONNX Runtime and look at
|
|
# its input and output.
|
|
|
|
import onnxruntime as rt # noqa: E402
|
|
|
|
sess = rt.InferenceSession("logreg_iris.onnx", providers=rt.get_available_providers())
|
|
|
|
print(f"input name='{sess.get_inputs()[0].name}' and shape={sess.get_inputs()[0].shape}")
|
|
print(f"output name='{sess.get_outputs()[0].name}' and shape={sess.get_outputs()[0].shape}")
|
|
|
|
##################################
|
|
# We compute the predictions.
|
|
|
|
input_name = sess.get_inputs()[0].name
|
|
label_name = sess.get_outputs()[0].name
|
|
|
|
import numpy # noqa: E402
|
|
|
|
pred_onx = sess.run([label_name], {input_name: X_test.astype(numpy.float32)})[0]
|
|
print(confusion_matrix(pred, pred_onx))
|
|
|
|
###################################
|
|
# The prediction are perfectly identical.
|
|
#
|
|
# Probabilities
|
|
# +++++++++++++
|
|
#
|
|
# Probabilities are needed to compute other
|
|
# relevant metrics such as the ROC Curve.
|
|
# Let's see how to get them first with
|
|
# scikit-learn.
|
|
|
|
prob_sklearn = clr.predict_proba(X_test)
|
|
print(prob_sklearn[:3])
|
|
|
|
#############################
|
|
# And then with ONNX Runtime.
|
|
# The probabilies appear to be
|
|
|
|
prob_name = sess.get_outputs()[1].name
|
|
prob_rt = sess.run([prob_name], {input_name: X_test.astype(numpy.float32)})[0]
|
|
|
|
import pprint # noqa: E402
|
|
|
|
pprint.pprint(prob_rt[0:3])
|
|
|
|
###############################
|
|
# Let's benchmark.
|
|
from timeit import Timer # noqa: E402
|
|
|
|
|
|
def speed(inst, number=5, repeat=10):
|
|
timer = Timer(inst, globals=globals())
|
|
raw = numpy.array(timer.repeat(repeat, number=number))
|
|
ave = raw.sum() / len(raw) / number
|
|
mi, ma = raw.min() / number, raw.max() / number
|
|
print(f"Average {ave:1.3g} min={mi:1.3g} max={ma:1.3g}")
|
|
return ave
|
|
|
|
|
|
print("Execution time for clr.predict")
|
|
speed("clr.predict(X_test)")
|
|
|
|
print("Execution time for ONNX Runtime")
|
|
speed("sess.run([label_name], {input_name: X_test.astype(numpy.float32)})[0]")
|
|
|
|
###############################
|
|
# Let's benchmark a scenario similar to what a webservice
|
|
# experiences: the model has to do one prediction at a time
|
|
# as opposed to a batch of prediction.
|
|
|
|
|
|
def loop(X_test, fct, n=None):
|
|
nrow = X_test.shape[0]
|
|
if n is None:
|
|
n = nrow
|
|
for i in range(n):
|
|
im = i % nrow
|
|
fct(X_test[im : im + 1])
|
|
|
|
|
|
print("Execution time for clr.predict")
|
|
speed("loop(X_test, clr.predict, 50)")
|
|
|
|
|
|
def sess_predict(x):
|
|
return sess.run([label_name], {input_name: x.astype(numpy.float32)})[0]
|
|
|
|
|
|
print("Execution time for sess_predict")
|
|
speed("loop(X_test, sess_predict, 50)")
|
|
|
|
#####################################
|
|
# Let's do the same for the probabilities.
|
|
|
|
print("Execution time for predict_proba")
|
|
speed("loop(X_test, clr.predict_proba, 50)")
|
|
|
|
|
|
def sess_predict_proba(x):
|
|
return sess.run([prob_name], {input_name: x.astype(numpy.float32)})[0]
|
|
|
|
|
|
print("Execution time for sess_predict_proba")
|
|
speed("loop(X_test, sess_predict_proba, 50)")
|
|
|
|
#####################################
|
|
# This second comparison is better as
|
|
# ONNX Runtime, in this experience,
|
|
# computes the label and the probabilities
|
|
# in every case.
|
|
|
|
##########################################
|
|
# Benchmark with RandomForest
|
|
# +++++++++++++++++++++++++++
|
|
#
|
|
# We first train and save a model in ONNX format.
|
|
from sklearn.ensemble import RandomForestClassifier # noqa: E402
|
|
|
|
rf = RandomForestClassifier(n_estimators=10)
|
|
rf.fit(X_train, y_train)
|
|
|
|
initial_type = [("float_input", FloatTensorType([1, 4]))]
|
|
onx = convert_sklearn(rf, initial_types=initial_type)
|
|
with open("rf_iris.onnx", "wb") as f:
|
|
f.write(onx.SerializeToString())
|
|
|
|
###################################
|
|
# We compare.
|
|
|
|
sess = rt.InferenceSession("rf_iris.onnx", providers=rt.get_available_providers())
|
|
|
|
|
|
def sess_predict_proba_rf(x):
|
|
return sess.run([prob_name], {input_name: x.astype(numpy.float32)})[0]
|
|
|
|
|
|
print("Execution time for predict_proba")
|
|
speed("loop(X_test, rf.predict_proba, 50)")
|
|
|
|
print("Execution time for sess_predict_proba")
|
|
speed("loop(X_test, sess_predict_proba_rf, 50)")
|
|
|
|
##################################
|
|
# Let's see with different number of trees.
|
|
|
|
measures = []
|
|
|
|
for n_trees in range(5, 51, 5):
|
|
print(n_trees)
|
|
rf = RandomForestClassifier(n_estimators=n_trees)
|
|
rf.fit(X_train, y_train)
|
|
initial_type = [("float_input", FloatTensorType([1, 4]))]
|
|
onx = convert_sklearn(rf, initial_types=initial_type)
|
|
with open(f"rf_iris_{n_trees}.onnx", "wb") as f:
|
|
f.write(onx.SerializeToString())
|
|
sess = rt.InferenceSession(f"rf_iris_{n_trees}.onnx", providers=rt.get_available_providers())
|
|
|
|
def sess_predict_proba_loop(x):
|
|
return sess.run([prob_name], {input_name: x.astype(numpy.float32)})[0] # noqa: B023
|
|
|
|
tsk = speed("loop(X_test, rf.predict_proba, 25)", number=5, repeat=4)
|
|
trt = speed("loop(X_test, sess_predict_proba_loop, 25)", number=5, repeat=4)
|
|
measures.append({"n_trees": n_trees, "sklearn": tsk, "rt": trt})
|
|
|
|
from pandas import DataFrame # noqa: E402
|
|
|
|
df = DataFrame(measures)
|
|
ax = df.plot(x="n_trees", y="sklearn", label="scikit-learn", c="blue", logy=True)
|
|
df.plot(x="n_trees", y="rt", label="onnxruntime", ax=ax, c="green", logy=True)
|
|
ax.set_xlabel("Number of trees")
|
|
ax.set_ylabel("Prediction time (s)")
|
|
ax.set_title("Speed comparison between scikit-learn and ONNX Runtime\nFor a random forest on Iris dataset")
|
|
ax.legend()
|