Пашырэнне магчымасцяў Spark з дапамогай MLflow

Прывітанне, хабраўчане. Як мы ўжо пісалі, у гэтым месяцы OTUS запускае адразу два курсы па машынным навучанні, а менавіта базавы и прасунуты. У сувязі з гэтым працягваем дзяліцца карысным матэрыялам.

Мэта гэтага артыкула – расказаць пра наш першы досвед выкарыстання MLflow.

Мы пачнем агляд MLflow з яго tracking-сервера і пралагуем ўсе ітэрацыі даследаванні. Затым падзелімся досведам злучэння Spark з MLflow з дапамогай UDF.

Кантэкст

мы ў Alpha Health выкарыстоўваем машыннае навучанне і штучны інтэлект, каб даць людзям магчымасць клапаціцца аб сваім здароўі і дабрабыце. Таму мадэлі машыннага навучання ляжаць у аснове распрацоўваных намі прадуктаў апрацоўкі дадзеных, і менавіта таму нашу ўвагу прыцягнула MLflow - платформа з адкрытым зыходным кодам, якая ахоплівае ўсе аспекты жыццёвага цыкла машыннага навучання.

MLflow

Асноўная мэта MLflow – забяспечыць дадатковы пласт па-над машынным навучаннем, які дазволіў бы спецыялістам па data science працаваць практычна з любой бібліятэкай машыннага навучання (h2o, керас, mleap, піторх, склерн и tensorflow), выводзячы яе працу на новы ўзровень.

MLflow забяспечвае тры кампаненты:

  • Адсочванне – запіс і запыты да эксперыментаў: код, даныя, канфігурацыя і вынікі. Сачыць за працэсам стварэння мадэлі вельмі важна.
  • праектаў – Фармат упакоўкі для запуску на любой платформе (напрыклад, SageMaker)
  • мадэлі - Агульны фармат адпраўкі мадэляў у розныя прылады разгортвання.

MLflow (на момант напісання артыкула ў alpha-версіі) - платформа з адкрытым зыходным кодам, якая дазваляе кіраваць жыццёвым цыклам машыннага навучання, у тым ліку эксперыментамі, перавыкарыстаннем і разгортваннем.

Настройка MLflow

Для выкарыстання MLflow трэба спачатку наладзіць усё асяроддзе Python, для гэтага мы скарыстаемся PyEnv (каб усталяваць Python на Mac, зазірніце сюды). Так мы зможам стварыць віртуальнае асяроддзе, куды ўсталюем усе неабходныя для запуску бібліятэкі.

```
pyenv install 3.7.0
pyenv global 3.7.0 # Use Python 3.7
mkvirtualenv mlflow # Create a Virtual Env with Python 3.7
workon mlflow
```

Усталюем патрабаваныя бібліятэкі.

```
pip install mlflow==0.7.0 
            Cython==0.29  
            numpy==1.14.5 
            pandas==0.23.4 
            pyarrow==0.11.0
```

Заўвага: мы выкарыстоўваем PyArrow для запуску такіх мадэляў, як UDF. Версіі PyArrow і Numpy трэба было выправіць, паколькі апошнія версіі канфліктавалі паміж сабой.

Запускаем Tracking UI

MLflow Tracking дазваляе нам лагіраваць і рабіць запыты да эксперыментаў з дапамогай Python і REST API. Апроч гэтага, можна вызначыць, дзе захоўваць артэфакты мадэлі (localhost, Amazon S3, Azure Blob Storage, Google Cloud Storage або SFTP-сервер). Паколькі ў Alpha Health мы карыстаемся AWS, у якасці сховішчы артэфактаў будзе S3.

# Running a Tracking Server
mlflow server 
    --file-store /tmp/mlflow/fileStore 
    --default-artifact-root s3://<bucket>/mlflow/artifacts/ 
    --host localhost
    --port 5000

MLflow рэкамендуе выкарыстоўваць сталае файлавае сховішча. Файлавае сховішча - гэта месца, дзе сервер будзе захоўваць метададзеныя запускаў і эксперыментаў. Пры запуску сервера пераканайцеся, што ён паказвае на сталае файлавае сховішча. Тут для эксперыменту мы проста скарыстаемся /tmp.

Памятайце аб тым, што, калі мы хочам выкарыстоўваць сервер mlflow для запуску старых эксперыментаў, яны павінны прысутнічаць у файлавым сховішчы. Аднак і без гэтага мы б змаглі іх выкарыстоўваць у UDF, паколькі нам патрэбен толькі шлях да мадэлі.

Заўвага: Майце на ўвазе, што Tracking UI і кліент мадэлі павінны мець доступ да месцазнаходжання артэфакта. Гэта значыць па-за залежнасцю ад таго, што Tracking UI размяшчаецца ў асобніку EC2, пры лакальным запуску MLflow у машыны павінен быць прамы доступ да S3 для запісу мадэляў артэфактаў.

