Weights & Biasesを使用したデータサイエンス実験管理
MNISTを用いたPytorchのサンプルコードを例に、Weights & Biasesで実験管理をする手順を紹介します。
Created on June 25|Last edited on September 1
Comment
はじめにWeights & Biases についてチュートリアルStep0: アカウントの作成・ログインStep1: データ準備・EDAStep2: モデル構築Step3: ハイパーパラメータチューニングStep4: モデルの検証・最終モデルの準備Step5: 報告・チームへの連携おわりに・他の学習コンテンツ
はじめに
機械学習(ML)や深層学習(DL)のプロジェクトを進めるにあたり、データサイエンティストは多くのモデルを学習させ、さまざまなハイパーパラメーターやアーキテクチャを試す実験を行い、さらにオプティマイザ、学習率、エポック数など、様々な条件下での比較実験を行います。しかし、これらの比較は徐々に複雑さを増していき、その結果を整理し続けること自体が難しくなります。そこで、この記事ではWeights & Biases(W&B)のプラットフォームを使って、MLやDLの実験を効率的かつ適切に記録・管理する方法をお伝えします。
Weights & Biases について
W&B は、モデルやデータセット、システム情報などのトラッキングを容易にするプラットフォームです。数行のコードで、関連するすべての情報を追跡できます。チームによるご利用は、通常有料のユーティリティですが、個人でのご利用やアカデミックなご利用においては無料となります。W&BはTensorFlow、Keras、PyTorch、Sklearnなどあらゆる開発フレームワークと合わせてご利用いただけます。
すべてのトラッキング情報はW&BのUI上の専用プロジェクトページに送信されます。このページではトラッキングしている情報を可視化したり、複数のモデルやパラメータースイープの結果を集約・比較することができます。実験の情報をクラウドに保存できると、どのようなメリットがあるでしょうか。一つには、プロジェクト内でで共同で作業を行い、チーム内で容易に結果の共有ができることです。
W&BはMLやDLのプロジェクトを支援するend to endのソリューションを提供しています。詳細は、ホームページをご覧ください。本記事では、W&Bの基本的な実験管理機能を中心としたチュートリアルとなっています。

チュートリアル
本記事のチュートリアルで使用するコードをGoogle Colaboratoryで用意しました。是非お試し下さい。MNISTのデータを学習するPytorchのコードが多くを占めますが、W&Bに関連するコードの周辺には🐝マークを入れています。W&Bのツールは、ユーザー様が記載されたコードに、W&Bと連携させるコードを差し込むだけで、簡単に実験管理をすることができるようになっています。
今回のチュートリアルは、「W&Bの基本的な機能を一通り試しながら、それらの操作を理解する」ことをゴールに設定します。下記がゴールを達成するためのチュートリアルの大きな流れです。
順番にみていきましょう。なお、下記の解説では一部コードを抜粋して説明しています。

