Pretraining & Finetuning of Protein Language Model with BioNeMO & WandB JP
Created on May 29|Last edited on July 14
Comment
このレポートに関する質問やwandbに関する質問は、contact-jp@wandb.comまでご連絡ください。

生成AIの代表的なユースケースはチャットボットですが、その技術革新はチャットに留まらず、様々な分野に応用されています。特に創薬の分野では、膨大な分子の組み合わせから新しい薬を開発するのに多くの時間と資金がかかりますが、AIを活用することで創薬サイクルを短縮する試みが日々行われています。
そのようなAI創薬において、Transformerの登場以降、アミノ酸や分子配列を学習したタンパク質言語モデルや生化学モデルを用いた予測性能が飛躍的に向上し、生成AIを活用した創薬の可能性に注目が集まっています。実際、AmgenやGenentechなどは生成AIを用いた創薬の事例を報告しています。
しかし、生成AIを用いた創薬においては膨大なデータを扱う必要があるため、マルチノードGPUを用いた分散処理や、モデル構造を理解した効率的な計算が求められます。これには、データ分析の理解だけでなく、高いエンジニアリング力も必要となり、参入障壁が高い分野となっていました。このような背景から、創薬領域における基盤モデルを簡単に活用できるフレームワーク「NVIDIAのBioNeMo」が開発・公開されました。
このレポートでは、BioNeMoを初めて使用する方を対象に、タンパク質言語モデルの事前学習からファインチューニングまでの実装方法を紹介します。また、実装例においては、グローバルで多くの製薬企業がBioNeMoと共に活用しているWeights & Biasesの便利な活用方法も意識した形で紹介をしていきます。おおまかな流れは下記になります。

Fig: 実装のおおまかな流れ
環境構築PrerequisitesRequest access / Account setupSet up使用するcode & Test code実装Pre-Training (ハンズオンの手順が追って更新されます)Preparation of script & wandbData pre-processingPre-trainingModel registryへの登録Finetuning (ハンズオンの手順が追って更新されます)Preparation of script & wandbData preprocessing & Model preparationFinetuning最後に
環境構築
Prerequisites
- x86 Linux systems
- Docker (with GPU support, docker engine >= 19.03)
- Python 3.10 or above
- Pytorch 1.13.1 or above
- NeMo pinned to version 1.20 NVIDIA GPU, if you intend to do model training.
- Tested GPUs: DGX-H100, A100, V100 RTX A6000, A8000 Tesla T4 GeForce RTX 2080 Ti (GPUs with known issues: Tesla K80)
- bfloat16 precision requires an Ampere generation GPU or higher.
Request access / Account setup
- Weights & Biases Account
- Access to BioNeMo Framework from NVIDIA. ("Get Started With NVIDIA BioNeMo"の"Training Framework"にアクセスできるようにする)
- Access to NGC ( NVIDIA GPU CLOUD)
- (Optional) Access to NVIDIA DGX compute infrastructure (DGX-Cloud or DGX-Pod). (ややこしいですが、こちらはOptionalです)
Set up
(1) Dockerの立ち上げ image file (Image: nvcr.io/nvidia/clara/bionemo-framework:1.5)
以下のコマンドはあくまで一例です。ご自身のGPU環境に合わせて、Dockerを立ち上げてください
login
docker login nvcr.ioUsername: $oauthtokenPassword <insert NGC API token here>
docker imageをpull
docker pull nvcr.io/nvidia/clara/bionemo-framework:1.5
DockerのLaunch
docker run -it --rm --gpus all nvcr.io/nvidia/clara/bionemo-framework:1.5 bash
(2) NGC CLIのdownload
wget --content-disposition https://api.ngc.nvidia.com/v2/resources/nvidia/ngc-apps/ngc_cli/versions/3.42.0/files/ngccli_linux.zip -O ngccli_linux.zip && unzip ngccli_linux.zipfind ngc-cli/ -type f -exec md5sum {} + | LC_ALL=C sort | md5sum -c ngc-cli.md5sha256sum ngccli_linux.zipchmod u+x ngc-cli/ngcecho "export PATH=\"\$PATH:$(pwd)/ngc-cli\"" >> ~/.bash_profile && source ~/.bash_profilengc config set
- API キーはNGCのAPIキーを入力してください
- Org は ’no-org’ 以外のものを選択
- format_typeは'json'を選択
- その他はデフォルト値でOK
(3) 環境変数の設定
export BIONEMO_HOME="/workspace/bionemo"# もしdedicated cloud版またはオンプレミス版のwandbを使用している場合は、"WANDB_BASE_URL"を適切に設定してください。# あなたの会社のwandb管理者が"WANDB_BASE_URL"をご存知です。[optional] export WANDB_BASE_URL=<your wandb base url>
使用するcode & Test code実装
基本的にはDocker内のsample scriptや関数を使用しますが、例題の一連の手順を入れたjupyter labや一部wandb連携のために変更する必要があるscriptを以下のgithub repositoryに格納しています。手元にdownloadをして、ご自身の環境に配備してください(今後gitpullへの対応・そもそものDocker imageへの組み込みも考えております)。
こちらの題材のハンズオンに参加される方↓
github repositoryの中のtest_code.ipynlを以下のようにworkspace ディレクトリに配置して実装し、errorなく実行できることを確認して下さい。エラーなく実装され、最後の実装時にwandbへのloginと保存が完了していれば(wandbのURLが表示されます。Failedなどが出なければ問題ありません)。

