Zgjerimi i mundësive të Spark me MLflow

Përshëndetje, habrovçanë. Siç kemi shkruar më parë, këtë muaj OTUS po lançon dy kurse për mësimin e makinerive, konkretisht bazik dhe të avancuar. Në këtë kontekst, vazhdojmë të ndajmë material të dobishëm.

Qëllimi i kësaj artikulli është të tregojmë për përvojën tonë të parë me MLflow.

Do të fillojmë përmbledhjen MLflow nga serveri i tij të ndjekjes dhe do të regjistrojmë të gjitha iteracionet e hulumtimit. Më pas, do të ndajmë përvojën tonë të lidhjes së Spark me MLflow përmes UDF.

Konteksti

Ne në Alpha Health përdor mësimin e makinerive dhe inteligjencën artificiale për të mundësuar që njerëzit të kujdesen për shëndetin dhe mirëqenien e tyre. Prandaj, modelet e mësimit të makinerive janë në bazë të produkteve që po zhvillojmë për përpunimin e të dhënave, dhe kjo është arsyeja pse na tërhoqi vëmendjen MLflow - një platformë me burim të hapur që mbulon të gjitha aspektet e ciklit të jetës së mësimit të makinerive.

MLflow

Qëllimi kryesor i MLflow është të ofrojë një shtresë shtesë mbi mësimin e makinerive, që të lejojë specialistët e shkencës së të dhënave të punojnë me çdo bibliotekë të mundshme të mësimit të makinerive (h2o, keras, mleap, pytorch, sklearn dhe tensorflow), duke e çuar punën e saj në një nivel të ri.

MLflow ofron tre komponentë:

  • Ndjekja – regjistrimi dhe kĂ«rkesat pĂ«r eksperimentet: kodi, tĂ« dhĂ«nat, konfigurimi dhe rezultatet. TĂ« ndjekĂ«sh procesin e krijimit tĂ« modelit Ă«shtĂ« shumĂ« e rĂ«ndĂ«sishme.
  • Projekti – Formati i paketimit pĂ«r ekzekutimin nĂ« çdo platformĂ« (p.sh., SageMaker)
  • Modelet – formati i pĂ«rgjithshĂ«m pĂ«r dĂ«rgimin e modeleve nĂ« mjete tĂ« ndryshme tĂ« shpĂ«rndarjes.

MLflow (në momentin e shkrimit të këtij artikulli në versionin alpha) - një platformë me burim të hapur që lejon menaxhimin e ciklit të jetës së mësimit të makinerive, duke përfshirë eksperimentet, ripërdorimin dhe shpërndarjen.

Konfigurimi i MLflow

Për të përdorur MLflow duhet së pari të konfiguroni të gjithë mjedisin Python, për këtë do të përdorim PyEnv (për të instaluar Python në Mac, shikoni . Kërkesat e dërguara përmes mënyrave të tjera nuk do të shqyrtohen.). Kështu do të jemi në gjendje të krijojmë një ambient virtual ku do të instalojmë të gjitha bibliotekat e nevojshme për ekzekutim.

```
pyenv install 3.7.0
pyenv global 3.7.0 # Përdorni Python 3.7
mkvirtualenv mlflow # Krijoni një Ambient Virtual me Python 3.7
workon mlflow
```

Të instalojmë bibliotekat e nevojshme.

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

Shënim: ne përdorim PyArrow për të ekzekutuar modele të tilla si UDF. Versionet e PyArrow dhe Numpy duhej të ishin rregulluar, pasi versionet e fundit kishin konflikt midis tyre.

Nisja e Ndjekjes UI

MLflow Tracking na lejon të regjistrojmë dhe bëjmë kërkesa për eksperimentet përmes Python dhe REST API. Përveç kësaj, mund të definoni ku të ruani artefaktet e modelit (localhost, Amazon S3, Azure Blob Storage, Google Cloud Storage ose Server SFTP). Duke qenë se në Alpha Health ne përdorim AWS, ruajtja e artefakteve do të jetë S3.

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

MLflow rekomandon të përdorni një ruajtje të qëndrueshme skedarësh. Ruajtja e skedarëve është vendi ku serveri do të ruajë metadatat e ekzekutimeve dhe eksperimenteve. Kur nisni serverin, sigurohuni që ai të tregojë në një ruajtje të qëndrueshme skedarësh. Këtu për eksperimentin do të përdorim thjesht /tmp.

