Proširivanje Sparka sa MLflow-om

Zdravo, stanovnici Khabrovsk. Kao što smo već pisali, ovog mjeseca OTUS pokreće dva kursa mašinskog učenja odjednom, naime baza и napredni. S tim u vezi, nastavljamo dijeliti koristan materijal.

Svrha ovog članka je govoriti o našem prvom iskustvu korištenja MLflow.

Počećemo sa pregledom MLflow sa svog servera za praćenje i evidentirati sve iteracije studije. Zatim ćemo podijeliti naše iskustvo povezivanja Spark-a sa MLflow-om koristeći UDF.

Kontekst

Unutra smo Alpha Health Koristimo mašinsko učenje i umjetnu inteligenciju kako bismo osnažili ljude da preuzmu odgovornost za svoje zdravlje i dobrobit. Zato su modeli mašinskog učenja u srcu proizvoda nauke o podacima koje razvijamo, i zato smo bili privučeni MLflow-om, platformom otvorenog koda koja pokriva sve aspekte životnog ciklusa mašinskog učenja.

MLflow

Glavni cilj MLflow-a je da obezbijedi dodatni sloj na vrhu mašinskog učenja koji bi omogućio naučnicima podataka da rade sa gotovo bilo kojom bibliotekom mašinskog učenja (h2o, keras, mleap, pytorch, sklearn и tensorflow), podižući njen rad na viši nivo.

MLflow pruža tri komponente:

  • praćenje – snimanje i zahtjevi za eksperimente: kod, podaci, konfiguracija i rezultati. Praćenje procesa kreiranja modela je veoma važno.
  • projekata – Format pakovanja za rad na bilo kojoj platformi (npr. SageMaker)
  • modeli – zajednički format za podnošenje modela različitim alatima za implementaciju.

MLflow (u alfa verziji u vrijeme pisanja) je platforma otvorenog koda koja vam omogućava da upravljate životnim ciklusom strojnog učenja, uključujući eksperimentiranje, ponovnu upotrebu i implementaciju.

Postavljanje MLflow-a

Da biste koristili MLflow, prvo morate podesiti cijelo svoje Python okruženje, za to ćemo koristiti PyEnv (da biste instalirali Python na Mac, provjerite ovdje). Na ovaj način možemo kreirati virtuelno okruženje u koje ćemo instalirati sve biblioteke potrebne za njegovo pokretanje.

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

Hajde da instaliramo potrebne biblioteke.

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

Napomena: Koristimo PyArrow za pokretanje modela kao što je UDF. Verzije PyArrow i Numpy je trebalo popraviti jer su potonje verzije bile u sukobu jedna s drugom.

Pokrenite korisničko sučelje za praćenje

MLflow Tracking nam omogućava da evidentiramo i postavljamo upite o eksperimentima koristeći Python i REST API. Osim toga, možete odrediti gdje ćete pohraniti artefakte modela (localhost, Amazon S3, Azure Blob skladište, Google Cloud Storage ili SFTP server). Budući da koristimo AWS u Alpha Health-u, naše skladište artefakata će biti S3.

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

MLflow preporučuje korištenje trajne pohrane datoteka. Skladištenje datoteka je mjesto gdje će server pohraniti metapodatke o pokretanju i eksperimentu. Prilikom pokretanja servera, uvjerite se da ukazuje na trajnu datoteku. Ovdje ćemo za eksperiment jednostavno koristiti /tmp.

Zapamtite da ako želimo da koristimo mlflow server za pokretanje starih eksperimenata, oni moraju biti prisutni u skladištu datoteka. Međutim, i bez toga bismo ih mogli koristiti u UDF-u, jer nam je potreban samo put do modela.

Napomena: Imajte na umu da UI za praćenje i model klijent moraju imati pristup lokaciji artefakta. To jest, bez obzira na činjenicu da se korisničko sučelje za praćenje nalazi u EC2 instanci, kada lokalno pokreće MLflow, mašina mora imati direktan pristup S3 za pisanje modela artefakata.

Proširivanje Sparka sa MLflow-om
UI za praćenje pohranjuje artefakte u S3 kantu

Trčanje modela

Čim server za praćenje bude pokrenut, možete započeti obuku modela.

Kao primjer, koristit ćemo modifikaciju vina iz primjera MLflow u Sklearn.

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

Kao što smo već raspravljali, MLflow vam omogućava da evidentirate parametre modela, metrike i artefakte tako da možete pratiti kako se razvijaju tokom iteracija. Ova funkcija je izuzetno korisna jer na ovaj način možemo reproducirati najbolji model kontaktiranjem servera za praćenje ili razumijevanjem koji je kod izveo potrebnu iteraciju koristeći git hash dnevnike urezivanja.

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

Proširivanje Sparka sa MLflow-om
Vinske iteracije

Serverski dio za model