Step0: アカウントの作成・ログイン
早速Pytorchのコードに移ります。W&Bを利用するためには、wandbをインストール・インポートし、ログインするだけです。初期のログイン時にはAPI keyを求められますが、W&Bの画面右上の人アイコンをクリックし、User settingを押してスクロールダウンするとAPI keysが見つかりますので、それを貼り付けてください。
※なお、環境変数に登録をしておくと、毎回API keyを入力せずにログインすることが可能です。
また、W&Bの実験は大きく、エンティティ => プロジェクト => Run(実行)という単位で管理されます。エンティティはチームの単位です。デフォルトでは個人専用のエンティティになっていますが、チームのエンティティを作り、チームで同じプロジェクトを管理することが可能です。なお、個人やアカデミック利用の場合は個人のエンティティ以外にもう1つのエンティティに参加することしかできません。エンティティの下の単位が、プロジェクトです。名前の通り、MLやDLの1つのプロジェクトとしてお使いください。そのプロジェクトの中で多くの実験をする必要がありますが、プロジェクトの下でRunが管理されます。なお、エンティティとプロジェクトは手動で作成し、Runは自動的に毎回の実行で作成されていきます。下記のコードでは、今回のチュートリアルで使用するプロジェクトの名前をここで定義をしています。
#🐝 wandbのインストール!pip install wandb -Uq...# 必要なライブラリ・モジュールのインストール・インポート...#🐝 wandのインポートとログインimport wandbwandb.login()# project nameの指定project_name = "mnist-pytorch-demo"
Step1: データ準備・EDA
次にデータ準備です。まずは、データを読み込んで、W&Bでバージョン管理をします。W&Bとの連携を開始する際には、基本的に wandb.init()で初期化し、 wandb.finish() で終了させるのが基本的な流れです。下記は、すべてを wandb.init のコンテキスト内で実行する方法を使っていますが、with句を使用すると、エラーが生じた際なども( wandb.finish()の実行なしで)wandbのプロセスが終了し、必要なログがW&Bに連携されるようになります。
データのバージョン管理にはアーティファクトが便利です。モデルの学習や推論のプロセスを進めるにあたり、どのデータを用いたのかをアーティファクトを使ってW&Bに連携しておくと、実験プロセスが整理され、再現性も高くなります。W&Bのアーティファクトを定義し、 run.log_artifact(raw_data) でログをしていきます。これが使用するデータ管理の大まかな流れです。
def load_and_log():#🐝 wandbのrunを作成with wandb.init(project=project_name, job_type="load-data") as run:datasets = load() # separate code for loading the datasetsnames = ["training", "validation", "test"]#🐝 Artifactを定義raw_data = wandb.Artifact("mnist-raw", type="dataset",description="Raw MNIST dataset, split into train/val/test",metadata={"source": "torchvision.datasets.MNIST","sizes": [len(dataset) for dataset in datasets]})for name, subset in zip(names, datasets):# Artifactへの保存のためにsubdatasetをTensorDatasetに変換data = transform_subset2tensordataset(subset)with raw_data.new_file(name + ".pt", mode="wb") as file:x, y = data.tensorstorch.save((x, y), file)#🐝 ArtifactをW&Bに保存run.log_artifact(raw_data)...load_and_log()
実行をするとW&BのプロジェクトやRunのURLが表示されますが、プロジェクトURLからの左にあるアーティファクトをクリックすると、W&Bに今回のデータが登録されていることがわかります。

さて、モデルを構築する前には一般的には前処理をすることが多いですが、元データを用いて前処理をする工程もみていきましょう。どのデータを使って前処理をしたかをW&Bで管理しやすくするために明示的に元データのアーティファクトを呼び出します。下記の run.use_artifact('mnist-raw:v0')がそのプロセスにあたりますが、上図のUsageというタブを押すと、そのデータの名称を含めたコードを手にいれることができるようになります。あとは、前処理をしたデータを先ほどと同じようにアーティファクトとして保存するだけです。
def preprocess_and_log(steps):#🐝 wandbのinitializationwith wandb.init(project=project_name, job_type="preprocess-data") as run:processed_data = wandb.Artifact("mnist-preprocess", type="dataset",description="Preprocessed MNIST dataset",metadata=steps)#🐝 どのArtifactを使用するかを定義し、必要に応じてダウンロードraw_data_artifact = run.use_artifact('mnist-raw:v0')raw_dataset = raw_data_artifact.download()for split in ["training", "validation", "test"]:raw_split = read(raw_dataset, split)processed_dataset = preprocess(raw_split, **steps)with processed_data.new_file(split + ".pt", mode="wb") as file:x, y = processed_dataset.tensorstorch.save((x, y), file)run.log_artifact(processed_data)
前処理をしたデータのアーティファクトをクリックし、Linegeというタブを押してください。そうすると、ダイアグラムが見えますが、これは前処理をして保存されたデータがどのデータを使用して、どのRunを回すことで生成されたものなのかを示しています。自分でダイアグラムを書かなくても自動で作成されていくのですが、たくさんのモデルを構築する中で、どのモデルがどのデータを使用したのかをわかりやすく確認することができるようになっているので、個人としてもチームとしてもプロジェクトの再現性を高めることができるようになります!(下記の図はすべてのcodeを実行した例です)

