ΠΡΠΈΠ²Π΅Ρ, Ρ
Π°Π±ΡΠΎΠ²ΡΠ°Π½Π΅. ΠΠ°ΠΊ ΠΌΡ ΡΠΆΠ΅ ΠΏΠΈΡΠ°Π»ΠΈ, Π² ΡΡΠΎΠΌ ΠΌΠ΅ΡΡΡΠ΅ OTUS Π·Π°ΠΏΡΡΠΊΠ°Π΅Ρ ΡΡΠ°Π·Ρ Π΄Π²Π° ΠΊΡΡΡΠ° ΠΏΠΎ ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠΌΡ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ
Π¦Π΅Π»Ρ ΡΡΠΎΠΉ ΡΡΠ°ΡΡΠΈ β ΡΠ°ΡΡΠΊΠ°Π·Π°ΡΡ ΠΎ Π½Π°ΡΠ΅ΠΌ ΠΏΠ΅ΡΠ²ΠΎΠΌ ΠΎΠΏΡΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ
ΠΡ Π½Π°ΡΠ½Π΅ΠΌ ΠΎΠ±Π·ΠΎΡ
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ
ΠΡ Π²
MLflow
ΠΡΠ½ΠΎΠ²Π½Π°Ρ ΡΠ΅Π»Ρ MLflow β ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ ΡΠ»ΠΎΠΉ ΠΏΠΎΠ²Π΅ΡΡ
ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ» Π±Ρ ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΡΡΠ°ΠΌ ΠΏΠΎ data science ΡΠ°Π±ΠΎΡΠ°ΡΡ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Ρ Π»ΡΠ±ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΎΠΉ ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ (
MLflow ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ ΡΡΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°:
- Tracking β Π·Π°ΠΏΠΈΡΡ ΠΈ Π·Π°ΠΏΡΠΎΡΡ ΠΊ ΡΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠ°ΠΌ: ΠΊΠΎΠ΄, Π΄Π°Π½Π½ΡΠ΅, ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ ΠΈ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ. Π‘Π»Π΅Π΄ΠΈΡΡ Π·Π° ΠΏΡΠΎΡΠ΅ΡΡΠΎΠΌ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΎΡΠ΅Π½Ρ Π²Π°ΠΆΠ½ΠΎ.
- Projects β Π€ΠΎΡΠΌΠ°Ρ ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠΈ Π΄Π»Ρ Π·Π°ΠΏΡΡΠΊΠ° Π½Π° Π»ΡΠ±ΠΎΠΉ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ΅ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ,
SageMaker ) - Models β ΠΎΠ±ΡΠΈΠΉ ΡΠΎΡΠΌΠ°Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π² ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ ΡΠ°Π·Π²Π΅ΡΡΡΠ²Π°Π½ΠΈΡ.
MLflow (Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ Π½Π°ΠΏΠΈΡΠ°Π½ΠΈΡ ΡΡΠ°ΡΡΠΈ Π² alpha-Π²Π΅ΡΡΠΈΠΈ) β ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ° Ρ ΠΎΡΠΊΡΡΡΡΠΌ ΠΈΡΡ ΠΎΠ΄Π½ΡΠΌ ΠΊΠΎΠ΄ΠΎΠΌ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΏΡΠ°Π²Π»ΡΡΡ ΠΆΠΈΠ·Π½Π΅Π½Π½ΡΠΌ ΡΠΈΠΊΠ»ΠΎΠΌ ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ, Π² ΡΠΎΠΌ ΡΠΈΡΠ»Π΅ ΡΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠ°ΠΌΠΈ, ΠΏΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΈ ΡΠ°Π·Π²Π΅ΡΡΡΠ²Π°Π½ΠΈΠ΅ΠΌ.
ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° MLflow
ΠΠ»Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ MLflow Π½ΡΠΆΠ½ΠΎ ΡΠ½Π°ΡΠ°Π»Π° Π½Π°ΡΡΡΠΎΠΈΡΡ Π²ΡΡ ΡΡΠ΅Π΄Ρ Python, Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΌΡ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ
```
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 Π½ΡΠΆΠ½ΠΎ Π±ΡΠ»ΠΎ ΠΏΠΎΠΏΡΠ°Π²ΠΈΡΡ, ΠΏΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅ Π²Π΅ΡΡΠΈΠΈ ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠΎΠ²Π°Π»ΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠΎΠ±ΠΎΠΉ.
ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ Tracking UI
MLflow Tracking ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π½Π°ΠΌ Π»ΠΎΠ³ΠΈΡΠΎΠ²Π°ΡΡ ΠΈ Π΄Π΅Π»Π°ΡΡ Π·Π°ΠΏΡΠΎΡΡ ΠΊ ΡΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠ°ΠΌ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Python ΠΈ
# 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 Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π°ΡΡΠ΅ΡΠ°ΠΊΡΠΎΠ².
Tracking UI Ρ
ΡΠ°Π½ΠΈΡ Π°ΡΡΠ΅ΡΠ°ΠΊΡΡ Π² Π±Π°ΠΊΠ΅ΡΠ΅ S3
ΠΠ°ΠΏΡΡΠΊ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ
ΠΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ Π±ΡΠ΄Π΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ Tracking-ΡΠ΅ΡΠ²Π΅Ρ, ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΠΈΠ½Π°ΡΡ ΠΎΠ±ΡΡΠ°ΡΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ.
Π ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΏΡΠΈΠΌΠ΅ΡΠ° ΠΌΡ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΠ΅ΠΉ wine ΠΈΠ· ΠΏΡΠΈΠΌΠ΅ΡΠ° MLflow Π²
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 ΠΊΠΎΠΌΠΌΠΈΡΠΎΠ².
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")
ΠΡΠ΅ΡΠ°ΡΠΈΠΈ wine
Π‘Π΅ΡΠ²Π΅ΡΠ½Π°Ρ ΡΠ°ΡΡΡ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ
Tracking-ΡΠ΅ΡΠ²Π΅Ρ MLflow, Π·Π°ΠΏΡΡΠ΅Π½Π½ΡΠΉ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ βmlflow serverβ, ΠΈΠΌΠ΅Π΅Ρ REST API Π΄Π»Ρ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΡ Π·Π°ΠΏΡΡΠΊΠΎΠ² ΠΈ Π·Π°ΠΏΠΈΡΠΈ Π΄Π°Π½Π½ΡΡ Π² Π»ΠΎΠΊΠ°Π»ΡΠ½ΡΡ ΡΠ°ΠΉΠ»ΠΎΠ²ΡΡ ΡΠΈΡΡΠ΅ΠΌΡ. ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΡΠΊΠ°Π·Π°ΡΡ Π°Π΄ΡΠ΅Ρ tracking-ΡΠ΅ΡΠ²Π΅ΡΠ° Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΡΡΠ΅Π΄Ρ Β«MLFLOW_TRACKING_URIΒ» ΠΈ tracking API MLflow Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ²ΡΠΆΠ΅ΡΡΡ Ρ tracking-ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ ΠΏΠΎ ΡΡΠΎΠΌΡ Π°Π΄ΡΠ΅ΡΡ, ΡΡΠΎΠ±Ρ ΡΠΎΠ·Π΄Π°ΡΡ/ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ Π·Π°ΠΏΡΡΠΊΠ΅, ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π»ΠΎΠ³ΠΎΠ² ΠΈ Ρ.Π΄.
ΠΡΡΠΎΡΠ½ΠΈΠΊ:
Docs// Running a tracking server
Π§ΡΠΎΠ±Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ Π½Π°ΠΌ ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΠΈΡΡΡ Π·Π°ΠΏΡΡΠ΅Π½Π½ΡΠΉ tracking-ΡΠ΅ΡΠ²Π΅Ρ (ΡΠΌ. ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ Π·Π°ΠΏΡΡΠΊΠ°) ΠΈ Run ID ΠΌΠΎΠ΄Π΅Π»ΠΈ.
Run 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 serve, Π½Π°ΠΌ ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΠΈΡΡΡ Π΄ΠΎΡΡΡΠΏ ΠΊ Tracking UI, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠ°ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΏΡΠΎΡΡΠΎ ΡΠΊΠ°Π·Π°Π² --run_id
.
ΠΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΠΌΠΎΠ΄Π΅Π»Ρ ΡΠ²ΡΠ·ΡΠ²Π°Π΅ΡΡΡ Ρ Tracking-ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π½ΠΎΠ²ΡΡ ΠΊΠΎΠ½Π΅ΡΠ½ΡΡ ΡΠΎΡΠΊΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ.
# 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-ΡΠ΅ΡΠ²Π΅Ρ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΌΠΎΡΠ½ΡΠΉ Π΄Π»Ρ ΠΎΠ±ΡΠ»ΡΠΆΠΈΠ²Π°Π½ΠΈΡ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π² ΡΠ΅ΠΆΠΈΠΌΠ΅ ΡΠ΅Π°Π»ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ, ΠΈΡ
ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π°serve (ΠΈΡΡΠΎΡΠ½ΠΈΠΊ:
ΠΡΠ΅Π΄ΡΡΠ°Π²ΡΡΠ΅, ΡΡΠΎ Π²Ρ ΠΏΡΠΎΡΡΠΎ ΠΏΡΠΎΠ²Π΅Π»ΠΈ ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ Π² ΠΎΡΡΠ»Π°ΠΉΠ½Π΅, Π° ΠΏΠΎΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅Π½ΠΈΠ»ΠΈ Π²ΡΡ ΠΎΠ΄Π½ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ ΠΊΠΎ Π²ΡΠ΅ΠΌ Π²Π°ΡΠΈΠΌ Π΄Π°Π½Π½ΡΠΌ. ΠΠΌΠ΅Π½Π½ΠΎ ΡΡΡ Spark ΠΈ MLflow ΠΏΠΎΠΊΠ°ΠΆΡΡ ΡΠ΅Π±Ρ Ρ Π»ΡΡΡΠ΅ΠΉ ΡΡΠΎΡΠΎΠ½Ρ.
Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ PySpark + Jupyter + Spark
ΠΡΡΠΎΡΠ½ΠΈΠΊ:
Get started PySpark β Jupyter
Π§ΡΠΎΠ±Ρ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ, ΠΊΠ°ΠΊ ΠΌΡ ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ ΠΌΠΎΠ΄Π΅Π»ΠΈ MLflow ΠΊ Π΄Π°ΡΠ°ΡΡΠ΅ΠΉΠΌΠ°ΠΌ Spark, Π½ΡΠΆΠ½ΠΎ Π½Π°ΡΡΡΠΎΠΈΡΡ ΡΠΎΠ²ΠΌΠ΅ΡΡΠ½ΡΡ ΡΠ°Π±ΠΎΡΡ Jupyter notebooks Ρ PySpark.
ΠΠ°ΡΠ½ΠΈΡΠ΅ Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅ΠΉ ΡΡΠ°Π±ΠΈΠ»ΡΠ½ΠΎΠΉ Π²Π΅ΡΡΠΈΠΈ
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
, ΠΌΡ ΡΠΌΠΎΠΆΠ΅ΠΌ Ρ
ΡΠ°Π½ΠΈΡΡ Π½Π°ΡΠΈ notebook-ΠΈ Π² ΠΆΠ΅Π»Π°Π΅ΠΌΠΎΠΉ ΠΏΠ°ΠΏΠΊΠ΅.
ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ Jupyter ΠΈΠ· PySpark
ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΌΡ ΡΠΌΠΎΠ³Π»ΠΈ Π½Π°ΡΡΡΠΎΠΈΡΡ Jupiter Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ Π΄ΡΠ°ΠΉΠ²Π΅ΡΠ° PySpark, ΡΠ΅ΠΏΠ΅ΡΡ ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Jupyter notebook Π² ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ΅ 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
ΠΠ°ΠΊ Π±ΡΠ»ΠΎ ΡΠΊΠ°Π·Π°Π½ΠΎ Π²ΡΡΠ΅, 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)
PySpark β ΠΡΠ²ΠΎΠ΄ ΠΏΡΠΎΠ³Π½ΠΎΠ·Π° ΠΊΠ°ΡΠ΅ΡΡΠ²Π° Π²ΠΈΠ½Π°
ΠΠΎ ΡΡΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½ΡΠ° ΠΌΡ Π³ΠΎΠ²ΠΎΡΠΈΠ»ΠΈ ΠΎ ΡΠΎΠΌ, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ PySpark Ρ MLflow, Π·Π°ΠΏΡΡΠΊΠ°Ρ ΠΏΡΠΎΠ³Π½ΠΎΠ·ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° Π²ΠΈΠ½Π° Π½Π° Π²ΡΠ΅ΠΌ Π½Π°Π±ΠΎΡΠ΅ Π΄Π°Π½Π½ΡΡ wine. ΠΠΎ ΡΡΠΎ Π΄Π΅Π»Π°ΡΡ, Π΅ΡΠ»ΠΈ Π½ΡΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΌΠΎΠ΄ΡΠ»ΠΈ Python MLflow ΠΈΠ· Scala Spark?
ΠΡ ΠΏΡΠΎΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π»ΠΈ ΠΈ ΡΡΠΎ, ΡΠ°Π·Π΄Π΅Π»ΠΈΠ² ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ Spark ΠΌΠ΅ΠΆΠ΄Ρ Scala ΠΈ Python. Π’ΠΎ Π΅ΡΡΡ ΠΌΡ Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π»ΠΈ MLflow UDF Π² Python, ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΠΈ Π΅Π³ΠΎ ΠΈΠ· Scala (Π΄Π°, Π²ΠΎΠ·ΠΎΠΆΠ½ΠΎ, Π½Π΅ Π»ΡΡΡΠ΅Π΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅, Π½ΠΎ ΡΡΠΎ ΠΈΠΌΠ΅Π΅ΠΌ).
Scala Spark + MLflow
ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠ° ΠΌΡ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ
Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ 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
```
ΠΠ°ΠΊ Π²ΠΈΠ΄Π½ΠΎ ΠΈΠ· ΠΏΡΠΈΠΊΡΠ΅ΠΏΠ»Π΅Π½Π½ΠΎΠ³ΠΎ notebook-Π°, 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 Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ Π² Alpha-Π²Π΅ΡΡΠΈΠΈ, ΠΎΠ½Π° Π²ΡΠ³Π»ΡΠ΄ΠΈΡ Π΄ΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΌΠ½ΠΎΠ³ΠΎΠΎΠ±Π΅ΡΠ°ΡΡΠ΅. ΠΠ΄Π½Π° Π»ΠΈΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠΎΠ² ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΈΡ ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ ΠΊΠΎΠ½Π΅ΡΠ½ΠΎΠΉ ΡΠΎΡΠΊΠΈ Π²ΡΠ²ΠΎΠ΄ΠΈΡ ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ ΡΠΈΡΡΠ΅ΠΌΡ Π½Π° Π½ΠΎΠ²ΡΠΉ ΡΡΠΎΠ²Π΅Π½Ρ.
Π ΡΠΎΠΌΡ ΠΆΠ΅, MLflow ΡΠ±Π»ΠΈΠΆΠ°Π΅Ρ Data-ΠΈΠ½ΠΆΠ΅Π½Π΅ΡΠΎΠ² ΠΈ ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΡΡΠΎΠ² ΠΏΠΎ Data Science, ΠΏΡΠΎΠΊΠ»Π°Π΄ΡΠ²Π°Ρ ΠΌΠ΅ΠΆΠ΄Ρ Π½ΠΈΠΌΠΈ ΠΎΠ±ΡΠΈΠΉ ΡΠ»ΠΎΠΉ.
ΠΠΎΡΠ»Π΅ ΡΡΠΎΠ³ΠΎ ΠΈΡΡΠ»Π΅Π΄ΠΎΠ²Π°Π½ΠΈΡ MLflow, ΠΌΡ ΡΠ²Π΅ΡΠ΅Π½Ρ, ΡΡΠΎ ΠΏΠΎΠΉΠ΄Π΅ΠΌ Π΄Π°Π»ΡΡΠ΅ ΠΈ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΅Π΅ Π΄Π»Ρ Π½Π°ΡΠΈΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ² Spark ΠΈ Π² ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠ΅Π»ΡΠ½ΡΡ ΡΠΈΡΡΠ΅ΠΌΠ°Ρ .
ΠΡΠ»ΠΎ Π±Ρ Π½Π΅ΠΏΠ»ΠΎΡ
ΠΎ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°ΠΉΠ»ΠΎΠ²ΠΎΠ΅ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈΡΠ΅ Ρ Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½ΡΡ
, Π²ΠΌΠ΅ΡΡΠΎ ΡΠ°ΠΉΠ»ΠΎΠ²ΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΡ. Π’Π°ΠΊ ΠΌΡ Π΄ΠΎΠ»ΠΆΠ½Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΊΠΎΠ½Π΅ΡΠ½ΡΡ
ΡΠΎΡΠ΅ΠΊ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠ³ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΎΠ΄Π½ΠΎ ΠΈ ΡΠΎ ΠΆΠ΅ ΡΠ°ΠΉΠ»ΠΎΠ²ΠΎΠ΅ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈΡΠ΅. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΠΎΠ²
ΠΠΎΠ΄Π²ΠΎΠ΄Ρ ΠΈΡΠΎΠ³ΠΈ, Ρ ΠΎΡΠ΅ΡΡΡ ΡΠΊΠ°Π·Π°ΡΡ ΡΠΏΠ°ΡΠΈΠ±ΠΎ ΡΠΎΠΎΠ±ΡΠ΅ΡΡΠ²Ρ MLFlow Π·Π° ΡΠΎ, ΡΡΠΎ Π΄Π΅Π»Π°Π΅ΡΠ΅ Π½Π°ΡΡ ΡΠ°Π±ΠΎΡΡ Ρ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½Π΅Π΅.
ΠΡΠ»ΠΈ Π²Ρ ΠΈΠ³ΡΠ°Π΅ΡΠ΅ΡΡ Ρ MLflow, Π½Π΅ ΡΡΠ΅ΡΠ½ΡΠΉΡΠ΅ΡΡ ΠΏΠΈΡΠ°ΡΡ Π½Π°ΠΌ ΠΈ ΡΠ°ΡΡΠΊΠ°Π·ΡΠ²Π°ΡΡ, ΠΊΠ°ΠΊ Π²Ρ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΠ΅, ΠΈ ΡΠ΅ΠΌ Π±ΠΎΠ»Π΅Π΅, Π΅ΡΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΠ΅ Π΅Π³ΠΎ Π½Π° ΠΏΡΠΎΠ΄Π°ΠΊΡΠ΅Π½Π΅.
Π£Π·Π½Π°ΡΡ ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ ΠΎ ΠΊΡΡΡΠ°Ρ
:
Π§ΠΈΡΠ°ΡΡ Π΅ΡΡ:
Π ΠΈΡΠΊΠΈ ΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ΅ΡΠ΅ΠΆΠ΅Π½ΠΈΡ ΠΏΡΠΈ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΈ ΠΌΠ΅ΡΠΎΠ΄Π° Π³Π»Π°Π²Π½ΡΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ ΠΊ Π·Π°Π΄Π°ΡΠ°ΠΌ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ Ρ ΡΡΠΈΡΠ΅Π»Π΅ΠΌ Π Π°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°Π΅ΠΌ ΠΌΠΎΠ΄Π΅Π»Ρ ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ Ρ Docker β Π§Π°ΡΡΡ 1 Π Π°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°Π΅ΠΌ ΠΌΠΎΠ΄Π΅Π»Ρ ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ Ρ Docker β Π§Π°ΡΡΡ 2
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com