A Basic Overview of Using ML Flow

ML flow is a tool for montoring and taracking ml runs with a full server UI here we go over some exaples of use and how it can be incorperted into a google colab.

In [1]:
#Here is the code (meant to be run on a Colab notebook)

!pip install mlflow 
!pip install pyngrok 
Collecting mlflow
  Downloading mlflow-1.22.0-py3-none-any.whl (15.5 MB)
     |████████████████████████████████| 15.5 MB 12.5 MB/s eta 0:00:01
Collecting docker>=4.0.0
  Downloading docker-5.0.3-py2.py3-none-any.whl (146 kB)
     |████████████████████████████████| 146 kB 13.6 MB/s eta 0:00:01
Requirement already satisfied: pyyaml>=5.1 in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (5.3)
Collecting databricks-cli>=0.8.7
  Downloading databricks-cli-0.16.2.tar.gz (58 kB)
     |████████████████████████████████| 58 kB 11.7 MB/s eta 0:00:01
Requirement already satisfied: gitpython>=2.1.0 in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (3.1.14)
Requirement already satisfied: click>=7.0 in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (7.0)
Requirement already satisfied: requests>=2.17.3 in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (2.24.0)
Requirement already satisfied: numpy in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (1.19.5)
Collecting alembic<=1.4.1
  Using cached alembic-1.4.1.tar.gz (1.1 MB)
Requirement already satisfied: packaging in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (20.1)
Collecting querystring-parser
  Using cached querystring_parser-1.2.4-py2.py3-none-any.whl (7.9 kB)
Collecting prometheus-flask-exporter
  Downloading prometheus_flask_exporter-0.18.6-py3-none-any.whl (17 kB)
Collecting gunicorn; platform_system != "Windows"
  Using cached gunicorn-20.1.0-py3-none-any.whl (79 kB)
Requirement already satisfied: pandas in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (1.0.5)
Requirement already satisfied: protobuf>=3.7.0 in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (3.13.0)
Requirement already satisfied: pytz in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (2019.3)
Requirement already satisfied: Flask in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (1.1.1)
Requirement already satisfied: entrypoints in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (0.3)
Requirement already satisfied: sqlalchemy in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (1.3.13)
Collecting importlib-metadata!=4.7.0,>=3.7.0
  Downloading importlib_metadata-4.8.2-py3-none-any.whl (17 kB)
Collecting sqlparse>=0.3.1
  Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 3.2 MB/s  eta 0:00:01
Requirement already satisfied: cloudpickle in /opt/anaconda3/lib/python3.7/site-packages (from mlflow) (1.3.0)
Collecting websocket-client>=0.32.0
  Downloading websocket_client-1.2.3-py3-none-any.whl (53 kB)
     |████████████████████████████████| 53 kB 4.5 MB/s eta 0:00:01
Requirement already satisfied: tabulate>=0.7.7 in /opt/anaconda3/lib/python3.7/site-packages (from databricks-cli>=0.8.7->mlflow) (0.8.9)
Requirement already satisfied: six>=1.10.0 in /opt/anaconda3/lib/python3.7/site-packages (from databricks-cli>=0.8.7->mlflow) (1.15.0)
Requirement already satisfied: gitdb<5,>=4.0.1 in /opt/anaconda3/lib/python3.7/site-packages (from gitpython>=2.1.0->mlflow) (4.0.7)
Requirement already satisfied: certifi>=2017.4.17 in /opt/anaconda3/lib/python3.7/site-packages (from requests>=2.17.3->mlflow) (2019.11.28)
Requirement already satisfied: idna<3,>=2.5 in /opt/anaconda3/lib/python3.7/site-packages (from requests>=2.17.3->mlflow) (2.8)
Requirement already satisfied: chardet<4,>=3.0.2 in /opt/anaconda3/lib/python3.7/site-packages (from requests>=2.17.3->mlflow) (3.0.4)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/anaconda3/lib/python3.7/site-packages (from requests>=2.17.3->mlflow) (1.25.8)
Collecting Mako
  Downloading Mako-1.1.6-py2.py3-none-any.whl (75 kB)
     |████████████████████████████████| 75 kB 8.5 MB/s  eta 0:00:01
