{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Memory usage\n", "\n", "The [first benchmark](http://www.xavierdupre.fr/app/_benchmarks/helpsphinx/sklbench_results/index.html) based on [scikti-learn's benchmark](https://github.com/jeremiedbb/scikit-learn_benchmarks) shows high peaks of memory usage for the python runtime on linear models. Let's see how to measure that."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [{"data": {"text/html": ["
run previous cell, wait for 2 seconds
\n", ""], "text/plain": [""]}, "execution_count": 2, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Artificial huge data "]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/plain": ["0.48"]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["import numpy\n", "N, nfeat = 300000, 200\n", "N * nfeat * 8 / 1e9"]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"data": {"text/plain": ["((300000, 200), (300000, 50))"]}, "execution_count": 4, "metadata": {}, "output_type": "execute_result"}], "source": ["X = numpy.random.random((N, nfeat))\n", "y = numpy.empty((N, 50))\n", "for i in range(y.shape[1]):\n", " y[:, i] = X.sum(axis=1) + numpy.random.random(N)\n", "X.shape, y.shape"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": ["from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.1)"]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["LinearRegression()"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.linear_model import LinearRegression\n", "clr = LinearRegression()\n", "clr.fit(X_train, y_train)"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["from mlprodict.onnx_conv import to_onnx\n", "from mlprodict.onnxrt import OnnxInference\n", "clr_onnx = to_onnx(clr, X_train[:1].astype(numpy.float32))\n", "oinfpy = OnnxInference(clr_onnx, runtime='python')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Let's minimize the cost of verifications on scikit-learn's side."]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": ["from sklearn import set_config\n", "set_config(assume_finite=True)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Profiling the prediction function"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["\n", " _ ._ __/__ _ _ _ _ _/_ Recorded: 15:51:37 Samples: 4\n", " /_//_/// /_\\ / //_// / //_'/ // Duration: 0.439 CPU time: 0.797\n", "/ _/ v3.0.1\n", "\n", "Program: c:\\python372_x64\\lib\\site-packages\\ipykernel_launcher.py -f C:\\Users\\xavie\\AppData\\Roaming\\jupyter\\runtime\\kernel-4e37b7b5-7bfc-4784-9e5a-cae5acd320c1.json\n", "\n", "0.439 profile pyquickhelper\\pycode\\profiling.py:49\n", "|- 0.427 :2\n", "| `- 0.427 predict sklearn\\linear_model\\_base.py:222\n", "| `- 0.427 _decision_function sklearn\\linear_model\\_base.py:215\n", "| |- 0.371 inner_f sklearn\\utils\\validation.py:60\n", "| | `- 0.370 safe_sparse_dot sklearn\\utils\\extmath.py:118\n", "| `- 0.056 [self] \n", "`- 0.012 [self] \n", "\n", "\n"]}], "source": ["from pyquickhelper.pycode.profiling import profile\n", "print(profile(lambda: clr.predict(X_test), \n", " pyinst_format='text')[1])"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"scrolled": false}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["\n", " _ ._ __/__ _ _ _ _ _/_ Recorded: 15:51:39 Samples: 5\n", " /_//_/// /_\\ / //_// / //_'/ // Duration: 0.378 CPU time: 0.453\n", "/ _/ v3.0.1\n", "\n", "Program: c:\\python372_x64\\lib\\site-packages\\ipykernel_launcher.py -f C:\\Users\\xavie\\AppData\\Roaming\\jupyter\\runtime\\kernel-4e37b7b5-7bfc-4784-9e5a-cae5acd320c1.json\n", "\n", "0.378 profile pyquickhelper\\pycode\\profiling.py:49\n", "|- 0.370 :6\n", "| |- 0.233 run mlprodict\\onnxrt\\onnx_inference.py:471\n", "| | `- 0.233 _run_sequence_runtime mlprodict\\onnxrt\\onnx_inference.py:551\n", "| | `- 0.233 run mlprodict\\onnxrt\\onnx_inference_node.py:141\n", "| | `- 0.233 run mlprodict\\onnxrt\\ops_cpu\\_op.py:374\n", "| | `- 0.233 run mlprodict\\onnxrt\\ops_cpu\\_op.py:289\n", "| | `- 0.233 _run mlprodict\\onnxrt\\ops_cpu\\op_linear_regressor.py:27\n", "| | |- 0.215 numpy_dot_inplace mlprodict\\onnxrt\\ops_cpu\\_op_numpy_helper.py:8\n", "| | | `- 0.215 dot <__array_function__ internals>:2\n", "| | `- 0.018 [self] \n", "| |- 0.112 nastype32 :3\n", "| `- 0.026 [self] \n", "`- 0.008 [self] \n", "\n", "\n"]}], "source": ["import numpy\n", "\n", "def nastype32(mat):\n", " return mat.astype(numpy.float32)\n", "\n", "print(profile(lambda: oinfpy.run({'X': nastype32(X_test)}), \n", " pyinst_format='text')[1])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Most of the time is taken out into casting into float. Let's take it out."]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["\n", " _ ._ __/__ _ _ _ _ _/_ Recorded: 15:51:43 Samples: 3\n", " /_//_/// /_\\ / //_// / //_'/ // Duration: 0.081 CPU time: 0.141\n", "/ _/ v3.0.1\n", "\n", "Program: c:\\python372_x64\\lib\\site-packages\\ipykernel_launcher.py -f C:\\Users\\xavie\\AppData\\Roaming\\jupyter\\runtime\\kernel-4e37b7b5-7bfc-4784-9e5a-cae5acd320c1.json\n", "\n", "0.080 profile pyquickhelper\\pycode\\profiling.py:49\n", "|- 0.074 :3\n", "| `- 0.074 run mlprodict\\onnxrt\\onnx_inference.py:471\n", "| `- 0.074 _run_sequence_runtime mlprodict\\onnxrt\\onnx_inference.py:551\n", "| `- 0.074 run mlprodict\\onnxrt\\onnx_inference_node.py:141\n", "| `- 0.074 run mlprodict\\onnxrt\\ops_cpu\\_op.py:374\n", "| `- 0.074 run mlprodict\\onnxrt\\ops_cpu\\_op.py:289\n", "| `- 0.074 _run mlprodict\\onnxrt\\ops_cpu\\op_linear_regressor.py:27\n", "| |- 0.059 numpy_dot_inplace mlprodict\\onnxrt\\ops_cpu\\_op_numpy_helper.py:8\n", "| | `- 0.059 dot <__array_function__ internals>:2\n", "| `- 0.015 [self] \n", "`- 0.007 [self] \n", "\n", "\n"]}], "source": ["X_test32 = X_test.astype(numpy.float32)\n", "\n", "print(profile(lambda: oinfpy.run({'X': X_test32}), \n", " pyinst_format='text')[1])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Much better."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## SGDClasifier\n", "\n", "This models is implemented with many ONNX nodes. Let's how it behaves."]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"data": {"text/plain": ["SGDClassifier()"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.linear_model import SGDClassifier\n", "from sklearn.datasets import load_iris\n", "data = load_iris()\n", "Xir, yir = data.data, data.target\n", "Xir_train, Xir_test, yir_train, yir_test = train_test_split(Xir, yir)\n", "sgcl = SGDClassifier()\n", "sgcl.fit(Xir_train, yir_train)"]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"name": "stderr", "output_type": "stream", "text": ["C:\\xavierdupre\\__home_\\github_fork\\scikit-learn\\sklearn\\utils\\deprecation.py:101: FutureWarning: Attribute average_coef_ was deprecated in version 0.23 and will be removed in 0.25.\n", " warnings.warn(msg, category=FutureWarning)\n", "C:\\xavierdupre\\__home_\\github_fork\\scikit-learn\\sklearn\\utils\\deprecation.py:101: FutureWarning: Attribute average_intercept_ was deprecated in version 0.23 and will be removed in 0.25.\n", " warnings.warn(msg, category=FutureWarning)\n", "C:\\xavierdupre\\__home_\\github_fork\\scikit-learn\\sklearn\\utils\\deprecation.py:101: FutureWarning: Attribute standard_coef_ was deprecated in version 0.23 and will be removed in 0.25.\n", " warnings.warn(msg, category=FutureWarning)\n", "C:\\xavierdupre\\__home_\\github_fork\\scikit-learn\\sklearn\\utils\\deprecation.py:101: FutureWarning: Attribute standard_intercept_ was deprecated in version 0.23 and will be removed in 0.25.\n", " warnings.warn(msg, category=FutureWarning)\n"]}], "source": ["sgd_onnx = to_onnx(sgcl, Xir_train.astype(numpy.float32))"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["%load_ext mlprodict"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", ""], "text/plain": [""]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["%onnxview sgd_onnx"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": ["sgd_oinf = OnnxInference(sgd_onnx)"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"data": {"text/plain": ["{'output_label': array([0], dtype=int64),\n", " 'output_probability': [{0: -65.8407, 1: -158.60867, 2: -100.55802}]}"]}, "execution_count": 17, "metadata": {}, "output_type": "execute_result"}], "source": ["def call_n_times_x1(n, X_test, sgd_oinf):\n", " for i in range(n):\n", " res = sgd_oinf.run({'X': X_test})\n", " return res\n", "\n", "call_n_times_x1(20, Xir_test[:1].astype(numpy.float32), sgd_oinf)"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([[ -65.840706 , -158.60864916, -100.55799704]])"]}, "execution_count": 18, "metadata": {}, "output_type": "execute_result"}], "source": ["sgcl.decision_function(Xir_test[:1])"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["\n", " _ ._ __/__ _ _ _ _ _/_ Recorded: 15:52:03 Samples: 1022\n", " /_//_/// /_\\ / //_// / //_'/ // Duration: 1.432 CPU time: 1.453\n", "/ _/ v3.0.1\n", "\n", "Program: c:\\python372_x64\\lib\\site-packages\\ipykernel_launcher.py -f C:\\Users\\xavie\\AppData\\Roaming\\jupyter\\runtime\\kernel-4e37b7b5-7bfc-4784-9e5a-cae5acd320c1.json\n", "\n", "1.432 profile pyquickhelper\\pycode\\profiling.py:49\n", "`- 1.432 :3\n", " `- 1.432 call_n_times_x1 :1\n", " |- 1.412 run mlprodict\\onnxrt\\onnx_inference.py:471\n", " | |- 1.381 _run_sequence_runtime mlprodict\\onnxrt\\onnx_inference.py:551\n", " | | |- 1.218 run mlprodict\\onnxrt\\onnx_inference_node.py:141\n", " | | | |- 0.398 [self] \n", " | | | |- 0.311 run mlprodict\\onnxrt\\ops_cpu\\_op.py:132\n", " | | | | |- 0.193 _run mlprodict\\onnxrt\\ops_cpu\\op_array_feature_extractor.py:59\n", " | | | | | |- 0.170 _array_feature_extrator mlprodict\\onnxrt\\ops_cpu\\op_array_feature_extractor.py:17\n", " | | | | | `- 0.023 [self] \n", " | | | | |- 0.047 _run mlprodict\\onnxrt\\ops_cpu\\op_cast.py:37\n", " | | | | | `- 0.033 _run_inplace mlprodict\\onnxrt\\ops_cpu\\op_cast.py:42\n", " | | | | | `- 0.020 mlprodict\\onnxrt\\ops_cpu\\op_cast.py:35\n", " | | | | |- 0.028 [self] \n", " | | | | |- 0.022 _run mlprodict\\onnxrt\\ops_cpu\\op_zipmap.py:221\n", " | | | | `- 0.021 _run mlprodict\\onnxrt\\ops_cpu\\op_reshape.py:16\n", " | | | |- 0.299 run mlprodict\\onnxrt\\ops_cpu\\_op.py:337\n", " | | | | `- 0.287 run mlprodict\\onnxrt\\ops_cpu\\_op.py:289\n", " | | | | `- 0.281 _run mlprodict\\onnxrt\\ops_cpu\\op_argmax.py:69\n", " | | | | `- 0.277 _run mlprodict\\onnxrt\\ops_cpu\\op_argmax.py:42\n", " | | | | `- 0.271 _argmax mlprodict\\onnxrt\\ops_cpu\\op_argmax.py:12\n", " | | | | |- 0.159 expand_dims <__array_function__ internals>:2\n", " | | | | | `- 0.155 expand_dims numpy\\lib\\shape_base.py:512\n", " | | | | | [10 frames hidden] numpy\n", " | | | | |- 0.059 argmax <__array_function__ internals>:2\n", " | | | | | |- 0.041 argmax numpy\\core\\fromnumeric.py:1112\n", " | | | | | | [4 frames hidden] numpy\n", " | | | | | `- 0.018 [self] \n", " | | | | `- 0.052 [self] \n", " | | | |- 0.171 run mlprodict\\onnxrt\\ops_cpu\\_op.py:517\n", " | | | | |- 0.155 run mlprodict\\onnxrt\\ops_cpu\\_op.py:453\n", " | | | | | |- 0.075 _run mlprodict\\onnxrt\\ops_cpu\\_op.py:550\n", " | | | | | `- 0.067 _run mlprodict\\onnxrt\\ops_cpu\\op_matmul.py:16\n", " | | | | | `- 0.066 numpy_dot_inplace mlprodict\\onnxrt\\ops_cpu\\_op_numpy_helper.py:8\n", " | | | | | `- 0.055 dot <__array_function__ internals>:2\n", " | | | | `- 0.016 [self] \n", " | | | `- 0.038 mlprodict\\onnxrt\\onnx_inference_node.py:153\n", " | | `- 0.158 [self] \n", " | `- 0.031 [self] \n", " `- 0.020 [self] \n", "\n", "\n"]}], "source": ["xir_32 = Xir_test[:1].astype(numpy.float32)\n", "\n", "print(profile(lambda: call_n_times_x1(20000, xir_32, sgd_oinf), \n", " pyinst_format='text')[1])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The code in ``mlprodict/onnxrt/onnx_inference_node.py`` just calls an operator and updates the list containing all the results. The time in here is significant if the number of node is huge if the python runtime is used."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Memory profiling"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": ["%matplotlib inline"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["from memory_profiler import memory_usage\n", "memprof_skl = memory_usage((clr.predict, (X_test, )), timestamps=True, interval=0.01)"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [{"data": {"text/plain": ["[(811.3515625, 1594129928.0175571),\n", " (811.671875, 1594129932.2684996),\n", " (822.36328125, 1594129932.28645),\n", " (832.11328125, 1594129932.30241),\n", " (847.05078125, 1594129932.3183646),\n", " (860.5625, 1594129932.333325),\n", " (874.48828125, 1594129932.3482847),\n", " (883.73828125, 1594129932.3642418),\n", " (898.80078125, 1594129932.380199),\n", " (907.98828125, 1594129932.3961573),\n", " (935.03515625, 1594129932.4121134),\n", " (965.03515625, 1594129932.4280717),\n", " (998.59765625, 1594129932.4440289),\n", " (949.73828125, 1594129932.4599853),\n", " (914.75390625, 1594129932.464972)]"]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}], "source": ["memprof_skl"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["import matplotlib.pyplot as plt\n", "from pandas import DataFrame, to_datetime\n", "\n", "def mem_profile_plot(mem, title):\n", " fig, ax = plt.subplots(1, 1, figsize=(4, 4))\n", " df = DataFrame(mem, columns=[\"memory\", \"timestamp\"])\n", " df[\"timestamp\"] = to_datetime(df.timestamp)\n", " df[\"timestamp\"] -= df.timestamp.min()\n", " df.set_index(\"timestamp\").plot(ax=ax)\n", " ax.set_title(title + \"\\nmemory usage\")\n", " return ax\n", "\n", "mem_profile_plot(memprof_skl, \"clr.predict\");"]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["memprof_onx = memory_usage((oinfpy.run, ({'X': X_test32}, )), timestamps=True, interval=0.01)\n", "mem_profile_plot(memprof_onx, \"oinfpy.run\");"]}, {"cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["memprof_onx2 = memory_usage((oinfpy.run, ({'X': X_test.astype(numpy.float32, copy=False)}, )),\n", " timestamps=True, interval=0.01)\n", "mem_profile_plot(memprof_onx2, \"oinfpy.run + astype(numpy.float32)\");"]}, {"cell_type": "markdown", "metadata": {}, "source": ["This is not very informative."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Memory profiling outside the notebook\n", "\n", "More precise."]}, {"cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Overwriting mprof_clr_predict.py\n"]}], "source": ["%%writefile mprof_clr_predict.py\n", "\n", "import numpy\n", "N, nfeat = 300000, 200\n", "X = numpy.random.random((N, nfeat))\n", "y = numpy.empty((N, 50))\n", "for i in range(y.shape[1]):\n", " y[:, i] = X.sum(axis=1) + numpy.random.random(N)\n", " \n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.1) \n", "\n", "from sklearn.linear_model import LinearRegression\n", "clr = LinearRegression()\n", "clr.fit(X_train, y_train)\n", "\n", "from sklearn import set_config\n", "set_config(assume_finite=True) \n", "\n", "from memory_profiler import profile\n", "@profile\n", "def clr_predict():\n", " clr.predict(X_test)\n", " \n", "clr_predict()"]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Filename: mprof_clr_predict.py\n", "\n", "Line # Mem usage Increment Line Contents\n", "================================================\n", " 20 1234.7 MiB 1234.7 MiB @profile\n", " 21 def clr_predict():"]}], "source": ["!python -m memory_profiler mprof_clr_predict.py --timestamp"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The notebook seems to increase the memory usage."]}, {"cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Overwriting mprof_onnx_run.py\n"]}], "source": ["%%writefile mprof_onnx_run.py\n", "\n", "import numpy\n", "N, nfeat = 300000, 200\n", "X = numpy.random.random((N, nfeat))\n", "y = numpy.empty((N, 50))\n", "for i in range(y.shape[1]):\n", " y[:, i] = X.sum(axis=1) + numpy.random.random(N)\n", " \n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.1) \n", "\n", "from sklearn.linear_model import LinearRegression\n", "clr = LinearRegression()\n", "clr.fit(X_train, y_train)\n", "\n", "from mlprodict.onnx_conv import to_onnx\n", "from mlprodict.onnxrt import OnnxInference\n", "clr_onnx = to_onnx(clr, X_train[:1].astype(numpy.float32))\n", "oinfpy = OnnxInference(clr_onnx, runtime='python')\n", "X_test32 = X_test.astype(numpy.float32)\n", "\n", "from sklearn import set_config\n", "set_config(assume_finite=True) \n", "\n", "from memory_profiler import profile\n", "@profile\n", "def oinfpy_predict():\n", " oinfpy.run({'X': X_test32})\n", " \n", "oinfpy_predict()"]}, {"cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Filename: mprof_onnx_run.py\n", "\n", "Line # Mem usage Increment Line Contents\n", "================================================\n", " 26 1498.8 MiB 1498.8 MiB @profile\n", " 27 def oinfpy_predict():\n", " 28 1500.1 MiB 1.3 MiB oinfpy.run({'X': X_test32})\n", "\n", "\n"]}], "source": ["!python -m memory_profiler mprof_onnx_run.py --timestamp"]}, {"cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Overwriting mprof_onnx_run32.py\n"]}], "source": ["%%writefile mprof_onnx_run32.py\n", "\n", "import numpy\n", "N, nfeat = 300000, 200\n", "X = numpy.random.random((N, nfeat))\n", "y = numpy.empty((N, 50))\n", "for i in range(y.shape[1]):\n", " y[:, i] = X.sum(axis=1) + numpy.random.random(N)\n", " \n", "from sklearn.model_selection import train_test_split\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.1) \n", "\n", "from sklearn.linear_model import LinearRegression\n", "clr = LinearRegression()\n", "clr.fit(X_train, y_train)\n", "\n", "from mlprodict.onnx_conv import to_onnx\n", "from mlprodict.onnxrt import OnnxInference\n", "clr_onnx = to_onnx(clr, X_train[:1].astype(numpy.float32))\n", "oinfpy = OnnxInference(clr_onnx, runtime='python')\n", "\n", "from sklearn import set_config\n", "set_config(assume_finite=True) \n", "\n", "from memory_profiler import profile\n", "@profile\n", "def oinfpy_predict32():\n", " oinfpy.run({'X': X_test.astype(numpy.float32)})\n", " \n", "oinfpy_predict32()"]}, {"cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Filename: mprof_onnx_run32.py\n", "\n", "Line # Mem usage Increment Line Contents\n", "================================================\n", " 25 1293.1 MiB 1293.1 MiB @profile\n", " 26 def oinfpy_predict32():\n", " 27 1294.4 MiB 1.3 MiB oinfpy.run({'X': X_test.astype(numpy.float32)})\n", "\n", "\n"]}], "source": ["!python -m memory_profiler mprof_onnx_run32.py --timestamp"]}, {"cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}}, "nbformat": 4, "nbformat_minor": 2}