Sparkin laajentaminen MLflow:lla

Hei, Habrovskin asukkaat. Kuten jo kirjoitimme, tässä kuussa OTUS käynnistää kaksi koneoppimiskurssia kerralla, nimittäin pohja и pitkälle kehittynyt. Tältä osin jatkamme hyödyllisen materiaalin jakamista.

Tämän artikkelin tarkoituksena on kertoa ensimmäisestä käyttökokemuksestamme MLvirtaus.

Aloitamme tarkastelun MLvirtaus seurantapalvelimestaan ​​ja kirjaa kaikki tutkimuksen iteraatiot. Sitten jaamme kokemuksemme Sparkin yhdistämisestä MLflow:n kanssa UDF:n avulla.

konteksti

Olemme sisällä Alfa terveys Käytämme koneoppimista ja tekoälyä antaaksemme ihmisille mahdollisuuden ottaa vastuu terveydestään ja hyvinvoinnistaan. Siksi koneoppimismallit ovat kehittämiemme datatieteen tuotteiden ytimessä, ja siksi meidät houkutteli MLflow, avoimen lähdekoodin alusta, joka kattaa kaikki koneoppimisen elinkaaren osa-alueet.

MLvirtaus

MLflow:n päätavoite on tarjota koneoppimisen päälle lisäkerros, jonka avulla datatieteilijät voivat työskennellä lähes minkä tahansa koneoppimiskirjaston kanssa (h2o, Keras, höpöttää, pytorch, sklearn и tensorflow), vie hänen työnsä uudelle tasolle.

MLflow sisältää kolme osaa:

  • Seuranta – tallennus ja kokeiden pyynnöt: koodi, tiedot, kokoonpano ja tulokset. Mallin luomisprosessin seuranta on erittäin tärkeää.
  • Projektit – Pakkausmuoto käytettäväksi millä tahansa alustalla (esim. SageMaker)
  • Mallit – yleinen muoto mallien lähettämiseksi erilaisiin käyttöönottotyökaluihin.

MLflow (kirjoitushetkellä alfaversiossa) on avoimen lähdekoodin alusta, jonka avulla voit hallita koneoppimisen elinkaarta, mukaan lukien kokeilut, uudelleenkäytöt ja käyttöönotto.

MLflow:n määrittäminen

MLflow:n käyttämiseksi sinun on ensin määritettävä koko Python-ympäristösi, jota käytämme PyEnv (Jos haluat asentaa Pythonin Maciin, tutustu täällä). Tällä tavalla voimme luoda virtuaalisen ympäristön, johon asennamme kaikki sen suorittamiseen tarvittavat kirjastot.

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

Asennamme tarvittavat kirjastot.

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

Huomautus: Käytämme PyArrowa ajaaksemme malleja, kuten UDF. PyArrow- ja Numpy-versiot piti korjata, koska jälkimmäiset versiot olivat ristiriidassa keskenään.

Käynnistä seurantakäyttöliittymä

MLflow Tracking mahdollistaa kokeiden kirjaamisen ja kyselyn Pythonilla ja REST API. Lisäksi voit määrittää, missä malliartefaktit tallennetaan (localhost, Amazon S3, Azure Blob -tallennustila, Google Cloud Storage tai SFTP-palvelin). Koska käytämme Alpha Healthissa AWS:ää, artefaktivarastomme on S3.

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

MLflow suosittelee pysyvän tiedostojen tallennustilan käyttöä. Tiedoston tallennuspaikka on paikka, johon palvelin tallentaa ajon ja kokeilun metatiedot. Kun käynnistät palvelimen, varmista, että se osoittaa pysyvään tiedostosäilöön. Käytämme tässä kokeilua varten /tmp.

Muista, että jos haluamme käyttää mlflow-palvelinta vanhojen kokeilujen suorittamiseen, niiden on oltava tiedostomuistissa. Kuitenkin myös ilman tätä voisimme käyttää niitä UDF:ssä, koska tarvitsemme vain polun malliin.

Huomautus: Muista, että seurantakäyttöliittymällä ja malliasiakkaalla on oltava pääsy artefaktin sijaintiin. Toisin sanoen riippumatta siitä, että seurantakäyttöliittymä sijaitsee EC2-esiintymässä, kun MLflow suoritetaan paikallisesti, koneella on oltava suora pääsy S3:een artefaktimallien kirjoittamista varten.

Sparkin laajentaminen MLflow:lla
Seurantakäyttöliittymä tallentaa artefaktit S3-ämpäriin

Juoksevia malleja

Heti kun seurantapalvelin on käynnissä, voit aloittaa mallien harjoittelun.

Esimerkkinä käytämme MLflow-esimerkin viinimuunnoksia Sklearn.

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

Kuten olemme jo keskustelleet, MLflow antaa sinun kirjata mallin parametreja, mittareita ja artefakteja, jotta voit seurata niiden kehittymistä iteraatioiden aikana. Tämä ominaisuus on erittäin hyödyllinen, koska tällä tavalla voimme toistaa parhaan mallin ottamalla yhteyttä seurantapalvelimeen tai ymmärtämällä, mikä koodi suoritti vaaditun iteroinnin git-hajautuslokien avulla.

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

Sparkin laajentaminen MLflow:lla
Viinitoistot

Mallin palvelinosa

