TT Lab
はじめる
学ぶ 学習パス コース

先週のモデルの方が良かった。誰も見つけられない

一度の学習を蘇らせる最小の記録

TT Labで続きを見る

一言でいうと

学習1回を再現できるようにする最小の記録単位が実行(run)で、実験追跡は、その記録を人の記憶ではなくファイルに強制的に残させる仕組みです。

なぜ必要なのか

モデルを作る作業は、たいてい静かです。Jupyterノートブックで学習率を少し上げ、エポックを増やしてみて、シードを変えて回し直します。数字がよくなれば嬉しく、悪くなれば元に戻します。この過程で実際に残るのは、最後に回したセルの出力1つだけです。そして2週間後、誰かが「先週、もっといいものが出たと言っていませんでしたか」と聞きます。

そのとき再現しようとすると、3つのことが一度に問題になります。どのパラメーターだったのか、どのデータだったのか、そしてそのときの学習コードが今のコードと同じなのか。3つのうち1つだけが欠けていても、同じ数字はもう出てきません。もっと悪いのは、似た数字が出てくることです。完全に違う値になれば、何かが間違っているとわかりますが、0.78の代わりに0.76が出ると、人は「もともとこのくらいだったかな」と流してしまいます。そうして流された記録は、二度と復元できません。

MLflowのドキュメントは、実行を「データサイエンスのコードを1回実行したもの」と定義し、各実行が、メタデータ(指標・パラメーター・開始と終了の時刻)と、成果物(モデルの重み・画像のような出力ファイル)を一緒に記録すると書いています(MLflow Tracking)。定義がこのような形をしている理由は明らかです。この4つがそろってはじめて、その実行を立て直せ、1つでも欠けると、その実行は「あったという噂」になります。

どう動くのか

追跡ツールが実際にすることは、単純です。学習が始まるときに実行を1つ開き、コードがlog_paramとlog_metricを呼ぶたびに、その値を保存先に書き、終わったら閉じます。特別なサーバーを立てなければ、ローカルのディレクトリに溜まります。保存先を変えたければ、追跡環境を別に設定します。

import mlflow

with mlflow.start_run():
    mlflow.log_param("lr", 0.001)
    # 학습 코드
    mlflow.log_metric("val_loss", val_loss)

実行が複数溜まったら、その次は問い合わせです。MLflowは、MlflowClient.search_runsで、「この実験で検証損失が最も低い実行」のような検索をサポートし、MLflow 3からは、search_logged_modelsで、指標・パラメーターの条件をSQLに似た文字列で絞り込んで、モデルを探せます。ここで重要なのは、並べ替えの基準をコードで書くことです。人が表を目で眺めて選ぶと、来週もう一度選んだときに、別の答えが出ます。

記録すべきもののリストは、ツールごとに少しずつ違いますが、再現という目的から逆算すると、たいてい同じところに着きます。パラメーター、指標、そして入力の正体です。MLflowのデータセット追跡は、この3つ目のために、データセットごとに、名前とダイジェスト(指紋)、元の場所を持つオブジェクトを、実行に付けます(MLflow Dataset Tracking)。指紋が必要な理由は、ファイル名がバージョンではないからです。train.csvは、昨日も今日もtrain.csvです。

自動記録(autolog)は、これらすべてをライブラリが代わりに書いてくれる機能で、サポート一覧にあるフレームワークなら、mlflow.autolog()の1行でオンにします(Automatic Logging)。便利ですが、何が書かれるのかを知らないと、抜けているものにも気づけません。そのため、最初の1回は、手で書いてみるほうがよいです。

現場での姿

最もよくある事故は、ツールを使わなかったことではなく、半分だけ使ったことです。パラメーターは書かれているのに、データのバージョンがありません。指標はあるのに、コードのコミットがありません。すると、表は華やかなのに、どの行も再現されません。表があるので、誰も問題を感じないまま、規制への対応や事故の調査のように、「このモデルがどう作られたのかを証明せよ」という要求が来たときに、一度に表に出ます。

2つ目は、保存先です。コンテナの中で学習を回して、結果をコンテナの中に書くと、そのPodが消えるときに、記録も一緒に消えます。ラボのPodにもボリュームがないので、セッションが終わると/rootがまるごとなくなりますが、これは不便な制約ではなく、現実の縮図です。記録は、計算が行われた場所の外に残らなければなりません。

3つ目は、名前です。実行の識別子をtest、test2、test_finalとつける習慣は、その日は楽ですが、1か月後には何も教えてくれません。識別子は、人が読むためにあるのではなく、ほかの記録とつなぐためにあるので、短くて重ならなければ十分です。その代わり、「何を試したのか」は、パラメーターとメモに書きます。

次のラボですること

JSON Linesファイル1つで、実験元帳を自分で作ります。実行ごとに、パラメーター・指標・コードとデータのSHA-256の指紋を残し、目標の指標で最良の実行をコードで取り出し、その記録だけを見て、同じ数字をもう一度作ってみます。最後に、パラメーターが書かれないまま消えた実行のログを開き、何がなくて再現できないのかを、項目で数えてみます。