Пашырэнне магчымасцяў Spark з дапамогай MLflow
Tracking UI захоўвае артэфакты ў бакеце S3

Запуск мадэляў

Як толькі будзе працаваць Tracking-сервер, можна пачынаць навучаць мадэлі.

У якасці прыкладу мы скарыстаемся мадыфікацыяй wine з прыкладу MLflow у Склеарн.

MLFLOW_TRACKING_URI=http://localhost:5000 python wine_quality.py 
  --alpha 0.9
  --l1_ration 0.5
  --wine_file ./data/winequality-red.csv

Як мы ўжо казалі, MLflow дазваляе лагіраваць параметры, метрыкі і артэфакты мадэляў, каб можна было адсочваць, як яны развіваюцца па меры ітэрацый. Гэтая функцыя вельмі карысная, паколькі так мы зможам прайграць лепшую мадэль, звярнуўшыся ў Tracking-серверу ці зразумеўшы, які код выканаў патрэбную ітэрацыю, скарыстаўшыся логамі git hash комітаў.

with mlflow.start_run():

    ... model ...

    mlflow.log_param("source", wine_path)
    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)

    mlflow.set_tag('domain', 'wine')
    mlflow.set_tag('predict', 'quality')
    mlflow.sklearn.log_model(lr, "model")

Пашырэнне магчымасцяў Spark з дапамогай MLflow
Ітэрацыі wine

Серверная частка для мадэлі

Tracking-сервер MLflow, запушчаны з дапамогай каманды "mlflow server", мае REST API для адсочвання запускаў і запісы дадзеных у лакальную файлавую сістэму. Вы можаце пазначыць адрас tracking-сервера з дапамогай пераменнага асяроддзя «MLFLOW_TRACKING_URI» і tracking API MLflow аўтаматычна звяжацца з tracking-серверам па гэтым адрасе, каб стварыць/атрымаць інфармацыю аб запуску, метрыкі логаў і г.д.

Крыніца: Docs// Running a tracking server

Каб забяспечыць мадэль серверам нам спатрэбіцца запушчаны tracking-сервер (гл. інтэрфейс запуску) і Run ID мадэлі.

Пашырэнне магчымасцяў Spark з дапамогай MLflow
Run ID

# Serve a sklearn model through 127.0.0.0:5005
MLFLOW_TRACKING_URI=http://0.0.0.0:5000 mlflow sklearn serve 
  --port 5005  
  --run_id 0f8691808e914d1087cf097a08730f17 
  --model-path model

Для абслугоўвання мадэляў з дапамогай функцыяналу MLflow serve, нам спатрэбіцца доступ да Tracking UI, каб атрымліваць інфармацыю аб мадэлі проста паказаўшы --run_id.

Як толькі мадэль звязваецца з Tracking-серверам, мы можам атрымаць новую канчатковую кропку мадэлі.

# Query Tracking Server Endpoint
curl -X POST 
  http://127.0.0.1:5005/invocations 
  -H 'Content-Type: application/json' 
  -d '[
	{
		"fixed acidity": 3.42, 
		"volatile acidity": 1.66, 
		"citric acid": 0.48, 
		"residual sugar": 4.2, 
		"chloridessssss": 0.229, 
		"free sulfur dsioxide": 19, 
		"total sulfur dioxide": 25, 
		"density": 1.98, 
		"pH": 5.33, 
		"sulphates": 4.39, 
		"alcohol": 10.8
	}
]'

> {"predictions": [5.825055635303461]}

Запуск мадэляў з Spark

