Ընդլայնելով Spark-ը MLflow-ով

Բարև Խաբրովսկի բնակիչներ։ Ինչպես արդեն գրել ենք, այս ամիս OTUS-ը սկսում է միանգամից երկու մեքենայական ուսուցման դասընթացներ, մասնավորապես հիմք и առաջադեմ. Այս առումով մենք շարունակում ենք կիսվել օգտակար նյութերով։

Այս հոդվածի նպատակն է խոսել օգտագործման մեր առաջին փորձի մասին MLflow.

Մենք կսկսենք վերանայումը MLflow իր հետևող սերվերից և գրանցել ուսումնասիրության բոլոր կրկնությունները: Այնուհետև մենք կկիսվենք Spark-ը MLflow-ի հետ UDF-ի միջոցով միացնելու մեր փորձով:

Համատեքստ

Մենք ներս ենք Ալֆա Առողջություն Մենք օգտագործում ենք մեքենայական ուսուցում և արհեստական ​​ինտելեկտ՝ մարդկանց հնարավորություն տալու իրենց առողջության և բարեկեցության համար պատասխանատվություն ստանձնելու համար: Ահա թե ինչու մեքենայական ուսուցման մոդելները գտնվում են տվյալների գիտության արտադրանքի հիմքում, որը մենք մշակում ենք, և այդ պատճառով մեզ գրավեց MLflow՝ բաց կոդով հարթակ, որն ընդգրկում է մեքենայական ուսուցման կյանքի ցիկլի բոլոր ասպեկտները:

MLflow

MLflow-ի հիմնական նպատակն է ապահովել լրացուցիչ շերտ մեքենայական ուսուցման վերևում, որը թույլ կտա տվյալների գիտնականներին աշխատել գրեթե ցանկացած մեքենայական ուսուցման գրադարանի հետ (h2o, կապեր, թռչկոտել, բիտորխ, սքլե սովորել и tensorflow), նրա աշխատանքը տեղափոխելով հաջորդ մակարդակ:

MLflow-ն ապահովում է երեք բաղադրիչ.

  • Հետեւում է – Ձայնագրում և փորձերի հարցումներ՝ կոդ, տվյալներ, կոնֆիգուրացիա և արդյունքներ: Մոդելի ստեղծման գործընթացի մոնիտորինգը շատ կարևոր է։
  • ծրագրեր – Փաթեթավորման ձևաչափ՝ ցանկացած հարթակում գործարկելու համար (օրինակ. SageMaker)
  • Models – Տարբեր տեղակայման գործիքներին մոդելներ ներկայացնելու ընդհանուր ձևաչափ:

MLflow-ը (գրելու պահին ալֆայում) բաց կոդով հարթակ է, որը թույլ է տալիս կառավարել մեքենայական ուսուցման կյանքի ցիկլը, ներառյալ փորձարկումը, վերօգտագործումը և տեղակայումը:

MLflow-ի կարգավորում

MLflow-ն օգտագործելու համար նախ պետք է կարգավորեք ձեր ամբողջ Python միջավայրը, դրա համար մենք կօգտագործենք PyEnv (Python-ը Mac-ում տեղադրելու համար ստուգեք այստեղ) Այս կերպ մենք կարող ենք ստեղծել վիրտուալ միջավայր, որտեղ մենք կտեղադրենք այն գործարկելու համար անհրաժեշտ բոլոր գրադարանները:

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

Եկեք տեղադրենք անհրաժեշտ գրադարանները:

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

Նշում. Մենք օգտագործում ենք PyArrow մոդելները, ինչպիսիք են UDF-ն գործարկելու համար: PyArrow-ի և Numpy-ի տարբերակները պետք է շտկվեին, քանի որ վերջին տարբերակները հակասում էին միմյանց:

Գործարկեք Հետևման միջերեսը

MLflow Tracking-ը մեզ թույլ է տալիս գրանցել և հարցումներ կատարել փորձերի միջոցով՝ օգտագործելով Python և ՀԱՆԳՍՏՅԱՆ API. Բացի այդ, դուք կարող եք որոշել, թե որտեղ պետք է պահել մոդելային արտեֆակտները (localhost, Amazon S3, Azure Blob Storage, Google Ամպային կամ SFTP սերվեր) Քանի որ մենք օգտագործում ենք AWS Alpha Health-ում, մեր արտեֆակտի պահեստը կլինի S3:

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

MLflow-ը խորհուրդ է տալիս օգտագործել մշտական ​​ֆայլերի պահեստավորում: Ֆայլերի պահեստավորումն այն է, որտեղ սերվերը կպահի գործարկվող և փորձի մետատվյալները: Սերվերը միացնելիս համոզվեք, որ այն մատնանշում է մշտական ​​ֆայլերի պահեստը: Այստեղ փորձի համար մենք պարզապես կօգտագործենք /tmp.

