Skip to content

Instantly share code, notes, and snippets.

@Ben-Epstein
Created July 17, 2020 17:32
Show Gist options
  • Save Ben-Epstein/594dc5ac1c8316e20ad9c03939d52735 to your computer and use it in GitHub Desktop.
Save Ben-Epstein/594dc5ac1c8316e20ad9c03939d52735 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Splice + MLflow: What you need to know\n## Just like the last notebook, maybe an image here of the Splice Logo with a <3 and the MLflow Logo\n<blockquote><p class='quotation'><span style='font-size:15px'>Mlflow allows you to track experiments and share results with teammates easily.<br>At Splice Machine, MLflow is embedded directly into your database (MLManager). This means that all of the configuration is taken care of for you, and <b>everything</b> you track in mlflow is persisted to the database.<br><br>\n MLflow requires the NSDS (or ExtNSDS) as a parameter to connect to the database. If are unfamliar with our NSDS, check out the <a href=\"./7.1 Splice and Spark.ipynb\">previous notebook</a> on using Splice Machine and Spark.<footer>Splice Machine</footer>\n</blockquote>\n\n#### Let's start our Spark Session"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup\nfrom pyspark.sql import SparkSession\nfrom splicemachine.spark import PySpliceContext\n\nspark = SparkSession.builder.getOrCreate()\nsplice = PySpliceContext(spark)\n","execution_count":1,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Importing MLflow Support\n<blockquote><p class='quotation'><span style='font-size:15px'>Using MLflow on Splice is as easy as a single import. After imporing, you immediately have access to the <code>mlflow</code> module. <br>You will have access to all of the functions in the standard MLflow API as well as some extra ones that are custom to Splice Machine.<br> You can check out our full <a href='https://pysplice.readthedocs.io/en/dbaas-4100/splicemachine.mlflow_support.html'>documentation</a> for everything available and our <a href=\"https://www.github.com/splicemachine/pysplice\">GitHub</a> repo to raise issues and ask questions. <br>After importing, you can register your Splice Context for access to even more functions.<br><br><footer>Splice Machine</footer>\n</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# MLFlow Setup\nfrom splicemachine.mlflow_support import *\nmlflow.register_splice_context(splice)","execution_count":3,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Step 0: The MLflow UI\n<blockquote> You can access the MLflow UI in 2 ways:\n <ul>\n <li>From the url at <a href=/mlflow>/mlflow</a></li>\n <li>From the Notebook as an IFrame using the <code>get_mlflow_ui</code> function. You can also pass in an optional experiment ID and/or run ID to open the IFrame directly to your experiment/run.</li>\n </ul>\n</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"from splicemachine.notebook import get_mlflow_ui\nget_mlflow_ui()","execution_count":4,"outputs":[{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/0>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"execute_result","execution_count":4,"data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6d86fa0c50>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/0\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"## MLflow concepts\n<blockquote>MLflow Tracking is organized around the concept <code>experiments</code> and <code>runs</code>:<br> \n <ul>\n <li>Experiments can be thought of as the problem you are trying to track or solve (ie Performance Testing TPC-C</li>\n <li>Runs are single executions of some piece of code (ie a single full execution of TPC-C with some database configuration). Experiments have multiple runs (1-to-many).</li>\n </ul>\n</blockquote>"},{"metadata":{},"cell_type":"markdown","source":"### Setting an Experiment\n<blockquote>To start an Experiment, you can call <code>mlflow.set_experiment('EXP_NAME')</code> and pass in an experiment name.<br> \n If the Experiment exists, it will be set to the <code>active</code> experiment. Otherwise, mlflow will create the Experiment for you and set it to active.\n\n</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"help(mlflow.set_experiment)","execution_count":5,"outputs":[{"output_type":"stream","text":"Help on function set_experiment in module mlflow.tracking.fluent:\n\nset_experiment(experiment_name)\n Set given experiment as active experiment. If experiment does not exist, create an experiment\n with provided name.\n \n :param experiment_name: Name of experiment to be activated.\n\n","name":"stdout"}]},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.set_experiment('mlflow_api_demo')","execution_count":6,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### View Your [Experiment](/mlflow)"},{"metadata":{"trusted":true},"cell_type":"code","source":"exp_id = mlflow.client.get_experiment_by_name('mlflow_api_demo').experiment_id\nget_mlflow_ui(exp_id)","execution_count":7,"outputs":[{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/26>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"execute_result","execution_count":7,"data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6dee735b10>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/26\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"### Starting a run\n<blockquote>Once you have an Experiment, you can start your run by calling <code>mlflow.start_run(run_name='RUN_NAME')</code> and pass in a run name. You can also pass in the optional <code>tags</code> parameter as a dictionary and store key value pairs associated to the run.<br> \nWhen you start a run, MLFlow (MLManager) automatically logs some information for you:\n <ul>\n <li>Start Date</li>\n <li>Current User</li>\n <li>Run ID</li>\n <li>DB Transaction ID</li>\n <li>Source (where the run came from)</li>\n </ul>\n</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"help(mlflow.start_run)","execution_count":8,"outputs":[{"output_type":"stream","text":"Help on function _start_run in module splicemachine.mlflow_support.mlflow_support:\n\n_start_run(run_id=None, tags=None, experiment_id=None, run_name=None, nested=False)\n Start a new run\n :param tags: a dictionary containing metadata about the current run.\n For example:\n {\n 'team': 'pd',\n 'purpose': 'r&d'\n }\n :param run_name: an optional name for the run to show up in the MLFlow UI\n :param run_id: if you want to reincarnate an existing run, pass in the run id\n :param experiment_id: if you would like to create an experiment/use one for this run\n :param nested: Controls whether run is nested in parent run. True creates a nest run\n\n","name":"stdout"}]},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.start_run(run_name='First_pass_default_settings', tags={'team': 'pd', 'purpose':'performance testing'})","execution_count":16,"outputs":[{"output_type":"execute_result","execution_count":16,"data":{"text/plain":"<ActiveRun: >"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"### Tracking Concepts\n<blockquote>There are 4 main conepts when tracking a run:<br>\n <ul>\n <li><b>Tags</b>: Any key value pair that likely won't be used for comparison between runs (non-measurable items). Only tags can be overwritten</li>\n <li><b>Parameters</b>: Configuration options that were made before starting the run that may have a measurable effect on the outcome</li>\n <li><b>Metrics</b>: The measured outcomes between runs that can be compared. Metrics have an optional <code>step</code> parmeter if you want to track metrics over time for a specific run</li>\n <li><b>Artifacts</b>: Objects (files, images, notebooks, etc) to be associated with a run</li>\n </ul>\n</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"help(mlflow.set_tag)\nprint('---------------------------------------------------------------------------------')\nhelp(mlflow.lp)\nprint('---------------------------------------------------------------------------------')\nhelp(mlflow.lm)\nprint('---------------------------------------------------------------------------------')\nhelp(mlflow.log_artifact)","execution_count":17,"outputs":[{"output_type":"stream","text":"Help on function set_tag in module mlflow.tracking.fluent:\n\nset_tag(key, value)\n Set a tag under the current run. If no run is active, this method will create a\n new active run.\n \n :param key: Tag name (string)\n :param value: Tag value (string, but will be string-ified if not)\n\n---------------------------------------------------------------------------------\nHelp on function _lp in module splicemachine.mlflow_support.mlflow_support:\n\n_lp(key, value)\n Add a shortcut for logging parameters in MLFlow.\n Accessible from mlflow.lp\n :param key: key for the parameter\n :param value: value for the parameter\n\n---------------------------------------------------------------------------------\nHelp on function _lm in module splicemachine.mlflow_support.mlflow_support:\n\n_lm(key, value, step=None)\n Add a shortcut for logging metrics in MLFlow.\n Accessible from mlflow.lm\n :param key: key for the parameter\n :param value: value for the parameter\n\n---------------------------------------------------------------------------------\nHelp on function _log_artifact in module splicemachine.mlflow_support.mlflow_support:\n\n_log_artifact(file_name, name, run_uuid=None)\n Log an artifact for the active run\n :param file_name: (str) the name of the file name to log\n :param name: (str) the name of the run relative name to store the model under\n :param run_uuid: the run uuid of a previous run, if none, defaults to current run\n NOTE: We do not currently support logging directories. If you would like to log a directory, please zip it first\n and log the zip file\n\n","name":"stdout"}]},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.set_tag('teammates', 'carol, daniel')","execution_count":18,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.lp('spark executors', '5')","execution_count":19,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.lm('execution time sec', 25)","execution_count":20,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setting metrics over \"steps\"\nfor i in range(10):\n mlflow.lm('Build time', i*3, step=i)","execution_count":21,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"get_mlflow_ui(mlflow.current_exp_id(), mlflow.current_run_id())","execution_count":22,"outputs":[{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/26/runs/8b0159a70a5c>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"execute_result","execution_count":22,"data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6d8638c2d0>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/26/runs/8b0159a70a5c\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"### End Run\n<blockquote>When you finish a run, you call <code>mlflow.end_run()</code>.<br> You know a run is ended in the MLFlow UI because there is a green check mark next to it</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"mlflow.end_run()","execution_count":23,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Artifacts\n<blockquote>Artifacts can be any file type. The artifact is serialized as a BLOB and stored in the database. When storing artifacts in the database, files with file extensions such as <code>.txt</code>, <code>.pdf</code>, <code>.yaml</code>, <code>.pdf</code>, <code>.jpeg</code> etc. will be available for preview in the mlflow ui <br>We can use some neat Jupyter tricks like <code>writefile</code> to make artifacts even more useful.\n</blockquote>\n\n#### Write a yaml file"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile my_env.yaml\n\nname: datatest \nchannels:\n- defaults\n- conda-forge\n- ericmjl\ndependencies:\n- python=3.6\n- colorama=0.3.9\n- jupyter=1.0.0\n- ipykernel=4.6.1\n- jupyterlab=0.25.2\n- pytest=3.1.3\n- pytest-cov=2.5.1\n- tinydb=3.3.1\n- pyyaml=3.12\n- pandas-summary=0.0.41\n- environment_kernels=1.1\n- missingno=0.3.7\n","execution_count":24,"outputs":[{"output_type":"stream","text":"Overwriting my_env.yaml\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"#### Write a code snippet"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile harm_mean.py\ndef harm_mean(nums, rnd=4):\n \"\"\"\n Calculates the harmonic mean of n numbers rounded to rnd decimal places\n :param nums: List of numbers\n :param rnd: Number of decimal places to round the result\n \"\"\"\n return round(len(nums)/sum([1/i for i in nums]),rnd)","execution_count":25,"outputs":[{"output_type":"stream","text":"Overwriting harm_mean.py\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"## Put it together\n#### Start a run, log our artifacts, view the results"},{"metadata":{"trusted":true},"cell_type":"code","source":"!jupyter nbconvert --to html '7.2 Splice MLflow Support.ipynb'\nwith mlflow.start_run(run_name='environment_requirements'):\n run_id = mlflow.current_run_id()\n exp_id = mlflow.current_exp_id()\n mlflow.log_artifact('my_env.yaml', name='my_env.yaml')\n mlflow.log_artifact('harm_mean.py', name='harm_mean.py')\n mlflow.log_artifact('7.2 Splice MLflow Support.ipynb', name='training_notebook.ipynb')\n mlflow.log_artifact('7.2 Splice MLflow Support.html', name='training_notebook.html')","execution_count":26,"outputs":[{"output_type":"stream","text":"[NbConvertApp] Converting notebook 7.2 Splice MLflow Support.ipynb to html\n[NbConvertApp] Writing 358977 bytes to 7.2 Splice MLflow Support.html\nSaving artifact of size: 0.349 KB to Splice Machine DB\nSaving artifact of size: 0.328 KB to Splice Machine DB\nSaving artifact of size: 53.573 KB to Splice Machine DB\nSaving artifact of size: 359.035 KB to Splice Machine DB\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"#### Click on one of your artifacts to render the results!"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"get_mlflow_ui(exp_id, run_id)","execution_count":27,"outputs":[{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/26/runs/26342e253ff0>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"execute_result","execution_count":27,"data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6d86390290>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/26/runs/26342e253ff0\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"#### Another Artifact Example"},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom random import random\nwith mlflow.start_run(run_name='my_plot'):\n plt.rcParams.update({\n \"pgf.texsystem\": \"pdflatex\",\n \"pgf.preamble\": [\n r\"\\usepackage[utf8x]{inputenc}\",\n r\"\\usepackage[T1]{fontenc}\",\n r\"\\usepackage{cmbright}\",\n ]\n })\n\n plt.figure(figsize=(4.5, 2.5))\n plt.plot([random()*19 for _ in range(10)])\n plt.text(0.5, 3., \"serif\", family=\"serif\")\n plt.text(0.5, 2., \"monospace\", family=\"monospace\")\n plt.text(2.5, 2., \"sans-serif\", family=\"sans-serif\")\n plt.xlabel(r\"µ is not $\\mu$\")\n plt.tight_layout(.5)\n\n plt.savefig(\"pgf_texsystem.png\")\n mlflow.log_artifact('pgf_texsystem.png', 'results.png')\n display(get_mlflow_ui(mlflow.current_exp_id(), mlflow.current_run_id()))","execution_count":28,"outputs":[{"output_type":"stream","text":"/opt/conda/lib/python3.7/site-packages/matplotlib/backend_bases.py:57: DeprecationWarning: PILLOW_VERSION is deprecated and will be removed in a future release. Use __version__ instead.\n from PIL import PILLOW_VERSION\n","name":"stderr"},{"output_type":"stream","text":"Saving artifact of size: 11.711 KB to Splice Machine DB\n","name":"stdout"},{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/26/runs/7c10c68d11b3>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6d85bab550>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/26/runs/7c10c68d11b3\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 324x180 with 1 Axes>","image/png":"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\n"},"metadata":{"needs_background":"light"}}]},{"metadata":{},"cell_type":"markdown","source":"### Context Managers in Runs\n<blockquote>There are 2 Context Managers in MLManager/MLflow. <code>start_run</code> and <code>timer</code>.<br>\nContext managers enable some autologging and cleanup functions for you. To use a Context Manager, prepend the command with the <code>with</code> call append a <code>:</code> after the call, and indent all lines after it.<br>\nAnother great feature is if the run fails for some reason MLflow will track that for you</blockquote>"},{"metadata":{"trusted":true},"cell_type":"code","source":"with mlflow.start_run(run_name='run with context manager'):\n mlflow.lp('foo','bar')\n mlflow.lm('score', 92)","execution_count":29,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with mlflow.start_run(run_name='a run that failed'):\n raise Exception","execution_count":30,"outputs":[{"output_type":"error","ename":"Exception","evalue":"","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mException\u001b[0m Traceback (most recent call last)","\u001b[0;32m<ipython-input-30-583755d4e51d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mmlflow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstart_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrun_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'a run that failed'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;31mException\u001b[0m: "]}]},{"metadata":{"trusted":true},"cell_type":"code","source":"from time import sleep\n# Multiple context managers\nwith mlflow.start_run(run_name='using the timer too'):\n with mlflow.timer('run time'):\n sleep(2)\n print('done!')","execution_count":31,"outputs":[{"output_type":"stream","text":"Starting Code Block run time... Done.\nCode Block run time:\nRan in 2.001 secs\nRan in 0.033 mins\ndone!\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"#### Timers are default stored as parameters, but can also be stored as metrics"},{"metadata":{"trusted":true},"cell_type":"code","source":"from time import sleep\n# Multiple context managers\nwith mlflow.start_run(run_name='using the timer as a metric'):\n with mlflow.timer('run time', param=False):\n sleep(2)\n print('done!')","execution_count":32,"outputs":[{"output_type":"stream","text":"Starting Code Block run time... Done.\nCode Block run time:\nRan in 2.002 secs\nRan in 0.033 mins\ndone!\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"### Nested Runs\n<blockquote>MLFlow supports the concept of <code>nested</code> runs. A nested run is a run that occurs underneath a parent run. In machine learning, this could be used for hyperparmeter tuning (like choosing K in a k-means clustering algorithm). But it can be used for anything you find useful.<br> To use it, simply pass <code>nested=True</code> to the <code>start_run</code> function</blockquote>"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"from random import randint, sample\nfrom time import sleep\nfrom tqdm.notebook import tqdm\nexec_time = [1,3,5,2]\nnum_execs = []\nwith mlflow.start_run(run_name='parent run'):\n for i in tqdm(range(4)):\n with mlflow.start_run(run_name=f'child {i+1}', nested=True):\n with mlflow.timer('run time', param=False):\n sleep(exec_time[i])\n mlflow.set_tag('child', 'yes')\n mlflow.lp('num_executors', i+1)\n num_execs.append(i+1)\n # Plot results\n plt.figure(figsize=(4.5, 2.5))\n plt.plot(num_execs, exec_time)\n\n plt.ylabel('exec time')\n plt.xlabel('num executors')\n plt.tight_layout(.5)\n plt.savefig(\"spark_results.png\")\n mlflow.log_artifact('spark_results.png','spark_results.png')\n display(get_mlflow_ui(mlflow.current_exp_id()))","execution_count":33,"outputs":[{"output_type":"display_data","data":{"text/plain":"HBox(children=(FloatProgress(value=0.0, max=4.0), HTML(value='')))","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"b6847259d96749388c62fea2fd98f271"}},"metadata":{}},{"output_type":"stream","text":"Starting Code Block run time... Done.\nCode Block run time:\nRan in 1.001 secs\nRan in 0.017 mins\nStarting Code Block run time... Done.\nCode Block run time:\nRan in 3.002 secs\nRan in 0.05 mins\nStarting Code Block run time... Done.\nCode Block run time:\nRan in 5.004 secs\nRan in 0.083 mins\nStarting Code Block run time... Done.\nCode Block run time:\nRan in 2.002 secs\nRan in 0.033 mins\n\nSaving artifact of size: 8.37 KB to Splice Machine DB\n","name":"stdout"},{"output_type":"display_data","data":{"text/plain":"<IPython.core.display.HTML object>","text/html":"<font size=\"+1\"><a target=\"_blank\" href=/mlflow/#/experiments/26>MLFlow UI</a></font>"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<IPython.lib.display.IFrame at 0x7f6d856c2c10>","text/html":"\n <iframe\n width=\"100%\"\n height=\"500px\"\n src=\"/mlflow/#/experiments/26\"\n frameborder=\"0\"\n allowfullscreen\n ></iframe>\n "},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"<Figure size 324x180 with 1 Axes>","image/png":"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\n"},"metadata":{"needs_background":"light"}}]},{"metadata":{},"cell_type":"markdown","source":"## Storing ML Models\n<blockquote><p class='quotation'><span style='font-size:15px'>Just like everything else we've tracked so far, tracking ML Models is easy with Splice Machine's MLManager. The <code>log_model</code> and <code>load_model</code> functions are all you need. \n <footer>Splice Machine</footer> \n</blockquote>\n\n#### Let's try it out"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn import svm\nfrom sklearn import datasets\nfrom sklearn.metrics import accuracy_score\n\n# Start a run\nwith mlflow.start_run(run_name='my first model'):\n # Load some sklearn data\n digits = datasets.load_digits()\n\n # Build a simple model\n clf = svm.SVC(gamma=0.001, C=100.)\n # Log parameters to mlflow\n mlflow.lp('gamma', 0.001)\n mlflow.lp('C', 100.0)\n\n # Train the model\n with mlflow.timer('train_time'):\n clf.fit(digits.data[:-1], digits.target[:-1])\n\n # Predict with some data\n preds = clf.predict(digits.data[:-1])\n\n # Measure accuracy\n acc = accuracy_score(digits.target[:-1], preds)\n print('Accuracy:',acc)\n # Log metric to mlflow\n mlflow.lm('accuracy', acc)\n \n # Save model\n mlflow.log_model(clf, 'clf_model')\n rid = mlflow.current_run_id()","execution_count":45,"outputs":[{"output_type":"stream","text":"Starting Code Block train_time... Done.\nCode Block train_time:\nRan in 0.156 secs\nRan in 0.003 mins\nAccuracy: 1.0\nSaving artifact of size: 473.58 KB to Splice Machine DB\n","name":"stdout"}]},{"metadata":{},"cell_type":"markdown","source":"#### Load our model back and make new predictions"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"loaded_model = mlflow.load_model(run_id=rid, name='clf_model')\ndisplay(loaded_model)\n# Make a new prediction\nnew_data = [ \n 0., 0., 12., 10., 0., 0., 0., 0., 0., 0., 14., 16., 16.,\n 14., 0., 0., 0., 0., 13., 16., 15., 10., 1., 0., 0., 0.,\n 11., 16., 16., 7., 0., 0., 0., 0., 0., 4., 7., 16., 7.,\n 0., 0., 0., 0., 0., 4., 16., 9., 0., 0., 0., 5., 4.,\n 12., 16., 4., 0., 0., 0., 9., 16., 16., 10., 0., 0.\n]\nprint('Prediction on new data:', loaded_model.predict([new_data])[0])","execution_count":56,"outputs":[{"output_type":"display_data","data":{"text/plain":"SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0,\n decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf',\n max_iter=-1, probability=False, random_state=None, shrinking=True,\n tol=0.001, verbose=False)"},"metadata":{}},{"output_type":"stream","text":"Prediction on new data: 5\n","name":"stdout"}]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Fantastic!\n<blockquote> \nNow you have all of the tools necessary to start accessing and manipulating your Big Data with Spark and Splice Machine. Again, feel free to check out our <a href=\"https://pysplice.readthedocs.io/en/dbaas-4100/splicemachine.mlflow_support.html\">documentation</a>!<br><br>\n Next Up: <a href='./7.3 Data Exploration.ipynb'>Using MLManager to explore and analyze your data</a>\n<footer>Splice Machine</footer>\n</blockquote>"}],"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"toc":{"nav_menu":{},"number_sections":false,"sideBar":true,"skip_h1_title":false,"base_numbering":1,"title_cell":"Table of Contents","title_sidebar":"Contents","toc_cell":false,"toc_position":{"height":"calc(100% - 180px)","width":"242px","left":"10px","top":"150px"},"toc_section_display":true,"toc_window_display":true}},"nbformat":4,"nbformat_minor":4}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment