{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Converts a logistic regression into C\n", "\n", "The logistic regression is trained in python and executed in C."]}, {"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": {"collapsed": true}, "source": ["## Train a linear regression"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/plain": ["LogisticRegression()"]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.linear_model import LogisticRegression\n", "from sklearn.datasets import load_iris\n", "iris = load_iris()\n", "X = iris.data[:, :2]\n", "y = iris.target\n", "y[y == 2] = 1\n", "lr = LogisticRegression()\n", "lr.fit(X, y)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Export into C"]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"data": {"text/plain": [""]}, "execution_count": 4, "metadata": {}, "output_type": "execute_result"}], "source": ["# grammar is the expected scoring model.\n", "from mlprodict.grammar_sklearn import sklearn2graph\n", "gr = sklearn2graph(lr, output_names=['Prediction', 'Score'])\n", "gr"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We can even check what the function should produce as a score. Types are strict."]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["[ 0. -11.264062]\n"]}], "source": ["import numpy\n", "X = numpy.array([[numpy.float32(1), numpy.float32(2)]])\n", "e2 = gr.execute(Features=X[0, :])\n", "print(e2)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We compare with scikit-learn."]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([-11.26406172])"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["lr.decision_function(X[0:1, :])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Conversion into C:"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["int LogisticRegression (float* pred, float* Features)\n", "{\n", " // 2290909222952-LogisticRegression - children\n", " // 2290909222728-concat - children\n", " // 2290909222672-sign - children\n", " // 2290909222616-+ - children\n", " // 2290909222560-adot - children\n", " float pred0c0c00c0[2] = {(float)3.3882975578308105, (float)-3.164527654647827};\n", " float* pred0c0c00c1 = Features;\n", " // 2290909222560-adot - itself\n", " float pred0c0c00;\n", " adot_float_float(&pred0c0c00, pred0c0c00c0, pred0c0c00c1, 2);\n", " // 2290909222560-adot - done\n", " float pred0c0c01 = (float)-8.323304176330566;\n", " // 2290909222616-+ - itself\n", " float pred0c0c0 = pred0c0c00 + pred0c0c01;\n", " // 2290909222616-+ - done\n", " // 2290909222672-sign - itself\n", " float pred0c0;\n", " sign_float(&pred0c0, pred0c0c0);\n", " // 2290909222672-sign - done\n", " // 2290909222728-concat - itself\n", " float pred0[2];\n", " concat_float_float(pred0, pred0c0, pred0c0c0);\n", " // 2290909222728-concat - done\n", " memcpy(pred, pred0, 2*sizeof(float));\n", " // 2290909222952-LogisticRegression - itself\n", " return 0;\n", " // 2290909222952-LogisticRegression - done\n", "}\n"]}], "source": ["res = gr.export(lang='c', hook={'array': lambda v: v.tolist(), 'float32': lambda v: float(v)})\n", "print(res[\"code\"])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We execute the code with module [cffi](https://cffi.readthedocs.io/en/latest/)."]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": [".wrapper_float(features, output=None)>"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["from mlprodict.grammar_sklearn.cc import compile_c_function\n", "fct = compile_c_function(res[\"code\"], 2)\n", "fct"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([ 0. , -11.264062], dtype=float32)"]}, "execution_count": 9, "metadata": {}, "output_type": "execute_result"}], "source": ["e2 = fct(X[0, :])\n", "e2"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Time comparison"]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["64.9 \u00b5s \u00b1 5.84 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10000 loops each)\n"]}], "source": ["%timeit lr.decision_function(X[0:1, :])"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["6.17 \u00b5s \u00b1 380 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n"]}], "source": ["%timeit fct(X[0, :])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["There is a significant speedup on this example. It could be even faster by removing some Python part and optimizing the code produced by [cffi](https://cffi.readthedocs.io/en/latest/). We can also save the creation of the array which contains the output by reusing an existing one."]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": ["out = fct(X[0, :])"]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["6.33 \u00b5s \u00b1 430 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n"]}], "source": ["%timeit fct(X[0, :], out)"]}, {"cell_type": "code", "execution_count": 13, "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}