また、データを保存するだけではなく、W&Bのテーブル機能を使うと非構造データと数値データを同一のテーブルでインタラクティブな可視化機能とともに確認することが可能です。可視化だけではなく、W&B上でインタクティブにフィルターや並び替えなどの処理を行うことができます。また、今回はシンプルな画像の例を示しましたが、セグメンテーションのためのラベルがついた画像であれば、ラベルの表示をオンオフしたり、分子構造やタンパク質構造であれば、くるくるとW&B内で立体構造を確認することができます。また、音声や動画にも対応をしています。
table = wandb.Table(columns=["image", "label","split"])
Run set
15
Step2: モデル構築
次にモデルのトレーニングを進めていきます。まずは、全体のパイプライン model_pipelineを定義しましょう。標準的なパイプラインとの唯一の違いは、先ほどと同じようにすべてを wandb.init() のコンテキスト内で実行するということです。先ほどとの違いは、configを定義しているところです。一般的なワークフローでは configディクショナリーにハイパーパラメータやメタデータを保存しておいて、必要に応じてそれらにアクセスします。 model_pipelineの中では以下のようなことを行なっています。
make: モデルアーキテクチャの定義・データローダー・損失関数・最適化手法の設定を行います。基本的には通常のPytorchのプロセスと同じです。先ほど保存したアーティファクトを使用することで、今回のモデルのトレーニングがどのデータを使用したかの記録をLineageに保存することができます。
train: モデルをトレーニングし、検証データに対して検証を行います。ここでは wandb の watchと logの2つの関数が登場します。
- wandb.watchは、Pytorchとのインテグレーションを行う際のみに使用できる関数です。モデルの勾配とパラメータを、トレーニングの log_freq ステップごとにログに記録します。トレーニングを開始する前に、単純に wandb.watch を呼び出すだけです。トレーニングの残りのコードは変わりません。
- wandb.logはメトリクスなどの任意の情報を記録することができます。また、トレーニングのどの step であるかをオプションでログに記録することもできます。
config = dict(epochs=10,kernels=[16, 32],batch_size=128,dropout =0.1,learning_rate=0.005,optimizer="adam",log_prediction_iamge=True,classes=10,dataset="MNIST",architecture="CNN")def model_pipeline(config):#🐝 wandbのrunを作成with wandb.init(project=project_name, config=config) as run:config = wandb.config# モデルアーキテクチャの定義・データローダー・損失関数・最適化手法の設定model, train_loader, validation_loader, criterion, optimizer = make(config, run)# モデルをトレーニングし、検証データに対して検証train(model, train_loader,validation_loader, criterion, optimizer, config, run)#🐝 Artifactにモデルを保存artifact = wandb.Artifact('model', type='model')with artifact.new_file('model.pt',mode='wb') as file:torch.save(model.state_dict(), file)run.log_artifact(artifact)return model...def train(model, training_loader, validation_loader, criterion, optimizer, config, run):#🐝 wandb.watchを用いてモデルのgradientsやweightsなどをトラックwandb.watch(model, criterion, log="all", log_freq=10)# 学習の開始example_ct = 0for epoch in tqdm(range(config.epochs)):for step, (images, labels) in enumerate(training_loader):loss = train_batch(images, labels, model, optimizer, criterion)example_ct += len(images)#🐝 run.logを用いてモデルのlossをトラックrun.log({"epoch": epoch, "train_loss": loss}, step=example_ct, commit=False)validation(model, validation_loader, criterion, run, log_images=config.log_prediction_iamge)...model_pipeline(config)
出力されたRunのURLをクリックすると、GPUの使用率などのシステムに関する情報やlossなどのモデルの精度に関する情報などが可視化されているのが確認できます。学習後だけではなく、学習途中もW&Bとデータ連携しているため、大規模なモデルを学習中にlossが下がっているか確認しながら、もしlossが下がっていなかったり、途中で爆発していた場合には計算を中断する意思決定をすることで、貴重な計算リソースや時間を節約することができます。

