Estensjoni ta' Spark b'MLflow

Hello, residenti Khabrovsk. Kif diġà ktibna, dan ix-xahar l-OTUS qed iniedi żewġ korsijiet ta’ tagħlim tal-magni f’daqqa, jiġifieri bażi и avvanzat. F'dan ir-rigward, inkomplu naqsmu materjal utli.

L-iskop ta 'dan l-artikolu huwa li nitkellmu dwar l-ewwel esperjenza tagħna bl-użu MLflow.

Nibdew ir-reviżjoni MLflow mis-server tat-traċċar tiegħu u illoggja l-iterazzjonijiet kollha tal-istudju. Imbagħad se naqsmu l-esperjenza tagħna tal-konnessjoni ta 'Spark ma' MLflow bl-użu ta 'UDF.

Kuntest

Aħna qegħdin fih Alpha Health Aħna nużaw it-tagħlim tal-magni u l-intelliġenza artifiċjali biex nagħtu s-setgħa lin-nies biex jieħdu ħsieb is-saħħa u l-benessri tagħhom. Huwa għalhekk li l-mudelli tat-tagħlim tal-magni huma fil-qalba tal-prodotti tax-xjenza tad-dejta li niżviluppaw, u għalhekk ġejna miġbuda lejn MLflow, pjattaforma open source li tkopri l-aspetti kollha taċ-ċiklu tal-ħajja tat-tagħlim tal-magni.

MLflow

L-għan ewlieni ta 'MLflow huwa li jipprovdi saff addizzjonali fuq it-tagħlim tal-magni li jippermetti lix-xjenzati tad-dejta jaħdmu ma' kważi kull librerija tat-tagħlim tal-magni (h2o, keras, mleap, pitorċa, sklearn и tensorflow), tieħu x-xogħol tagħha għal-livell li jmiss.

MLflow jipprovdi tliet komponenti:

  • Traċċar – reġistrazzjoni u talbiet għal esperimenti: kodiċi, data, konfigurazzjoni u riżultati. Il-monitoraġġ tal-proċess tal-ħolqien ta 'mudell huwa importanti ħafna.
  • proġetti – Format tal-ippakkjar biex jaħdem fuq kwalunkwe pjattaforma (eż. SageMaker)
  • Mudelli – format komuni għas-sottomissjoni ta' mudelli għal diversi għodod ta' skjerament.

