{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# ONNX graph, single or double floats\n", "\n", "The notebook shows discrepencies obtained by using double floats instead of single float in two cases. The second one involves [GaussianProcessRegressor](https://scikit-learn.org/stable/modules/generated/sklearn.gaussian_process.GaussianProcessRegressor.html)."]}, {"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": ["## Simple case of a linear regression\n", "\n", "A linear regression is simply a matrix multiplication followed by an addition: $Y=AX+B$. Let's train one with [scikit-learn](https://scikit-learn.org/stable/)."]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/plain": ["LinearRegression()"]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.linear_model import LinearRegression\n", "from sklearn.datasets import load_boston\n", "from sklearn.model_selection import train_test_split\n", "data = load_boston()\n", "X, y = data.data, data.target\n", "X_train, X_test, y_train, y_test = train_test_split(X, y)\n", "clr = LinearRegression()\n", "clr.fit(X_train, y_train)"]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"data": {"text/plain": ["0.7305965839248935"]}, "execution_count": 4, "metadata": {}, "output_type": "execute_result"}], "source": ["clr.score(X_test, y_test)"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([-1.15896254e-01, 3.85174778e-02, 1.59315996e-02, 3.22074735e+00,\n", " -1.85418374e+01, 3.21813935e+00, 1.12610939e-02, -1.32043742e+00,\n", " 3.67002299e-01, -1.41101521e-02, -1.10152072e+00, 6.17018918e-03,\n", " -5.71549389e-01])"]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["clr.coef_"]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["43.97633987084284"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["clr.intercept_"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Let's predict with *scikit-learn* and *python*."]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.72795971, 18.69312745, 21.13760633, 16.65607505, 22.47115623])"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["ypred = clr.predict(X_test)\n", "ypred[:5]"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.72795971, 18.69312745, 21.13760633, 16.65607505, 22.47115623])"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["py_pred = X_test @ clr.coef_ + clr.intercept_\n", "py_pred[:5]"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"text/plain": ["(dtype('float64'), dtype('float64'))"]}, "execution_count": 9, "metadata": {}, "output_type": "execute_result"}], "source": ["clr.coef_.dtype, clr.intercept_.dtype"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## With ONNX\n", "\n", "With *ONNX*, we would write this operation as follows... We still need to convert everything into single floats = float32."]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": ["%load_ext mlprodict"]}, {"cell_type": "code", "execution_count": 10, "metadata": {"scrolled": false}, "outputs": [{"data": {"text/html": ["
\n", ""], "text/plain": [""]}, "execution_count": 11, "metadata": {}, "output_type": "execute_result"}], "source": ["from skl2onnx.algebra.onnx_ops import OnnxMatMul, OnnxAdd\n", "import numpy\n", "\n", "onnx_fct = OnnxAdd(OnnxMatMul('X', clr.coef_.astype(numpy.float32), op_version=12),\n", " numpy.array([clr.intercept_], dtype=numpy.float32),\n", " output_names=['Y'], op_version=12)\n", "onnx_model32 = onnx_fct.to_onnx({'X': X_test.astype(numpy.float32)})\n", "\n", "# add -l 1 if nothing shows up\n", "%onnxview onnx_model32"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The next line uses a python runtime to compute the prediction."]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.727959, 18.693125, 21.137608, 16.656076, 22.471157],\n", " dtype=float32)"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["from mlprodict.onnxrt import OnnxInference\n", "oinf = OnnxInference(onnx_model32, inplace=False)\n", "ort_pred = oinf.run({'X': X_test.astype(numpy.float32)})['Y']\n", "ort_pred[:5]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["And here is the same with [onnxruntime](https://github.com/microsoft/onnxruntime)..."]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.727959, 18.693125, 21.137608, 16.656076, 22.471157],\n", " dtype=float32)"]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["from mlprodict.tools.asv_options_helper import get_ir_version_from_onnx\n", "# line needed when onnx is more recent than onnxruntime\n", "onnx_model32.ir_version = get_ir_version_from_onnx()\n", "oinf = OnnxInference(onnx_model32, runtime=\"onnxruntime1\")\n", "ort_pred = oinf.run({'X': X_test.astype(numpy.float32)})['Y']\n", "ort_pred[:5]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## With double instead of single float\n", "\n", "[ONNX](https://onnx.ai/) was originally designed for deep learning which usually uses floats but it does not mean cannot be used. Every number is converted into double floats."]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["onnx_fct = OnnxAdd(OnnxMatMul('X', clr.coef_.astype(numpy.float64), op_version=12),\n", " numpy.array([clr.intercept_], dtype=numpy.float64),\n", " output_names=['Y'], op_version=12)\n", "onnx_model64 = onnx_fct.to_onnx({'X': X_test.astype(numpy.float64)})"]}, {"cell_type": "markdown", "metadata": {}, "source": ["And now the *python* runtime..."]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.72795971, 18.69312745, 21.13760633, 16.65607505, 22.47115623])"]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["oinf = OnnxInference(onnx_model64)\n", "ort_pred = oinf.run({'X': X_test})['Y']\n", "ort_pred[:5]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["And the *onnxruntime* version of it."]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.72795971, 18.69312745, 21.13760633, 16.65607505, 22.47115623])"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["oinf = OnnxInference(onnx_model64, runtime=\"onnxruntime1\")\n", "ort_pred = oinf.run({'X': X_test.astype(numpy.float64)})['Y']\n", "ort_pred[:5]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## And now the GaussianProcessRegressor\n", "\n", "This shows a case"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"data": {"text/plain": ["GaussianProcessRegressor(alpha=10, kernel=DotProduct(sigma_0=1))"]}, "execution_count": 17, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.gaussian_process import GaussianProcessRegressor\n", "from sklearn.gaussian_process.kernels import DotProduct\n", "gau = GaussianProcessRegressor(alpha=10, kernel=DotProduct())\n", "gau.fit(X_train, y_train)"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.25 , 19.59375 , 21.34375 , 17.625 , 21.953125, 30. ,\n", " 18.875 , 19.625 , 9.9375 , 20.5 , -0.53125 , 16.375 ,\n", " 16.8125 , 20.6875 , 27.65625 , 16.375 , 39.0625 , 36.0625 ,\n", " 40.71875 , 21.53125 , 29.875 , 30.34375 , 23.53125 , 15.25 ,\n", " 35.5 ], dtype=float32)"]}, "execution_count": 18, "metadata": {}, "output_type": "execute_result"}], "source": ["from mlprodict.onnx_conv import to_onnx\n", "onnxgau32 = to_onnx(gau, X_train.astype(numpy.float32))\n", "oinf32 = OnnxInference(onnxgau32, runtime=\"python\", inplace=False)\n", "ort_pred32 = oinf32.run({'X': X_test.astype(numpy.float32)})['GPmean']\n", "numpy.squeeze(ort_pred32)[:25]"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([17.22940605, 19.07756253, 21.000277 , 17.33514034, 22.37701168,\n", " 30.10867125, 18.72937468, 19.2220674 , 9.74660609, 20.3440565 ,\n", " -0.1354653 , 16.47852265, 17.12332707, 21.04137646, 27.21477015,\n", " 16.2668399 , 39.31065954, 35.99032274, 40.53761676, 21.51909954,\n", " 29.49016665, 30.22944875, 23.58969906, 14.56499415, 35.28957228])"]}, "execution_count": 19, "metadata": {}, "output_type": "execute_result"}], "source": ["onnxgau64 = to_onnx(gau, X_train.astype(numpy.float64))\n", "oinf64 = OnnxInference(onnxgau64, runtime=\"python\", inplace=False)\n", "ort_pred64 = oinf64.run({'X': X_test.astype(numpy.float64)})['GPmean']\n", "numpy.squeeze(ort_pred64)[:25]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The differences between the predictions for single floats and double floats..."]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([0.51618747, 0.54317928, 0.61256575, 0.63292898, 0.68500585])"]}, "execution_count": 20, "metadata": {}, "output_type": "execute_result"}], "source": ["numpy.sort(numpy.sort(numpy.squeeze(ort_pred32 - ort_pred64)))[-5:]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Who's right or wrong... The differences between the predictions with the original model..."]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": ["pred = gau.predict(X_test.astype(numpy.float64))"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([0.51618747, 0.54317928, 0.61256575, 0.63292898, 0.68500585])"]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}], "source": ["numpy.sort(numpy.sort(numpy.squeeze(ort_pred32 - pred)))[-5:]"]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([0., 0., 0., 0., 0.])"]}, "execution_count": 23, "metadata": {}, "output_type": "execute_result"}], "source": ["numpy.sort(numpy.sort(numpy.squeeze(ort_pred64 - pred)))[-5:]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Double predictions clearly wins."]}, {"cell_type": "code", "execution_count": 23, "metadata": {"scrolled": false}, "outputs": [{"data": {"text/html": ["
\n", ""], "text/plain": [""]}, "execution_count": 24, "metadata": {}, "output_type": "execute_result"}], "source": ["# add -l 1 if nothing shows up\n", "%onnxview onnxgau64"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Saves...\n", "\n", "Let's keep track of it."]}, {"cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [{"data": {"text/html": ["gpr_dot_product_boston_32.onnx
"], "text/plain": ["C:\\xavierdupre\\__home_\\GitHub\\mlprodict\\_doc\\notebooks\\gpr_dot_product_boston_32.onnx"]}, "execution_count": 25, "metadata": {}, "output_type": "execute_result"}], "source": ["with open(\"gpr_dot_product_boston_32.onnx\", \"wb\") as f:\n", " f.write(onnxgau32.SerializePartialToString())\n", "from IPython.display import FileLink\n", "FileLink('gpr_dot_product_boston_32.onnx')"]}, {"cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [{"data": {"text/html": ["gpr_dot_product_boston_64.onnx
"], "text/plain": ["C:\\xavierdupre\\__home_\\GitHub\\mlprodict\\_doc\\notebooks\\gpr_dot_product_boston_64.onnx"]}, "execution_count": 26, "metadata": {}, "output_type": "execute_result"}], "source": ["with open(\"gpr_dot_product_boston_64.onnx\", \"wb\") as f:\n", " f.write(onnxgau64.SerializePartialToString())\n", "FileLink('gpr_dot_product_boston_64.onnx')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Side by side\n", "\n", "We may wonder where the discrepencies start. But for that, we need to do a side by side."]}, {"cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
metricstepv[0]v[1]cmpnamevalue[0]shape[0]value[1]shape[1]
0nb_results-199.000000e+00OKNaNNaNNaNNaNNaN
1abs-diff004.902064e-08OKX[[0.21977, 0.0, 6.91, 0.0, 0.448, 5.602, 62.0,...(127, 13)[[0.21977, 0.0, 6.91, 0.0, 0.448, 5.602, 62.0,...(127, 13)
2abs-diff102.402577e-02e<0.1GPmean[[17.25, 19.59375, 21.34375, 17.625, 21.953125...(1, 127)[[17.229406048412784, 19.077562531849253, 21.0...(1, 127)
3abs-diff205.553783e-08OKkgpd_MatMulcst[[16.8118, 0.26169, 7.67202, 0.57529, 1.13081,...(13, 379)[[16.8118, 0.26169, 7.67202, 0.57529, 1.13081,...(13, 379)
4abs-diff302.421959e-08OKkgpd_Addcst[1117.718](1,)[1117.718044648797](1,)
5abs-diff405.206948e-08OKgpr_MatMulcst[-0.040681414, -0.37079695, -0.7959402, 0.4380...(379,)[-0.04068141268069173, -0.37079693473728526, -...(379,)
6abs-diff500.000000e+00OKgpr_Addcst[[0.0]](1, 1)[[0.0]](1, 1)
7abs-diff601.856291e-07OKkgpd_Y0[[321007.53, 235496.9, 319374.4, 230849.73, 22...(127, 379)[[321007.55279690475, 235496.9156560601, 31937...(127, 379)
8abs-diff701.856291e-07OKkgpd_C0[[321007.53, 235496.9, 319374.4, 230849.73, 22...(127, 379)[[321007.55279690475, 235496.9156560601, 31937...(127, 379)
9abs-diff802.402577e-02e<0.1gpr_Y0[17.25, 19.59375, 21.34375, 17.625, 21.953125,...(127,)[17.229406048412784, 19.077562531849253, 21.00...(127,)
\n", "
"], "text/plain": [" metric step v[0] v[1] cmp name \\\n", "0 nb_results -1 9 9.000000e+00 OK NaN \n", "1 abs-diff 0 0 4.902064e-08 OK X \n", "2 abs-diff 1 0 2.402577e-02 e<0.1 GPmean \n", "3 abs-diff 2 0 5.553783e-08 OK kgpd_MatMulcst \n", "4 abs-diff 3 0 2.421959e-08 OK kgpd_Addcst \n", "5 abs-diff 4 0 5.206948e-08 OK gpr_MatMulcst \n", "6 abs-diff 5 0 0.000000e+00 OK gpr_Addcst \n", "7 abs-diff 6 0 1.856291e-07 OK kgpd_Y0 \n", "8 abs-diff 7 0 1.856291e-07 OK kgpd_C0 \n", "9 abs-diff 8 0 2.402577e-02 e<0.1 gpr_Y0 \n", "\n", " value[0] shape[0] \\\n", "0 NaN NaN \n", "1 [[0.21977, 0.0, 6.91, 0.0, 0.448, 5.602, 62.0,... (127, 13) \n", "2 [[17.25, 19.59375, 21.34375, 17.625, 21.953125... (1, 127) \n", "3 [[16.8118, 0.26169, 7.67202, 0.57529, 1.13081,... (13, 379) \n", "4 [1117.718] (1,) \n", "5 [-0.040681414, -0.37079695, -0.7959402, 0.4380... (379,) \n", "6 [[0.0]] (1, 1) \n", "7 [[321007.53, 235496.9, 319374.4, 230849.73, 22... (127, 379) \n", "8 [[321007.53, 235496.9, 319374.4, 230849.73, 22... (127, 379) \n", "9 [17.25, 19.59375, 21.34375, 17.625, 21.953125,... (127,) \n", "\n", " value[1] shape[1] \n", "0 NaN NaN \n", "1 [[0.21977, 0.0, 6.91, 0.0, 0.448, 5.602, 62.0,... (127, 13) \n", "2 [[17.229406048412784, 19.077562531849253, 21.0... (1, 127) \n", "3 [[16.8118, 0.26169, 7.67202, 0.57529, 1.13081,... (13, 379) \n", "4 [1117.718044648797] (1,) \n", "5 [-0.04068141268069173, -0.37079693473728526, -... (379,) \n", "6 [[0.0]] (1, 1) \n", "7 [[321007.55279690475, 235496.9156560601, 31937... (127, 379) \n", "8 [[321007.55279690475, 235496.9156560601, 31937... (127, 379) \n", "9 [17.229406048412784, 19.077562531849253, 21.00... (127,) "]}, "execution_count": 27, "metadata": {}, "output_type": "execute_result"}], "source": ["from mlprodict.onnxrt.validate.side_by_side import side_by_side_by_values\n", "sbs = side_by_side_by_values([(oinf32, {'X': X_test.astype(numpy.float32)}),\n", " (oinf64, {'X': X_test.astype(numpy.float64)})])\n", "\n", "from pandas import DataFrame\n", "df = DataFrame(sbs)\n", "# dfd = df.drop(['value[0]', 'value[1]', 'value[2]'], axis=1).copy()\n", "df"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The differences really starts for output ``'O0'`` after the matrix multiplication. This matrix melts different number with very different order of magnitudes and that alone explains the discrepencies with doubles and floats on that particular model."]}, {"cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [{"data": {"image/png": "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", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["%matplotlib inline\n", "ax = df[['name', 'v[1]']].iloc[1:].set_index('name').plot(kind='bar', figsize=(14,4), logy=True)\n", "ax.set_title(\"Relative differences for each output between float32 and \"\n", " \"float64\\nfor a GaussianProcessRegressor\");"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Before going further, let's check how sensitive the trained model is about converting double into floats."]}, {"cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([1.53295696e-06, 1.60621130e-06, 1.65373785e-06, 1.66549580e-06,\n", " 2.36724736e-06])"]}, "execution_count": 29, "metadata": {}, "output_type": "execute_result"}], "source": ["pg1 = gau.predict(X_test)\n", "pg2 = gau.predict(X_test.astype(numpy.float32).astype(numpy.float64))\n", "numpy.sort(numpy.sort(numpy.squeeze(pg1 - pg2)))[-5:]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Having float or double inputs should not matter. We confirm that with the model converted into ONNX."]}, {"cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([1.53295696e-06, 1.60621130e-06, 1.65373785e-06, 1.66549580e-06,\n", " 2.36724736e-06])"]}, "execution_count": 30, "metadata": {}, "output_type": "execute_result"}], "source": ["p1 = oinf64.run({'X': X_test})['GPmean']\n", "p2 = oinf64.run({'X': X_test.astype(numpy.float32).astype(numpy.float64)})['GPmean']\n", "numpy.sort(numpy.sort(numpy.squeeze(p1 - p2)))[-5:]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Last verification."]}, {"cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [{"data": {"image/png": "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", "text/plain": ["
"]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["sbs = side_by_side_by_values([(oinf64, {'X': X_test.astype(numpy.float32).astype(numpy.float64)}),\n", " (oinf64, {'X': X_test.astype(numpy.float64)})])\n", "df = DataFrame(sbs)\n", "ax = df[['name', 'v[1]']].iloc[1:].set_index('name').plot(kind='bar', figsize=(14,4), logy=True)\n", "ax.set_title(\"Relative differences for each output between float64 and float64 rounded to float32\"\n", " \"\\nfor a GaussianProcessRegressor\");"]}, {"cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2"}}, "nbformat": 4, "nbformat_minor": 2}