Нягледзячы на ​​тое, што Tracking-сервер досыць магутны для абслугоўвання мадэляў у рэжыме рэальнага часу, іх навучання і выкарыстанні функцыяналуserve (крыніца: mlflow // docs // models # local), прымяненне Spark (batch або streaming) - яшчэ больш магутнае рашэнне за кошт размеркаванасці.

Уявіце, што вы проста правялі навучанне ў афлайне, а потым ужылі выходную мадэль да ўсіх вашых дадзеных. Менавіта тут Spark і MLflow пакажуць сябе з лепшага боку.

Усталёўваны PySpark + Jupyter + Spark

Крыніца: Get started PySpark - Jupyter

Каб паказаць, як мы ўжываем мадэлі MLflow да датафрэймаў Spark, трэба наладзіць сумесную працу Jupyter notebooks з PySpark.

Пачніце з усталёўкі апошняй стабільнай версіі Apache Spark:

cd ~/Downloads/
tar -xzf spark-2.4.3-bin-hadoop2.7.tgz
mv ~/Downloads/spark-2.4.3-bin-hadoop2.7 ~/
ln -s ~/spark-2.4.3-bin-hadoop2.7 ~/spark̀

Усталюйце PySpark і Jupyter у віртуальнае асяроддзе:

pip install pyspark jupyter

Наладзьце зменныя асяроддзі:

export SPARK_HOME=~/spark
export PATH=$SPARK_HOME/bin:$PATH
export PYSPARK_DRIVER_PYTHON=jupyter
export PYSPARK_DRIVER_PYTHON_OPTS="notebook --notebook-dir=${HOME}/Projects/notebooks"

вызначыўшы notebook-dir, мы зможам захоўваць нашы notebook-і ў жаданай тэчцы.

Запускаем Jupyter з PySpark

Паколькі мы змаглі наладзіць Jupiter у якасці драйвера PySpark, зараз мы можам запускаць Jupyter notebook у кантэксце PySpark.

(mlflow) afranzi:~$ pyspark
[I 19:05:01.572 NotebookApp] sparkmagic extension enabled!
[I 19:05:01.573 NotebookApp] Serving notebooks from local directory: /Users/afranzi/Projects/notebooks
[I 19:05:01.573 NotebookApp] The Jupyter Notebook is running at:
[I 19:05:01.573 NotebookApp] http://localhost:8888/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745
[I 19:05:01.573 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 19:05:01.574 NotebookApp]

    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://localhost:8888/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745

Пашырэнне магчымасцяў Spark з дапамогай MLflow

Як было сказана вышэй, MLflow падае функцыю лагавання артэфактаў мадэлі ў S3. Як толькі ў нас у руках з'яўляецца абраная мадэль, мы маем магчымасць імпартаваць яе як UDF з дапамогай модуля mlflow.pyfunc.

import mlflow.pyfunc

model_path = 's3://<bucket>/mlflow/artifacts/1/0f8691808e914d1087cf097a08730f17/artifacts/model'
wine_path = '/Users/afranzi/Projects/data/winequality-red.csv'
wine_udf = mlflow.pyfunc.spark_udf(spark, model_path)

df = spark.read.format("csv").option("header", "true").option('delimiter', ';').load(wine_path)
columns = [ "fixed acidity", "volatile acidity", "citric acid",
            "residual sugar", "chlorides", "free sulfur dioxide",
            "total sulfur dioxide", "density", "pH",
            "sulphates", "alcohol"
          ]
          
df.withColumn('prediction', wine_udf(*columns)).show(100, False)

Пашырэнне магчымасцяў Spark з дапамогай MLflow
PySpark - Выснова прагнозу якасці віна

Да гэтага моманту мы казалі аб тым, як выкарыстоўваць PySpark з MLflow, запускаючы прагназаванне якасці віна на ўсім наборы дадзеных wine. Але што рабіць, калі трэба выкарыстоўваць модулі Python MLflow са Scala Spark?

Мы пратэставалі і гэта, падзяліўшы кантэкст Spark паміж Scala і Python. Гэта значыць, мы зарэгістравалі MLflow UDF у Python, і выкарыстоўвалі яго з Scala (так, магчыма, не лепшае рашэнне, але што маем).

Scala Spark + MLflow

Для гэтага прыкладу мы дадамо Toree Kernel у існуючы Jupiter.

Усталёўваны Spark + Toree + Jupyter

pip install toree
jupyter toree install --spark_home=${SPARK_HOME} --sys-prefix
jupyter kernelspec list
```
```
Available kernels:
  apache_toree_scala    /Users/afranzi/.virtualenvs/mlflow/share/jupyter/kernels/apache_toree_scala
  python3               /Users/afranzi/.virtualenvs/mlflow/share/jupyter/kernels/python3
```

Як відаць з прымацаванага notebook-а, UDF выкарыстоўваецца сумесна Spark і PySpark. Мы спадзяемся, што гэтая частка будзе карысная тым, хто кахае Scala і жадае разгарнуць мадэлі машыннага навучання на прадакшэне.

import org.apache.spark.sql.functions.col
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.{Column, DataFrame}
import scala.util.matching.Regex

val FirstAtRe: Regex = "^_".r
val AliasRe: Regex = "[\s_.:@]+".r

def getFieldAlias(field_name: String): String = {
    FirstAtRe.replaceAllIn(AliasRe.replaceAllIn(field_name, "_"), "")
}

def selectFieldsNormalized(columns: List[String])(df: DataFrame): DataFrame = {
    val fieldsToSelect: List[Column] = columns.map(field =>
        col(field).as(getFieldAlias(field))
    )
    df.select(fieldsToSelect: _*)
}

def normalizeSchema(df: DataFrame): DataFrame = {
    val schema = df.columns.toList
    df.transform(selectFieldsNormalized(schema))
}

FirstAtRe = ^_
AliasRe = [s_.:@]+

getFieldAlias: (field_name: String)String
selectFieldsNormalized: (columns: List[String])(df: org.apache.spark.sql.DataFrame)org.apache.spark.sql.DataFrame
normalizeSchema: (df: org.apache.spark.sql.DataFrame)org.apache.spark.sql.DataFrame
Out[1]:
[s_.:@]+
In [2]:
val winePath = "~/Research/mlflow-workshop/examples/wine_quality/data/winequality-red.csv"
val modelPath = "/tmp/mlflow/artifactStore/0/96cba14c6e4b452e937eb5072467bf79/artifacts/model"

winePath = ~/Research/mlflow-workshop/examples/wine_quality/data/winequality-red.csv
modelPath = /tmp/mlflow/artifactStore/0/96cba14c6e4b452e937eb5072467bf79/artifacts/model
Out[2]:
/tmp/mlflow/artifactStore/0/96cba14c6e4b452e937eb5072467bf79/artifacts/model
In [3]:
val df = spark.read
              .format("csv")
              .option("header", "true")
              .option("delimiter", ";")
              .load(winePath)
              .transform(normalizeSchema)

df = [fixed_acidity: string, volatile_acidity: string ... 10 more fields]
Out[3]:
[fixed_acidity: string, volatile_acidity: string ... 10 more fields]
In [4]:
%%PySpark
import mlflow
from mlflow import pyfunc

model_path = "/tmp/mlflow/artifactStore/0/96cba14c6e4b452e937eb5072467bf79/artifacts/model"
wine_quality_udf = mlflow.pyfunc.spark_udf(spark, model_path)

spark.udf.register("wineQuality", wine_quality_udf)
Out[4]:
<function spark_udf.<locals>.predict at 0x1116a98c8>
In [6]:
df.createOrReplaceTempView("wines")
In [10]:
%%SQL
SELECT 
    quality,
    wineQuality(
        fixed_acidity,
        volatile_acidity,
        citric_acid,
        residual_sugar,
        chlorides,
        free_sulfur_dioxide,
        total_sulfur_dioxide,
        density,
        pH,
        sulphates,
        alcohol
    ) AS prediction
FROM wines
LIMIT 10
Out[10]:
+-------+------------------+
|quality|        prediction|
+-------+------------------+
|      5| 5.576883967129615|
|      5|  5.50664776916154|
|      5| 5.525504822954496|
|      6| 5.504311247097457|
|      5| 5.576883967129615|
|      5|5.5556903912725755|
|      5| 5.467882654744997|
|      7| 5.710602976324739|
|      7| 5.657319539336507|
|      5| 5.345098606538708|
+-------+------------------+

In [17]:
spark.catalog.listFunctions.filter('name like "%wineQuality%").show(20, false)

+-----------+--------+-----------+---------+-----------+
|name       |database|description|className|isTemporary|
+-----------+--------+-----------+---------+-----------+
|wineQuality|null    |null       |null     |true       |
+-----------+--------+-----------+---------+-----------+

наступныя крокі

Нягледзячы на ​​тое, што на момант напісання артыкула MLflow знаходзіцца ў Alpha-версіі, яна выглядае даволі шматабяцальна. Адна толькі магчымасць запускаць некалькі фрэймворкаў машыннага навучання і выкарыстоўваць іх з адной канчатковай кропкі выводзіць рэкамендацыйныя сістэмы на новы ўзровень.

Да таго ж, MLflow збліжае Data-інжынераў і адмыслоўцаў па Data Science, пракладваючы паміж імі агульны пласт.

Пасля гэтага даследавання MLflow, мы ўпэўненыя, што пойдзем далей і будзем выкарыстоўваць яе для нашых пайплайнаў Spark і ў рэкамендацыйных сістэмах.

Было б нядрэнна сінхранізаваць файлавае сховішча з базай дадзеных, замест файлавай сістэмы. Так мы павінны атрымаць некалькі канчатковых кропак, якія могуць выкарыстоўваць адно і тое ж файлавае сховішча. Напрыклад, выкарыстоўваць некалькі экзэмпляраў Престо и Афіна з адным і тым жа Glue metastore.

Падводзячы вынікі, жадаецца сказаць дзякуй супольнасці MLFlow за тое, што робіце нашу працу з дадзенымі цікавей.

Калі вы гуляецеся з MLflow, не саромейцеся пісаць нам і распавядаць, як вы яго карыстаецеся, і тым больш, калі карыстаецеся яго на прадакшэне.

Даведацца больш падрабязна аб курсах:
Machine Learning. Базавы курс
Machine Learning. Прасунуты курс

Чытаць яшчэ:

Крыніца: habr.com

Дадаць каментар