MLflow-seurantapalvelimessa, joka käynnistettiin "mlflow server" -komennolla, on REST API, joka seuraa suorituksia ja kirjoittaa tietoja paikalliseen tiedostojärjestelmään. Voit määrittää seurantapalvelimen osoitteen käyttämällä ympäristömuuttujaa "MLFLOW_TRACKING_URI", ja MLflow-seurantasovellusliittymä ottaa automaattisesti yhteyttä seurantapalvelimeen tässä osoitteessa luodakseen/vastaanottaakseen käynnistystietoja, lokimittareita jne.

Lähde: Docs// Seurantapalvelimen käyttäminen

Jotta mallille voidaan toimittaa palvelin, tarvitsemme käynnissä olevan seurantapalvelimen (katso käynnistysrajapinta) ja mallin Run ID:n.

Sparkin laajentaminen MLflow:lla
Suorita 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

Jotta voimme palvella malleja käyttämällä MLflow-palvelutoimintoa, tarvitsemme pääsyn seurantakäyttöliittymään saadaksemme tietoja mallista yksinkertaisesti määrittämällä --run_id.

Kun malli ottaa yhteyttä seurantapalvelimeen, voimme saada uuden mallin päätepisteen.

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

Sparkin juoksevat mallit

Huolimatta siitä, että seurantapalvelin on tarpeeksi tehokas palvelemaan malleja reaaliajassa, kouluttamaan niitä ja käyttämään palvelimen toimintoja (lähde: mlflow // docs // mallit # paikallinen), Sparkin käyttö (erä tai suoratoisto) on jakelun ansiosta vieläkin tehokkaampi ratkaisu.

Kuvittele, että suoritit koulutuksen offline-tilassa ja sovelsit sitten tulosmallia kaikkiin tietoihisi. Täällä Spark ja MLflow loistavat.

Asenna PySpark + Jupyter + Spark

Lähde: Aloita PySpark - Jupyter

Jotta voimme näyttää, kuinka käytämme MLflow-malleja Spark-tietokehyksiin, meidän on määritettävä Jupyter-muistikirjat toimimaan yhdessä PySparkin kanssa.

Aloita asentamalla uusin vakaa versio 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̀

Asenna PySpark ja Jupyter virtuaaliympäristöön:

pip install pyspark jupyter

Määritä ympäristömuuttujat:

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"

Päätettyään notebook-dir, voimme tallentaa muistikirjamme haluamaasi kansioon.

Jupyterin käynnistäminen PySparkista

Koska pystyimme konfiguroimaan Jupiterin PySpark-ohjaimeksi, voimme nyt käyttää Jupyter-muistikirjaa PySparkin yhteydessä.

(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

Sparkin laajentaminen MLflow:lla

Kuten edellä mainittiin, MLflow tarjoaa ominaisuuden mallin artefaktien kirjaamiseen S3:ssa. Heti kun valittu malli on käsissämme, meillä on mahdollisuus tuoda se UDF:nä moduulin avulla 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)

Sparkin laajentaminen MLflow:lla
PySpark - Antaa viinin laatuennusteita

Tähän asti olemme puhuneet PySparkin käyttämisestä MLflow:n kanssa, jolloin viinin laatuennusteet suoritetaan koko viinitietojoukossa. Mutta entä jos sinun on käytettävä Scala Sparkin Python MLflow -moduuleja?

Testasimme myös tämän jakamalla Spark-kontekstin Scalan ja Pythonin välillä. Eli rekisteröimme MLflow UDF:n Pythonissa ja käytimme sitä Scalasta (kyllä, ei ehkä paras ratkaisu, mutta mitä meillä on).

Scala Spark + MLflow

Tätä esimerkkiä varten lisäämme Toree ydin olemassa olevaan Jupiteriin.

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

Kuten liitteenä olevasta muistikirjasta näkyy, UDF on jaettu Sparkin ja PySparkin välillä. Toivomme, että tämä osa on hyödyllinen niille, jotka rakastavat Scalaa ja haluavat ottaa koneoppimismalleja käyttöön tuotannossa.

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

РЎР »РµРґСѓСЋС ‰ РёРµ С € Р ° РіРё

Vaikka MLflow on kirjoitushetkellä Alpha-versiossa, se näyttää varsin lupaavalta. Pelkkä kyky suorittaa useita koneoppimiskehyksiä ja käyttää niitä yhdestä päätepisteestä vie suositusjärjestelmät seuraavalle tasolle.

Lisäksi MLflow tuo tietoteknikot ja tietotieteen asiantuntijat lähemmäksi toisiaan ja muodostaa yhteisen kerroksen heidän välilleen.

Tämän MLflow-tutkimuksen jälkeen olemme varmoja, että siirrymme eteenpäin ja käytämme sitä Spark-putkistoissamme ja suositusjärjestelmissämme.

Olisi mukavaa synkronoida tiedostojen tallennus tietokannan kanssa tiedostojärjestelmän sijaan. Tämän pitäisi antaa meille useita päätepisteitä, jotka voivat käyttää samaa tiedostotallennustilaa. Käytä esimerkiksi useita esiintymiä Presto и Athena saman Liima-metastoren kanssa.

Yhteenvetona haluan kiittää MLFlow-yhteisöä siitä, että se teki työstämme datan parissa mielenkiintoisemman.

Jos pelaat MLflow:n kanssa, älä epäröi kirjoittaa meille ja kertoa meille, miten käytät sitä, ja vielä enemmän, jos käytät sitä tuotannossa.

Lue lisää kursseista:
Koneoppiminen. Peruskurssi
Koneoppiminen. Jatkokurssi

Lue lisää:

Lähde: will.com

Lisää kommentti