Pre-Training (ハンズオンの手順が追って更新されます)
今回はbionemoのdocker imageに含まれているデータセットUniref50とUniref90を使用して事前学習を行います。Uniref50 はトレーニング、検証、テスト用に分割されています。トレーニング中に Uniref50 のミニバッチがサンプリングされますが、このバッチの各シーケンスは、データのサイズと多様性を増加させるために、対応する Uniref90 クラスターのシーケンスに置き換えられます(Uniref50は類似度が50%のシーケンスをクラスタリングして代表的なシーケンスを保存している一方、Uniref90は類似度が90%のシーケンスをクラスタリングして代表的なシーケンスを保存しています。つまりUniref90の方がより多くのデータが含まれているデータになります)。"Language models of protein sequences at the scale of evolution enable accurate structure prediction"を参照してください。Uniref90 はトレーニング時にのみ使用され、検証やテストには使用されません。
Preparation of script & wandb
(1) ベースとしてはnvcr.io/nvidia/clara/bionemo-framework:1.5の中のデータとスクリプトを使いつつ、いくつかのスクリプトについては、https://github.com/olachinkei/BioNeMo_WandB/tree/mainの中のコードを使用します。
Dockerのcustom imageの作成やgithubのrepositoryを今後用意しますが、updateが激しいbionemoなので、不格好ではありますがofficialのdocker imageに対してscriptを手動で足し算する形で進めます。
💡
(2) workspace 下に github repository内のProtein/01_protein_LLM.ipynb を配置し、このjupyter notebookをメインで使用します!
(3) workspace/bionemo/examples/protein/esm2nv/pretrain.pyを github repository内のProtein/pretrain.pyに置き換えます。
(4) workspace/bionemo/examples/protein/esm2nv/conf/base_config.yamlをgithub repository内のProtein/base_config.yaml に置き換えます
(5) 01_protein_LLM.ipynbを開き、実行をしていきます。まずはwandbの環境変数の設定をし、wandb内で保存する場所を決定します。
wandbへの保存場所は、下図のような構成になっています。チームメートと同じentity (team)で作業をしていると、 自動的にリアルタイムにその結果が共有されます。
import osos.environ["WANDB_ENTITY"]="<your team where you want to log>"os.environ["WANDB_PROJECT"]="BioNeMo_protein_LLM_pretraining"

Data pre-processing
01_protein_LLM.ipynb内の"データの前処理"に進みます。
ここで、事前学習に使用するデータを準備しますが、今回はbionemoのdocker imageに含まれているデータセットUniref50とUniref90を使用します。
(1) scriptを順番に実行し、uniref202104_esm2_qc_test200_val200.zipを解凍します。

