เบ‚เบฐเบซเบเบฒเบ Spark เบ”เป‰เบงเบ MLflow

เบชเบฐเบšเบฒเบเบ”เบต, เบŠเบฒเบงเป€เบกเบทเบญเบ‡ Khabrovsk. เบ”เบฑเปˆเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เบ‚เบฝเบ™เปเบฅเป‰เบง, เปƒเบ™เป€เบ”เบทเบญเบ™เบ™เบตเป‰ OTUS เบเปเบฒเบฅเบฑเบ‡เป€เบ›เบตเบ”เบ•เบปเบงเบชเบญเบ‡เบซเบผเบฑเบเบชเบนเบ”เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบเปƒเบ™เป€เบงเบฅเบฒเบ”เบฝเบงเบเบฑเบ™, เบ„เบท เบžเบทเป‰เบ™เบ–เบฒเบ™ ะธ เบ‚เบฑเป‰เบ™เบชเบนเบ‡. เปƒเบ™เป€เบฅเบทเปˆเบญเบ‡เบ™เบตเป‰, เบžเบงเบเป€เบฎเบปเบฒเบชเบทเบšเบ•เปเปˆเปเบšเปˆเบ‡เบ›เบฑเบ™เบญเบธเบ›เบฐเบเบญเบ™เบ—เบตเปˆเป€เบ›เบฑเบ™เบ›เบฐเป‚เบซเบเบ”.

เบˆเบธเบ”เบ›เบฐเบชเบปเบ‡เบ‚เบญเบ‡เบšเบปเบ”เบ„เบงเบฒเบกเบ™เบตเป‰เปเบกเปˆเบ™เป€เบžเบทเปˆเบญเบชเบปเบ™เบ—เบฐเบ™เบฒเบเปˆเบฝเบงเบเบฑเบšเบ›เบฐเบชเบปเบšเบเบฒเบ™เบ—เปเบฒเบญเบดเบ”เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰ MLflow.

เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเป€เบฅเบตเปˆเบกเบเบฒเบ™เบเบงเบ”เบชเบญเบš MLflow เบˆเบฒเบเป€เบŠเบตเบšเป€เบงเบตเบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเบ‚เบญเบ‡เบกเบฑเบ™ เปเบฅเบฐเบšเบฑเบ™เบ—เบถเบเบเบฒเบ™เป€เบฎเบฑเบ”เบŠเป‰เบณเบ—เบฑเบ‡เปเบปเบ”เบ‚เบญเบ‡เบเบฒเบ™เบชเบถเบเบชเบฒ. เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเปเบšเปˆเบ‡เบ›เบฑเบ™เบ›เบฐเบชเบปเบšเบเบฒเบ™เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเปƒเบ™เบเบฒเบ™เป€เบŠเบทเปˆเบญเบกเบ•เปเปˆ Spark เบเบฑเบš MLflow เป‚เบ”เบเปƒเบŠเป‰ UDF.

เบชเบฐเบžเบฒเบšเบเบฒเบ™