MLflow server za praćenje, pokrenut pomoću naredbe “mlflow server”, ima REST API za praćenje pokretanja i pisanje podataka u lokalni sistem datoteka. Možete odrediti adresu servera za praćenje koristeći varijablu okruženja “MLFLOW_TRACKING_URI” i API za praćenje MLflow će automatski kontaktirati server za praćenje na ovoj adresi kako bi kreirao/primio informacije o pokretanju, metriku evidencije itd.

izvor: Dokumenti// Pokretanje servera za praćenje

Da bismo modelu dali server, potreban nam je server za praćenje koji radi (pogledajte interfejs za pokretanje) i Run ID modela.

Proširivanje Sparka sa MLflow-om
Pokreni 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

Za posluživanje modela koji koriste funkciju posluživanja MLflow, trebat će nam pristup korisničkom sučelju za praćenje kako bismo primili informacije o modelu jednostavnim navođenjem --run_id.

Kada model kontaktira server za praćenje, možemo dobiti novu krajnju tačku modela.

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

Trčanje modela iz Spark-a

Uprkos činjenici da je Tracking server dovoljno moćan da opslužuje modele u realnom vremenu, obučava ih i koristi funkcionalnost servera (izvor: mlflow // dokumenti // modeli # lokalni), korištenje Spark-a (batch ili streaming) je još moćnije rješenje zbog distribucije.

Zamislite da ste jednostavno obavili obuku van mreže, a zatim primijenili izlazni model na sve svoje podatke. Ovo je mjesto gdje Spark i MLflow blistaju.

Instalirajte PySpark + Jupyter + Spark

izvor: Započnite PySpark - Jupyter

Da bismo pokazali kako primjenjujemo MLflow modele na Spark okvire podataka, moramo podesiti Jupyter notebook računare da rade zajedno sa PySparkom.

Počnite instaliranjem najnovije stabilne verzije 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̀

Instalirajte PySpark i Jupyter u virtuelnom okruženju:

pip install pyspark jupyter

Postavite varijable okruženja:

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"

Odlučivši notebook-dir, možemo pohraniti naše bilježnice u željeni folder.

Pokretanje Jupytera iz PySparka

Pošto smo uspeli da konfigurišemo Jupiter kao PySpark drajver, sada možemo da pokrenemo Jupyter notebook u kontekstu PySpark-a.

(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

Proširivanje Sparka sa MLflow-om

Kao što je gore spomenuto, MLflow pruža funkciju za evidentiranje artefakata modela u S3. Čim imamo odabrani model u rukama, imamo mogućnost da ga uvezemo kao UDF koristeći modul 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)

Proširivanje Sparka sa MLflow-om
PySpark - Izlaz predviđanja kvaliteta vina

Do ove tačke smo razgovarali o tome kako koristiti PySpark sa MLflow-om, pokrećući predviđanja kvaliteta vina na čitavom skupu podataka o vinu. Ali šta ako trebate koristiti Python MLflow module iz Scala Spark?

I ovo smo testirali tako što smo Spark kontekst podijelili između Scale i Pythona. Odnosno, registrovali smo MLflow UDF u Python-u, i koristili ga iz Scale (da, možda nije najbolje rješenje, ali ono što imamo).

Scala Spark + MLflow

Za ovaj primjer ćemo dodati Toree Kernel u postojeći Jupiter.

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

Kao što možete vidjeti iz priložene bilježnice, UDF se dijeli između Spark-a i PySpark-a. Nadamo se da će ovaj dio biti koristan onima koji vole Scalu i žele primijeniti modele strojnog učenja u proizvodnji.

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

Sljedeći koraci

Iako je MLflow bio u Alpha verziji u vrijeme pisanja, izgleda prilično obećavajuće. Samo mogućnost pokretanja više okvira za mašinsko učenje i njihovog korišćenja sa jedne krajnje tačke podiže sisteme za preporuke na viši nivo.

Osim toga, MLflow zbližava inženjere podataka i stručnjake za nauku o podacima, postavljajući zajednički sloj između njih.

Nakon ovog istraživanja MLflow-a, uvjereni smo da ćemo krenuti naprijed i koristiti ga za naše Spark cjevovode i sisteme preporuka.

Bilo bi lijepo sinkronizirati skladište datoteka s bazom podataka umjesto sa sistemom datoteka. Ovo bi nam trebalo dati više krajnjih tačaka koje mogu koristiti istu pohranu datoteka. Na primjer, koristite više instanci Presto и Atina sa istim Glue metastoreom.

Da rezimiramo, želio bih da se zahvalim MLFlow zajednici što je naš rad s podacima učinio zanimljivijim.

Ako se igrate sa MLflow-om, ne ustručavajte se da nam pišete i kažete kako ga koristite, a još više ako ga koristite u produkciji.

Saznajte više o kursevima:
Mašinsko učenje. Osnovni kurs
Mašinsko učenje. Napredni kurs

Čitaj više:

izvor: www.habr.com

Dodajte komentar