Zgjatja e Shkëndijës me MLflow

Përshëndetje, banorë të Khabrovsk. Siç kemi shkruar tashmë, këtë muaj OTUS po lançon dy kurse të mësimit të makinerive njëherësh, domethënë baze и i avancuar. Në këtë drejtim, ne vazhdojmë të ndajmë materiale të dobishme.

Qëllimi i këtij artikulli është të flasim për përvojën tonë të parë duke përdorur MLflow.

Ne do të fillojmë rishikimin MLflow nga serveri i tij gjurmues dhe regjistroni të gjitha përsëritjet e studimit. Më pas do të ndajmë përvojën tonë të lidhjes së Spark me MLflow duke përdorur UDF.

Kontekst

Ne jemi në Shëndeti Alfa Ne përdorim mësimin e makinerive dhe inteligjencën artificiale për të fuqizuar njerëzit që të marrin përgjegjësinë për shëndetin dhe mirëqenien e tyre. Kjo është arsyeja pse modelet e mësimit të makinerive janë në qendër të produkteve të shkencës së të dhënave që ne zhvillojmë, dhe kjo është arsyeja pse ne u tërhoqëm nga MLflow, një platformë me burim të hapur që mbulon të gjitha aspektet e ciklit jetësor të mësimit të makinerive.

MLflow

Qëllimi kryesor i MLflow është të sigurojë një shtresë shtesë në krye të mësimit të makinerisë që do t'i lejonte shkencëtarët e të dhënave të punojnë me pothuajse çdo bibliotekë të mësimit të makinerive (h2o, keras, zbavitje, pytorch, sklearin и tensorflow), duke e çuar punën e saj në një nivel tjetër.

MLflow ofron tre komponentë:

  • Ndjekja – regjistrimi dhe kërkesat për eksperimente: kodi, të dhënat, konfigurimi dhe rezultatet. Monitorimi i procesit të krijimit të një modeli është shumë i rëndësishëm.
  • projektet – Formati i paketimit për të ekzekutuar në çdo platformë (p.sh. SageMaker)
  • Modele – një format i zakonshëm për paraqitjen e modeleve në mjete të ndryshme vendosjeje.

MLflow (në alfa në kohën e shkrimit) është një platformë me burim të hapur që ju lejon të menaxhoni ciklin jetësor të mësimit të makinerive, duke përfshirë eksperimentimin, ripërdorimin dhe vendosjen.

Vendosja e MLflow

Për të përdorur MLflow, së pari duhet të konfiguroni të gjithë mjedisin tuaj Python, për këtë ne do të përdorim PyEnv (për të instaluar Python në Mac, shikoni këtu). Në këtë mënyrë ne mund të krijojmë një mjedis virtual ku do të instalojmë të gjitha bibliotekat e nevojshme për ta ekzekutuar atë.

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

Le të instalojmë bibliotekat e kërkuara.