เบžเบงเบเป€เบฎเบปเบฒเบขเบนเปˆเปƒเบ™ เบชเบธเบ‚เบฐเบžเบฒเบšเบญเบฑเบ™เบŸเบฒ เบžเบงเบเป€เบฎเบปเบฒเปƒเบŠเป‰เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เบ‚เบญเบ‡เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ เปเบฅเบฐเบ›เบฑเบ™เบเบฒเบ›เบฐเบ”เบดเบ”เป€เบžเบทเปˆเบญเบชเป‰เบฒเบ‡เบ„เบงเบฒเบกเป€เบ‚เบฑเป‰เบกเปเบ‚เบ‡เปƒเบซเป‰เบ„เบปเบ™เปƒเบ™เบเบฒเบ™เบ„เบธเป‰เบกเบ„เบญเบ‡เบชเบธเบ‚เบฐเบžเบฒเบš เปเบฅเบฐเบชเบธเบ‚เบฐเบžเบฒเบšเบ‚เบญเบ‡เป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒ. เบ™เบฑเป‰เบ™เปเบกเปˆเบ™เป€เบซเบ”เบœเบปเบ™เบ—เบตเปˆเบ•เบปเบงเปเบšเบšเบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เบ‚เบญเบ‡เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบเปเบกเปˆเบ™เบˆเบธเบ”เปƒเบˆเบเบฒเบ‡เบ‚เบญเบ‡เบœเบฐเบฅเบดเบ”เบ•เบฐเบžเบฑเบ™เบงเบดเบ—เบฐเบเบฒเบชเบฒเบ”เบ‚เปเป‰เบกเบนเบ™เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบžเบฑเบ”เบ—เบฐเบ™เบฒ, เปเบฅเบฐเบ™เบฑเป‰เบ™เปเบกเปˆเบ™เป€เบซเบ”เบœเบปเบ™เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ–เบทเบเบ”เบถเบ‡เบ”เบนเบ”เป€เบญเบปเบฒเบกเบฒเบชเบนเปˆ MLflow, เป€เบŠเบดเปˆเบ‡เป€เบ›เบฑเบ™เปเบžเบฅเบฐเบ•เบฐเบŸเบญเบกเปเบซเบผเปˆเบ‡เป€เบ›เบตเบ”เบ—เบตเปˆเบเบงเบกเป€เบญเบปเบฒเบ—เบธเบเบ”เป‰เบฒเบ™เบ‚เบญเบ‡เบงเบปเบ‡เบˆเบญเบ™เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ.

MLflow

เป€เบ›เบปเป‰เบฒเบซเบกเบฒเบเบ•เบปเป‰เบ™เบ•เปเบ‚เบญเบ‡ MLflow เปเบกเปˆเบ™เป€เบžเบทเปˆเบญเบชเบฐเบซเบ™เบญเบ‡เบŠเบฑเป‰เบ™เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเบขเบนเปˆเป€เบ—เบดเบ‡เบ‚เบญเบ‡เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบเบ—เบตเปˆเบˆเบฐเบŠเปˆเบงเบเปƒเบซเป‰เบ™เบฑเบเบงเบดเบ—เบฐเบเบฒเบชเบฒเบ”เบ‚เปเป‰เบกเบนเบ™เบชเบฒเบกเบฒเบ”เป€เบฎเบฑเบ”เบงเบฝเบเบเบฑเบšเป€เบเบทเบญเบšเบ—เบธเบเบซเป‰เบญเบ‡เบชเบฐเบซเบกเบธเบ”เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ (h2o, keras, เบกเบปเบ™, pytorch, sklearn ะธ tensorflow), เป€เบญเบปเบฒเบงเบฝเบเบ‡เบฒเบ™เบ‚เบญเบ‡เบ™เบฒเบ‡เป„เบ›เปƒเบ™เบฅเบฐเบ”เบฑเบšเบ•เปเปˆเป„เบ›.

MLflow เบชเบฐเบซเบ™เบญเบ‡เบชเบฒเบกเบญเบปเบ‡เบ›เบฐเบเบญเบš:

  • เบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบก - เบเบฒเบ™โ€‹เบšเบฑเบ™โ€‹เบ—เบถเบโ€‹เปเบฅเบฐโ€‹เบเบฒเบ™โ€‹เบฎเป‰เบญเบ‡โ€‹เบ‚เปโ€‹เบชเปเบฒโ€‹เบฅเบฑเบšโ€‹เบเบฒเบ™โ€‹เบ—เบปเบ”โ€‹เบฅเบญเบ‡โ€‹: เบฅเบฐโ€‹เบซเบฑเบ”โ€‹, เบ‚เปเป‰โ€‹เบกเบนเบ™โ€‹, เบเบฒเบ™โ€‹เบ•เบฑเป‰เบ‡โ€‹เบ„เปˆเบฒโ€‹เปเบฅเบฐโ€‹เบœเบปเบ™โ€‹เป„เบ”เป‰โ€‹เบฎเบฑเบšโ€‹. เบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเบ‚เบฐเบšเบงเบ™เบเบฒเบ™เบชเป‰เบฒเบ‡เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เปเบกเปˆเบ™เบกเบตเบ„เบงเบฒเบกเบชเปเบฒเบ„เบฑเบ™เบซเบผเบฒเบ.
  • เป‚เบ„เบ‡เบเบฒเบ™ - เบฎเบนเบšโ€‹เปเบšเบšโ€‹เบเบฒเบ™โ€‹เบซเบธเป‰เบกโ€‹เบซเปเปˆโ€‹เบ—เบตเปˆโ€‹เบˆเบฐโ€‹เบ”เปเบฒโ€‹เป€เบ™เบตเบ™โ€‹เบเบฒเบ™โ€‹เปƒเบ™โ€‹เป€เบงโ€‹เบ—เบตโ€‹เปƒเบ”โ€‹เบซเบ™เบถเปˆเบ‡ (e.g. SageMaker)
  • เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡ - เบฎเบนเบšเปเบšเบšเบ—เบปเปˆเบงเป„เบ›เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบชเบปเปˆเบ‡เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เป„เบ›เบซเบฒเป€เบ„เบทเปˆเบญเบ‡เบกเบทเบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰เบ•เปˆเบฒเบ‡เป†.