MLflow (f'alpha fil-ħin tal-kitba) hija pjattaforma ta' sors miftuħ li tippermettilek timmaniġġja ċ-ċiklu tal-ħajja tat-tagħlim tal-magni, inkluż l-esperimentazzjoni, l-użu mill-ġdid u l-iskjerament.

Twaqqif ta' MLflow

Biex tuża MLflow trid l-ewwel twaqqaf l-ambjent Python kollu tiegħek, għal dan aħna se nużaw PyEnv (biex tinstalla Python fuq Mac, iċċekkja hawn). Dan il-mod nistgħu noħolqu ambjent virtwali fejn se ninstallaw il-libreriji kollha meħtieġa biex inħaddmuh.

```
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
```

Ejja ninstallaw il-libreriji meħtieġa.

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

Nota: Aħna nużaw PyArrow biex inħaddmu mudelli bħal UDF. Il-verżjonijiet ta 'PyArrow u Numpy kellhom jiġu ffissati minħabba li l-verżjonijiet tal-aħħar kienu f'kunflitt ma' xulxin.

Tnedija Tracking UI

MLflow Tracking jippermettilna nilloggjaw u nistaqsu esperimenti bl-użu ta' Python u SERĦAN API. Barra minn hekk, tista 'tiddetermina fejn taħżen l-artifatti tal-mudell (localhost, Amazon S3, Ħażna Azure Blob, Google Cloud Storage jew Server SFTP). Peress li nużaw AWS f'Alpha Health, il-ħażna tal-artifact tagħna se tkun S3.

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

MLflow jirrakkomanda li tuża ħażna ta 'fajls persistenti. Il-ħażna tal-fajls hija fejn is-server se jaħżen il-metadata tal-ġiri u l-esperiment. Meta tibda s-server, kun żgur li jindika l-maħżen tal-fajls persistenti. Hawnhekk għall-esperiment se nużaw sempliċement /tmp.

Ftakar li jekk irridu nużaw is-server mlflow biex imexxu esperimenti qodma, iridu jkunu preżenti fil-ħażna tal-fajls. Madankollu, anki mingħajr dan nistgħu nużawhom fl-UDF, peress li għandna bżonn biss it-triq għall-mudell.

Nota: Żomm f'moħħok li Tracking UI u l-klijent mudell għandu jkollhom aċċess għall-post tal-artifact. Jiġifieri, irrispettivament mill-fatt li l-UI ta 'Traċċar tgħix f'istanza EC2, meta tħaddem MLflow lokalment, il-magna għandu jkollha aċċess dirett għal S3 biex tikteb mudelli ta' artifact.

Estensjoni ta' Spark b'MLflow
Tracking UI jaħżen artifacts f'barmil S3

Mudelli tat-tmexxija

Hekk kif is-server ta 'Traċċar ikun qed jaħdem, tista' tibda tħarreġ il-mudelli.

Bħala eżempju, se nużaw il-modifika tal-inbid mill-eżempju MLflow fi Sklearn.

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

Kif diġà ddiskutejna, MLflow jippermettilek tilloggja l-parametri tal-mudell, il-metriċi, u l-artifacts sabiex tkun tista 'ssegwi kif jevolvu fuq iterazzjonijiet. Din il-karatteristika hija estremament utli għaliex b'dan il-mod nistgħu nirriproduċu l-aħjar mudell billi nikkuntattjaw lis-server tat-Traċċar jew nifhmu liema kodiċi lesta l-iterazzjoni meħtieġa billi tuża l-git hash logs of commits.

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")

Estensjoni ta' Spark b'MLflow
Iterazzjonijiet tal-inbid

Parti tas-server għall-mudell

Is-server ta 'traċċar MLflow, imniedi bl-użu tal-kmand "server mlflow", għandu API REST għat-traċċar tal-ġirjiet u l-kitba tad-dejta fis-sistema tal-fajls lokali. Tista 'tispeċifika l-indirizz tas-server tat-traċċar billi tuża l-varjabbli ambjentali "MLFLOW_TRACKING_URI" u l-API tat-traċċar MLflow se tikkuntattja awtomatikament lis-server tat-traċċar f'dan l-indirizz biex toħloq/jirċievi informazzjoni dwar it-tnedija, metriċi ta' log, eċċ.

Sors: Docs// Tmexxija ta' server ta' traċċar

Biex nipprovdu l-mudell b'server, neħtieġu server ta 'traċċar li jaħdem (ara l-interface tat-tnedija) u l-ID Run tal-mudell.

Estensjoni ta' Spark b'MLflow
Mexxi 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

Biex inservu mudelli bl-użu tal-funzjonalità MLflow serve, ikollna bżonn aċċess għall-UI tat-Traċċar biex nirċievu informazzjoni dwar il-mudell sempliċement billi nispeċifikaw --run_id.

Ladarba l-mudell jikkuntattja lis-server tat-Traċċar, nistgħu niksbu punt tat-tmiem tal-mudell ġdid.

# 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]}

Mudelli tat-tmexxija minn Spark

Minkejja l-fatt li s-server tat-Traċċar huwa b'saħħtu biżżejjed biex iservi mudelli f'ħin reali, tħarreġhom u uża l-funzjonalità tas-server (sors: mlflow // docs // mudelli # lokali), l-użu ta 'Spark (lott jew streaming) huwa soluzzjoni saħansitra aktar qawwija minħabba d-distribuzzjoni.

Immaġina li sempliċement għamilt it-taħriġ offline u mbagħad applikajt il-mudell tal-output għad-dejta kollha tiegħek. Dan huwa fejn Spark u MLflow shine.

Installa PySpark + Jupyter + Spark

Sors: Ibda PySpark - Jupyter

Biex nuru kif napplikaw mudelli MLflow għal dataframes Spark, għandna bżonn inwaqqfu notebooks Jupyter biex jaħdmu flimkien ma 'PySpark.

Ibda billi tinstalla l-aħħar verżjoni stabbli 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̀

Installa PySpark u Jupyter fl-ambjent virtwali:

pip install pyspark jupyter

Stabbilixxi varjabbli ambjentali:

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"

Wara li ddeterminat notebook-dir, nistgħu naħżnu n-notebooks tagħna fil-folder mixtieq.

Tnedija ta' Jupyter minn PySpark

Peress li stajna nikkonfiguraw Jupiter bħala sewwieq PySpark, issa nistgħu nħaddmu notebook Jupyter fil-kuntest ta '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

Estensjoni ta' Spark b'MLflow

Kif imsemmi hawn fuq, MLflow jipprovdi karatteristika għall-illoggjar artifacts mudell fl-S3. Hekk kif ikollna l-mudell magħżul f'idejna, għandna l-opportunità li nimportawh bħala UDF billi tuża l-modulu 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)

Estensjoni ta' Spark b'MLflow
PySpark - Jipproduċu tbassir tal-kwalità tal-inbid

Sa dan il-punt, tkellimna dwar kif tuża PySpark ma 'MLflow, billi tmexxi tbassir tal-kwalità tal-inbid fuq is-sett tad-dejta tal-inbid kollu. Imma x'jiġri jekk għandek bżonn tuża moduli Python MLflow minn Scala Spark?

Ittestjajna dan ukoll billi qsamna l-kuntest Spark bejn Scala u Python. Jiġifieri, irreġistrajna MLflow UDF f'Python, u użajna minn Scala (iva, forsi mhux l-aħjar soluzzjoni, imma dak li għandna).

Scala Spark + MLflow

Għal dan l-eżempju se nżidu Toree Kernel fil-Ġove eżistenti.

Installa 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
```

Kif tistgħu taraw min-notebook mehmuż, l-UDF hija maqsuma bejn Spark u PySpark. Nittamaw li din il-parti tkun utli għal dawk li jħobbu lil Scala u jridu jużaw mudelli ta’ tagħlim tal-magni fil-produzzjoni.

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       |
+-----------+--------+-----------+---------+-----------+

Il-passi li jmiss

Anke jekk MLflow huwa fil-verżjoni Alpha fil-ħin tal-kitba, jidher pjuttost promettenti. Sempliċement il-ħila li tħaddem oqfsa multipli tat-tagħlim tal-magni u tikkonsmahom minn endpoint wieħed tieħu s-sistemi ta' rakkomandazzjoni għal-livell li jmiss.

Barra minn hekk, MLflow iġib l-Inġiniera tad-Data u l-ispeċjalisti tax-Xjenza tad-Data eqreb lejn xulxin, billi jistabbilixxi saff komuni bejniethom.

Wara din l-esplorazzjoni ta 'MLflow, aħna kunfidenti li se nimxu 'l quddiem u nużawha għall-pipelines Spark tagħna u s-sistemi ta' rakkomandazzjoni.

Ikun sabiħ li tissinkronizza l-ħażna tal-fajls mad-database minflok mas-sistema tal-fajls. Dan għandu jagħtina endpoints multipli li jistgħu jużaw l-istess ħażna tal-fajls. Per eżempju, uża każijiet multipli Presto и Athena bl-istess Glue metastore.

Fil-qosor, nixtieq ngħid grazzi lill-komunità MLFlow talli għamilt ix-xogħol tagħna bid-dejta aktar interessanti.

Jekk qed tilgħab ma' MLflow, toqgħodx lura milli tikteb lilna u għidilna kif tużah, u aktar u aktar jekk tużah fil-produzzjoni.

Sir af aktar dwar il-korsijiet:
Tagħlim bil-magni. Kors bażiku
Tagħlim bil-magni. Kors avvanzat

Aqra iktar:

Sors: www.habr.com

Żid kumment