MONAI 1.0 : PyTorch ユーザのための MONAI (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/01/2022 (1.0.1)
* 本ページは、MONAI の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- 人工知能研究開発支援
- 人工知能研修サービス(経営者層向けオンサイト研修)
- テクニカルコンサルティングサービス
- 実証実験(プロトタイプ構築)
- アプリケーションへの実装
- 人工知能研修サービス
- PoC(概念実証)を失敗させないための支援
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
- 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
- sales-info@classcat.com ; Web: www.classcat.com ; ClassCatJP
MONAI 1.0 : PyTorch ユーザのための MONAI
このチュートリアルは MONAI API を簡単に紹介してその柔軟性と使い易さにハイライトを当てます。それは PyTorch の基本的な理解を前提とし、MONAI がヘルスケア画像処理における深層学習用にドメインに最適化された機能を提供する方法を示します。
パッケージのインストール
MONAI のコア機能は Python で書かれていて Numpy と Pytorch にのみ依存しています。
このセクションは MONAI の最新版をインストールしてインストールを検証します。
# install the latest weekly preview version of MONAI
%pip install -q "monai-weekly[tqdm, nibabel, gdown, ignite]"
import warnings
warnings.filterwarnings("ignore") # remove some scikit-image warnings
import monai
monai.config.print_config()
MONAI version: 0.10.dev2237 Numpy version: 1.21.6 Pytorch version: 1.12.1+cu113 MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False MONAI rev id: 533b9b8f56542f7cbca718e062271fd976c267c1 MONAI __file__: /usr/local/lib/python3.7/dist-packages/monai/__init__.py Optional dependencies: Pytorch Ignite version: 0.4.10 Nibabel version: 3.0.2 scikit-image version: 0.18.3 Pillow version: 7.1.2 Tensorboard version: 2.8.0 gdown version: 4.4.0 TorchVision version: 0.13.1+cu113 tqdm version: 4.64.1 lmdb version: 0.99 psutil version: 5.4.8 pandas version: 1.3.5 einops version: NOT INSTALLED or UNKNOWN VERSION. transformers version: NOT INSTALLED or UNKNOWN VERSION. mlflow version: NOT INSTALLED or UNKNOWN VERSION. pynrrd version: NOT INSTALLED or UNKNOWN VERSION. For details about installing the optional dependencies, please visit: https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies
数行のコードでパブリックな医用画像データセットへアクセス
公開されているベンチマークの使用はオープンで再現性のある研究のために重要です。MONAI は良く知られた公開データセットへの素早いアクセスを提供することを目的としています。このセクションは医療セグメンテーション・デカスロン (= Medical Segmentation Decathlon ) のデータセットから始めます。
DecathlonDataset オブジェクトは torch.data.utils.Dataset の薄いラッパーです。それは __getitem__ と __len__ を実装していて、PyTorch の組込みデータローダ torch.data.utils.DataLoader と完全に互換です。
PyTorch データセット API と比較して、DecathlonDataset は以下の追加機能を持ちます :
- 自動的なデータのダウンロードと解凍
- データと前処理の中間結果のキャッシング
- 訓練、検証とテストのランダムな分割
from monai.apps import DecathlonDataset
dataset = DecathlonDataset(root_dir="./", task="Task05_Prostate", section="training", transform=None, download=True)
print(f"\nnumber of subjects: {len(dataset)}.\nThe first element in the dataset is {dataset[0]}.")
2022-09-16 06:55:41,150 - INFO - Verified 'Task05_Prostate.tar', md5: 35138f08b1efaef89d7424d2bcc928db. 2022-09-16 06:55:41,152 - INFO - File exists: Task05_Prostate.tar, skipped downloading. 2022-09-16 06:55:41,156 - INFO - Non-empty folder exists in Task05_Prostate, skipped extracting. Loading dataset: 100%|██████████| 26/26 [00:00<00:00, 186095.40it/s] number of subjects: 26. The first element in the dataset is {'image': 'Task05_Prostate/imagesTr/prostate_46.nii.gz', 'label': 'Task05_Prostate/labelsTr/prostate_46.nii.gz'}.
コードセクションは公開レポジトリから "Task05_Prostate.tar" (download=True) をダウンロードして、それを解凍し、そしてアーカイブにより提供される JSON ファイルを解析することにより DecathlonDataset を作成しました。
これは前立腺 (= prostate) 移行 (= transitional) ゾーンと周辺 (= peripheral) ゾーンの輪郭を描く (= delineate) ための 3 クラス・セグメンテーション・タスクです (背景, TZ, PZ クラス)。入力は 2 つの様式、つまり T2 と ADC MRI を持ちます。
len(dataset) と dataset[0] は、それぞれデータセットのサイズを問い合わせ、データセットの最初の要素を取り出します。データセットのためのどのような画像変換も指定していませんので、この iterable なデータセットの出力は画像とセグメンテーション・ファイル名の単なるペアです。
柔軟な画像データ変換
このセクションはファイル名をメモリ内のデータ配列に変換する MONAI 変換を導入します、これにより深層学習モデルにより消費される準備ができます。前処理パイプラインのより多くのサンプルは tutorial レポジトリ と 開発者ガイド で利用可能です。ここでは画像前処理の主要な機能を簡単にカバーします。
配列 vs 辞書ベースの変換
配列変換は MONAI の基本的なビルディングブロックで、それは torchvision.transforms と同様な単純な callable です。2 つの違いがあります :
- MONAI 変換は医用画像特有の処理機能を実装しています。
- MONAI 変換は入力が numpy 配列、pytorch テンソルかテンソル like なオブジェクトであることを前提としています。
以下はローダー変換を開始します、これはファイル名文字列を実際の画像データに変換します。
この変換への より多くのオプションについてのドキュメント を参照してください。
from monai.transforms import LoadImage
loader = LoadImage(image_only=True)
img_array = loader("Task05_Prostate/imagesTr/prostate_02.nii.gz")
print(img_array.shape)
(320, 320, 24, 2)
辞書変換は配列バージョンのラッパーに過ぎません。配列ベースのものと比べて、同じ種類の演算やステートメントを複数のデータ入力に適用することがより簡単です。
以下のセクションは画像とセグメンテーション・マスクのペアを読みます、変換が辞書のどの項目が処理されるべきかを知れるようにキーが指定される必要があることに注意してください。
from monai.transforms import LoadImageD
dict_loader = LoadImageD(keys=("image", "label"))
data_dict = dict_loader({"image": "Task05_Prostate/imagesTr/prostate_02.nii.gz",
"label": "Task05_Prostate/labelsTr/prostate_02.nii.gz"})
print(f"image shape: {data_dict['image'].shape}, \nlabel shape: {data_dict['label'].shape}")
image shape: (320, 320, 24, 2), label shape: (320, 320, 24)
変換の構成
多くの場合、変換のチェインを構築して、前処理パラメータを調整して、高速な前処理パイプラインを作成することは有益です。monai.transforms.Compose はこれらのユースケースのために設計されています。
以下のコードは複数の前処理ステップを行なうために変換チェインを開始しています :
- Nifti 画像を (画像メタデータ情報と共に) ロードします
- 画像とラベルの両方をチャネル first にする (画像を reshape してラベルのためにチャネル次元を追加します)
- 画像とラベルを 1 mm 四方にする
- 画像とラベルの両方を "RAS" 座標系にあるようにする
- 画像強度をスケールする
- 画像とラベルを空間サイズ (64, 64, 32) mm にリサイズする
- 画像をランダムに回転とスケールしますが、出力サイズは (64, 64, 32) mm に保持します。
- 画像とラベルを torch テンソルに変換する
import numpy as np
from monai.transforms import \
LoadImageD, EnsureChannelFirstD, AddChannelD, ScaleIntensityD, ToTensorD, Compose, \
AsDiscreteD, SpacingD, OrientationD, ResizeD, RandAffineD
KEYS = ("image", "label")
xform = Compose([
LoadImageD(KEYS),
EnsureChannelFirstD("image"),
AddChannelD("label"),
OrientationD(KEYS, axcodes='RAS'),
SpacingD(KEYS, pixdim=(1., 1., 1.), mode=('bilinear', 'nearest')),
ScaleIntensityD(keys="image"),
ResizeD(KEYS, (64, 64, 32), mode=('trilinear', 'nearest')),
RandAffineD(KEYS, spatial_size=(-1, -1, -1),
rotate_range=(0, 0, np.pi/2),
scale_range=(0.1, 0.1),
mode=('bilinear', 'nearest'),
prob=1.0),
ToTensorD(KEYS),
])
data_dict = xform({"image": "Task05_Prostate/imagesTr/prostate_02.nii.gz",
"label": "Task05_Prostate/labelsTr/prostate_02.nii.gz"})
print(data_dict["image"].shape, data_dict["label"].shape)
(2, 64, 64, 32) (1, 64, 64, 32)
MONAI には有用な変換のセットがあり、今後更に増えます。詳細は https://docs.monai.io/en/latest/transforms.html を見てください。
データセット、変換とデータローダ
私達が持っているものをまとめると :
- Dataset : torch.utils.data.Dataset の薄いラッパー
- Transform : callable、Compose により作成される変換チェインの一部です。
- データセットへの変換のセッティングはデータロードと前処理パイプラインを可能にします。
パイプラインは pytorch ネイティブのデータローダと連携できて、これはマルチプロセッシングのサポートと柔軟なバッチサンプリング・スキームを提供します。
けれども、MONAI データローダ monai.data.DataLoader と連携することが推奨されます、これは pytorch ネイティブのラッパーです。MONAI データローダは以下の機能を主として追加します :
- マルチプロセスのコンテキストでランダム化された増強を正しく処理します。
- マルチサンプルデータのリストを個々の訓練サンプルに平坦化するためのカスタマイズされた collate 関数
DecathlonDataset の初期化は (非ランダム化) 変換結果のキャッシングを含みます。それは遅いかもしれません、複数エポックの訓練のために初期化されたオブジェクトを使用するとき、遥かに改良された速度のために空間を効果的にトレードオフします。
import torch
from monai.data import DataLoader
# start a chain of transforms
xform = Compose([
LoadImageD(KEYS),
EnsureChannelFirstD("image"),
AddChannelD("label"),
OrientationD(KEYS, axcodes='RAS'),
SpacingD(KEYS, pixdim=(1., 1., 1.), mode=('bilinear', 'nearest')),
ScaleIntensityD(keys="image"),
ResizeD(KEYS, (64, 64, 32), mode=('trilinear', 'nearest')),
RandAffineD(KEYS, spatial_size=(-1, -1, -1),
rotate_range=(0, 0, np.pi/2),
scale_range=(0.1, 0.1),
mode=('bilinear', 'nearest'),
prob=1.0),
ToTensorD(KEYS),
])
# start a dataset
dataset = DecathlonDataset(root_dir="./", task="Task05_Prostate", section="training", transform=xform, download=True)
# start a pytorch dataloader
# data_loader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, num_workers=1)
data_loader = DataLoader(dataset, batch_size=1, shuffle=True, num_workers=1)
2022-09-16 06:55:43,240 - INFO - Verified 'Task05_Prostate.tar', md5: 35138f08b1efaef89d7424d2bcc928db. 2022-09-16 06:55:43,241 - INFO - File exists: Task05_Prostate.tar, skipped downloading. 2022-09-16 06:55:43,246 - INFO - Non-empty folder exists in Task05_Prostate, skipped extracting. Loading dataset: 100%|██████████| 26/26 [00:21<00:00, 1.20it/s]
data_dict で何が起きているか覗いてみましょう (以下のセクションの再実行はデータセットからランダムに増強されたサンプルを生成します) :
import matplotlib.pyplot as plt
import numpy as np
data_dict = next(iter(data_loader))
print(data_dict["image"].shape, data_dict["label"].shape, data_dict["image_meta_dict"]["filename_or_obj"])
plt.subplots(1, 3)
plt.subplot(1, 3, 1); plt.imshow(data_dict["image"][0, 0, ..., 16])
plt.subplot(1, 3, 2); plt.imshow(data_dict["image"][0, 1, ..., 16])
plt.subplot(1, 3, 3); plt.imshow(data_dict["label"][0, 0, ..., 16])
plt.show()
print(f"unique labels: {np.unique(data_dict['label'])}")
(1, 2, 64, 64, 32) (1, 1, 64, 64, 32) ['Task05_Prostate/imagesTr/prostate_25.nii.gz']
データローダは、深層学習モデルに対応できるように、画像とラベルの両方にバッチ次元を追加しました。
ラベルのために "nearest" 補完モードが使用されますので、変換中に一意のクラスの数が保持されます。
層、ブロック、ネットワークと損失関数
データ入力パイプラインを通り抜けました。適切に前処理されたデータは、2 つの様式の入力を使用して 3 クラス・セグメンテーション・タスクのための準備ができました。
このセクションは UNet モデル、そして損失関数と optimzer を作成します。
これら総てのモジュールは (torch.nn.Module のような) PyTorch インターフェイスの直接的な使用か拡張です。それらは、コードが標準 PyTorch API に従うのであれば、任意のカスタマイズされた Python コードで置き換え可能です。
MONAI のモジュールは医用画像解析のために拡張モジュールを提供することに焦点を当てています :
- 柔軟性とコード可読性の両者を目的とした参照ネットワークの実装
- 1D, 2D と 3D ネットワークと互換な事前定義された層とブロック
- ドメイン固有の損失関数
from monai.networks.nets import UNet
from monai.networks.layers import Norm
from monai.losses import DiceLoss
device = torch.device('cuda:0')
net = UNet(dimensions=3, in_channels=2, out_channels=3, channels=(16, 32, 64, 128, 256),
strides=(2, 2, 2, 2), num_res_units=2, norm=Norm.BATCH).to(device)
loss = DiceLoss(to_onehot_y=True, softmax=True)
opt = torch.optim.Adam(net.parameters(), 1e-2)
UNet は dimensions パラメータで定義されます。それは Conv1d, Conv2d と Conv3d のような、pytorch API の空間次元の数を指定します。同じ実装で、1D, 2D, 3D とマルチモーダル訓練のために容易に構成できます。
torch.nn.Module の拡張としての UNet は特定の方法で体系化された MONAI ブロックと層のセットです。ブロックと層は、"Conv. + Feature Norm. + Activation" のような一般に使用される組合せのように、再利用可能なサブモジュールとして設計されています。
スライディング・ウィンドウ推論
この一般に使用されるモジュールについて、MONAI は単純な PyTorch ベースの実装を提供します、これはウィンドウサイズと入力モデル (これは torch.nn.Module 実装であり得ます) の仕様だけを必要とします。
以下のデモは、総ての空間位置を通して実行される (40, 40) 空間サイズ・ウィンドウを集約することにより、(1, 1, 200, 200) の入力画像上のスライディング・ウィンドウ推論の toy を示します。
roi_size, sw_batch_size と overlap パラメータをそれらのスライディング・ウィンドウ出力上のインパクトを見るために変更することができます。
from monai.inferers import SlidingWindowInferer
class ToyModel:
# A simple model generates the output by adding an integer `pred` to input.
# each call of this instance increases the integer by 1.
pred = 0
def __call__(self, input):
self.pred = self.pred + 1
input = input + self.pred
return input
infer = SlidingWindowInferer(roi_size=(40, 40), sw_batch_size=1, overlap=0)
input_tensor = torch.zeros(1, 1, 200, 200)
output_tensor = infer(input_tensor, ToyModel())
plt.imshow(output_tensor[0, 0]); plt.show()
訓練ワークフローの開始 (エポック毎に検証)
入力パイプライン、ネットワーク・アーキテクチャ、損失関数は総て既存の pytorch ベースのワークフローと互換です。様々なユースケースについてはチュートリアルを参照してください : https://github.com/Project-MONAI/tutorials
ここで PyTorch-Ignite ベースで MONAI により構築された、ワークフロー・ユティリティにハイライトを当てたいです。主要な目標は、比較的標準的な訓練ワークフローを構築する際にユーザの労力を軽減することです。
import ignite
print(ignite.__version__)
0.4.10
以下のコマンドは SupervisedTrainer インスタンスを起動します。PyTorch ignite の機能の拡張として、それは前述した総ての要素を結合します。trainer.run() の呼び出しは 2 エポックの間ネットワークを訓練して、総てのエポックの最後に訓練データに基づいて MeadDice メトリックを計算します。
key_train_metric はモデルの品質向上の進捗を追跡するために使用されます。追加のハンドラが早期停止と学習率スケジューリングを行なうために設定できます。
StatsHandler は診断情報を stdout にプリントするために訓練反復毎にトリガーされます。これらはユーザ指定の頻度で詳細な訓練ログを生成するように構成できます。
イベント処理システムの詳細は、ドキュメント https://docs.monai.io/en/latest/handlers.html を参照してください。
注目すべき点は、これらの機能は通常の訓練と検証パイプラインの高速なプロトタイピングを容易にすることです。ユーザは前のセクションで述べたモジュールを利用して、独自のパイプラインを構築することを常に選択できます。
from monai.engines import SupervisedTrainer
from monai.inferers import SlidingWindowInferer
from monai.handlers import StatsHandler, MeanDice, from_engine
from monai.transforms import AsDiscreteD
import sys
import logging
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
trainer = SupervisedTrainer(
device=device,
max_epochs=2,
train_data_loader=data_loader,
network=net,
optimizer=opt,
loss_function=loss,
inferer=SlidingWindowInferer((32, 32, -1), sw_batch_size=2),
postprocessing=AsDiscreteD(keys=["pred", "label"], argmax=(True, False), to_onehot=3),
key_train_metric={"train_meandice": MeanDice(output_transform=from_engine(["pred", "label"]))},
train_handlers=StatsHandler(tag_name="train_loss", output_transform=from_engine(["loss"], first=True)),
)
trainer.run()
INFO:ignite.engine.engine.SupervisedTrainer:Engine run resuming from iteration 0, epoch 0 until 2 epochs INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 1/26 -- train_loss: 0.8139 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 2/26 -- train_loss: 0.7707 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 3/26 -- train_loss: 0.6901 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 4/26 -- train_loss: 0.6979 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 5/26 -- train_loss: 0.7192 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 6/26 -- train_loss: 0.6859 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 7/26 -- train_loss: 0.6445 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 8/26 -- train_loss: 0.6273 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 9/26 -- train_loss: 0.6346 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 10/26 -- train_loss: 0.6078 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 11/26 -- train_loss: 0.5424 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 12/26 -- train_loss: 0.5851 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 13/26 -- train_loss: 0.5647 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 14/26 -- train_loss: 0.5551 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 15/26 -- train_loss: 0.5925 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 16/26 -- train_loss: 0.5389 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 17/26 -- train_loss: 0.5662 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 18/26 -- train_loss: 0.6309 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 19/26 -- train_loss: 0.6168 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 20/26 -- train_loss: 0.5556 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 21/26 -- train_loss: 0.5243 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 22/26 -- train_loss: 0.5801 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 23/26 -- train_loss: 0.5132 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 24/26 -- train_loss: 0.4951 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 25/26 -- train_loss: 0.4870 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 1/2, Iter: 26/26 -- train_loss: 0.5108 INFO:ignite.engine.engine.SupervisedTrainer:Got new best metric of train_meandice: 0.4181462824344635 INFO:ignite.engine.engine.SupervisedTrainer:Epoch[1] Metrics -- train_meandice: 0.4181 INFO:ignite.engine.engine.SupervisedTrainer:Key metric: train_meandice best value: 0.4181462824344635 at epoch: 1 INFO:ignite.engine.engine.SupervisedTrainer:Epoch[1] Complete. Time taken: 00:00:08 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 1/26 -- train_loss: 0.5620 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 2/26 -- train_loss: 0.5373 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 3/26 -- train_loss: 0.4764 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 4/26 -- train_loss: 0.5111 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 5/26 -- train_loss: 0.5922 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 6/26 -- train_loss: 0.5519 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 7/26 -- train_loss: 0.6246 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 8/26 -- train_loss: 0.4363 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 9/26 -- train_loss: 0.5052 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 10/26 -- train_loss: 0.5900 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 11/26 -- train_loss: 0.5997 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 12/26 -- train_loss: 0.4996 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 13/26 -- train_loss: 0.4969 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 14/26 -- train_loss: 0.5740 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 15/26 -- train_loss: 0.5852 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 16/26 -- train_loss: 0.5460 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 17/26 -- train_loss: 0.5034 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 18/26 -- train_loss: 0.5233 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 19/26 -- train_loss: 0.5109 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 20/26 -- train_loss: 0.4877 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 21/26 -- train_loss: 0.5745 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 22/26 -- train_loss: 0.5044 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 23/26 -- train_loss: 0.4623 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 24/26 -- train_loss: 0.4399 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 25/26 -- train_loss: 0.4553 INFO:ignite.engine.engine.SupervisedTrainer:Epoch: 2/2, Iter: 26/26 -- train_loss: 0.5245 INFO:ignite.engine.engine.SupervisedTrainer:Got new best metric of train_meandice: 0.4688393473625183 INFO:ignite.engine.engine.SupervisedTrainer:Epoch[2] Metrics -- train_meandice: 0.4688 INFO:ignite.engine.engine.SupervisedTrainer:Key metric: train_meandice best value: 0.4688393473625183 at epoch: 2 INFO:ignite.engine.engine.SupervisedTrainer:Epoch[2] Complete. Time taken: 00:00:08 INFO:ignite.engine.engine.SupervisedTrainer:Engine run complete. Time taken: 00:00:16
決定論的訓練
決定論的訓練サポートは再現可能な研究のために重要です。MONAI は現在 2 つのメカニズムを提供しています :
- 総てのランダム変換のランダム状態を設定します。これはグローバルなランダム状態には影響しません。例えば :
# define a transform chain for pre-processing train_transforms = monai.transforms.Compose([ LoadImaged(keys=['image', 'label']), RandRotate90d(keys=['image', 'label'], prob=0.2, spatial_axes=[0, 2]), ... ... ]) # set determinism for reproducibility train_transforms.set_random_state(seed=0)
- 1 行のコードでグローバルに python, numpy と pytorch のための決定論的訓練を有効にします、例えば :
monai.utils.set_determinism(seed=0, additional_settings=None)
まとめ
MONAI の主要なモジュールを通り抜けてきました。高度に柔軟な拡張とラッパーを作成することにより、MONAI は医用画像解析の観点から pytorch API を強化しています。
以下のような、この短いチュートリアルではカバーされなかったソフトウェア機能があります :
- 後処理変換
- 視覚化インターフェイス
- サードパーティの医用画像ツールキットからの組み込めるデータ変換
- 他の人気のある深層学習フレームワークを使用するワークフローの構築
- MONAI 研究
最新のマイルストーンのハイライトの詳細については、https://docs.monai.io/en/latest/highlights.html にアクセスしてください。
MONAI を深く理解するには、examples レポジトリは良い開始点です : https://github.com/Project-MONAI/tutorials
API ドキュメントについては、https://docs.monai.io にアクセスしてください。
以上