Mbani mend se, nëse duam të përdorim serverin mlflow për të ekzekutuar eksperimentet e vjetra, ato duhet të jenë të pranishme në ruajtjen e skedarëve. Megjithatë, edhe pa këtë do të ishim në gjendje t'i përdornim në UDF, pasi na nevojitet vetëm rruga drejt modelit.

Shënim: Keni parasysh se Ndjekja UI dhe kliente modeli duhet të kenë akses në vendndodhjen e artefaktit. Këtu nënkuptohet se, pavarësisht se Ndjekja UI është në një instancë EC2, kur ekzekutohet lokal MLflow, makina duhet të ketë akses të drejtpërdrejtë në S3 për të regjistruar modelet e artefakteve.

Zgjerimi i mundësive të Spark me MLflow
Ndjekja UI ruan artefaktet në një gotë S3

Nisja e modeleve

Shkurt, sapo të funksionojë serveri i Ndjekjes, mund të filloni të trajnoni modelet.

Si një shembull, ne do të përdorim modifikimin e verës nga shembulli i MLflow në Sklearn.

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

Siç thamë më parë, MLflow lejon regjistrimin e parametrave, metrikeve dhe artefakteve të modeleve, në mënyrë që të mund të ndiqni se si ato zhvillohen me kalimin e iteracioneve. Kjo funksion është shumë e dobishme pasi mund të riprodhojmë modelin më të mirë, duke u drejtuar në serverin e Ndjekjes ose duke kuptuar se cili kod e ekzekutoi iteracionin e nevojshëm, duke përdorur log-in e hash commit-eve të git.

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

Zgjerimi i mundësive të Spark me MLflow
Iteracionet e verës

Pjesa serverike për modelin

Serveri i gjurmimit MLflow, i aktivizuar me komandĂ«n “mlflow server”, ka njĂ« API REST pĂ«r tĂ« gjurmuar ekzekutimet dhe pĂ«r tĂ« regjistruar tĂ« dhĂ«nat nĂ« sistemin tuaj tĂ« skedarĂ«ve lokal. Ju mund tĂ« caktoni adresĂ«n e serverit tĂ« gjurmimit duke pĂ«rdorur variablĂ«n e mjedisit «MLFLOW_TRACKING_URI» dhe API i gjurmimit tĂ« MLflow do tĂ« lidhet automatikisht me serverin e gjurmimit nĂ« kĂ«tĂ« adresĂ« pĂ«r tĂ« krijuar/marrĂ« informacionin rreth ekzekutimit, metricat e regjistrimeve, etj.

Burimi: Dokumentet // Duke e drejtuar një server gjurmimi

Për të siguruar modelin me një server, na nevojitet një server gjurmimi i aktivizuar (shih ndërfaqen e aktivizimit) dhe ID e ekzekutimit të modelit.

Zgjerimi i mundësive të Spark me MLflow
ID e ekzekutimit

# 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

Për të menaxhuar modelet duke përdorur funksionalitetin MLflow serve, na nevojitet qasje në UI-në e gjurmimit, për të marrë informacionin rreth modelit thjesht duke specifikuar --run_id.

Sapo modeli lidhet me serverin e gjurmimit, ne mund të marrim një pikë të re fundore për modelin.

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

Ekzekutimi i modeleve nga Spark