(3) データの前処理を行います。以下のpretrain.pyでは、生データが入っているwandbのartifactsを受け付け、再度別のartfactsとしてwandbの登録するように変更しています。
!python examples/protein/esm2nv/pretrain.py\--config-path=conf\--config-name=pretrain_esm2_650M\++do_training=False\++exp_manager.wandb_logger_kwargs.name='preproceed_data_upload'\++exp_manager.wandb_logger_kwargs.job_type='data_upload'\++wandb_artifacts.wandb_use_artifact_path='${oc.env:WANDB_ENTITY}/${oc.env:WANDB_PROJECT}/uniref202104_esm2_qc_test200_val200:v0'\++wandb_artifacts.wandb_log_artifact_name='uniref202104_esm2_qc_test200_val200_preprocessed'\++model.data.val_size=500\++model.data.test_size=100\++model.data.uf50_datapath=/uniref50_train_filt.fasta\++model.data.uf90_datapath=/ur90_ur50_sampler.fasta\++model.data.cluster_mapping_tsv=/mapping.tsv\++model.data.dataset_path=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uf50\++model.data.uf90.uniref90_path=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uf90\++model.data.train.uf50_datapath=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uniref50_train_filt.fasta\++model.data.train.uf90_datapath=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/ur90_ur50_sampler.fasta\++model.data.train.cluster_mapping_tsv=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/mapping.tsv\++model.data.val.uf50_datapath=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uniref50_train_filt.fasta\++model.data.test.uf50_datapath=/workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uniref50_train_filt.fasta
-- で始まるパラメータは、コマンドライン引数として pretrain.py に渡されます。例えば、 config-path と config-name は、設定 YAML ファイルのフォルダとyaml ファイル名を指定します。このパスは pretrain.py に対して相対的です。conf はexamples/protein/esm2nv/confを指し、pretrain_esm2_650M はexamples/protein/esm2nv/conf/pretrain_esm2_650M.yaml を指します。
++ で始まるパラメータは、YAML ファイルで設定可能です。 例えば、base_config.yaml から継承された pretrain_esm2_650M.yaml では、以下のパラメータを見つけることができます:
- do_training: データの前処理のみを行い、トレーニングは行わないように False に設定します
- exp_manager.wandb_logger_kwargs.name: wandbのrun nameを指定します
- exp_manager.wandb_logger_kwargs.job_type: wandbのjob_typeを指定します(job_typeは後でrunの情報を整理する時に役立つメタデータになります。これによって実装が変わることはありません。)
- wandb_artifacts.wandb_use_artifact_path: 前処理をするデータのwandbのartifactsのpathを設定します。
- wandb_artifacts.wandb_log_artifact_name: 前処理をした後のデータを保存する際のwandbのartifacts名を指定します
- model.data.val_size と model.data.test_size: 検証およびテストデータセットのサイズを指定します。
- model.data.uf50_datapath: uniref50 fasta ファイルへのパスを指定します。
- model.data.uf90_datapath: uniref90 fasta ファイルへのパスを指定します。
- model.data.cluster_mapping_tsv: uniref50 クラスターを uniref90 シーケンスにマッピングするファイルへのパスを指定します。
- model.data.dataset_path: 前処理された uniref50 データの出力ディレクトリへのパスを指定します。このフォルダはトレイン、検証、テストの分割を含むことになります。
- model.data.uf90.uniref90_path: 前処理されたuniref90 データの出力ディレクトリへのパスを指定します。このフォルダは u90_csvs というフォルダのみを持ち、uniref90 はトレーニングでのみ使用されるため、トレイン/テスト/検証の分割は持ちません。
- model.data.train.uf50_datapath: uniref50 fasta ファイルへのパスを指定します。
- model.data.train.uf90_datapath: uniref90 fasta ファイルへのパスを指定します。
- model.data.train.cluster_mapping_tsv: uniref50 クラスターを uniref90 シーケンスにマッピングするファイルへのパスを指定します。
- model.data.val.uf50_datapath: uniref50 fasta ファイルへのパスを指定します。
- model.data.test.uf50_datapath: uniref50 fasta ファイルへのパスを指定します。
また、上記のようにコマンドラインを通じて引数を上書きするのではなく、直接 YAML ファイルを変更することもできます。処理が完了すると、前処理されたデータは /workspace/bionemo/examples/tests/test_data/uniref202104_esm2_qc_test200_val200/uf50/uf50/ にあります。もし独自のデータを利用して事前学習、ファインチューニングや推論をしたい場合は、パスを/workspace/bionemo/mydata/ に指定してください。ただし、データの構造やフォーマットをサンプルデータに揃える必要があります。
実行すると、以下のようにデータが作成され、lineageも自動的に作成されていることがわかります。これでデータ準備の完成です。
uniref202104_esm2_qc_test200_val200_preprocessed
Direct lineage view
Some nodes are concealed in this view - Break out items to reveal more.
Pre-training
データの準備ができたので、その後のコードを順次実行し、最終的に以下のコードを実行して、事前学習を進めていきます。
!python examples/protein/esm2nv/pretrain.py \--config-path=conf \--config-name=pretrain_esm2_650M \++do_training=True \++do_testing=True \++wandb_artifacts.wandb_use_artifact_path='${oc.env:WANDB_ENTITY}/${oc.env:WANDB_PROJECT}/uniref202104_esm2_qc_test200_val200_preprocessed:v0'\++model.data.dataset_path=/ \++model.data.uf90.uniref90_path=/uf90 \++trainer.devices=1 \++model.tensor_model_parallel_size=1 \++model.micro_batch_size=4 \++trainer.max_steps=1 \++trainer.val_check_interval=1 \++exp_manager.create_wandb_logger=True \++exp_manager.checkpoint_callback_params.save_top_k=10
以下、上記で設定している主なパラメータの説明です。
- do_training: モデルをトレーニングするために True に設定します。これはデータが前処理されたこ��を前提としています。
- do_testing: テストをスキップするために False に設定します。
- wandb_artifacts.wandb_use_artifact_path: 学習に使用するデータセットのパスを入力します
- model.data.dataset_path: トレーニング/検証/テスト分割が含まれる前処理済みのuniref50データフォルダのパスを指定します。
- model.data.uf90.uniref90_path: 前処理済みの uniref90 データのパスを指定します。このフォルダには u90_csvs という別のフォルダが含まれている必要があります。u90_csvs フォルダ内には、x000.csv から x049.csv のファイルが存在する必要があります。
- trainer.devices: 使用するGPUの数を指定します。
- model.tensor_model_parallel_size: テンソルモデル並列サイズを設定します。
- model.micro_batch_size: バッチサイズを設定します。メモリエラーが発生しない限り、これをできるだけ増やします。
- trainer.max_steps: トレーニングの最大ステップ数を指定します。デモのために 100 に設定しました。1 ステップ = 1 バッチの処理です。まず、total_batches = サンプル総数 / バッチサイズを計算します。N エポックでトレーニングしたい場合は、max_steps をN * total_batches に設定します。
- trainer.val_check_interval: 検証セットを実行する間隔を指定します。
- exp_manager.create_wandb_logger: wandb へのログ記録を無効にするために False に設定します。True の場合は、wandb API キーを提供する必要があります。
- exp_manager.checkpoint_callback_params.save_top_k: 保存する最適のチェックポイントの数を指定します。 トレーニングされた結果が /workspace/bionemo/results/nemo_experiments/ に保存されます。
なお、事前学習ではなく、継続事前学習を行いたい場合は、base_config.yamlの中のrestore_from_pathのスタートポイントとなるモデルのパスを入れることで行うことができます。
💡
学習過程や設定はwandbに保存され、トレーニングされたモデルもwandbのartifactsに保存されます。以下は、wandbでトラックされた例です。
Run: pretraining_240603-153108
1
model-41vz8yh8
Direct lineage view
Model registryへの登録
Artifactsにモデルがあるままだと、他のチームの方がどのモデルが現在最高レベルのものなのか少しわかりづらい状態です。チームコラボレーションをより容易にするために、wandbのModel registryがあります。Model registryに事前学習したモデルを登録しましょう。

