kumilog.net

データ分析やプログラミングの話などを書いています。

スマホアプリで学習状況を監視するHyperdash入門

WebアプリやiOS/Androidアプリで機械学習の学習状況を見ることができるHyperdashの使い方をまとめてみます。

f:id:xkumiyu:20180102175747g:plain:w300

インストールとユーザ登録

はじめにインストールとユーザ登録を行います。

インストールは、pipで簡単に行えます。

$ pip install hyperdash

ユーザ登録は、メールアドレスでの登録とGithubアカウントでの認証の2種類があります。

$ hyperdash signup --email
$ hyperdash signup --github

Githubアカウントで認証の場合、ブラウザでGithubの認証ページが開かれるので、そこで承認します。

また、pipでインストールすると、hyperdashというコマンドの他にhdがエイリアスとしてインストールされています。

$ hd signup

iOS/Androidのアプリは以下のリンクよりインストールできます。

Webアプリは以下のリンクより使うことができます。

インストールしたら、登録したアカウントでログインします。iPhoneで使ってみます。

f:id:xkumiyu:20171230144937p:plain:w300

ログの表示

どんなコードでも実行できますが、KerasのExampleを使ってみます。

$ hd run -n "MNIST" python mnist_mlp.py

-nオプションはアプリ側で識別するための名前です。同じ名前にしておくとまとめられます(#1, #2, ...といったサフィックスがつきます)

実行させると、アプリで状況を見ることができます。これだけだと、標準出力がLogsに表示されるだけで、MetricsParametersにはなにも表示されませんが、既存のコードでもすぐに実行することができます。

f:id:xkumiyu:20171230154308p:plain:w300f:id:xkumiyu:20171230154319p:plain:w300

パイプによる実行もできます。

$ python mnist_mlp.py | hd pipe -n "MNIST"

コードに少しの修正を加えることでも同じように実行できます。Experiment()の引数が、-nオプションと同じくアプリに表示させる名前になります。

from hyperdash import Experiment

exp = Experiment("MNIST")

# 学習コード
# ...

exp.end()

コードを修正した場合はの実行は、

$ python mnist_mlp.py

とするだけです。

また、途中終了や完了して終了すると通知がきます。

f:id:xkumiyu:20180103142133p:plain:w300

パラメータやスコアをトラッキング

パラメータやスコアを表示させるには、先程のコードを修正する方法に、さらに修正を加えます。

パラメータを表示させるには、exp.param()を使います。スコアの表示は、exp.metric()です。どちらも、(名前, 値)を引数とします。

# sample.py
from hyperdash import Experiment
import numpy as np
from time import sleep

exp = Experiment('SAMPLE')
n_iters = exp.param('n_iters', 100)
for _ in range(n_iters):
    exp.metric('acc', np.random.rand())
    sleep(1)
exp.end()
$ python sample.py
f:id:xkumiyu:20171230161937p:plain:w300f:id:xkumiyu:20171230161947p:plain:w300

標準出力でも表示されます。

{ n_iters: 100 }
| acc:   0.305129 |
| acc:   0.693012 |
...
This run of SAMPLE ran for 0:01:40 and logs are available locally at: ~/.hyperdash/logs/sample/sample_2017-12-27t19-37-15-923598.log

また、paramはユニークである必要があり、更新ができません。なので、学習率のように途中で変化させる値を表示したい場合は、metricに設定するしかありませが、metricはグラフ表示で軸が一つなので、スケールの異なる複数のパラメータを表示させるのには向いていません。

それでは、いくつかのフレームワークで実際に使ってみたいと思います。

Chainer

Chainerの場合、TrainerのExtensionを自作することでLossの値などを取得できます。chainer.training.extension.Extensionを継承してクラスをつくります。PrintReportのコードを参考に実装しました。

from chainer.training import extension
from chainer.training.extensions import log_report as log_report_module


class Hyperdash(extension.Extension):

    def __init__(self, entries, exp, log_report='LogReport'):
        self._entries = entries
        self._exp = exp
        self._log_report = log_report
        self._log_len = 0

    def __call__(self, trainer):
        log_report = self._log_report
        if isinstance(log_report, str):
            log_report = trainer.get_extension(log_report)
        elif isinstance(log_report, log_report_module.LogReport):
            log_report(trainer)
        else:
            raise TypeError('log report has a wrong type %s' %
                            type(log_report))

        log = log_report.log
        log_len = self._log_len
        while len(log) > log_len:
            for entrie in self._entries:
                self._exp.metric(entrie, log[log_len][entrie])
            log_len += 1
        self._log_len = log_len

PrintReportを同じように使うことができます。

from hyperdash import Experiment

exp = Experiment('Chainer MNIST')

# モデル定義やTrainerの準備など
# ...

trainer.extend(Hyperdash(
    ['main/loss', 'validation/main/loss'], exp),
    trigger=(1, 'epoch'))
trainer.run()
exp.end()

Keras

Kerasの場合は、Callbackを継承してクラスを作成します。以下の記事を参考にしました。

Kerasの学習過程をスマホで見る - Qiita

from keras.callbacks import Callback

class Hyperdash(Callback):
    def __init__(self, entries, exp):
        super(Hyperdash, self).__init__()
        self.entries = entries
        self.exp = exp

    def on_epoch_end(self, epoch, logs=None):
        for entrie in self.entries:
            log = logs.get(entrie)
            if log is not None:
                self.exp.metric(entrie, log)

fit()の引数に作成したcallbackを指定します。

from hyperdash import Experiment

exp = Experiment('Keras MNIST')

# モデル定義やデータの準備など
# ...

hd_callback = Hyperdash(['val_acc', 'val_loss'], exp)
history = model.fit(x_train, y_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test, y_test),
                    callbacks=[hd_callback])
exp.end()

XGBoost

XGBoostの場合は、callback関数を作成します。

def hyperdash(entries, exp):
    def callback(env):
        result_dict = {r[0]: r[1] for r in env.evaluation_result_list}
        for entrie in entries:
            exp.metric(entrie, result_dict[entrie])
    return callback
from hyperdash import Experiment
import xgboost as xgb

exp = Experiment('XGBoost')

# データやパラメータの準備など
# ...

d_train = xgb.DMatrix(X_train, label=y_train)
d_valid = xgb.DMatrix(X_valid, label=y_valid)
watchlist = [(d_train, 'train'), (d_valid, 'valid')]
hd_callback = hyperdash(['train-rmse', 'valid-rmse'], exp)
xgb.train(params, d_train,
          evals=watchlist,
          callbacks=[hd_callback])

exp.end()

まとめ

Chainer/Keras/XGboostの学習状況をHyperdashを使って、スマホアプリでを見る方法について説明しました。今回、紹介しませんでしたが、Jupyterからも使えるそうです。

DeepLearningの学習は時間がかかることが多く、手軽にスマホやWebで見れるととても便利です。高度なことはできませんが、どのプラットフォームからでも使えるのも良い点です。