{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[Sebastian Raschka](http://sebastianraschka.com), 2016\n", "\n", "https://github.com/rasbt/python-machine-learning-book" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the optional watermark extension is a small IPython notebook plugin that I developed to make the code reproducible. You can just skip the following line(s)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sebastian Raschka 2016-03-23 \n", "\n", "CPython 3.5.1\n", "IPython 4.0.3\n", "\n", "scikit-learn 0.17.1\n", "numpy 1.10.4\n", "scipy 0.17.0\n" ] } ], "source": [ "%load_ext watermark\n", "%watermark -a 'Sebastian Raschka' -v -d -p scikit-learn,numpy,scipy" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# to install watermark just uncomment the following line:\n", "#%install_ext https://raw.githubusercontent.com/rasbt/watermark/master/watermark.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Bonus Material - Scikit-learn Model Persistence using JSON" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In many situations, it is desirable to store away a trained model for future use. These situations where we want to persist a model could be the deployment of a model in a web application, for example, or scientific reproducibility of our experiments." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I [wrote](http://nbviewer.jupyter.org/github/rasbt/python-machine-learning-book/blob/master/code/ch09/ch09.ipynb#Serializing-fitted-scikit-learn-estimators) a little bit about serializing scikit-learn models using `pickle` in context of the web applications that we developed in chapter 8. Also, you can find an excellent [tutorial section](http://scikit-learn.org/stable/modules/model_persistence.html) on scikit-learn's website. Honestly, I would say that pickling Python objects via the [`pickle`](https://docs.python.org/3.5/library/pickle.html), [`dill`](https://pypi.python.org/pypi/dill) or [`joblib`](https://pythonhosted.org/joblib/) modules is probably the most convenient approach to model persistence. However, pickling Python objects can sometimes be a little bit problematic, for example, deserializing a model in Python 3.x that was originally pickled in Python 2.7x and vice versa. Also, pickle offers different protocols (currently the protocols `0-4`), which are not necessarily backwards compatible. \n", "Thus, to prepare for the worst case scenario -- corrupted pickle files or version incompatibilities -- there's at least one other (a little bit more tedious) way to model persistence using [JSON](http://www.json.org). \n", "\n", "> JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. [Source: http://www.json.org]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the advantages of JSON is that it is a human-readable format. So, if push comes to shove, we should still be able to read the parameter files and model coefficients \"manually\" and assign these values to the respective scikit-learn estimator or build our own model to reproduce scientific results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see how that works ... First, let us train a simple logistic regression classifier on Iris:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "from sklearn.linear_model import LogisticRegression \n", "from sklearn.datasets import load_iris\n", "import matplotlib.pyplot as plt\n", "from mlxtend.plotting import plot_decision_regions\n", "\n", "iris = load_iris()\n", "y, X = iris.target, iris.data[:, [0, 2]] # only use 2 features\n", "lr = LogisticRegression(C=100.0, \n", " class_weight=None, \n", " dual=False, \n", " fit_intercept=True,\n", " intercept_scaling=1, \n", " max_iter=100, \n", " multi_class='multinomial', \n", " n_jobs=1,\n", " penalty='l2', \n", " random_state=1, \n", " solver='newton-cg', \n", " tol=0.0001,\n", " verbose=0, \n", " warm_start=False)\n", "lr.fit(X, y)\n", "plot_decision_regions(X=X, y=y, clf=lr, legend=2)\n", "plt.xlabel('sepal length')\n", "plt.ylabel('petal length')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Luckily, we don't have to retype or copy & paste all the estimator parameters manually if we want to store them away. To get a dictionary of these parameters, we can simply use the handy \"get_params\" method:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'C': 100.0,\n", " 'class_weight': None,\n", " 'dual': False,\n", " 'fit_intercept': True,\n", " 'intercept_scaling': 1,\n", " 'max_iter': 100,\n", " 'multi_class': 'multinomial',\n", " 'n_jobs': 1,\n", " 'penalty': 'l2',\n", " 'random_state': 1,\n", " 'solver': 'newton-cg',\n", " 'tol': 0.0001,\n", " 'verbose': 0,\n", " 'warm_start': False}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lr.get_params()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Storing them in JSON format is easy, we simply import the `json` module from Python's standard library and dump the dictionary to a file:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "with open('./sckit-model-to-json/params.json', 'w', encoding='utf-8') as outfile:\n", " json.dump(lr.get_params(), outfile)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we read the file, we can see that the JSON file is just a 1-to-1 copy of our Python dictionary in text format:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"dual\": false, \"max_iter\": 100, \"warm_start\": false, \"verbose\": 0, \"C\": 100.0, \"class_weight\": null, \"random_state\": 1, \"fit_intercept\": true, \"multi_class\": \"multinomial\", \"intercept_scaling\": 1, \"penalty\": \"l2\", \"solver\": \"newton-cg\", \"n_jobs\": 1, \"tol\": 0.0001}\n" ] } ], "source": [ "with open('./sckit-model-to-json/params.json', 'r', encoding='utf-8') as infile:\n", " print(infile.read())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, the trickier part is to identify the \"fit\" parameters of the estimator, i.e., the parameters of our logistic regression model. However, in practice it's actually pretty straight forward to figure it out by heading over to the respective [documentation page](http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html): Just look out for the \"attributes\" in the \"Attribute\" section that have a trailing underscore (thanks, scikit-learn team, for the beautifully thought-out API!). In case of logistic regression, we are interested in the weights `.coef_`, the bias unit `.intercept_`, and the `classes_` and `n_iter_` attributes." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['classes_', 'coef_', 'intercept_', 'n_iter_']\n" ] } ], "source": [ "attrs = [i for i in dir(lr) if i.endswith('_') and not i.endswith('__')]\n", "print(attrs)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "attr_dict = {i: getattr(lr, i) for i in attrs}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to deserialize NumPy arrays to JSON objects, we need to cast the arrays to (nested) Python lists first, however, it's not that much of a hassle thanks to the `tolist` method. (Also, consider saving the attributes to separate JSON files, e.g., intercept.json and coef.json, for clarity.)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "for k in attr_dict:\n", " if isinstance(attr_dict[k], np.ndarray):\n", " attr_dict[k] = attr_dict[k].tolist()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we are ready to dump our \"attribute dictionary\" to a JSON file:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "with open('./sckit-model-to-json/attributes.json', 'w', encoding='utf-8') as outfile: \n", " json.dump(attr_dict, \n", " outfile, \n", " separators=(',', ':'), \n", " sort_keys=True, \n", " indent=4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If everything went fine, our JSON file should look like this -- in plaintext format:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"classes_\":[\n", " 0,\n", " 1,\n", " 2\n", " ],\n", " \"coef_\":[\n", " [\n", " 0.42625236403173844,\n", " -8.557501546363858\n", " ],\n", " [\n", " 1.5644231337040186,\n", " -1.6783659020502222\n", " ],\n", " [\n", " -1.990675497337773,\n", " 10.235867448186507\n", " ]\n", " ],\n", " \"intercept_\":[\n", " 27.533384852155145,\n", " 4.18509910962595,\n", " -31.71848396177913\n", " ],\n", " \"n_iter_\":[\n", " 27\n", " ]\n", "}\n" ] } ], "source": [ "with open('./sckit-model-to-json/attributes.json', 'r', encoding='utf-8') as infile:\n", " print(infile.read())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With similar ease, we can now use `json`'s `loads` method to read the data back from the \".json\" files and re-assign them to Python objects. (Imagine the following happens in a new Python session.)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "import codecs\n", "import json\n", "\n", "obj_text = codecs.open('./sckit-model-to-json/params.json', 'r', encoding='utf-8').read()\n", "params = json.loads(obj_text)\n", "\n", "obj_text = codecs.open('./sckit-model-to-json/attributes.json', 'r', encoding='utf-8').read()\n", "attributes = json.loads(obj_text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we just need to initialize a default `LogisticRegression` estimator, feed it the desired parameters via the `set_params` method, and reassign the other attributes using Python's built-in `setattr` (don't forget to recast the Python lists to NumPy arrays, though!):" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "from sklearn.linear_model import LogisticRegression \n", "from sklearn.datasets import load_iris\n", "import matplotlib.pyplot as plt\n", "from mlxtend.plotting import plot_decision_regions\n", "import numpy as np\n", "\n", "iris = load_iris()\n", "y, X = iris.target, iris.data[:, [0, 2]] # only use 2 features\n", "lr = LogisticRegression()\n", "\n", "lr.set_params(**params)\n", "for k in attributes:\n", " if isinstance(attributes[k], list):\n", " setattr(lr, k, np.array(attributes[k]))\n", " else:\n", " setattr(lr, k, attributes[k])\n", "\n", "\n", "plot_decision_regions(X=X, y=y, clf=lr, legend=2)\n", "plt.xlabel('sepal length')\n", "plt.ylabel('petal length')\n", "plt.show()" ] } ], "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.6.0" } }, "nbformat": 4, "nbformat_minor": 1 }