Chainerでcomet.mlを使って学習を可視化してみた



# 1. Comet.ml とは？
Comet.mlは機械学習の実験支援ツールの一つです。
ざっくり言うと、以下のようなことができます。

1. 実験結果（lossやaccuracyなど）の記録
2. ハイパーパラメータやネットワーク構造の保存
3. 実行コードの保存
4. ベイズ最適化によるハイパーパラメータ探索（有料プラン）

Tensorflow用の実験支援ツールとしては[Tensorboard](https://www.tensorflow.org/programmers_guide/summaries_and_tensorboard)が有名ですが、実験ログに関してはかなり近い感覚だと思います。
日本語の紹介記事はこのあたりが分かりやすいです。

- [CometMLは「機械学習のためのGitHub」になることを狙う](https://jp.techcrunch.com/2018/04/06/2018-04-05-cometml-wants-to-do-for-machine-learning-what-github-did-for-code/)
- [機械学習のためのGithub、CometMLを使ってみた](https://medium.com/liaro-engineering-blog/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEgithub-cometml%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F-eed920be46c9)


Comet.mlが公式にサポートを発表しているディープラーニングフレームワークは、「Keras, Tensorflow, Pytorch, Theano」ですが、僕はどうしてもChainerが使いたかったので、今回はChainerのMNISTのExampleでComet.mlを動かしてみました。

また、ディープラーニング以外にも、scikit-learnで実行させるサンプルも公式ドキュメントで公開されていました。(https://www.comet.ml/docs/python-sdk/scikit/)

[![image.png](https://qiita-image-store.s3.amazonaws.com/0/170782/05ebf86e-3558-5f0d-14e0-fea92970248d.png)](https://www.comet.ml/)


# 2. Comet.mlアカウントの準備
## 2.1 アカウントの登録
Comet.mlで実験結果を管理するためにはアカウントを登録する必要があります。
メールアドレスでも登録できますが、Githubのアカウントで登録することもできます。

僕はまだ試してないのですが、Githubとのインテグレーション機能もあるらしいので、Githubアカウントをお持ちの方はそちらで登録すると良いかもしれません。

## 2.2 APIキーの取得
アカウントが作成できたら、まずはプロジェクトを作ってみましょう。

ダッシュボードの右上の「+ New Project」というボタンから作成できます。
このときプロジェクトの公開非公開を設定できますが、ひとまず非公開(Private)にしておくと良いでしょう。

プロジェクトページに入ると、ページ上部のバーに「API Key」というボタンがあるので、そこからAPIキーは取得できます。
このキーは自分の全プロジェクトに共通のものなので、一度取得すればその後は変更しなくて大丈夫だと思います。（おそらく）

さて、ここまででComet.mlのアカウント作成とAPIキーの取得が完了しました。

# 3. Chainerで動かす
以下はPythonでchainerを動かすことを想定しています。

今回は、公式に公開されているMNISTのExampleを少し改変し、Comet.mlでログを記録するようにしました。
コード全体は[Github](https://github.com/29Takuya/chainer-cometml)で公開していますので、こちらを参照してください。

まずはじめに、Comet.mlのPythonパッケージをインストールする必要があります。
こちらはpipでインストールできます。

```bash
$ pip install comet_ml
```

さて、ここから具体的に実装の話に入っていきますが、やるべきことは主に以下の3つだけです。

1. `Experimet`インスタンスの生成
2. ハイパーパラメータの記録
3. 訓練中のロスや正答率の記録

まずは、`comet_ml`モジュールの`Experiment`インスタンスをインポートしてください。

```py
from comet_ml import Experiment
```

## 3.1 Experimentインスタンスの生成
comet.ml上の自分のアカウントと紐付けるために、まずは`Experiment`インスタンスを生成する必要があります。

```py
experiment = Experiment(api_key='自分のAPIキー', project_name='プロジェクト名')
```

プロジェクト名は先程作成したものを使います。
指定したプロジェクト名が自分のアカウント上に存在しない場合でも、自動でPrivateなプロジェクトが生成されるため、特に問題はありません。

## 3.2 ハイパーパラメータの記録
ディープラーニングの実験を行う上で最も必要な作業の一つがハイパーパラメータの記録ですよね。
こちらは以下のメソッドで行います。

```py
hyper_params = {
    'batch_size': 64,
    'epoch': 20,
    'n_hidden_unit': 32}

experiment.log_multiple_params(hyper_params)
```

`hyper_params`の中身は何でも構いません。自分に必要そうなものを辞書型で格納してください。

また、ひとつずつハイパーパラメータを記録する際には、

```py
experiment.log_parameter(name, value)
```

を使っても構いません。

## 3.3 訓練中のロスや正答率の記録
こちらもハイパーパラメータを記録する場合とほぼ同じで。

```py
metrics = {
    'train_loss': train_loss,
    'train_acc': train_acc,
    'test_loss': test_loss,
    'test_acc': test_acc}

experiment.log_multiple_metrics(metrics, step=i)
```

または、

```py
experiment.log_parameter('train_loss', train_loss, step=i)
```

のような形で書きます。

一つだけ違う点は、`step`という引数を加えている点で、ここにはイテレーション数やエポック数を入れます。
従って、各イテレーションや各エポックごとにこのコードを実行する必要があります。

可視化の際には、stepの値をX軸として、グラフが表示されます
（実は`log_multiple_params`などにも`step`引数があるみたいなのですが、今の所使い道が分かっていません。）

今回は`chainer.training.extension`を用いてこれを実現しました。
trainerを引数として、comet.mlへログを記録する関数`_log_exp`を作成し、それを`trainer.extend`に渡しています。



```py:extension実装の例
def log_cometml(exp, _log_report='LogReport'):
    @training.make_extension(trigger=(1, 'epoch'))
    def _log_exp(trainer):
        log_report = trainer.get_extension(_log_report)
        lastest_log = log_report.log[-1]
        n_epoch = lastest_log.pop('epoch')
        n_iter = lastest_log.pop('iteration')
        exp.log_multiple_metrics(lastest_log, step=n_epoch)
    return _log_exp

'省略'

trainer.extend(extensions.LogReport())
trainer.extend(log_cometml(experiment))
```

自作Extensionについては、こちら方のプログが非常に参考になりました。
[chainer: Extensionを自作してディープラーニングの訓練に独自処理を挟み込む](http://mizti.hatenablog.com/entry/2017/09/23/202750)

# 4. 結果の可視化
実際に見たほうが早いと思うので、僕が作成したプロジェクトページをご覧ください。
https://www.comet.ml/29takuya/chainer-mnist

簡単に画面の説明をしていきます。

以下はプロジェクトのダッシュボードページです
一つの行が一つの実験に対応していて、パラメータやロスを一覧で表示されることもできます。
（同じプロジェクト名で複数回実験を行うとこのように表示されます）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170782/fc523d9c-f637-10de-70e9-d261af32ce09.png)


次に、ある実験を選択した時の画面がこちらです。
よく使う項目は以下の4つかと思います。
1. Chart：log_metricで保存した変数がグラフ化されています
2. Code：実行した際のコードが保存されています。
3. Hyper parameters：log_parameterで保存した変数を参照できます。
4. Metrics：Chartに表示されるMetricを選択できます。また、MaxやMinなどの情報も見れます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170782/4738bd72-54a7-1e28-f512-e3cb5f2dcb2b.png)

また、以下のような感じで複数の実験結果を比較することもできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170782/b0256baf-ae01-fc20-7cd1-cf8a766171c6.png)

# 5. おわりに
今回は機械学習用の実験支援ツールであるcomet.mlを試してみました。

今までは逐次テキストに出力したり、画像を出力してログを取っていましたが、これからはこのツールを上手く使っていけたら良いなと思います。
また、「もしかすると」学生の方は有料プランを無料で使えるようなので、承認された場合パラメータ最適化などの機能も試してみたいと思います。

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

# 6. リンク集
- 公式ページ：https://www.comet.ml/
- MNIST分類プロジェクトページ：https://www.comet.ml/29takuya/chainer-mnist
- chainerによるMNIST分類のソース：https://github.com/29Takuya/chainer-cometml