エブリーエンジニアブログ エブリーエンジニアブログ

MLflowとOptunaを使ってMLOps環境を構築してみた

はじめまして。2020年4月からエブリーに新卒で入社した伊藤です。 データエンジニア・データサイエンティストとしてデータ関連部門に所属し、日々データ業務に関わっています。

データ業務の1つである機械学習モデルの開発は、実験環境でモデルの精度を確認した上で本番環境に適用するプロセスを経ます。

今回は機械学習の実装で利用したMLflowとOptunaを組み合わせが、モデルの開発・運用・レビューで高いアジリティを提供できると分かり、導入事例として紹介できたらと思います。

取り組んだ問題

最近のデータ業務で、DELISH KITCHENユーザの過去の行動を分析し、ある特定のアクションが将来どの程度の確率で行われるかを機械学習で予測する、という問題に取り組みました。

ユーザがDELISH KITCHENをどのように使っているのか(レシピのお気に入り登録など)という情報は、集計された状態でデータウェアハウスに蓄積されています1

まずはそれらを抽出し、予測を行うための特徴量データセットとして用意した後、パラメータの調整や特徴量の取り方などを試行錯誤しつつ、実験環境で機械学習モデルを構築しました。

大学の研究やデータコンペティションでは、多くの場合高い精度のモデルができたら一旦区切りとなりますが、企業で開発を行う場合にはこれを実際のビジネス施策でも使う必要があります。

そのためには、実験環境で行った「特徴量の抽出」→「モデルの学習」→「モデルの予測」→「最終結果の出力」という4つの段階が本番環境で1つのパイプラインとして自動化されており、かつ持続的に運用できる状態でなければなりません。

MLOps

ここでMLOpsという概念を紹介したいと思います。

MLOpsとは機械学習のライフサイクルの管理やその環境を指す考え方で、機械学習(Machine Learning)と運用(Operations)を組み合わせた言葉です。

MLOpsの考え方に基づくと、上に挙げた4段階それぞれの品質を持続的に維持・改善しており、かつ全体としても1つのパイプラインとして運用できる環境の構築が重要になります2

特に、ユーザ行動を使う今回のようなケースでは、予測したい行動データが日々更新され、実験では良い結果が出ていたモデルも時間が経つと「古い」モデルとなってしまうため、新しいデータを使ってモデルを定期的に更新していかなければなりません。

さらに、将来の研究でさらに良さそうなモデルが見つかった場合は過去のモデルと比較してより良いものをパイプラインに組み込めるような設計になっていると、より効果的な運用が可能になります。

このようなMLOps環境を実現するため、今回はMLflowとOptunaという2つのツールを組み合わせて活用しました。

MLflow

MLflow3とはDatabricks社が開発した機械学習のライフサイクルを管理するためのプラットフォームです。

MLflowを使うと、学習結果の保存や過去の学習結果との比較が簡単に行えるようになります。

簡単な例としてロジスティック回帰によるアイリスデータセットの分類問題を考えると、実行環境によって設定は多少異なりますが、「ハイパーパラメータ」「予測精度」「学習モデル」の3つが対応した学習結果をおおよそ次のように登録できます。

from sklearn.linear_model import LogisticRegression
import mlflow
import mlflow.sklearn

with mlflow.start_run():
    lr_c = 0.1
    model = LogisticRegression(C=lr_c).fit(x_train, y_train)    
    score = model.score(x_test, y_test)
    
    mlflow.log_param('C', lr_c)
    mlflow.log_metric('Mean Accuracy', score)
    mlflow.sklearn.log_model(
        sk_model=model, 
        artifact_path='mlflow_demo', 
        registered_model_name='lr_iris'
    )

登録された学習モデルはMLflowを通してバージョン管理され、バージョンを指定したロードもできるため、新しいモデルと古いモデルとの性能比較を行ったり、時期や状況に応じたモデルの入れ替えも可能です。

No Image

それぞれのバージョンに対して、パラメータと予測精度が保存されています。

No Image

Optuna

Optuna4は、Preferred Networks社が開発したハイパーパラメータチューニングのためのフレームワークです。

本来ハイパーパラメータチューニングは、パラメータの値を変更した学習結果を確認しながら最適値を見つける、非常に手間の掛かる作業です。

そのため、パラメータそれぞれに候補となる値を用意し、それらの組み合わせを全て試して最適なものを見つける、グリッドサーチと呼ばれる方法が主に使われていました。 しかし、グリッドサーチでチューニングの工程は自動化できるものの、パラメータの種類・候補が多いほど組み合わせが爆発的に増加するため探索に時間がかかってしまう、そもそも候補に含まれない値は探索できない、といった問題がありました。

Optunaでは、探索する値の候補を探索範囲として渡すことが可能です。 また、過去の探索結果に基づいて次に探索すべき範囲を判断するようなアルゴリズムが実装されているため、指定された範囲に含まれる値全てを試さずに、より確からしい最適解を導き出すことができます。 これにより、Optunaを使うとグリッドサーチよりも柔軟で効率的なハイパーパラメータチューニングが実現できます。

もう一度ロジスティック回帰によるアイリスデータセットの分類問題を考えます。 先ほどの例ではハイパーパラメータ C を決め打ちで設定していましたが、ここではOptunaを使い交差検証によるチューニングをしてみます。

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
import optuna

def objective(trial):
    lr_c = trial.suggest_loguniform('C', 1e-4, 1e2)
    model = LogisticRegression(C=lr_c)
    score = cross_val_score(model, x_train, y_train, cv=3)
    accuracy = score.mean()
    
    return accuracy
  
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=10)

best_params = study.best_params

最適なパラメータは best_params として辞書形式で得られるので、その後は最適なパラメータでモデルを学習 → MLflowで結果を保存、という流れになります。

今回モデルの学習に用いるユーザ行動は時間的に変化するデータであるため、モデルの品質を持続させるには定期的に新しいデータで再学習する必要があります。 Optunaを使うとデータに応じて適切なハイパーパラメータを自動的に探索・決定できるようになり、 手動による介入を行わずに一定レベルの品質でモデルの再学習を行えます5

MLOps環境の構築

それでは、MLOps環境をどのように構築したのかを紹介したいと思います。 エブリーではデータ分析基盤としてDatabricksを使っているため、Databricks notebookをベースに環境構築を行いました。

tech.every.tv

まず、一連のパイプラインを「特徴量の抽出」「モデルの学習」「モデルの推論」「最終結果の出力」という4つのステップに分け、それぞれを順番に実行できるようなジョブを作成しました。

肝となるのが「モデルの学習」と「モデルの推論」のステップで、ここでMLflowとOptunaを活用します。

「モデルの学習」では、MLflowに登録されている最新の前処理モデルと予測モデルの2種類をロードし、検証用のデータを使ってこれらのモデル性能の検証を行います。 検証結果が良ければそのまま次のステップへ進みますが、もし検証結果が悪いようなら、再学習するためのタスクを呼び出してこれらのモデルをアップデートします。

モデルの再学習では、実験環境には存在しない本番環境の最新のデータを利用したハイパーパラメータチューニング、モデルの学習を行います。

チューニングするパラメータはOptunaに登録されており、探索はOptunaに実装されているアルゴリズムに従って行われるため、データに合わせた柔軟なチューニングが自動で行われます。 これにより、データが更新される度に必要となるハイパーパラメータの検証工程が減り、パイプラインの維持・改良をスムーズにできるようになります。

再学習後に得られたモデルはMLflowでバージョン管理し、必要に応じて過去のモデルとの比較もできるようにしました。

「モデルの推論」ではMLflowを通して最新のモデルをロードし、最新の行動データに対する予測を行います。 1つ前のステップでモデルの性能に関する検証を行っているため、ここで得られる予測は(完全ではないかもしれませんが)ある程度品質が保証されたものになります。

まとめ

以上、実験環境で機械学習モデルを作成するところからMLOps環境に昇華させるまでを、簡単に紹介させていただきました。

ここで紹介したパイプラインは現在バッチとして登録されており、定期的にモデルの更新とユーザ行動の予測が行われています。

現時点で運用を始めて数ヶ月が経ちましたが、現在も当初の予測精度付近で安定しており、構築した環境がモデルの品質維持に役立っているのでは、と考えています。

今回の業務を通して、MLflowとOptunaの有効性を改めて確認できたとともに、エブリーに入社するまではあまり経験してこなかった実運用環境の構築について新しく学べました。

今後は、MLOps環境を運用しつつ、新たなビジネス施策にも貢献できれば嬉しく思います。

ここまで読んでいただきありがとうございました。