Հիշեք, որ եթե մենք ցանկանում ենք օգտագործել mlflow սերվերը հին փորձեր գործարկելու համար, դրանք պետք է ներկա լինեն ֆայլերի պահեստում: Այնուամենայնիվ, նույնիսկ առանց դրա մենք կարող էինք դրանք օգտագործել UDF-ում, քանի որ մեզ անհրաժեշտ է միայն մոդելի ճանապարհը:

Նշում. Նկատի ունեցեք, որ Tracking UI-ը և մոդել հաճախորդը պետք է մուտք ունենան արտեֆակտի գտնվելու վայրը: Այսինքն՝ անկախ այն հանգամանքից, որ Tracking UI-ը գտնվում է EC2 օրինակում, MLflow-ը լոկալ գործարկելու ժամանակ մեքենան պետք է ուղիղ մուտք ունենա S3՝ արտեֆակտ մոդելներ գրելու համար:

Ընդլայնելով Spark-ը MLflow-ով
Հետևող UI-ն պահում է արտեֆակտները S3 դույլով

Վազող մոդելներ

Հենց որ Tracking սերվերը գործարկվի, կարող եք սկսել մոդելների վերապատրաստումը:

Որպես օրինակ, մենք կօգտագործենք գինու փոփոխությունը MLflow օրինակից Sklein.

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

Ինչպես արդեն քննարկել ենք, MLflow-ը թույլ է տալիս գրանցել մոդելի պարամետրերը, չափումները և արտեֆակտները, որպեսզի կարողանաք հետևել, թե ինչպես են դրանք զարգանում կրկնությունների ընթացքում: Այս հատկությունը չափազանց օգտակար է, քանի որ այս կերպ մենք կարող ենք վերարտադրել լավագույն մոդելը՝ կապվելով Tracking սերվերի հետ կամ հասկանալով, թե որ կոդը է կատարել պահանջվող կրկնությունը՝ օգտագործելով git hash logs 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")

Ընդլայնելով Spark-ը MLflow-ով
Գինու կրկնություններ

Սերվերի մաս մոդելի համար

MLflow հետևող սերվերը, որը գործարկվել է «mlflow server» հրամանի միջոցով, ունի REST API՝ գործարկումներին հետևելու և տվյալները տեղական ֆայլային համակարգում գրելու համար: Դուք կարող եք նշել հետևող սերվերի հասցեն՝ օգտագործելով «MLFLOW_TRACKING_URI» միջավայրի փոփոխականը, և MLflow-ի հետագծման API-ն ավտոմատ կերպով կապ կհաստատի այս հասցեի հետագծման սերվերի հետ՝ ստեղծելու/ստանալու գործարկման մասին տեղեկատվություն, գրանցամատյանների չափումներ և այլն:

Source: Փաստաթղթեր// Հետևող սերվերի գործարկում

Մոդելը սերվերով ապահովելու համար մեզ անհրաժեշտ է գործող հետևող սերվեր (տես գործարկման ինտերֆեյսը) և մոդելի Run ID-ն:

Ընդլայնելով Spark-ը MLflow-ով
Գործարկեք 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

MLflow սպասարկման ֆունկցիոնալությունը օգտագործող մոդելներին սպասարկելու համար մեզ անհրաժեշտ կլինի մուտք գործել Tracking UI՝ մոդելի մասին տեղեկատվություն ստանալու համար՝ պարզապես նշելով. --run_id.

Երբ մոդելը կապ հաստատի Հետագծման սերվերի հետ, մենք կարող ենք նոր մոդելի վերջնակետ ստանալ:

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

Վազող մոդելներ Spark-ից