MLflow (เปƒเบ™ alpha เปƒเบ™เป€เบงเบฅเบฒเบ‚เบฝเบ™) เป€เบ›เบฑเบ™เปเบžเบฅเบฐเบ•เบฐเบŸเบญเบกเปเบซเบผเปˆเบ‡เป€เบ›เบตเบ”เบ—เบตเปˆเบŠเปˆเบงเบเปƒเบซเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบˆเบฑเบ”เบเบฒเบ™เบงเบปเบ‡เบˆเบญเบ™เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เบ‚เบญเบ‡เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ, เบฅเบงเบกเบ—เบฑเบ‡เบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡, เบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰เบ„เบทเบ™เปƒเบซเบกเปˆ, เปเบฅเบฐเบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰.

เบ•เบฑเป‰เบ‡เบ„เปˆเบฒ MLflow

เป€เบžเบทเปˆเบญเปƒเบŠเป‰ MLflow เบ—เปˆเบฒเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เป„เบ”เป‰เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบก Python เบ—เบฑเบ‡เบซเบกเบปเบ”เบ‚เบญเบ‡เบ—เปˆเบฒเบ™, เบชเปเบฒเบฅเบฑเบšเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเปƒเบŠเป‰ PyEnv (เป€เบžเบทเปˆเบญเบ•เบดเบ”เบ•เบฑเป‰เบ‡ Python เปƒเบ™ Mac, เบเบงเบ”เป€เบšเบดเปˆเบ‡ เบ—เบตเปˆเบ™เบตเป‰). เบงเบดเบ—เบตเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบชเป‰เบฒเบ‡เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบก virtual เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ•เบดเบ”เบ•เบฑเป‰เบ‡เบซเป‰เบญเบ‡เบชเบฐเบซเบกเบธเบ”เบ—เบฑเบ‡เบซเบกเบปเบ”เบ—เบตเปˆเบˆเปเบฒเป€เบ›เบฑเบ™เป€เบžเบทเปˆเบญเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบกเบฑเบ™.