Collecting python-editor>=0.3
  Using cached python_editor-1.0.4-py3-none-any.whl (4.9 kB)
Requirement already satisfied: python-dateutil in /opt/anaconda3/lib/python3.7/site-packages (from alembic<=1.4.1->mlflow) (2.8.1)
Requirement already satisfied: pyparsing>=2.0.2 in /opt/anaconda3/lib/python3.7/site-packages (from packaging->mlflow) (3.0.6)
Requirement already satisfied: prometheus-client in /opt/anaconda3/lib/python3.7/site-packages (from prometheus-flask-exporter->mlflow) (0.7.1)
Requirement already satisfied: setuptools>=3.0 in /opt/anaconda3/lib/python3.7/site-packages (from gunicorn; platform_system != "Windows"->mlflow) (46.0.0.post20200309)
Requirement already satisfied: itsdangerous>=0.24 in /opt/anaconda3/lib/python3.7/site-packages (from Flask->mlflow) (1.1.0)
Requirement already satisfied: Werkzeug>=0.15 in /opt/anaconda3/lib/python3.7/site-packages (from Flask->mlflow) (1.0.0)
Requirement already satisfied: Jinja2>=2.10.1 in /opt/anaconda3/lib/python3.7/site-packages (from Flask->mlflow) (2.11.1)
Requirement already satisfied: zipp>=0.5 in /opt/anaconda3/lib/python3.7/site-packages (from importlib-metadata!=4.7.0,>=3.7.0->mlflow) (3.4.1)
Requirement already satisfied: typing-extensions>=3.6.4; python_version < "3.8" in /opt/anaconda3/lib/python3.7/site-packages (from importlib-metadata!=4.7.0,>=3.7.0->mlflow) (3.7.4.3)
Requirement already satisfied: smmap<5,>=3.0.1 in /opt/anaconda3/lib/python3.7/site-packages (from gitdb<5,>=4.0.1->gitpython>=2.1.0->mlflow) (4.0.0)
Requirement already satisfied: MarkupSafe>=0.9.2 in /opt/anaconda3/lib/python3.7/site-packages (from Mako->alembic<=1.4.1->mlflow) (1.1.1)
Building wheels for collected packages: databricks-cli, alembic
  Building wheel for databricks-cli (setup.py) ... done
  Created wheel for databricks-cli: filename=databricks_cli-0.16.2-py3-none-any.whl size=106811 sha256=522ac4fa42a3bfc4d517b851819b157196c160c8ed5392ad4c9867094fdd633d
  Stored in directory: /Users/micintro/Library/Caches/pip/wheels/f4/5c/ed/e1ce20a53095f63b27b4964abbad03e59cf3472822addf7d29
  Building wheel for alembic (setup.py) ... done
  Created wheel for alembic: filename=alembic-1.4.1-py2.py3-none-any.whl size=158155 sha256=30fbb68afe86fcf4834728357003adb823f7c8c9ffac7fce942d901fea7f48a6
  Stored in directory: /Users/micintro/Library/Caches/pip/wheels/be/5d/0a/9e13f53f4f5dfb67cd8d245bb7cdffe12f135846f491a283e3
Successfully built databricks-cli alembic
ERROR: pytest-astropy 0.8.0 requires pytest-cov>=2.0, which is not installed.
ERROR: pytest-astropy 0.8.0 requires pytest-filter-subpackage>=0.1, which is not installed.
ERROR: virtualenv 20.0.21 has requirement importlib-metadata<2,>=0.12; python_version < "3.8", but you'll have importlib-metadata 4.8.2 which is incompatible.
ERROR: huggingface-hub 0.0.12 has requirement packaging>=20.9, but you'll have packaging 20.1 which is incompatible.
ERROR: dvc 2.8.3 has requirement ruamel.yaml>=0.17.11, but you'll have ruamel-yaml 0.15.87 which is incompatible.
Installing collected packages: websocket-client, docker, databricks-cli, Mako, python-editor, alembic, querystring-parser, prometheus-flask-exporter, gunicorn, importlib-metadata, sqlparse, mlflow
  Attempting uninstall: importlib-metadata
    Found existing installation: importlib-metadata 1.5.0
    Uninstalling importlib-metadata-1.5.0:
      Successfully uninstalled importlib-metadata-1.5.0
