【機械学習】MLflowのQuickstartやってみた（２）

# 前回の記事
[前回の記事](https://qiita.com/panda531/items/9074d7ce8679a09cc1ed)の続きです。

# 環境
- macOS High Sierra
- pyenv 1.2.1
- anaconda3-5.0.1
- Python 3.6.8
- MLflow==0.8.2

# `MLflow Projects`を実行してみる
## `MLflow Projects`とは
`MLflow Projects`は、機械学習を実行するための情報を`MLproject`というファイルにまとめることで実験を再現しやすいようにしたものです。
`MLproject`ファイルには実行するコマンドやcondaの設定ファイルなどが記述してあります。
condaの設定ファイルには、依存するライブラリの情報などを記載することで、実行時にその環境が再現できるようになっています。

## サンプル
[ここ](https://github.com/mlflow/mlflow-example)にサンプルがおいてあります。
中身はこんな感じです。

```bash
mlflow-example
├── LICENSE.txt
├── MLproject
├── README.md
├── conda.yaml
├── train.py
└── wine-quality.csv
```

`MLproject`ファイルの中身はこんな感じ

```bash:MLproject
name: tutorial

conda_env: conda.yaml

entry_points:
  main:
    parameters:
      alpha: float
      l1_ratio: {type: float, default: 0.1}
    command: "python train.py {alpha} {l1_ratio}"
```

`conda_env`にcondaの設定ファイル、`entry_points`に実行するコマンドや引数の情報が記載されています。わかりやすいですね。

次は`conda.yaml`ファイルの中身です。

```bash:conda.yaml
name: tutorial
channels:
  - defaults
dependencies:
  - numpy=1.14.3
  - pandas=0.22.0
  - scikit-learn=0.19.1
  - pip:
    - mlflow
```

`dependencies`に依存ライブラリの情報が記載されています。
`channels`についてはよくわからなかったので調べてみると[こんな情報](https://qiita.com/yuj/items/8ce25959427ea97d373b)がありました。
`anaconda.org`に登録した独自のパッケージのインストールが必要なときなどに使用するようです。
一般的なライブラリならば`channels`は`defaults`で問題無さそうです。

## `MLproject`を実行してみる
[Quickstart](https://mlflow.org/docs/latest/quickstart.html#running-mlflow-projects)には以下の２種類の実行方法が記載されています。

> ①mlflow run tutorial -P alpha=0.5
> ②mlflow run git@github.com:mlflow/mlflow-example.git -P alpha=5

①はローカルにある`MLproject`を実行する方法で、②はgithub上の`MLproject`を実行する方法です。

まずはgithub上のリポジトリから直接起動してみます。②の方法ですね。

### githubリポジトリ上の`MLproject`を起動する
さっそく実行です。

```bash
$ mlflow run git@github.com:mlflow/mlflow-example.git -P alpha=5
```

はい。
エラーorz

```bash
2019/03/02 15:26:35 INFO mlflow.projects: === Fetching project from git@github.com:mlflow/mlflow-example.git into /var/folders/tl/lvx29tf163sbphlr4tqsfp_80000gn/T/tmpl53vj9ne ===
Traceback (most recent call last):
  File "/Users/takeshi/.local/bin/mlflow", line 11, in <module>
    load_entry_point('mlflow==0.8.2', 'console_scripts', 'mlflow')()
  File "/Users/takeshi/.local/lib/python3.6/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/takeshi/.local/lib/python3.6/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/mlflow/cli.py", line 129, in run
    run_id=run_id,
  File "/Users/takeshi/.local/lib/python3.6/site-packages/mlflow/projects/__init__.py", line 171, in run
    storage_dir=storage_dir, block=block, run_id=run_id)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/mlflow/projects/__init__.py", line 54, in _run
    git_username=git_username, git_password=git_password)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/mlflow/projects/__init__.py", line 297, in _fetch_project
    _fetch_git_repo(parsed_uri, version, dst_dir, git_username, git_password)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/mlflow/projects/__init__.py", line 347, in _fetch_git_repo
    origin.fetch()
  File "/Users/takeshi/.local/lib/python3.6/site-packages/git/remote.py", line 789, in fetch
    res = self._get_fetch_info_from_stderr(proc, progress)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/git/remote.py", line 675, in _get_fetch_info_from_stderr
    proc.wait(stderr=stderr_text)
  File "/Users/takeshi/.local/lib/python3.6/site-packages/git/cmd.py", line 415, in wait
    raise GitCommandError(self.args, status, errstr)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
  cmdline: git fetch -v origin
  stderr: 'fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.'
```

上記のコマンドではダメっぽいので以下のコマンドに変更したらいけました。

```bash
$ mlflow run https://github.com/mlflow/mlflow-example.git -P alpha=5
```

```bash
2019/03/02 16:07:35 INFO mlflow.projects: === Fetching project from https://github.com/mlflow/mlflow-example.git into /var/folders/tl/lvx29tf163sbphlr4tqsfp_80000gn/T/tmp255y1l6j ===
2019/03/02 16:07:40 INFO mlflow.projects: === Created directory /var/folders/tl/lvx29tf163sbphlr4tqsfp_80000gn/T/tmp4aockzav for downloading remote URIs passed to arguments of type 'path' ===
2019/03/02 16:07:40 INFO mlflow.projects: === Running command 'source activate mlflow-3eee9bd7a0713cf80a17bc0a4d659bc9c549efac && python train.py 5 0.1' in run with ID '156398506a8d4a94a27a7bbef191ac39' === 
Elasticnet model (alpha=5.000000, l1_ratio=0.100000):
  RMSE: 0.8594260117338262
  MAE: 0.6480675144220316
  R2: 0.046025292604596424
2019/03/02 16:07:44 INFO mlflow.projects: === Run (ID '156398506a8d4a94a27a7bbef191ac39') succeeded ===
```

githubからフェッチしてきて実行してその結果が表示されていますね！
指定した引数もきちんと渡っているようです。
_※一回目に実行したときに`conda.yaml`の情報に従って仮想環境が作成されます。私も作成されましたが何度か試行錯誤したのでコマンドログが消えてしまいました。。。
ちなみに私の場合は`mlflow-3eee9bd7a0713cf80a17bc0a4d659bc9c549efac`という名前の仮想環境が作成されていました_

`mlflow ui`コマンドでサーバーを起動すればもちろん`MLproject`の実行結果も確認できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/245628/97fff0f4-41a5-5882-f63b-0f206e7f9b06.png)

`Source`の部分が`mlflow-example`のリンクになっています。
クリックするとgithubのリポジトリに飛びました。
`Git Commit`のハッシュ値を使っていつのコードなのかを判断しているぽいですね。

また、`Artifacts`に保存されている`model`には`MLmodel`、`conda.yaml`、`model.pkl`が保存されており、次回の`Saving and Serving Models`で使うためのデータになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245628/245fff00-59c6-0254-335d-792756d75fce.png)


### ローカルの`MLproject`を起動する
それでは次はローカルの`MLproject`を起動してみます。
今回は、上記で使ったサンプルリポジトリをクローンして使います。

```bash
git clone https://github.com/mlflow/mlflow-example.git
```

これで以下のコマンドでいける…はず？
> $ mlflow run tutorial -P alpha=0.5

`tutorial`ってなんやねん。。。と思いながらもとりあえず実行。

```bash
2019/03/02 23:10:39 ERROR mlflow.cli: === Could not find subdirectory  of tutorial ===
```

ですよねぇー。
ということでコマンドを以下のように変更します。

```bash
$ mlflow run mlflow-example -P alpha=0.5
```

これで無事に実行できました。
`mlflow run xxxx`の`xxxx`部分は`MLproject`ファイルが含まれるディレクトリ名を指定する必要があるみたいです。

```bash
2019/03/02 23:12:14 INFO mlflow.projects: === Created directory /var/folders/tl/lvx29tf163sbphlr4tqsfp_80000gn/T/tmpvi_ejt9v for downloading remote URIs passed to arguments of type 'path' ===
2019/03/02 23:12:14 INFO mlflow.projects: === Running command 'source activate mlflow-3eee9bd7a0713cf80a17bc0a4d659bc9c549efac && python train.py 0.5 0.1' in run with ID 'c4515ad6506a44eeb9475461bbf360bb' === 
Elasticnet model (alpha=0.500000, l1_ratio=0.100000):
  RMSE: 0.7947931019036528
  MAE: 0.6189130834228137
  R2: 0.1841166871822183
2019/03/02 23:12:17 INFO mlflow.projects: === Run (ID 'c4515ad6506a44eeb9475461bbf360bb') succeeded ===
```

こちらはフェッチしてないですね。
パラメータ`alpha`の値が違うので結果も異なっています。
以下のようにチェックボックスを複数チェックすることで、異なる実験結果をブラウザ上で比較することも出来ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245628/9faf8e93-cf6b-5812-3ecf-e97e584d19e1.png)

`Compare`ボタンを押すと以下のような画面が表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245628/0cfc9a8f-44ba-e453-7872-2c58f4c1acb7.png)
実行日時や処理時間、パラメータやMetricsなどの比較ができます。

さらに、下図のように、パラメータとMetricsのそれぞれの値についてX軸とY軸に対応する値を選択することでグラフ上で関係を確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245628/4177278c-24ef-9ceb-191a-c9ff20ef7da6.png)

便利ですね。

# まとめ
`MLproject`について、githubから直接起動パターンとローカルで起動パターンの２つを試してみました。
またもや長くなってしまったので、`Saving and Serving Models`については次回にしたいと思います。