手順は簡単です。登録したいモデルから"Link to registry"をクリックします。

そうすると、組織のModel registryから今回のモデルが1つ管理されていることが確認できます。よりよい事前学習を行い、再度登録すると、自動的にv1, v2と新しいバージョンが作成されます。多くのバージョンができても、タグをつけることができるので、どのモデルがproductionで使われているのか、どのモデルがもっとも精度が良いかなどは簡単に管理することができます。

Finetuning (ハンズオンの手順が追って更新されます)
BioNemo Framework のサンプルコードは三つの下流タスクを提供しています。一つ目はタンパク質の 10 の細胞内局在部位を予測すること、二つ目はタンパク質の融解温度を予測すること、三つ目はタンパク質のSecondary Structureを予測することです。本レポートでは三つ目のタスクを例として説明します。具体的には、シーケンスの各アミノ酸について、それがヘリックス、シート、またはコイルのどれにあるかを予測します。
補足:3状態の予測
3状態の予測では、タンパク質の二次構造を以下の三つに分類します。
- ヘリックス (H) - アミノ酸のチェーンが螺旋状になっている部分。
- シート (E) - アミノ酸のチェーンが平行または反平行のシート構造を形成している部分。
- コイル (C) - ヘリックスやシートに分類されない、無秩序または他の任意の構造を取る部分。
補足:8状態の予測
8状態の予測では、タンパク質の二次構造をより詳細に以下のように分類します。
- H: αヘリックス
- E: 延伸された構造 (βシート)
- G: 3-10ヘリックス
- I: πヘリックス
- T: ターン
- S: 曲がり
- B: βブリッジ
- C: コイル
Preparation of script & wandb
(0) Pre-trainingと同じgithub repository内のProtein/01_protein_LLM.ipynbを使用します。
(1) workspace/bionemo/examples/protein/downstream/downstream_flip.pyを github repository内のProtein/downstream_flip.pyに置き換えます。
(2) bionemo/examples/protein/esm2nv/conf/downstream_sec_str_LORA.yamlをgithub repository内のProtein/downstream_sec_str_LORA.yaml に置き換えます
(3) 01_protein_LLM.ipynbを開き、実行をしていきます。まずはwandbの環境変数の設定をし、wandb内で保存する場所を決定します。
import osos.environ["WANDB_ENTITY"]="<your team where you want to log>"os.environ["WANDB_PROJECT"]="BioNeMo_protein_LLM_finetuning"
Data preprocessing & Model preparation
(1) 以下のコードを用いてデータをダウンロードします。
!wget -q -O /tmp/ngccli_linux.zip --content-disposition https://api.ngc.nvidia.com/v2/resources/nvidia/ngc-apps/ngc_cli/versions/3.38.0/files/ngccli_linux.zip && unzip -o /tmp/ngccli_linux.zip -d /tmp && chmod u+x /tmp/ngc-cli/ngc && rm /tmp/ngccli_linux.zip
(2) 以下のコードを用いてモデルをダウンロードします。
!python download_models.py --download_dir /workspace/bionemo/models esm2nv_650m
今回はハンズオンのためにesm2nv_650mをもとにしますが、上記の事前学習のプロセスで学習をしたmodel registryに登録をしたモデルを使用することも可能です。
💡
(2) finetuningに利用するモデルとデータをwandbにuploadしてバージョン管理を行います。
!python download_models.py --download_dir /workspace/bionemo/models esm2nv_650m# save modelimport wandbwith wandb.init(name="model_upload") as run:artifact = wandb.Artifact(name="esm2nv_650m",type="model",description="original esm2nv_650m",metadata={"path":"bionemo/models/esm2nv_650M_converted.nemo"},)artifact.add_file("/workspace/bionemo/models/esm2nv_650M_converted.nemo")run.log_artifact(artifact)# save datasetwith wandb.init(name="data_upload") as run:artifact = wandb.Artifact(name="downstream_taskdataset",type="dataset",description="bionemo/examples/tests/test_data/protein/downstream",metadata={"path":"/workspace/bionemo/examples/tests/test_data/protein/downstream"},)artifact.add_dir("/workspace/bionemo/examples/tests/test_data/protein/downstream")run.log_artifact(artifact)
Finetuning
最後に以下のコードを実行します。以下のdownstream_flip.pyは、上記でwandbのArtifactsに登録したデータやモデルをダウンロードして使えるように変更をしています。
なお、細かい設定については以下のyamlファイルで行うことができます。
/workspace/bionemo/examples/protein/esm2nv/conf/downstream_flip_sec_LORA.yaml
- restore_from_path: 事前学習済みのモデルのチェックポイントの .nemo ファイルのパスに設定します。
- trainer.devices, trainer.num_nodes: 使用する GPU とノードの数に設定します。
- trainer.max_epochs: トレーニングしたいエポック数に設定します。
- trainer.val_check_interval: 検証を実行するステップ数に設定します。
- model.micro_batch_size: トレーニングのマイクロバッチサイズに設定します。
- data.task_name: 任意の名前を設定します。
- data.task_type: 現在のオプションには、token-level-classification、classification (sequence level)、および regression (sequence level) があります。 preprocessed_data_path: dataset_path の親フォルダのパスに設定します。
- dataset_path: train/val/testフォルダが含まれるフォルダのパスに設定します。例えば、上記のpath/to/data というパスに設定します。
- dataset.train, dataset.val, dataset.test: CSV 名または範囲に設定します。
- sequence_column: シーケンスを含む列の名前に設定します。例:sequence
- target_column: ターゲットを含む列の名前に設定します。例:scl_label
- target_size: 分類のための各ラベルのクラス数。
- num_classes: target_size に設定します。
以下では、yamlファイルを上書きする形で、よく設定を変更したい変数をセットしています。
wandb_artifacts.wandb_use_artifact_data_pathは、使用するデータのwandb artifactsのpathです。
wandb_artifacts.wandb_use_artifact_model_pathは、使用するモデルのwandb artifactsのpathです。
!python examples/protein/downstream/downstream_flip.py\--config-path="../esm2nv/conf"\--config-name=downstream_sec_str_LORA\++trainer.max_epochs=15\++wandb_artifacts.wandb_use_artifact_data_path='${oc.env:WANDB_ENTITY}/${oc.env:WANDB_PROJECT}/downstream_taskdataset:v0'\++wandb_artifacts.wandb_use_artifact_model_path='${oc.env:WANDB_ENTITY}/${oc.env:WANDB_PROJECT}/esm2nv_650m:v0'\++model.data.dataset_path=/\++model.restore_encoder_path=/esm2nv_650M_converted.nemo
学習過程や設定はwandbに保存され、トレーニングされたモデルもwandbのartifactsに保存されます。以下は、wandbでトラックされた例です。
Run: esm2nv_flip_secondary_structure_finetuning_encoder_frozen_False
45
また、以下のようにfinetuningされたモデルはArtifactsでバージョン管理が可能になります。
model-mo32gf3o
Direct lineage view
今回、finetuningした後、testデータでの検証も行っていますが、10 epochほどでは精度が35.72とまだまだチャンスレートに近いレベルになっていることが確認でき、さらなるfinetuningが必要であることがわかります。wandbではtable機能を用いて、一つ一つのサンプルを保存して可視化することで深掘りもできるようになっています。
その方法についても今後このレポートでupdateしていきます。
最後に
このレポートでは、BioNeMoをこれから勉強する方向けにBioNeMoを用いたタンパク質言語モデルの事前学習とfinetuningの具体的な流れを紹介しました。また、BioNeMoはwandbとのintegrationが提供されていますが、さらに強固にwandbを使えるようなコードも提案し、その実装も紹介しました。創薬におけるAI活用をさらに進める貢献ができるレポートになっていれば幸いです。
このレポートに関する質問やwandbに関する質問は、contact-jp@wandb.comまでご連絡ください。
Add a comment