mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-18 18:52:16 +00:00
566 lines
13 KiB
ReStructuredText
566 lines
13 KiB
ReStructuredText
.. note::
|
|
:class: sphx-glr-download-link-note
|
|
|
|
Click :ref:`here <sphx_glr_download_auto_examples_plot_train_convert_predict.py>` to download the full example code
|
|
.. rst-class:: sphx-glr-example-title
|
|
|
|
.. _sphx_glr_auto_examples_plot_train_convert_predict.py:
|
|
|
|
|
|
|
|
.. _l-logreg-example:
|
|
|
|
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.
|
|
|
|
.. contents::
|
|
:local:
|
|
|
|
Train a logistic regression
|
|
+++++++++++++++++++++++++++
|
|
|
|
The first step consists in retrieving the iris datset.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
from sklearn.datasets import load_iris
|
|
iris = load_iris()
|
|
X, y = iris.data, iris.target
|
|
|
|
from sklearn.model_selection import train_test_split
|
|
X_train, X_test, y_train, y_test = train_test_split(X, y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Then we fit a model.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
from sklearn.linear_model import LogisticRegression
|
|
clr = LogisticRegression()
|
|
clr.fit(X_train, y_train)
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
c:\users\hasesh\appdata\local\programs\python\python36\lib\site-packages\sklearn\linear_model\logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.
|
|
FutureWarning)
|
|
c:\users\hasesh\appdata\local\programs\python\python36\lib\site-packages\sklearn\linear_model\logistic.py:469: FutureWarning: Default multi_class will be changed to 'auto' in 0.22. Specify the multi_class option to silence this warning.
|
|
"this warning.", FutureWarning)
|
|
|
|
|
|
|
|
We compute the prediction on the test set
|
|
and we show the confusion matrix.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
from sklearn.metrics import confusion_matrix
|
|
|
|
pred = clr.predict(X_test)
|
|
print(confusion_matrix(y_test, pred))
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
[[14 0 0]
|
|
[ 0 9 4]
|
|
[ 0 1 10]]
|
|
|
|
|
|
|
|
Conversion to ONNX format
|
|
+++++++++++++++++++++++++
|
|
|
|
We use module
|
|
`sklearn-onnx <https://github.com/onnx/sklearn-onnx>`_
|
|
to convert the model into ONNX format.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
from skl2onnx import convert_sklearn
|
|
from skl2onnx.common.data_types import FloatTensorType
|
|
|
|
initial_type = [('float_input', FloatTensorType([1, 4]))]
|
|
onx = convert_sklearn(clr, initial_types=initial_type)
|
|
with open("logreg_iris.onnx", "wb") as f:
|
|
f.write(onx.SerializeToString())
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
|
|
|
|
|
|
We load the model with ONNX Runtime and look at
|
|
its input and output.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
import onnxruntime as rt
|
|
sess = rt.InferenceSession("logreg_iris.onnx")
|
|
|
|
print("input name='{}' and shape={}".format(sess.get_inputs()[0].name, sess.get_inputs()[0].shape))
|
|
print("output name='{}' and shape={}".format(sess.get_outputs()[0].name, sess.get_outputs()[0].shape))
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
input name='float_input' and shape=[1, 4]
|
|
output name='output_label' and shape=[1]
|
|
|
|
|
|
|
|
We compute the predictions.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
input_name = sess.get_inputs()[0].name
|
|
label_name = sess.get_outputs()[0].name
|
|
|
|
import numpy
|
|
pred_onx = sess.run([label_name], {input_name: X_test.astype(numpy.float32)})[0]
|
|
print(confusion_matrix(pred, pred_onx))
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
[[14 0 0]
|
|
[ 0 10 0]
|
|
[ 0 0 14]]
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
prob_sklearn = clr.predict_proba(X_test)
|
|
print(prob_sklearn[:3])
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
[[0.02503056 0.43689584 0.53807361]
|
|
[0.00202039 0.19895737 0.79902224]
|
|
[0.01142149 0.64908707 0.33949145]]
|
|
|
|
|
|
|
|
And then with ONNX Runtime.
|
|
The probabilies appear to be
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
prob_name = sess.get_outputs()[1].name
|
|
prob_rt = sess.run([prob_name], {input_name: X_test.astype(numpy.float32)})[0]
|
|
|
|
import pprint
|
|
pprint.pprint(prob_rt[0:3])
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
[{0: 0.025030435994267464, 1: 0.4368962347507477, 2: 0.5380733609199524},
|
|
{0: 0.002020390471443534, 1: 0.1989573985338211, 2: 0.7990221977233887},
|
|
{0: 0.011421487666666508, 1: 0.6490871906280518, 2: 0.3394913375377655}]
|
|
|
|
|
|
|
|
Let's benchmark.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
from timeit import Timer
|
|
|
|
def speed(inst, number=10, repeat=20):
|
|
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("Average %1.3g min=%1.3g max=%1.3g" % (ave, mi, ma))
|
|
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]")
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
Execution time for clr.predict
|
|
Average 4.86e-05 min=4.49e-05 max=8.59e-05
|
|
Execution time for ONNX Runtime
|
|
Average 0.00163 min=0.00118 max=0.0024
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
def loop(X_test, fct, n=None):
|
|
nrow = X_test.shape[0]
|
|
if n is None:
|
|
n = nrow
|
|
for i in range(0, n):
|
|
im = i % nrow
|
|
fct(X_test[im: im+1])
|
|
|
|
print("Execution time for clr.predict")
|
|
speed("loop(X_test, clr.predict, 100)")
|
|
|
|
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, 100)")
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
Execution time for clr.predict
|
|
Average 0.00537 min=0.00411 max=0.017
|
|
Execution time for sess_predict
|
|
Average 0.00241 min=0.0015 max=0.00453
|
|
|
|
|
|
|
|
Let's do the same for the probabilities.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
print("Execution time for predict_proba")
|
|
speed("loop(X_test, clr.predict_proba, 100)")
|
|
|
|
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, 100)")
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
Execution time for predict_proba
|
|
Average 0.00673 min=0.00536 max=0.0101
|
|
Execution time for sess_predict_proba
|
|
Average 0.00159 min=0.00148 max=0.00184
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
from sklearn.ensemble import RandomForestClassifier
|
|
rf = RandomForestClassifier()
|
|
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())
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
c:\users\hasesh\appdata\local\programs\python\python36\lib\site-packages\sklearn\ensemble\forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
|
|
"10 in version 0.20 to 100 in 0.22.", FutureWarning)
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
|
|
|
|
|
|
We compare.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
sess = rt.InferenceSession("rf_iris.onnx")
|
|
|
|
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, 100)")
|
|
|
|
print("Execution time for sess_predict_proba")
|
|
speed("loop(X_test, sess_predict_proba_rf, 100)")
|
|
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
Execution time for predict_proba
|
|
Average 0.0881 min=0.0836 max=0.111
|
|
Execution time for sess_predict_proba
|
|
Average 0.00222 min=0.0016 max=0.00379
|
|
|
|
|
|
|
|
Let's see with different number of trees.
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
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("rf_iris_%d.onnx" % n_trees, "wb") as f:
|
|
f.write(onx.SerializeToString())
|
|
sess = rt.InferenceSession("rf_iris_%d.onnx" % n_trees)
|
|
def sess_predict_proba_loop(x):
|
|
return sess.run([prob_name], {input_name: x.astype(numpy.float32)})[0]
|
|
tsk = speed("loop(X_test, rf.predict_proba, 100)", number=5, repeat=5)
|
|
trt = speed("loop(X_test, sess_predict_proba_loop, 100)", number=5, repeat=5)
|
|
measures.append({'n_trees': n_trees, 'sklearn': tsk, 'rt': trt})
|
|
|
|
from pandas import DataFrame
|
|
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()
|
|
|
|
|
|
|
|
.. image:: /auto_examples/images/sphx_glr_plot_train_convert_predict_001.png
|
|
:class: sphx-glr-single-img
|
|
|
|
|
|
.. rst-class:: sphx-glr-script-out
|
|
|
|
Out:
|
|
|
|
.. code-block:: none
|
|
|
|
5
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.0557 min=0.054 max=0.06
|
|
Average 0.00168 min=0.00152 max=0.00199
|
|
10
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.0966 min=0.0881 max=0.106
|
|
Average 0.00167 min=0.00158 max=0.00185
|
|
15
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.121 min=0.119 max=0.126
|
|
Average 0.00199 min=0.00172 max=0.00227
|
|
20
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.156 min=0.15 max=0.164
|
|
Average 0.00227 min=0.00172 max=0.00346
|
|
25
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.189 min=0.184 max=0.192
|
|
Average 0.00191 min=0.0018 max=0.00217
|
|
30
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.212 min=0.202 max=0.238
|
|
Average 0.00191 min=0.00181 max=0.00196
|
|
35
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.245 min=0.232 max=0.26
|
|
Average 0.002 min=0.00194 max=0.00212
|
|
40
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.318 min=0.28 max=0.427
|
|
Average 0.00287 min=0.00252 max=0.00322
|
|
45
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.36 min=0.308 max=0.484
|
|
Average 0.00481 min=0.00458 max=0.00519
|
|
50
|
|
The maximum opset needed by this model is only 9.
|
|
The maximum opset needed by this model is only 1.
|
|
Average 0.491 min=0.428 max=0.539
|
|
Average 0.00233 min=0.00206 max=0.00259
|
|
|
|
|
|
|
|
|
|
.. rst-class:: sphx-glr-timing
|
|
|
|
**Total running time of the script:** ( 1 minutes 20.485 seconds)
|
|
|
|
|
|
.. _sphx_glr_download_auto_examples_plot_train_convert_predict.py:
|
|
|
|
|
|
.. only :: html
|
|
|
|
.. container:: sphx-glr-footer
|
|
:class: sphx-glr-footer-example
|
|
|
|
|
|
|
|
.. container:: sphx-glr-download
|
|
|
|
:download:`Download Python source code: plot_train_convert_predict.py <plot_train_convert_predict.py>`
|
|
|
|
|
|
|
|
.. container:: sphx-glr-download
|
|
|
|
:download:`Download Jupyter notebook: plot_train_convert_predict.ipynb <plot_train_convert_predict.ipynb>`
|
|
|
|
|
|
.. only:: html
|
|
|
|
.. rst-class:: sphx-glr-signature
|
|
|
|
`Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
|