```
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 เบ•เป‰เบญเบ‡เป„เบ”เป‰เบฎเบฑเบšเบเบฒเบ™เปเบเป‰เป„เบ‚เป€เบžเบฒเบฐเบงเปˆเบฒเบชเบฐเบšเบฑเบšเบชเบธเบ”เบ—เป‰เบฒเบเบ‚เบฑเบ”เบเบฑเบ™.

เป€เบ›เบตเบ”เบ•เบปเบงเบ•เบดเบ”เบ•เบฒเบก UI

เบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบก MLflow เบŠเปˆเบงเบเปƒเบซเป‰เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบšเบฑเบ™เบ—เบถเบเปเบฅเบฐเบชเบญเบšเบ–เบฒเบกเบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡เป‚เบ”เบเปƒเบŠเป‰ Python เปเบฅเบฐ REST API. เบ™เบญเบเบˆเบฒเบเบ™เบฑเป‰เบ™, เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบเปเบฒเบ™เบปเบ”เบšเปˆเบญเบ™เบ—เบตเปˆเบˆเบฐเป€เบเบฑเบšเบฎเบฑเบเบชเบฒ artifacts เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡ (localhost, Amazon S3, เบเบฒเบ™เป€เบเบฑเบšเบฎเบฑเบเบชเบฒ Azure Blob, เบšเปˆเบญเบ™เบˆเบฑเบ”เป€เบเบฑเบšเบ‚เปเป‰เบกเบนเบ™ Google Cloud เบซเบผเบท เป€เบŠเบตเบšเป€เบงเบต 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 เปเบ™เบฐเบ™เบณเปƒเบซเป‰เปƒเบŠเป‰เบšเปˆเบญเบ™เป€เบเบฑเบšเป„เบŸเบฅเปŒเบ„เบปเบ‡เบ—เบตเปˆ. เบเบฒเบ™เป€เบเบฑเบšเบฎเบฑเบเบชเบฒเป„เบŸเบฅเปŒเปเบกเปˆเบ™เบšเปˆเบญเบ™เบ—เบตเปˆเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบˆเบฐเป€เบเบฑเบšเบฎเบฑเบเบชเบฒเบเบฒเบ™เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เปเบฅเบฐเบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡ metadata. เป€เบกเบทเปˆเบญเป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ, เปƒเบซเป‰เปเบ™เปˆเปƒเบˆเบงเปˆเบฒเบกเบฑเบ™เบŠเบตเป‰เปƒเบซเป‰เป€เบซเบฑเบ™เป€เบ–เบดเบ‡เบšเปˆเบญเบ™เป€เบเบฑเบšเป„เบŸเบฅเปŒเบ„เบปเบ‡เบ—เบตเปˆ. เบ—เบตเปˆเบ™เบตเป‰เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเปƒเบŠเป‰เบžเบฝเบ‡เปเบ•เปˆ /tmp.

เบˆเบปเปˆเบ‡เบˆเบทเปˆเป„เบงเป‰เบงเปˆเบฒเบ–เป‰เบฒเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™เปƒเบŠเป‰เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ mlflow เป€เบžเบทเปˆเบญเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบ—เบปเบ”เบฅเบญเบ‡เป€เบเบปเปˆเบฒ, เบžเบงเบเป€เบ‚เบปเบฒเบ•เป‰เบญเบ‡เบกเบตเบขเบนเปˆเปƒเบ™เบšเปˆเบญเบ™เป€เบเบฑเบšเป„เบŸเบฅเปŒ. เบขเปˆเบฒเบ‡เปƒเบ”เบเปเบ•เบฒเบก, เป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเบšเปเปˆเบกเบตเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบ™เปเบฒเปƒเบŠเป‰เบžเบงเบเบกเบฑเบ™เบขเบนเปˆเปƒเบ™ UDF, เป€เบžเบฒเบฐเบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบžเบฝเบ‡เปเบ•เปˆเบ•เป‰เบญเบ‡เบเบฒเบ™เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡เป„เบ›เบชเบนเปˆเบ•เบปเบงเปเบšเบš.

เบซเบกเบฒเบเป€เบซเบ”: เบˆเบปเปˆเบ‡เบˆเบทเปˆเป„เบงเป‰เบงเปˆเบฒเบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบก UI เปเบฅเบฐเบฅเบนเบเบ„เป‰เบฒเบ•เบปเบงเปเบšเบšเบ•เป‰เบญเบ‡เบกเบตเบเบฒเบ™เป€เบ‚เบปเป‰เบฒเป€เบ–เบดเบ‡เบชเบฐเบ–เบฒเบ™เบ—เบตเปˆเบ›เบญเบก. เบ™เบฑเป‰เบ™เปเบกเปˆเบ™, เป‚เบ”เบเบšเปเปˆเบ„เปเบฒเบ™เบถเบ‡เป€เบ–เบดเบ‡เบ„เบงเบฒเบกเบˆเบดเบ‡เบ—เบตเปˆเบงเปˆเบฒ UI เบ•เบดเบ”เบ•เบฒเบกเบขเบนเปˆเปƒเบ™เบ•เบปเบงเบขเปˆเบฒเบ‡ EC2, เป€เบกเบทเปˆเบญเปเบฅเปˆเบ™ MLflow เบขเบนเปˆเปƒเบ™เบ—เป‰เบญเบ‡เบ–เบดเปˆเบ™, เป€เบ„เบทเปˆเบญเบ‡เบ•เป‰เบญเบ‡เบกเบตเบเบฒเบ™เป€เบ‚เบปเป‰เบฒเป€เบ–เบดเบ‡ S3 เป‚เบ”เบเบเบปเบ‡เป€เบžเบทเปˆเบญเบ‚เบฝเบ™เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เบ‚เบญเบ‡เบ›เบญเบก.

เบ‚เบฐเบซเบเบฒเบ Spark เบ”เป‰เบงเบ MLflow
เบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบก UI เป€เบเบฑเบšเบฎเบฑเบเบชเบฒเบงเบฑเบ”เบ–เบธเบšเบนเบฎเบฒเบ™เป„เบงเป‰เปƒเบ™เบ–เบฑเบ‡ S3

เปเบšเบšเปเบฅเปˆเบ™

เบ—เบฑเบ™เบ—เบตเบ—เบตเปˆเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเบเปเบฒเบฅเบฑเบ‡เปเบฅเปˆเบ™, เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบเบฒเบ™เบเบถเบเบญเบปเบšเบฎเบปเบกเปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เป„เบ”เป‰.

เป€เบ›เบฑเบ™เบ•เบปเบงเบขเปˆเบฒเบ‡, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ™เปเบฒเปƒเบŠเป‰เบเบฒเบ™เบ”เบฑเบ”เปเบ›เบ‡เป€เบซเบผเบปเป‰เบฒเปเบงเบ‡เบˆเบฒเบเบ•เบปเบงเบขเปˆเบฒเบ‡ MLflow เปƒเบ™ Sklearn.

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

เบ”เบฑเปˆเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เบชเบปเบ™เบ—เบฐเบ™เบฒเปเบฅเป‰เบง, MLflow เบŠเปˆเบงเบเปƒเบซเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบšเบฑเบ™เบ—เบถเบเบ•เบปเบงเบเปเบฒเบ™เบปเบ”เบเบฒเบ™เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡, เป€เบกเบ•เบฃเบดเบ, เปเบฅเบฐเบชเบดเปˆเบ‡เบ›เบฐเบ”เบดเบ”เป€เบžเบทเปˆเบญเปƒเบซเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ•เบดเบ”เบ•เบฒเบกเบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเปˆเบžเบงเบเบกเบฑเบ™เบžเบฑเบ”เบ—เบฐเบ™เบฒเปƒเบ™เป„เบฅเบเบฐเบเบฒเบ™เบŠเปเป‰เบฒเบ„เบทเบ™. เบ„เบธเบ™เบ™เบฐเบชเบปเบกเบšเบฑเบ”เบ™เบตเป‰เปเบกเปˆเบ™เป€เบ›เบฑเบ™เบ›เบฐเป‚เบซเบเบ”เบ—เบตเปˆเบชเบธเบ”เป€เบžเบฒเบฐเบงเปˆเบฒเบงเบดเบ—เบตเบเบฒเบ™เบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบœเบฐเบฅเบดเบ”เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เบ—เบตเปˆเบ”เบตเบ—เบตเปˆเบชเบธเบ”เป‚เบ”เบเบเบฒเบ™เบ•เบดเบ”เบ•เปเปˆเบเบฑเบšเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบ‚เบญเบ‡เบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเบซเบผเบทเป€เบ‚เบปเป‰เบฒเปƒเบˆเบงเปˆเบฒเบฅเบฐเบซเบฑเบ”เปƒเบ”เบ—เบตเปˆเบ›เบฐเบ•เบดเบšเบฑเบ” iteration เบ—เบตเปˆเบ•เป‰เบญเบ‡เบเบฒเบ™เป‚เบ”เบเปƒเบŠเป‰ git hash logs of 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 tracking API เบˆเบฐเบ•เบดเบ”เบ•เปเปˆเบเบฑเบšเป€เบŠเบตเบšเป€เบงเบตเบ•เบดเบ”เบ•เบฒเบกเบ—เบตเปˆเบขเบนเปˆเบ™เบตเป‰เป‚เบ”เบเบญเบฑเบ”เบ•เบฐเป‚เบ™เบกเบฑเบ”เป€เบžเบทเปˆเบญเบชเป‰เบฒเบ‡/เบฎเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบเบฒเบ™เป€เบ›เบตเบ”เบ•เบปเบง, เบšเบฑเบ™เบ—เบถเบเบเบฒเบ™เบงเบฑเบ”เปเบ—เบ, เปเบฅเบฐเบญเบทเปˆเบ™เป†.

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: Docs// เปเบฅเปˆเบ™เป€เบŠเบตเบšเป€เบงเบตเบ•เบดเบ”เบ•เบฒเบก

เป€เบžเบทเปˆเบญเบชเบฐเบซเบ™เบญเบ‡เบ•เบปเบงเปเบšเบšเบเบฑเบšเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ, เบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเบ—เบตเปˆเปเบฅเปˆเบ™ (เป€เบšเบดเปˆเบ‡เบเบฒเบ™เป‚เบ•เป‰เบ•เบญเบšเบเบฒเบ™เป€เบ›เบตเบ”เบ•เบปเบง) เปเบฅเบฐ 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, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ•เป‰เบญเบ‡เบเบฒเบ™เบเบฒเบ™เป€เบ‚เบปเป‰เบฒเป€เบ–เบดเบ‡ 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

เป€เบ–เบดเบ‡เบงเปˆเบฒเบˆเบฐเบกเบตเบ„เบงเบฒเบกเบˆเบดเบ‡เบ—เบตเปˆเบงเปˆเบฒเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบเบฒเบ™เบ•เบดเบ”เบ•เบฒเบกเปเบกเปˆเบ™เบกเบตเบญเปเบฒเบ™เบฒเบ”เบžเบฝเบ‡เบžเปเบ—เบตเปˆเบˆเบฐเปƒเบซเป‰เบšเปเบฅเบดเบเบฒเบ™เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡เปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเปเบ—เป‰เบˆเบดเบ‡, เบเบถเบเบญเบปเบšเบฎเบปเบกเปƒเบซเป‰เป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒเปเบฅเบฐเบ™เปเบฒเปƒเบŠเป‰เบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบ‚เบญเบ‡เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ (เปเบซเบผเปˆเบ‡: mlflow // docs // เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡ # เบ—เป‰เบญเบ‡เบ–เบดเปˆเบ™), เบเบฒเบ™เปƒเบŠเป‰ Spark (batch เบซเบผเบท streaming) เปเบกเปˆเบ™เบเบฒเบ™เปเบเป‰เป„เบ‚เบ—เบตเปˆเบกเบตเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบซเบผเบฒเบเบ‚เบถเป‰เบ™เบเป‰เบญเบ™เบเบฒเบ™เปเบˆเบเบขเบฒเบ.

เบˆเบดเบ™เบ•เบฐเบ™เบฒเบเบฒเบ™เบงเปˆเบฒเป€เบˆเบปเป‰เบฒเบซเบฒเบเปเปˆเบเบถเบเบญเบปเบšเบฎเบปเบกเปเบšเบšเบญเบญเบšเป„เบฅเบ™เปŒ เปเบฅเบฐเบˆเบฒเบเบ™เบฑเป‰เบ™เบ™เบณเปƒเบŠเป‰เบฎเบนเบšเปเบšเบšเบœเบปเบ™เบœเบฐเบฅเบดเบ”เปƒเบซเป‰เบเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบ‚เบญเบ‡เบ—เปˆเบฒเบ™เบ—เบฑเบ‡เปเบปเบ”. เบ™เบตเป‰เปเบกเปˆเบ™เบšเปˆเบญเบ™เบ—เบตเปˆ Spark เปเบฅเบฐ MLflow เบชเปˆเบญเบ‡เปเบชเบ‡.

เบ•เบดเบ”เบ•เบฑเป‰เบ‡ PySpark + Jupyter + Spark

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™ PySpark - Jupyter

เป€เบžเบทเปˆเบญเบชเบฐเปเบ”เบ‡เบงเบดเบ—เบตเบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ™เปเบฒเปƒเบŠเป‰เปเบšเบšเบˆเปเบฒเบฅเบญเบ‡ MLflow เบเบฑเบš Spark dataframes, เบžเบงเบเป€เบฎเบปเบฒเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบ•เบฑเป‰เบ‡เบ„เปˆเบฒ Jupyter notebooks เป€เบžเบทเปˆเบญเป€เบฎเบฑเบ”เบงเบฝเบเบฎเปˆเบงเบกเบเบฑเบ™เบเบฑเบš 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 เปƒเบ™เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบก virtual:

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

เป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบเบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบ•เบฑเป‰เบ‡เบ„เปˆเบฒ Jupiter เป€เบ›เบฑเบ™เป„เบ”เป€เบงเบต 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 เป€เบ‚เบปเป‰เบฒเป„เบ›เปƒเบ™ Jupiter เบ—เบตเปˆเบกเบตเบขเบนเปˆเปเบฅเป‰เบง.

เบ•เบดเบ”เบ•เบฑเป‰เบ‡ 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 เบขเบนเปˆเปƒเบ™เบชเบฐเบšเบฑเบš Alpha เปƒเบ™เป€เบงเบฅเบฒเบ‚เบฝเบ™, เบกเบฑเบ™เป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเบ‚เป‰เบญเบ™เบ‚เป‰เบฒเบ‡เบ”เบต. เบžเบฝเบ‡เปเบ•เปˆเบ„เบงเบฒเบกเบชเบฒเบกเบฒเบ”เปƒเบ™เบเบฒเบ™เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบเบญเบšเบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบเบซเบผเบฒเบเบญเบฑเบ™เปเบฅเบฐเบšเปเบฅเบดเป‚เบžเบเบžเบงเบเบกเบฑเบ™เบˆเบฒเบเบˆเบธเบ”เบชเบดเป‰เบ™เบชเบธเบ”เบ”เบฝเบงเบˆเบฐเบ™เปเบฒเบฅเบฐเบšเบปเบšเบ„เปเบฒเปเบ™เบฐเบ™เปเบฒเป„เบ›เบชเบนเปˆเบฅเบฐเบ”เบฑเบšเบ•เปเปˆเป„เบ›.

เบ™เบญเบเบˆเบฒเบเบ™เบฑเป‰เบ™, MLflow เบ™เปเบฒเบงเบดเบชเบฐเบงเบฐเบเบญเบ™เบ‚เปเป‰เบกเบนเบ™เปเบฅเบฐเบœเบนเป‰เบŠเปˆเบฝเบงเบŠเบฒเบ™เบ”เป‰เบฒเบ™เบงเบดเบ—เบฐเบเบฒเบชเบฒเบ”เบ‚เปเป‰เบกเบนเบ™เป€เบ‚เบปเป‰เบฒเบกเบฒเปƒเบเป‰เบŠเบดเบ”, เบงเบฒเบ‡เบŠเบฑเป‰เบ™เบ—เบปเปˆเบงเป„เบ›เบฅเบฐเบซเบงเปˆเบฒเบ‡เบžเบงเบเป€เบ‚เบปเบฒ.

เบซเบผเบฑเบ‡เบˆเบฒเบเบเบฒเบ™เบชเปเบฒเบซเบผเบงเบ” MLflow เบ™เบตเป‰, เบžเบงเบเป€เบฎเบปเบฒเบซเบกเบฑเป‰เบ™เปƒเบˆเบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบเป‰เบฒเบงเป„เบ›เบ‚เป‰เบฒเบ‡เบซเบ™เป‰เบฒเปเบฅเบฐเบ™เปเบฒเปƒเบŠเป‰เบกเบฑเบ™เบชเปเบฒเบฅเบฑเบšเบ—เปเปˆ Spark เปเบฅเบฐเบฅเบฐเบšเบปเบšเบ„เปเบฒเปเบ™เบฐเบ™เปเบฒเบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ.

เบกเบฑเบ™เบˆเบฐเป€เบ›เบฑเบ™เบเบฒเบ™เบ”เบตเบ—เบตเปˆเบˆเบฐ synchronize เบเบฒเบ™เป€เบเบฑเบšเบฎเบฑเบเบชเบฒเป„เบŸเบฅเปŒเบเบฑเบšเบ–เบฒเบ™เบ‚เปเป‰เบกเบนเบ™เปเบ—เบ™เบ—เบตเปˆเบˆเบฐเป€เบ›เบฑเบ™เบฅเบฐเบšเบปเบšเป„เบŸเบฅเปŒ. เบญเบฑเบ™เบ™เบตเป‰เบ„เบงเบ™เปƒเบซเป‰เบžเบงเบเป€เบฎเบปเบฒเบกเบตเบˆเบธเบ”เบชเบดเป‰เบ™เบชเบธเบ”เบซเบผเบฒเบเบญเบฑเบ™เบ—เบตเปˆเบชเบฒเบกเบฒเบ”เปƒเบŠเป‰เบšเปˆเบญเบ™เป€เบเบฑเบšเป„เบŸเบฅเปŒเบ”เบฝเบงเบเบฑเบ™เป„เบ”เป‰. เบ•เบปเบงเบขเปˆเบฒเบ‡, เปƒเบŠเป‰เบซเบผเบฒเบเบ•เบปเบงเบขเปˆเบฒเบ‡ Presto ะธ Athena เบเบฑเบš metastore เบเบฒเบงเบ”เบฝเบงเบเบฑเบ™.

เป€เบžเบทเปˆเบญเบชเบฐเบซเบผเบธเบš, เบ‚เป‰เบฒเบžเบฐเป€เบˆเบปเป‰เบฒเบขเบฒเบเป€เบงเบปเป‰เบฒเบงเปˆเบฒเบ‚เปเบ‚เบญเบšเปƒเบˆเบเบฑเบšเบŠเบธเบกเบŠเบปเบ™ MLFlow เบ—เบตเปˆเป€เบฎเบฑเบ”เปƒเบซเป‰เบงเบฝเบเบ‡เบฒเบ™เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเบเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบ—เบตเปˆเบซเบ™เป‰เบฒเบชเบปเบ™เปƒเบˆเบซเบผเบฒเบเบ‚เบถเป‰เบ™.

เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบซเบผเบตเป‰เบ™เบเบฑเบš MLflow, เบขเปˆเบฒเบฅเบฑเบ‡เป€เบฅเบ—เบตเปˆเบˆเบฐเบ‚เบฝเบ™เบซเบฒเบžเบงเบเป€เบฎเบปเบฒเปเบฅเบฐเบšเบญเบเบžเบงเบเป€เบฎเบปเบฒเบงเปˆเบฒเบ—เปˆเบฒเบ™เปƒเบŠเป‰เบกเบฑเบ™เปเบ™เบงเปƒเบ”, เปเบฅเบฐเบซเบผเบฒเบเบเบงเปˆเบฒเบ™เบฑเป‰เบ™เบ–เป‰เบฒเบ—เปˆเบฒเบ™เปƒเบŠเป‰เบกเบฑเบ™เปƒเบ™เบเบฒเบ™เบœเบฐเบฅเบดเบ”.

เบŠเบญเบเบซเบฒเบ‚เปเป‰เบกเบนเบ™เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเบเปˆเบฝเบงเบเบฑเบšเบซเบผเบฑเบเบชเบนเบ”:
เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ. เบซเบผเบฑเบเบชเบนเบ”เบžเบทเป‰เบ™เบ–เบฒเบ™
เบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰เป€เบ„เบทเปˆเบญเบ‡เบˆเบฑเบ. เบซเบผเบฑเบเบชเบนเบ”เบ‚เบฑเป‰เบ™เบชเบนเบ‡

เบญเปˆเบฒเบ™โ€‹เบ•เบทเปˆเบก:

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: www.habr.com

เป€เบžเบตเปˆเบกเบ„เบงเบฒเบกเบ„เบดเบ”เป€เบซเบฑเบ™