Successfully installed Mako-1.1.6 alembic-1.4.1 databricks-cli-0.16.2 docker-5.0.3 gunicorn-20.1.0 importlib-metadata-4.8.2 mlflow-1.22.0 prometheus-flask-exporter-0.18.6 python-editor-1.0.4 querystring-parser-1.2.4 sqlparse-0.4.2 websocket-client-1.2.3
Collecting pyngrok
  Downloading pyngrok-5.1.0.tar.gz (745 kB)
     |████████████████████████████████| 745 kB 469 kB/s eta 0:00:01
Requirement already satisfied: PyYAML in /opt/anaconda3/lib/python3.7/site-packages (from pyngrok) (5.3)
Building wheels for collected packages: pyngrok
  Building wheel for pyngrok (setup.py) ... done
  Created wheel for pyngrok: filename=pyngrok-5.1.0-py3-none-any.whl size=18990 sha256=4887e57eb940cba1d262d7df6ed8add385c9cb559432b4b90cf6a991f4cf583b
  Stored in directory: /Users/micintro/Library/Caches/pip/wheels/bf/e6/af/ccf6598ecefecd44104069371795cb9b3afbcd16987f6ccfb3
Successfully built pyngrok
Installing collected packages: pyngrok
Successfully installed pyngrok-5.1.0
In [1]:
# first import the ML flow lib
import mlflow
In [2]:
# start ml flow and set starting run params
with mlflow.start_run(run_name="MLflow on Colab"):
  mlflow.log_metric("m1", 2.0)
  mlflow.log_param("p1", "mlflow-colab")

# run tracking UI in the background
get_ipython().system_raw("mlflow ui --port 5000 &")
In [3]:
#import pyngrok

from pyngrok import ngrok

# Terminate open tunnels if exist
ngrok.kill()

Setting the authtoken (optional)

Get your authtoken from

https://dashboard.ngrok.com/auth

In [4]:
NGROK_AUTH_TOKEN = "1xiKn1eTJOmwpwdB4DtuzRRMXZf_6KBaaCrekZX8Vn7HQjQRP"
ngrok.set_auth_token(NGROK_AUTH_TOKEN)
In [5]:
# Open an HTTPs tunnel on port 5000 for http://localhost:5000
#if you are on the VPN you will have to disconect to use ngrok
#also comment out any proxys in your bash

ngrok_tunnel = ngrok.connect(addr="5000", proto="http", bind_tls=True)
print("MLflow Tracking UI:", ngrok_tunnel.public_url)
MLflow Tracking UI: https://77cc-64-121-43-37.ngrok.io
In [6]:
import mlflow

with mlflow.start_run(run_name="MLflow in Notebook"):
  mlflow.log_metric("m1", 2.0)
  mlflow.log_param("p1", "mlflow-colab")

final summary

The output of this notebook will be a pyngrok-generated URL like:

MLflow Tracking UI: https://0a23d7a7d0c4.ngrok.io clicking on which will lead to an MLfLow GUI screen.

(Slight modification of the original code thanks to pyngrok creator, Alex Laird)

Tested with MLflow versions 1.10.0 and 1.11.0.

next try setting up some ml to track with ngrok tutorials https://dashboard.ngrok.com/get-started/tutorials

Tutorial

This tutorial showcases how you can use MLflow end-to-end to:

Train a linear regression model

Package the code that trains the model in a reusable and reproducible model format

Deploy the model into a simple HTTP server that will enable you to score predictions

This tutorial uses a dataset to predict the quality of wine based on quantitative features like the wine’s “fixed acidity”, “pH”, “residual sugar”, and so on. The dataset is from UCI’s machine learning repository. 1

Table of Contents

What You’ll Need

Training the Model

Comparing the Models

Packaging Training Code in a Conda Environment

Specifying pip requirements using pip_requirements and extra_pip_requirements

Serving the Model

More Resources

What You’ll Need

To run this tutorial, you’ll need to:

PythonR Install MLflow and scikit-learn. There are two options for installing these dependencies:

Install MLflow with extra dependencies, including scikit-learn (via pip install mlflow[extras])

Install MLflow (via pip install mlflow) and install scikit-learn separately (via pip install scikit-learn)

Install conda