```
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ë rregulloheshin sepse versionet e fundit ishin në konflikt me njëri-tjetrin.

Hap ndërfaqen e gjurmimit

Ndjekja e MLflow na lejon të regjistrojmë dhe të kërkojmë eksperimente duke përdorur Python dhe Rest API. Përveç kësaj, ju mund të përcaktoni se ku të ruani objektet e modelit (localhost, Amazon S3, Magazinimi Azure Blob, Google Cloud Storage ose Serveri SFTP). Meqenëse ne përdorim AWS në Alpha Health, ruajtja jonë e objekteve 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 përdorimin e ruajtjes së vazhdueshme të skedarëve. Ruajtja e skedarëve është vendi ku serveri do të ruajë të dhënat meta të ekzekutuara dhe eksperimentale. Kur nisni serverin, sigurohuni që ai të tregojë te ruajtja e skedarëve të vazhdueshëm. Këtu për eksperimentin ne thjesht do të përdorim /tmp.

Mos harroni se nëse duam të përdorim serverin mlflow për të ekzekutuar eksperimente të vjetra, ato duhet të jenë të pranishme në ruajtjen e skedarëve. Sidoqoftë, edhe pa këtë ne mund t'i përdorim ato në UDF, pasi na duhet vetëm rruga drejt modelit.

Shënim: Kini parasysh se ndërfaqja e përdoruesit të gjurmimit dhe klienti i modelit duhet të kenë akses në vendndodhjen e objektit. Kjo do të thotë, pavarësisht nga fakti që UI-ja e gjurmimit ndodhet në një shembull EC2, kur ekzekutohet MLflow në nivel lokal, makina duhet të ketë qasje të drejtpërdrejtë në S3 për të shkruar modele artifakte.

Zgjatja e Shkëndijës me MLflow
Ndërfaqja e përdoruesit e gjurmimit ruan objekte në një kovë S3

Modele vrapimi

Sapo serveri i gjurmimit të funksionojë, mund të filloni trajnimin e modeleve.

Si shembull, ne do të përdorim modifikimin e verës nga shembulli MLflow in Mësoj.

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

Siç e kemi diskutuar tashmë, MLflow ju lejon të regjistroni parametrat e modelit, metrikat dhe artefaktet në mënyrë që të mund të gjurmoni se si ato evoluojnë gjatë përsëritjeve. Kjo veçori është jashtëzakonisht e dobishme sepse në këtë mënyrë ne mund të riprodhojmë modelin më të mirë duke kontaktuar serverin e gjurmimit ose duke kuptuar se cili kod ka kryer përsëritjen e kërkuar duke përdorur regjistrat git hash të 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")

Zgjatja e Shkëndijës me MLflow
Përsëritjet e verës

Pjesa e serverit për modelin

Serveri i gjurmimit MLflow, i nisur duke përdorur komandën "mlflow server", ka një API REST për gjurmimin e ekzekutimeve dhe shkrimin e të dhënave në sistemin lokal të skedarëve. Mund të specifikoni adresën e serverit gjurmues duke përdorur variablin e mjedisit "MLFLOW_TRACKING_URI" dhe API-ja e gjurmimit MLflow do të kontaktojë automatikisht me serverin gjurmues në këtë adresë për të krijuar/marrë informacione për nisjen, metrikat e regjistrave, etj.

Burimi: Docs// Ekzekutimi i një serveri gjurmues

Për t'i siguruar modelit një server, na duhet një server gjurmues që funksionon (shih ndërfaqen e nisjes) dhe Run ID-në e modelit.

Zgjatja e Shkëndijës me MLflow
ID-ja 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ë shërbyer modele duke përdorur funksionalitetin e shërbimit MLflow, do të na duhet qasje në ndërfaqen e përdoruesit të gjurmimit për të marrë informacione rreth modelit thjesht duke specifikuar --run_id.

Pasi modeli të kontaktojë serverin e gjurmimit, ne mund të marrim një pikë përfundimtare të modelit të ri.

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

Modele vrapimi nga Spark

Përkundër faktit se serveri Tracking është mjaft i fuqishëm për të shërbyer modele në kohë reale, për t'i trajnuar ato dhe për të përdorur funksionalitetin e serverit (burimi: mlflow // docs // modele # local), përdorimi i Spark (batch ose streaming) është një zgjidhje edhe më e fuqishme për shkak të shpërndarjes.

Imagjinoni që thjesht e keni bërë trajnimin jashtë linje dhe më pas keni aplikuar modelin e daljes në të gjitha të dhënat tuaja. Këtu shkëlqejnë Spark dhe MLflow.

Instaloni PySpark + Jupyter + Spark

Burimi: Filloni PySpark - Jupyter

Për të treguar se si aplikojmë modelet MLflow në kornizat e të dhënave Spark, duhet të konfigurojmë fletoret e Jupyter për të punuar së bashku me PySpark.

Filloni duke instaluar versionin më të fundit të qëndrueshëm 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ë mjedisin virtual:

pip install pyspark jupyter

Vendosni 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 vendosur notebook-dir, ne mund t'i ruajmë fletoret tona në dosjen e dëshiruar.

Nisja e Jupyter nga PySpark

Meqenëse ne ishim në gjendje të konfiguronim Jupiterin si një drejtues PySpark, tani mund të ekzekutojmë fletoren Jupyter në kontekstin e 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

Zgjatja e Shkëndijës me MLflow

Siç u përmend më lart, MLflow ofron një veçori për regjistrimin e objekteve të modelit në S3. Sapo të kemi në dorë modelin e përzgjedhur, kemi mundësinë ta importojmë si UDF duke përdorur modulin 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)

Zgjatja e Shkëndijës me MLflow
PySpark - Paraqitja e parashikimeve të cilësisë së verës

Deri në këtë pikë, ne kemi folur se si të përdorim PySpark me MLflow, duke ekzekutuar parashikime të cilësisë së verës në të gjithë grupin e të dhënave të verës. Por çfarë nëse duhet të përdorni module Python MLflow nga Scala Spark?

Ne e testuam këtë gjithashtu duke ndarë kontekstin Spark midis Scala dhe Python. Kjo do të thotë, ne regjistruam MLflow UDF në Python dhe e përdorëm atë nga Scala (po, ndoshta jo zgjidhja më e mirë, por ajo që kemi).

Scala Spark + MLflow

Për këtë shembull do të shtojmë Kernel Toree në Jupiterin ekzistues.

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

Siç mund ta shihni nga fletorja e bashkangjitur, UDF ndahet midis Spark dhe PySpark. Shpresojmë që kjo pjesë të jetë e dobishme për ata që e duan Scala-n dhe duan të vendosin 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.<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       |
+-----------+--------+-----------+---------+-----------+

Hapat e ardhshëm

Edhe pse MLflow është në versionin Alpha në kohën e shkrimit, duket mjaft premtues. Vetëm aftësia për të ekzekutuar korniza të shumta të mësimit të makinerive dhe për t'i konsumuar ato nga një pikë përfundimtare e vetme i çon sistemet e rekomanduesve në nivelin tjetër.

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

Pas këtij eksplorimi të MLflow, ne jemi të sigurt se do të ecim përpara dhe do ta përdorim atë për tubacionet tona Spark dhe sistemet rekomanduese.

Do të ishte mirë të sinkronizoni ruajtjen e skedarëve me bazën e të dhënave në vend të sistemit të skedarëve. Kjo duhet të na japë disa pika fundore që mund të përdorin të njëjtin ruajtje të skedarëve. Për shembull, përdorni shembuj të shumtë pasazh i shpejtë и Athinë me të njëjtin metastor Glue.

Për ta përmbledhur, do të doja të falënderoja komunitetin MLFlow që e bëri punën tonë me të dhënat më interesante.

Nëse jeni duke luajtur me MLflow, mos hezitoni të na shkruani dhe të na tregoni se si e përdorni atë, dhe aq më tepër nëse e përdorni në prodhim.

Mësoni më shumë rreth kurseve:
Mësimi i makinerisë. Kursi bazë
Mësimi i makinerisë. Kurs i avancuar

Lexo më shumë:

Burimi: www.habr.com

Shto një koment