実験管理やモデルレジストリなど,機械学習ライフサイクルをうまく管理するプラットフォームとして有名な「MLflow」に入門する.GitHub リポジトリの Star は 12000 もあってスゴイ!MLflow は MLOps の文脈でもよく聞くので,1度試しておこうと思った.
現在,MLflow には大きく「4種類」のコンポーネントがある.
- MLflow Tracking : 実験管理 / ハイパーパラメータや評価メトリクスなどを記録したり比較できたりする
- MLflow Projects : パッケージング / 機械学習を実行するための設定情報などを再現可能にする
- MLflow Models : モデル化 / さまざまなデプロイツールをサポートする汎用的なモデル形式を提供する
- MLflow Model Registry : モデルレジストリ / レジストリとしてモデルを管理する
github.com
MLflow Tutorial
今回は MLflow のドキュメントに載っている「Tutorial」と「Quickstart」を参考にしながら,MLflow の中で基本となるコンポーネント「MLflow Tracking」を試す.ドキュメントを読みながら進めて,特にハマるところもなく試せた.
mlflow.org
mlflow.org
準備
準備として MLflow と scikit-learn をインストールする.さらに MLflow の GitHub リポジトリにある examples
を使うため git clone
もしておく.今回は macOS を使って環境を構築する.それぞれのバージョンは以下の通り.
- MLflow :
1.26.1
- scikit-learn :
1.1.1
$ pip install mlflow
$ pip install scikit-learn
$ git clone https://github.com/mlflow/mlflow
次に mlflow ui
コマンドを実行して,実験結果を表示する画面を起動する.デフォルトでは http://127.0.0.1:5000/
で表示できる.準備 OK!
$ mlflow/examples
$ mlflow ui
MLflow 用語
今から出てくる MLflow 用語の関係性を以下にまとめておく.Experiment(実験)に複数の Run(実行)が紐付く.
MLflow Tracking サンプルコード
MLflow Tracking のイメージを掴むために,まず「Quickstart」に載っている quickstart/mlflow_tracking.py
を実行する.コードのポイントは大きく3点ある.
log_param()
関数を使って「パラメータ : param1
」を登録する
log_metric()
関数を使って「メトリクス : foo
」を登録する
log_artifacts()
関数を使って「アーティファクト : test.txt
」を登録する
import os
from random import random, randint
from mlflow import log_metric, log_param, log_artifacts
if __name__ == "__main__":
print("Running mlflow_tracking.py")
log_param("param1", randint(0, 100))
log_metric("foo", random())
log_metric("foo", random() + 1)
log_metric("foo", random() + 2)
if not os.path.exists("outputs"):
os.makedirs("outputs")
with open("outputs/test.txt", "w") as f:
f.write("hello world!")
log_artifacts("outputs")
MLflow の関数は以下のドキュメントに詳細に載っている.
今回は「計3回」実行する.
$ python quickstart/mlflow_tracking.py
$ python quickstart/mlflow_tracking.py
$ python quickstart/mlflow_tracking.py
実行後に画面を更新すると実行結果を確認できる.また param1
や foo
など登録したパラメータとメトリクスも一覧できる.
個別に実行を選択するとアーティファクトも確認できる.便利!
MLflow Tracking と scikit-learn を組み合わせる
次は「Tutorial」に載っている sklearn_elasticnet_wine/train.py
を使って実践的なトレーニングを実行する.今回のお題として,ワインの品質を予測する.アルゴリズムとしては scikit-learn の ElasticNet を使って回帰分析をする.ハイパーパラメータとしては alpha
(L1, L2 正規化項の合計)と l1_ratio
(L1 正則化項の割合)を変えながらパフォーマンスを確認する.モデルの評価メトリクスとしては RMSE(二乗平均平方根誤差) を使う.
そして,今回は「Tutorial」の手順を一部変更する.そのまま実行すると Default
Experiments に紐付くため,新しく sklearn-elasticnet-wine
Experiments を作って紐付ける.今回は id=1
の Experiments になった.
import mlflow
experiment_id = mlflow.create_experiment('sklearn-elasticnet-wine')
print(experiment_id)
コードのポイントは大きく4点ある.その他のコードはデータセットを分割したり,scikit-learn を使ってトレーニングをしたり,一般的な機械学習コードそのものなので,紹介は割愛する.
- 実行を
sklearn-elasticnet-wine
Experiments に紐付けるために mlflow.start_run()
を mlflow.start_run(experiment_id=1)
に変更する
log_param()
関数を使って「ハイパーパラメータ : alpha
と l1_ratio
」を登録する
log_metric()
関数を使って「メトリクス : rmse
と r2
と mae
」を登録する
log_model()
関数を使って「モデル」を登録する
import os
import warnings
import sys
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet
from urllib.parse import urlparse
import mlflow
import mlflow.sklearn
import logging
logging.basicConfig(level=logging.WARN)
logger = logging.getLogger(__name__)
def eval_metrics(actual, pred):
rmse = np.sqrt(mean_squared_error(actual, pred))
mae = mean_absolute_error(actual, pred)
r2 = r2_score(actual, pred)
return rmse, mae, r2
if __name__ == "__main__":
warnings.filterwarnings("ignore")
np.random.seed(40)
csv_url = (
"http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
)
try:
data = pd.read_csv(csv_url, sep=";")
except Exception as e:
logger.exception(
"Unable to download training & test CSV, check your internet connection. Error: %s", e
)
train, test = train_test_split(data)
train_x = train.drop(["quality"], axis=1)
test_x = test.drop(["quality"], axis=1)
train_y = train[["quality"]]
test_y = test[["quality"]]
alpha = float(sys.argv[1]) if len(sys.argv) > 1 else 0.5
l1_ratio = float(sys.argv[2]) if len(sys.argv) > 2 else 0.5
with mlflow.start_run(experiment_id=1):
lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
lr.fit(train_x, train_y)
predicted_qualities = lr.predict(test_x)
(rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)
print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
print(" RMSE: %s" % rmse)
print(" MAE: %s" % mae)
print(" R2: %s" % r2)
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)
tracking_url_type_store = urlparse(mlflow.get_tracking_uri()).scheme
if tracking_url_type_store != "file":
mlflow.sklearn.log_model(lr, "model", registered_model_name="ElasticnetWineModel")
else:
mlflow.sklearn.log_model(lr, "model")
今回はハイパーパラメータを変更しながら「計5回」実行する.
- 実行 1.
alpha=0.5 / l1_ratio=0.5
- 実行 2.
alpha=0.4 / l1_ratio=0.4
- 実行 3.
alpha=0.3 / l1_ratio=0.3
- 実行 4.
alpha=0.2 / l1_ratio=0.2
- 実行 5.
alpha=0.1 / l1_ratio=0.1
$ python sklearn_elasticnet_wine/train.py
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
RMSE: 0.7931640229276851
MAE: 0.6271946374319586
R2: 0.10862644997792614
$ python sklearn_elasticnet_wine/train.py 0.4 0.4
Elasticnet model (alpha=0.400000, l1_ratio=0.400000):
RMSE: 0.7644619587468349
MAE: 0.5966303605775048
R2: 0.17197111491474282
$ python sklearn_elasticnet_wine/train.py 0.3 0.3
Elasticnet model (alpha=0.300000, l1_ratio=0.300000):
RMSE: 0.7443224557281489
MAE: 0.5754825491733004
R2: 0.2150247343683439
$ python sklearn_elasticnet_wine/train.py 0.2 0.2
Elasticnet model (alpha=0.200000, l1_ratio=0.200000):
RMSE: 0.7336400911821402
MAE: 0.5643841279275428
R2: 0.23739466063584158
$ python sklearn_elasticnet_wine/train.py 0.1 0.1
Elasticnet model (alpha=0.100000, l1_ratio=0.100000):
RMSE: 0.7128829045893679
MAE: 0.5462202174984664
R2: 0.2799376066653344
実行後に画面を更新すると実行結果を確認できる.実行結果は sklearn-elasticnet-wine
Experiments に紐付いている.
MLflow では metrics.rmse < 0.74
のようなクエリを書くことで実行結果をフィルタできる.
クエリ構文は以下のドキュメントに詳細に載っている.
www.mlflow.org
さらに実行結果(今回だと5件)を選択して評価メトリクス RMSE を比較できる.
さらにハイパーパラメータと評価メトリクスの関係性も比較できる.以下の例では,ハイパーパラメータ alpha
と評価メトリクス RMSE の関係性を比較している.
そして,アーティファクトを確認するとモデル model.pkl
も含まれている.
モデルをデプロイして推論する
MLflow CLI で mlflow models serve
コマンドを実行すると,指定したモデルをデプロイした推論エンドポイントを起動できる.
www.mlflow.org
今回は最も RMSE の値が低くパフォーマンスが高かった実行 e8901371a1494c34bd0a26e8180c5441
のモデルをデプロイする.アーティファクトからパスを取得して,以下のように実行する.
$ mlflow models serve -m file:///Users/kakakakakku/mlflow/examples/mlruns/1/e8901371a1494c34bd0a26e8180c5441/artifacts/model -p 1234
推論エンドポイント http://127.0.0.1:1234
に以下のように curl
コマンドを実行すると推論結果を取得できる.mlflow models serve
コマンドのログを眺めていたら HTTP Server は Gunicorn を使っていた.
$ curl -X POST -H 'Content-Type:application/json; format=pandas-split' http://127.0.0.1:1234/invocations\
--data '{"columns":["alcohol", "chlorides", "citric acid", "density", "fixed acidity", "free sulfur dioxide", "pH", "residual sugar", "sulphates", "total sulfur dioxide", "volatile acidity"],"data":[[12.8, 0.029, 0.48, 0.98, 6.2, 29, 3.33, 1.2, 0.39, 75, 0.66]]}'
[10.652032783691832]
$ curl -X POST -H 'Content-Type:application/json; format=pandas-split' http://127.0.0.1:1234/invocations\
--data '{"columns":["alcohol", "chlorides", "citric acid", "density", "fixed acidity", "free sulfur dioxide", "pH", "residual sugar", "sulphates", "total sulfur dioxide", "volatile acidity"],"data":[[15.8, 0.029, 0.48, 0.98, 6.2, 29, 3.33, 1.2, 0.39, 75, 0.66]]}'
[10.83593352318585]
まとめ
今回は MLflow のドキュメントに載っている「Tutorial」と「Quickstart」を参考にしながら,MLflow の中で基本となるコンポーネント「MLflow Tracking」を試した.実験管理がしやすく便利だった.他にもグラフ画像などを登録する log_figure()
関数や簡単にパラメータとメトリクスを登録する Automatic Logging など,まだまだ気になる機能がある.引き続き試していくぞ!
www.mlflow.org