Clone (download) the MLflow repository via git clone https://github.com/mlflow/mlflow

cd into the examples directory within your clone of MLflow - we’ll use this working directory for running the tutorial. We avoid running directly from our clone of MLflow as doing so would cause the tutorial to use MLflow from source, rather than your PyPI installation of MLflow.

Training the Model

First, train a linear regression model that takes two hyperparameters: alpha and l1_ratio.

In [ ]:
# The data set used in this example is from http://archive.ics.uci.edu/ml/datasets/Wine+Quality
# P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis.
# Modeling wine preferences by data mining from physicochemical properties. In Decision Support Systems, Elsevier, 47(4):547-553, 2009.

import os
import warnings
import sys

import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet
from urllib.parse import urlparse
import mlflow
import mlflow.sklearn

import logging

logging.basicConfig(level=logging.WARN)
logger = logging.getLogger(__name__)
In [ ]:
def eval_metrics(actual, pred):
    rmse = np.sqrt(mean_squared_error(actual, pred))
    mae = mean_absolute_error(actual, pred)
    r2 = r2_score(actual, pred)
    return rmse, mae, r2
In [ ]:
def Build_ML_Flow():
  warnings.filterwarnings("ignore")
  np.random.seed(40)

  # Read the wine-quality csv file from the URL
  csv_url = (
      "http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
  )
  try:
      data = pd.read_csv(csv_url, sep=";")
  except Exception as e:
      logger.exception(
          "Unable to download training & test CSV, check your internet connection. Error: %s", e
      )



  # Split the data into training and test sets. (0.75, 0.25) split.
  train, test = train_test_split(data)

  # The predicted column is "quality" which is a scalar from [3, 9]
  train_x = train.drop(["quality"], axis=1)
  test_x = test.drop(["quality"], axis=1)
  train_y = train[["quality"]]
  test_y = test[["quality"]]

  try:
    alpha = float(sys.argv[1]) if len(sys.argv) > 1 else 0.5
  except:
    alpha =0.5
  try:
    l1_ratio = float(sys.argv[2]) if len(sys.argv) > 2 else 0.5
  except:
    l1_ratio =0.5



  #run ml flow
  with mlflow.start_run():
        lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
        lr.fit(train_x, train_y)

        predicted_qualities = lr.predict(test_x)

        (rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)

        print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
        print("  RMSE: %s" % rmse)
        print("  MAE: %s" % mae)
        print("  R2: %s" % r2)

        mlflow.log_param("alpha", alpha)
        mlflow.log_param("l1_ratio", l1_ratio)
        mlflow.log_metric("rmse", rmse)
        mlflow.log_metric("r2", r2)
        mlflow.log_metric("mae", mae)
In [ ]:
if __name__ == "__main__":
  Build_ML_Flow()
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
  RMSE: 0.7931640229276851
  MAE: 0.6271946374319586
  R2: 0.10862644997792614

Show the example

This example uses the familiar pandas, numpy, and sklearn APIs to create a simple machine learning model. The MLflow tracking APIs log information about each training run, like the hyperparameters alpha and l1_ratio, used to train the model and metrics, like the root mean square error, used to evaluate the model. The example also serializes the model in a format that MLflow knows how to deploy.

You can run the example with default hyperparameters as follows:

Make sure the current working directory is 'examples'

python sklearn_elasticnet_wine/train.py Try out some other values for alpha and l1_ratio by passing them as arguments to train.py:

Make sure the current working directory is 'examples'

python sklearn_elasticnet_wine/train.py Each time you run the example, MLflow logs information about your experiment runs in the directory mlruns.

Comparing the Models

Next, use the MLflow UI to compare the models that you have produced. In the same current working directory as the one that contains the mlruns run:

In [ ]:
# Open an HTTPs tunnel on port 5000 for http://localhost:5000
ngrok_tunnel = ngrok.connect(addr="5000", proto="http", bind_tls=True)
print("MLflow Tracking UI:", ngrok_tunnel.public_url)
MLflow Tracking UI: https://fea4-34-86-181-2.ngrok.io

Train And Trak Keras Model with MLflow

Trains and evaluate a simple MLP on the Reuters newswire topic classification task.