Չնայած այն հանգամանքին, որ Tracking սերվերը բավականաչափ հզոր է մոդելներին իրական ժամանակում սպասարկելու, դրանք վարժեցնելու և սերվերի ֆունկցիոնալությունից օգտվելու համար (աղբյուր. mlflow // docs // models # local), Spark-ի (խմբաքանակի կամ հոսքի) օգտագործումը բաշխման շնորհիվ էլ ավելի հզոր լուծում է:

Պատկերացրեք, որ դուք պարզապես ուսուցումն անցկացրիք անցանց, այնուհետև կիրառեք ելքային մոդելը ձեր բոլոր տվյալների վրա: Այստեղ փայլում են Spark-ը և MLflow-ը:

Տեղադրեք PySpark + Jupyter + Spark

Source: Սկսեք PySpark - Jupyter

Ցույց տալու համար, թե ինչպես ենք մենք կիրառում MLflow մոդելները Spark տվյալների շրջանակների վրա, մենք պետք է կարգավորենք Jupyter նոթատետրերը՝ PySpark-ի հետ համատեղ աշխատելու համար:

Սկսեք տեղադրելով վերջին կայուն տարբերակը 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̀

Տեղադրեք PySpark-ը և Jupyter-ը վիրտուալ միջավայրում.

pip install pyspark jupyter

Ստեղծեք շրջակա միջավայրի փոփոխականներ.

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"

Որոշելով notebook-dir, մենք կարող ենք պահել մեր նոթատետրերը ցանկալի թղթապանակում։

Jupyter-ի գործարկումը PySpark-ից

Քանի որ մենք կարողացանք կարգավորել Յուպիտերը որպես PySpark վարորդ, այժմ կարող ենք գործարկել Jupyter նոթատետրը 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

Ընդլայնելով Spark-ը MLflow-ով

Ինչպես նշվեց վերևում, MLflow-ը հնարավորություն է տալիս S3-ում մոդելային արտեֆակտները գրանցելու համար: Հենց որ մեր ձեռքում լինի ընտրված մոդելը, մենք հնարավորություն ունենք այն ներմուծել որպես UDF՝ օգտագործելով մոդուլը 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)

Ընդլայնելով Spark-ը MLflow-ով
PySpark - Գինու որակի կանխատեսումներ

Մինչև այս պահը մենք խոսել ենք այն մասին, թե ինչպես օգտագործել PySpark-ը MLflow-ի հետ՝ գինու որակի կանխատեսումներ իրականացնելով գինու ամբողջ տվյալների վրա: Բայց ի՞նչ, եթե Ձեզ անհրաժեշտ է օգտագործել Python MLflow մոդուլներ Scala Spark-ից:

Մենք սա նույնպես փորձարկեցինք՝ բաժանելով Spark համատեքստը Scala-ի և Python-ի միջև: Այսինքն, մենք գրանցեցինք MLflow UDF-ը Python-ում և օգտագործեցինք այն Scala-ից (այո, գուցե ոչ լավագույն լուծումը, բայց այն, ինչ ունենք):

Scala Spark + MLflow

Այս օրինակի համար մենք կավելացնենք Toree Kernel դեպի գոյություն ունեցող Յուպիտեր:

Տեղադրեք 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
```

Ինչպես տեսնում եք կից նոթատետրից, UDF-ը կիսվում է Spark-ի և PySpark-ի միջև: Հուսով ենք, որ այս մասը օգտակար կլինի նրանց համար, ովքեր սիրում են Scala-ն և ցանկանում են արտադրության մեջ կիրառել մեքենայական ուսուցման մոդելներ:

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

Հաջորդ քայլերը

Չնայած գրելու պահին MLflow-ը Ալֆա տարբերակում է, այն բավականին խոստումնալից է թվում: Պարզապես մի քանի մեքենայական ուսուցման շրջանակներ գործարկելու և դրանք մեկ վերջնական կետից սպառելու հնարավորությունը խորհուրդ տվող համակարգերը տեղափոխում է հաջորդ մակարդակ:

Բացի այդ, MLflow-ն ավելի է մոտեցնում Data Engineers-ին և Data Science-ի մասնագետներին՝ ընդհանուր շերտ դնելով նրանց միջև:

MLflow-ի այս ուսումնասիրությունից հետո մենք վստահ ենք, որ առաջ կշարժվենք և կօգտագործենք այն մեր Spark խողովակաշարերի և առաջարկող համակարգերի համար:

Լավ կլիներ ֆայլերի պահեստը համաժամեցնել տվյալների բազայի հետ՝ ֆայլային համակարգի փոխարեն: Սա մեզ պետք է տա ​​մի քանի վերջնակետեր, որոնք կարող են օգտագործել նույն ֆայլի պահեստը: Օրինակ, օգտագործեք բազմաթիվ օրինակներ Presto и Athena նույն Glue metastore-ով:

Ամփոփելու համար ես կցանկանայի շնորհակալություն հայտնել MLFlow համայնքին տվյալների հետ մեր աշխատանքը ավելի հետաքրքիր դարձնելու համար:

Եթե ​​դուք խաղում եք MLflow-ի հետ, մի հապաղեք գրել մեզ և պատմել մեզ, թե ինչպես եք այն օգտագործում, և նույնիսկ ավելին, եթե այն օգտագործում եք արտադրության մեջ:

Իմացեք ավելին դասընթացների մասին.
Մեքենայի ուսուցում. Հիմնական դասընթաց
Մեքենայի ուսուցում. Ընդլայնված դասընթաց

Կարդալ ավելին:

Source: www.habr.com

Добавить комментарий