Megjithëse serveri i gjurmimit është mjaft i fuqishëm për të menaxhuar modelet në kohë reale, trajnimi dhe përdorimi i funksionalitetit serve (burimi: mlflow // docs // modelet # lokal), përdorimi i Spark (me grumbull ose streaming) është një zgjidhje edhe më e fuqishme falë shpërndarjes.

Imagini se sapo keni kryer një trajnim offline dhe pastaj aplikoni modelin e daljes për të gjitha të dhënat tuaja. Këtu është vendi ku Spark dhe MLflow do të performojnë më mirë.

Instalimi i PySpark + Jupyter + Spark

Burimi: Filloni me PySpark — Jupyter

Për të treguar se si aplikojmë modelet MLflow në DataFrames të Spark, duhet të konfigurojmë bashkëpunimin e notave Jupyter me PySpark.

Filloni me instalimin e versionit më të fundit stabil 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

Instaloni PySpark dhe Jupyter në një ambient virtual:

pip install pyspark jupyter

Konfiguroni variablat e mjedisit:

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"

Duke përcaktuar notebook-dir, tani do të jemi në gjendje të ruajmë notat tona në dosjen e dëshiruar.

Duke ekzekutuar Jupyter nga PySpark

Duke qenë se arritëm të konfiguroni Jupyter si një drejtues PySpark, tani mund të ekzekutojmë notebook-un Jupyter në kontekstin e PySpark.

(mlflow) afranzi:~$ pyspark
[I 19:05:01.572 NotebookApp] zgjerimi sparkmagic i aktivizuar!
[I 19:05:01.573 NotebookApp] Shërbimi i notave nga dosja lokale: /Users/afranzi/Projects/notebooks
[I 19:05:01.573 NotebookApp] Notebook-u Jupyter po ekzekutohet në:
[I 19:05:01.573 NotebookApp] http://localhost:8888/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745
[I 19:05:01.573 NotebookApp] Përdorni Control-C për të ndaluar këtë shërbim dhe për të mbyllur të gjitha kernelët (dy herë për të anashkaluar konfirmimin).
[C 19:05:01.574 NotebookApp]

    Kopjoni/vendosni këtë URL në shfletuesin tuaj kur lidheni për herë të parë,
    për të hyrë me një token:
        http://localhost:8888/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745

Zgjerimi i mundësive të Spark me MLflow

Siç u tha më sipër, MLflow ofron funksionalitetin për regjistrimin e artefakteve të modelit në S3. Sapo të kemi modelin e zgjedhur, kemi mundësinë ta importojmë si UDF me modulin mlflow.pyfunc.

import mlflow.pyfunc

model_path = 's3:///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 = [ "acidi i fikst", "acidi i volitshëm", "acidi citrik",
            "sheqeri rezidual", "kloridët", "dioksidi i squfurit të lirë",
            "dioksidi i squfurit total", "densiteti", "pH",
            "sulphates", "alkooli"
          ]
          
df.withColumn('parashikim', wine_udf(*columns)).show(100, False)

Zgjerimi i mundësive të Spark me MLflow
PySpark – Parashikimi i cilĂ«sisĂ« sĂ« verĂ«s

Derisa flisnim për si të përdorim PySpark me MLflow, duke drejtuar parashikimin e cilësisë së verës në të gjithë setin e të dhënave. Por çfarë ndodh nëse duam të përdorim modulet Python të MLflow nga Scala Spark?

E kemi provuar këtë gjithashtu, duke ndarë kontekstin e Spark midis Scala dhe Python. Pra, regjistruam UDF të MLflow në Python dhe e përdorëm nga Scala (po, ndoshta, jo zgjidhja më e mirë, por ja çfarë kemi).

Scala Spark + MLflow

Për këtë shembull ne do të shtojmë Toree Kernel në ekzistuesin Jupiter.

Instalimi i Spark + Toree + Jupyter

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

Siç duket nga notebook-u i bashkëngjitur, UDF përdoret me bashkëpunim midis Spark dhe PySpark. Shpresojmë se kjo pjesë do të jetë e dobishme për ata që duan Scala dhe duan të implementojnë modele të mësimit të makinerive në prodhim.

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

Hapat e ardhshëm

Megjithëse në momentin e shkrimit të këtij artikulli, MLflow është në versionin Alpha, ajo duket shumë premtuese. Vetëm mundësia për të ekzekutuar disa framework-e të mësimit të makinerisë dhe për t'i përdorur ato nga një pikë përfundimtare e çon sistemet rekomanduese në një nivel të ri.

Për më tepër, MLflow afron inxhinierët e të dhënave dhe specialistët e shkencës së të dhënave, duke krijuar një shtresë të përbashkët midis tyre.

Pas këtij studimi me MLflow, ne jemi të sigurt se do të shkojmë përpara dhe do ta përdorim atë për pipeline-t tona Spark dhe për sistemet rekomanduese.

Do të ishte mirë të sinkronizohej ruajtja e skedarëve me bazën e të dhënave, në vend të sistemit të skedarëve. Kështu do të duhet të kishim disa pika përfundimtare që mund të përdorin të njëjtën ruajtje skedarësh. Për shembull, të përdorin disa instance Presto dhe Athena me të njëjtin Glue metastore.

Në përfundim, dëshirojmë të falënderojmë komunitetin e MLFlow për ta bërë punën tonë me të dhënat më interesante.

Nëse po e provoni MLflow, mos hezitoni të na kontaktoni dhe na tregonit se si e përdorni, sidomos nëse e përdorni në prodhim.

Mësoni më shumë rreth kurseve:
Mësimi i Makinerisë. Kursi i Bazës
Mësimi i Makinerisë. Kursi Avancuar

Lexoni më shumë:

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster