MLflow 〜これで機械学習のモデル管理から API 作成まで楽にできるかも〜



※下記に 1.0.0 版の記事書きました
[MLflow 1.0 リリース！機械学習ライフサイクルを始めよう！ - Qiita](https://qiita.com/fam_taro/items/155912068ff475a53e44)

# はじめに

機械学習をサービスとして運用するには以下のステップが必要となるのではないでしょうか。
（ちなみに仕事できかいがくしゅうしたことないので下記の 99 割は根拠無いです :innocent: ）

* 要件定義
  * 目的や目標値の確認
  * 「機械学習のスコアが高い」と「要件を満たす」は等価じゃないことに注意
  * どう提供するのか
    * 入力値がわかりきっているなら、夜間バッチで全通り予測するとか
    * とはいえ大抵分からないから随時入力を受け取ったら予測するようにしたいのです
       * API としてアプリケーションサーバーから呼ぶ ← 今回想定していること
* データの分析
  * EDA（探索的データ分析）ともいう
  * 困ったら最低下記だけでもやれば良い気がしてます
     * [【Pythonメモ】pandas-profilingが探索的データ解析にめちゃめちゃ便利だった件 - Qiita](https://qiita.com/h_kobayashi1125/items/02039e57a656abe8c48f)
  * 困ったら社内のホットでセクシーなイケメン DS(Data Scientist) にやってもらおう
* 特徴量設計
  * Feature Engineering ともいう
  * 最も大事なステップ説
  * 前処理と言えるほど単純な処理ではないことが多い
     * （たかが前処理とか言えるようになりたい）
  * Deep Learning だとここはできることが少ない分それ以降のステップが大変そう
* モデル選択
* 学習（チューニング）
* 学習結果の使用
* 要件を満たすか確認、随時上に戻る

MLflow は上記の2つ（学習と提供）をサポートしてくれるライブラリです。


# MLflow とは

* https://www.mlflow.org/
* https://www.mlflow.org/docs/latest/quickstart.html
* https://github.com/databricks/mlflow

機械学習の以下の部分について管理できる Python ライブラリです。

* ハイパーパラメータ
* モデル（学習済）
* 評価指標値
* 予測用の API 提供

# 何が嬉しいのか

* ハイパーパラメータ、パラメータ、モデルを一括して管理できる
  * これらを全部自分で日付や時間をつけて管理するのは大変そう・・・
  * 実際のプロジェクトだと、Precision さえ高ければ OK とはならない
     * 他の指標も含めてどのモデルやパラメータを採用するか判断するかもしれない
* 楽に API として提供できる
  * 何かしらの Web フレームワーク等で包まずにすむ
  * とはいえ flask 等なら大して苦にならないから関係ないか？？？


# 使ってみた



## Tutorial 通りに動かす

本家 tutorial 通りにやっていきます。
scikit-learn とかは適宜 `pip install` してください。

```bash
$ pip install mlflow
$ git clone https://github.com/databricks/mlflow
$ python mlflow/example/tutorial/train.py
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
  RMSE: 0.82224284976
  MAE: 0.627876141016
  R2: 0.126787219728
```

実行したディレクトリに `mlruns` ディレクトリができたことを確認して `mlflow ui` を実行します。

```bash
$ ls | grep mlruns
mlruns
$ mlflow ui
 * Serving Flask app "mlflow.server" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```

WARNING 出てますが、気にせず `http://127.0.0.1:5000/` をブラウザで開きます。
すると以下のようなナウい画面が出てくるはずです。

<img width="1280" alt="スクリーンショット 2018-06-09 18.25.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/33573/801a8eab-0f54-9ffb-c06e-4d9156f304bc.png">

試しに他のターミナルを開いて、もう一度学習を行ってみます。

```bash
$ python mlflow/example/tutorial/train.py
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
  RMSE: 0.82224284976
  MAE: 0.627876141016
  R2: 0.126787219728
```

そして先程のページを更新すると、結果が増えたことが確認できます。

<img width="1280" alt="スクリーンショット 2018-06-09 18.30.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/33573/bd27c056-ba55-f64e-d4f7-830c5e85e265.png">

そして日付のところをクリックすると、詳細結果が確認できます。

<img width="1280" alt="スクリーンショット 2018-06-09 18.33.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/33573/54fd4a5b-36dc-8a8b-8dd7-8193d4dabce6.png">

ここで詳細結果の下部にあるパスを見ながら、下記にようにコマンドを打ちます。

```bash
$ mlflow sklearn serve -p 1234 /Users/fujimotoyuusuke/Documents/mlruns/0/b7fb5085b7e04574b02f01b072bbc41e/artifacts/model
 * Serving Flask app "mlflow.sklearn" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:1234/ (Press CTRL+C to quit)
```

さらにターミナルをもう一つ開いて、下記のように問い合わせをしてみます。

```bash
$ curl -X POST -H "Content-Type:application/json" --data '[{"fixed acidity": 6.2, "volatile acidity": 0.66, "citric acid": 0.48, "residual sugar": 1.2, "chlorides": 0.029, "free sulfur dioxide": 29, "total sulfur dioxide": 75, "density": 0.98, "pH": 3.33, "sulphates": 0.39, "alcohol": 12.8}]' http://127.0.0.1:1234/invocations
{"predictions": [5.455573233630147]}
```

`{"predictions": [5.455573233630147]}` のような結果が帰ってくれば OK です。

そう、気づいたらあなたは `機械学習 API` を作って（自分に）提供してしまったのです。
この間たったの数分ですが、これでもうあなたは `機械学習 API 作ったことあります` と言えるのです。

## train.py における mlflow の書き方

`tutorial/train.py` 内から確認できますが、モデル学習時の mlflow の使い方は以下の通りです。

```python
import mlflow
import mlflow.sklearn

with mlflow.start_run():
    # ハイパーパラメータの記録
    mlflow.log_param("parameter", param)

    # 評価指標の記録
    mlflow.log_metric("Score", score)

    # モデルの記録
    mlflow.sklearn.log_model(model_trained, "model")
```

学習に用いたハイパーパラメータは `mlflow.log_param()` 、評価指標は `mlflow.log_metric()`、学習済みのモデル本体は `mlflow.sklearn.log_model()` で保存できます。


**※ 一度に複数の値は登録できなさそう？**



# 課題

* 現在は scikit-learn 内のモデルしか扱えない？
  * 要調査
  * scikit-learn のモデルを継承すれば使えるだろうけど・・・

# 他に試してみたいこと

* クラウド(GCP, AWS)上で動かしてみる
* scikit-learn に含まれていないライブラリを使う方法
    * やっぱナウでヤングでトレンディな私は light-gbm 使いたいので

# 最後に

まだまだ開発中らしいので、もっと良くしたいかたは下記へ GOGO！

https://github.com/databricks/mlflow