実験管理だけではなく、様々な深掘りもW&B上でできるようになります。例えば、今回テーブルには各ラベルの予測値の確率も記録されているのですが、歯車マークからCombined Plotをクリックし、3の予測確率を横���に、5の予測確率を選択することで、3と5を間違えやすい画像を確認することができます。各ポイントをマウスオーバーすると画像を確認することができます。
Run set
15
Step3: ハイパーパラメータチューニング
スイープは、ハイパーパラメータおよびモデルの最適化を行うツールです。まず、最適化するハイパーパラメータの要件を定義しましょう。また、ハイパーパラメータの最適化方式(ランダム検索またはグリッド検索)を選択してから、最適化するメトリックを選択します。あとは、スイープのエージェントをたて、複数の計算を投げていきます。
※計算を早くするために、スイープ実行時は予測画像のアップロードはオフにしています、。
sweep_config = {'method': 'random','metric': {'name': 'validation_loss','goal': 'minimize'},}parameters_dict = {'optimizer': {'values': ['adam', 'sgd']},'dropout': {'values': [0.1, 0.2, 0.3]},'learning_rate': {# 0から0.1の間を一様分布で乱数を発生'distribution': 'uniform','min': 0,'max': 0.1},'batch_size': {# 32から256の間で対数スケールにおいて等間隔の分布から乱数を発生'distribution': 'q_log_uniform_values','q': 8,'min': 32,'max': 256,},'kernels':{'values':[[16,32],[32,64]]},'epochs':{'value':5},'classes':{'value':10,},'dataset':{'value':'MNIST',},'architecture':{'value':'CNN',},'log_prediction_iamge':{'value':False},}sweep_config['parameters'] = parameters_dict#🐝 Sweep用に関数を作成def model_pipeline_sweep(config=None):#🐝 wandbのrunを作成with wandb.init(config=config) as run:config = wandb.config# モデルアーキテクチャの定義・データローダー・損失関数・最適化手法の設定model, train_loader, validation_loader, criterion, optimizer = make(config, run)# モデルをトレーニングし、検証データに対して検証train(model, train_loader, validation_loader, criterion, optimizer, config, run)#🐝 Artifactにモデルを保存artifact = wandb.Artifact('model', type='model')with artifact.new_file('model.pt',mode='wb') as file:torch.save(model.state_dict(), file)run.log_artifact(artifact)sweep_id = wandb.sweep(sweep_config, project=project_name)wandb.agent(sweep_id=sweep_id, function=model_pipeline_sweep, count=5)
スイープを実行すると、下図のようなパラレルチャートを確認することができます。どのパラメータの組み合わせで最も精度が高いモデルを獲得することができるかを確認することができます。また、左下のグラフでは、精度に対して影響度の高いパラメータを確認することができます(内部でツリー系のアルゴリズムを走らせ、feature importanceを計算しています)。
Sweep: l7ck927o 1
10
Sweep: l7ck927o 2
0
Step4: モデルの検証・最終モデルの準備
最も精度が高いパラメータの組み合わせまでわかりました。最後にプロダクションで使用するモデルを準備します。また、ホールドアウトデータに対する精度検証も行っていきます。
まず、Step3のプロセスで最も精度が良かったハイパーパラメータチューニングの組み合わせを取得します。手打ちする必要はなく、最も精度が良かったrunの configを下記のコードで取得することができます。最も精度の良かったエンティティ・プロジェクト・Runの組み合わせは、そのRunをクリックした際のURLか、一番左に見えるOverviewのRun pathから確認することができます。過去のrunの履歴をpythonで取得することができるので、下記の例では、sweepの中で最も精度が良いrunのpathを自動取得しています。
# sweepの後であれば、sweepのagentとの連携をまず切りますwandb.sdk.wandb_setup._setup(_reset=True)# もっとも精度の良いモデルのconfigを取得しますimport pandas as pdimport numpy as npapi = wandb.Api()# Replace 'username' and 'project' with your username and project nameruns = api.runs(project_name)name_list, path_list, sweepName_list,validation_loss_list = [], [], [], []for run in runs:name_list.append(run.name)path_list.append(run.path)sweepName_list.append(run.sweepName)validation_loss_list.append(run.summary.get("validation_loss", np.nan))runs_df = pd.DataFrame({"name": name_list,"path": path_list,"sweepName": sweepName_list,"validation_loss": validation_loss_list})best_sweep_path = runs_df.query("sweepName.notnull() and validation_loss == validation_loss.min()")["path"].values[0]best_sweep_path = '/'.join(best_sweep_path)best_sweep_path
configを獲得後、最終的なモデルを保存し、ホールドアウトデータに対する精度検証を行います。
def test_pipeline(config):#🐝 wandbのrunを作成with wandb.init(project=project_name, config=config) as run:config = wandb.config# モデルアーキテクチャの定義・データローダー・損失関数・最適化手法の設定model, train_loader, validation_loader,test_loader, criterion, optimizer = make(config, run)# モデルをトレーニングし、検証データに対して検証train(model, train_loader,validation_loader, criterion, optimizer, config, run)# テストデータで検証test(model, test_loader, criterion, run, config)#🐝 Artifactにモデルを保存artifact = wandb.Artifact('model', type='model')with artifact.new_file('model.pt',mode='wb') as file:torch.save(model.state_dict(), file)run.log_artifact(artifact)def test(model, test_loader, criterion, run, config):model.eval()table = wandb.Table(columns=["image", "pred", "target"]+[f"score_{i}" for i in range(10)]) # wandbのTableを作成with torch.no_grad():correct, total, test_loss = 0, 0, 0for images, labels in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()test_loss += criterion(outputs, labels)*labels.size(0)if config.log_prediction_iamge:for img, pred, targ, prob in zip(images.to("cpu"), predicted.to("cpu"), labels.to("cpu"), outputs.softmax(dim=1).to("cpu")):table.add_data(wandb.Image(img[0].numpy()*255), pred, targ, *prob.numpy())run.log({"test(holdout)_prediction_table":table}, commit=False)run.log({"test_loss(holdout)":test_loss / total ,"test_accuracy(holdout)": correct / total})test_pipeline(final_config)
ホールドアウトに対する精度は下の通りです。精度などの基準は、プロジェクトを始める前に決めておくことが一般的ですが、その基準を満たしているかどうかを確認します。なお、結果をグラフではなく、数値で表示していますが、runのダッシュボードの中のAdd panelより表示形式を変えて結果を表示することができます。
Run set
15
さて、最終的にプロダクションで使用するモデルを作成しました。基本的にはアーティファクトでデータやモデルを管理することができますが、プロダクションに使用するモデルに関しては、モデルレジストリという機能を使ってわかりやすくチームで管理することができます。
手順としては、モデルレジストリから管理するモデルの箱を用意し、そこにプロジェクトの中で作成したアーティファクトにあるモデルを登録して行きます。登録時に stagingや challengerなどのエイリアスを付与することも可能です。モデルレジストリでモデルを管理することで、アーティファクトで管理するよりもプロダクションで使用するべきモデルがわかりやすくなります。
詳細な手順は下記です。左上のW&Bのログマークを押してホーム画面にいき、モデルレジストリの中で登録するモデルの箱を用意します。その後、プロジェクトのアーティファクトに戻り、登録したいモデルをクリックして、"Link to registory"のボタンを押してモデルレジストリに登録すると、モデルレジストリ上で運用するモデルを管理することができます。

登録後、モデルレジストリでは下記のように表示されます。モデルの使用者もどのモデルを使用すれば良いか一目瞭然ですね。

Step5: 報告・チームへの連携
これまでデータの準備とモデルの構築に取り組んできました。すべてのRunには、実行したファイル、ライブラリのバージョン、使用したコードなど、多様なメタデータが保存されています。これにより、後から分析を行う際や、他のチームメンバーが分析を行う際に、高い再現性で分析を再開することが可能になります。
さらに、分かりやすいレポート形式でプロジェクトを共有することも可能です。実は、この記事自体がW&Bのレポート機能を使用して作成されています。レポート機能を使用すると、結果を直接引用することができ、さらに、その結果をインタラクティブに確認することができます。レポートの作成は簡単で、プロジェクト内で右上の「Create Report」ボタンをクリックするだけです。

さらに、レポートのテンプレートを一度作成しておけば、同じプロジェクト内の結果だけでなく、他のプロジェクトからでもそのレポートに各種結果を引用することができます。レポート内の結果は、どのRunを元にしたものかを追跡することができるため、元の結果や設定をレポートから逆に確認することも可能になります。レポートを活用して、チーム間のコラボレーションをさらに加速しましょう。
おわりに・他の学習コンテンツ
本記事では、W&Bの基本的な実験管理機能を中心とした一連の流れを体験していただきました。本記事で紹介をした機能以外にも便利な機能が様々あります。W&Bが提供している下記のコンテンツもご覧ください。
- Wandbot!!!!: wandb.me/jp-slackに参加し、#wandbotで質問をしてください!wandbに関する多くのことを自動で回答してくれます

Add a comment
Tags: Beginner, Domain Agnostic, Case Study, W&B Meta, Artifacts, Custom Charts, Panels, Plots, Sweeps, MNIST
Iterate on AI agents and models faster. Try Weights & Biases today.