In [ ]:
import numpy as np
from tensorflow import keras
from tensorflow.keras.datasets import reuters
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation
from tensorflow.keras.preprocessing.text import Tokenizer
In [ ]:
# The following import and function call are the only additions to code required
# to automatically log metrics and parameters to MLflow.
import mlflow.keras

mlflow.keras.autolog()

max_words = 1000
batch_size = 32
epochs = 5

print("Loading data...")
(x_train, y_train), (x_test, y_test) = reuters.load_data(num_words=max_words, test_split=0.2)

print(len(x_train), "train sequences")
print(len(x_test), "test sequences")
Loading data...
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/reuters.npz
2113536/2110848 [==============================] - 0s 0us/step
2121728/2110848 [==============================] - 0s 0us/step
/usr/local/lib/python3.7/dist-packages/mlflow/utils/autologging_utils/__init__.py:411: FutureWarning: Autologging support for keras >= 2.6.0 has been deprecated and will be removed in a future MLflow release. Use `mlflow.tensorflow.autolog()` instead.
  return _autolog(*args, **kwargs)
8982 train sequences
2246 test sequences
In [ ]:
num_classes = np.max(y_train) + 1
print(num_classes, "classes")

print("Vectorizing sequence data...")
tokenizer = Tokenizer(num_words=max_words)
x_train = tokenizer.sequences_to_matrix(x_train, mode="binary")
x_test = tokenizer.sequences_to_matrix(x_test, mode="binary")
print("x_train shape:", x_train.shape)
print("x_test shape:", x_test.shape)

print("Convert class vector to binary class matrix " "(for use with categorical_crossentropy)")
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
print("y_train shape:", y_train.shape)
print("y_test shape:", y_test.shape)
46 classes
Vectorizing sequence data...
x_train shape: (8982, 1000)
x_test shape: (2246, 1000)
Convert class vector to binary class matrix (for use with categorical_crossentropy)
y_train shape: (8982, 46)
y_test shape: (2246, 46)
In [ ]:
print("Building model...")
model = Sequential()
model.add(Dense(512, input_shape=(max_words,)))
model.add(Activation("relu"))
model.add(Dropout(0.5))
model.add(Dense(num_classes))
model.add(Activation("softmax"))

model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

history = model.fit(
    x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_split=0.1
)
score = model.evaluate(x_test, y_test, batch_size=batch_size, verbose=1)
print("Test score:", score[0])
print("Test accuracy:", score[1])
Building model...
2021/10/01 03:44:29 INFO mlflow.utils.autologging_utils: Created MLflow autologging run with ID '2b9415bf8613431ebeaadfb46622ca74', which will track hyperparameters, performance metrics, model artifacts, and lineage information for the current keras workflow
Epoch 1/5
253/253 [==============================] - 3s 7ms/step - loss: 1.4020 - accuracy: 0.6876 - val_loss: 1.0655 - val_accuracy: 0.7686
Epoch 2/5
253/253 [==============================] - 2s 6ms/step - loss: 0.7792 - accuracy: 0.8157 - val_loss: 0.9578 - val_accuracy: 0.7864
Epoch 3/5
253/253 [==============================] - 2s 6ms/step - loss: 0.5348 - accuracy: 0.8732 - val_loss: 0.8490 - val_accuracy: 0.8042
Epoch 4/5
253/253 [==============================] - 2s 6ms/step - loss: 0.4100 - accuracy: 0.8992 - val_loss: 0.8787 - val_accuracy: 0.8120
Epoch 5/5
253/253 [==============================] - 2s 7ms/step - loss: 0.3272 - accuracy: 0.9185 - val_loss: 0.9153 - val_accuracy: 0.8042
INFO:tensorflow:Assets written to: /tmp/tmpdhfamig2/model/data/model/assets
71/71 [==============================] - 0s 3ms/step - loss: 0.8927 - accuracy: 0.7876
Test score: 0.8927369713783264
Test accuracy: 0.7876224517822266

Review what you tracked in ml flow

In [ ]:
# Open an HTTPs tunnel on port 5000 for http://localhost:5000
ngrok_tunnel = ngrok.connect(addr="5000", proto="http", bind_tls=True)
print("MLflow Tracking UI:", ngrok_tunnel.public_url)
MLflow Tracking UI: https://af10-35-221-157-132.ngrok.io
In [ ]: