Amazon Web Services ブログ

Amazon SageMaker で DICOM イメージのアノテーションとMONAI フレームワークを使用した機械学習モデルを構築する

この記事は、“Annotate DICOM images and build an ML model using the MONAI framework on Amazon SageMaker” を翻訳したものです。

DICOM(Digital Imaging and Communications in Medicine)は、X線やMRIの画像と関連するメタデータを含む画像形式です。DICOMは、X線やMRIの表示と解釈を行う医療専門家および医療研究者のための標準です。この投稿の目的は、次の2つの問題を解決することです。

  • Amazon SageMaker Ground Truth は、組み込みまたはカスタムのデータラベリングワークフローをサポートするフルマネージド型のデータのラベリングサービスです。 カスタムのデータラベリングワークフローを使用してDICOM 画像を表示しラベル付けをします。
  • クラウド上で機械学習 (ML) モデルを準備、構築、トレーニング、デプロイするための専用ツールを備えた、包括的でフルマネージド型のデータサイエンスプラットフォームであるAmazon SageMakerMONAI フレームワークを使用して DenseNet 画像分類モデルを開発します。

この記事では、DICOM形式の胸部X線画像と、関連する放射線レポートをフリーテキストファイルとして公開しているMIMIC Chest X-Ray (MIMIC-CXR) Databaseに含まれる、胸部X線DICOM画像データセットを使用しています。ファイルにアクセスするには、ユーザー登録をして、データ使用契約書に署名する必要があります。

画像のラベル付けは、Ground Truth プライベートワークフォースを通じて行います。AWS は、医用画像のラベル付けの経験をもつプロフェッショナルなマネージドワーカーを提供することもできます。

ソリューションの概要

次の図は、以下の主要コンポーネントを含むハイレベルのワークフローを示しています。

  1. DICOM画像は、サードパーティの画像アーカイブ通信システム(PACS)またはベンダーニュートラルアーカイブ(VNA)に保存され、 DicomWeb TM を介して取得されます。
  2. 入力 となるmanifest.json ファイルを Amazon Simple Storage Service (Amazon S3) にアップロードします。このファイルには、データソースとして DICOMインスタンスID と、ラベル付けジョブの実行時にアノテータが使用する可能性のあるラベルが含まれます。
  3. Ground Truthでラベリングジョブを作成するには、次の 2 つの AWS Lambda 関数が必要です。
  1. ラベル付けジョブを送信し、出力オブジェクトを処理するための Crowd 要素を含む HTML テンプレートです。その後、ラベル付けジョブの出力は、出力ラベル S3 バケットに保存されます。
  2. SageMaker ノートブックは、ラベル付けジョブの出力を取得し、それらを使用して教師あり ML モデルをトレーニングできます。

私たちは、胸部X線DICOM画像を13の急性や慢性の心肺疾患の可能性から1つ以上のカテゴリに分類するための HTML テンプレートを構築しました。cornerstone.js の上に構築された HTML テンプレートは、DICOM 画像の取得と対話型の画像表示に加えて、いくつかのアノテーションと例にあるような一般的なCornerstone toolsをサポートしています。
次のセクションでは、DICOM データのラベリングワークフローの構築と、ラベリングジョブの出力を使用して ML モデルトレーニングを実行します。

サードパーティのPACS をAWS にデプロイする

この投稿では、オープンソースのOrthanc を軽快に動作する PACS として使用します。それでは他のPACS や VNAがサポートしているDicomWeb TM を使用できます。次の AWS CloudFormation スタックを起動して、 Orthanc for Docker コンテナを AWSにデプロイできます。

ホスティングする EC2 インスタンスおよびネットワークインフラストラクチャ(VPC と Subnets)にアクセスするための Amazon Elastic Compute Cloud(Amazon EC2)キーペアなど、デプロイ時に必要な情報を入力します。コンテナに NGINX サーバーが追加され、 HTTPS トラフィックをポート 8042 の Orthanc サーバーにプロキシします。これにより、クロスオリジンリソース共有 (CORS)用のアクセスコントロール許可-オリジンヘッダーも追加されます。Orthanc コンテナは Amazon Elastic Container Service (Amazon ECS) にデプロイされ、Amazon Aurora PostgreSQL データベースに接続されます。

CloudFormation スタックが正常に作成されたら、[Outputs] タブの Orthanc エンドポイント URL を書き留めます。

Lambda 関数、S3 バケット、および SageMaker ノートブックインスタンスの作成

次の CloudFormation スタックは、適切な AWS Identity and Access Management(IAM)ロール、入出力ファイル用のS3 バケット、サンプル Jupyter ノートブックを含む SageMaker ノートブックインスタンスを使用して、必要な Lambda 関数を作成します。

パラメータ PreLabelLambdaSourceEndpointURL には、前のステップの Orthanc エンドポイント URL を入力します。これは、プレラベリングタスク Lambda 関数が特定の DICOMインスタンスID の WADO-URI を生成するために使用します。イメージアノテーションの後に ML モデリングを実行するには、インスタンスタイプ ml.m5.xlarge のノートブックを作成することをお勧めします。

スタックのデプロイ後、 SMGTLabelingExecutionRole および SageMakerAnnotationS3Bucket の値を含む出力をメモします。

IAM ロール SMGTLabelingExecutionRole は、GroundTruthラベリングジョブを作成するために使用されます。これらのポリシーの追加方法と、CloudFormation スタックの起動後にGroundTruthラベリングジョブを実行する方法に関するステップバイステップのチュートリアルについては、Amazon SageMaker Ground Truth を使用したカスタムデータラベリングワークフローの構築を参照してください。

DICOM 画像をアップロードし、入力マニフェストを準備する

DICOM画像は、Web UI または WADO-RS REST API を使用して Orthanc サーバーにアップロードできます。(訳注 : Orthancサーバーの認証情報については、Orthanc Bookを参照ください。) DICOM画像をアップロードした後、それらの DICOMインスタンスID を取得し、インスタンスID を含むマニフェストファイルを生成できます。マニフェストファイル内の標準改行で区切られた各 JSON オブジェクトは、ラベル付けのためのワークフォースに送信される入力タスクを表します。この場合のデータオブジェクトには、インスタンスIDと可能性のあるラベルのメタデータ、画像で特定される 13 の疾病が含まれています。1つのDICOMインスタンス IDが502b0a4b-5cb43965-7f092716-bd6fe6d6-4f7fc3ceであると仮定すると、マニフェストファイル内の対応するJSONオブジェクトは次のようになります。(訳注 : Orthancに登録済のDICOMインスタンスIDはOrthancのエンドポイントに/instancesでリストを取得できます)

{"source": "502b0a4b-5cb43965-7f092716-bd6fe6d6-4f7fc3ce", "labels": "Atelectasis,Cardiomegaly,Consolidation,Edema,Enlarged Cardiomediastinum,Fracture,Lung Lesion,Lung Opacity,Pleural Effusion,Pneumonia,Pneumothorax,Pleural Other,Support Devices,No Finding"}

manifest.json ファイルを作成したら(訳注: 上記のDICOMインスタンスIDとラベルの候補を含むデータを画像数分の行を含むmanifest.jsonファイルとして作成する必要があります。) 、先に作成した S3 バケット (SageMakerAnnotationS3Bucket) にアップロードします。

カスタムのデータラベリングジョブを作成:

これで、Ground Truth でカスタムラベリングジョブを作成できるようになります。

  1. プライベートワークチームを作成し、メンバーをチームに追加します。

作業者は、ラベル付けポータルのサインイン URL が記載された E メールを受信します。これは Amazon SageMaker コンソールでも見つけることができます。

AWS では、お客様のデータのラベル付けを行う医用画像の専門家も用意しています。詳細については、AWS チームにお問い合わせください。

  1. 前に作成した SageMakerAnnotationS3Bucket バケットを使用して、入力および出力データの場所を指定します。
  2. SMGTLabelingExecutionRole をラベリングジョブの IAM ロールとして指定します。
  3. [Task] カテゴリで、[Custom] を選択します。

  1. liquid.html のコンテンツを [カスタムテンプレート] テキストフィールドに入力します。
  2. 前に作成した gt-prelabel-task-lambda および gt-postlabel-task-lambda 関数を設定します。
  3. [Create] を選択します。

  1. カスタムラベリングタスクを構成したら、[Preview] を選択します。

次のビデオは、プレビューを示しています。

プライベートワークフォースを作成した場合は、[ワークフォースのラベル付け] タブに移動して、アノテーションのコンソールリンクを見つけることができます。

ベース HTML テンプレートを使うか、画像、テキスト、およびオーディオデータのラベル付けジョブのGround Truth タスク UI のサンプルを変更して開始できます。カスタムテンプレートの基本的な構成要素はCrowd HTML 要素です。Ground Truth にアノテーションを送信するには、crowd-formcrowd-bottonが不可欠です。さらに、ジョブ自動化のために、テンプレートに Liquid オブジェクト、特に、 Lambda の事前ラベル付け関数で読み込まれるタスク入力オブジェクトが必要です。

<div id="document-text" style="display: none;"
    {{ task.input.text }}
</div>
<div id="document-image"  style="display:none;">
    {{ task.input.taskObject }}
</div>
<div id="document-labels">
    {{ task.input.labels }}
</div>

Cornerstone JavaScript ライブラリを使用して、HTML5 canvas要素をサポートする最新のウェブブラウザで DICOM 画像を表示するラベリング UI を構築し、Cornerstone ツールを使用してインタラクションをサポートし、さまざまな形状の関心領域 (ROI) アノテーションを有効にします。さらに、Cornerstone WADO Image Loaderを使用して、リモートのOrthancサーバのDICOMWeb プラグインを介して Web Access DICOM Object (WADO) URI への Web アクセスを取得します。

DICOM画像の取得と表示には、次の 2 つの機能が重要です。

  • DownloadAndView()cornerstone.js ファイルが画像ローダーを見つけることができるように、URL の先頭にwadouri: を追加します。
  • loadAndViewImage() — Cornerstoneライブラリを使用して画像を表示し、ズーム、パン、ROI アノーテーションなどの追加機能を使用できます。

次のカスタム HTML テンプレートを使用して、任意の DICOM画像に注釈を付けることができます。このテンプレートには、画像分類タスクの複数のオプション選択肢として使用可能なラベルがリストされます。

MONAI フレームワークを使用して ML モデルを構築

output-manifest.json ファイルの形式でラベル付きデータセットができたので、ML モデルの構築プロセスを開始できます。SageMaker ノートブックインスタンスは、以前のスタックデプロイメントを通じて作成しました。または、新しいノートブックインスタンスを作成することもできます。MONAI ライブラリとその他の追加パッケージはトレーニングスクリプトの同じフォルダにある requirements.txt で管理されます。

データのロードと前処理

Jupyter ノートブックを開いた後、DICOMのURLとラベルを含むoutput-manifest.json ファイルをロードします。
次の dicom_training.ipynb からの例は、output-manifest.jsonに含まれるラベル付きデータセット をパースします。

# Get SageMaker Ground Truth labeling data from annotation file
datadir = 'data'
metadata = '{}/output-manifest.json'.format(datadir)
s3 = boto3.client('s3')
s3.download_file(bucket, bucket_path, metadata)

# Load Labels
with open(metadata) as f:
    manifest = json.load(f)
    class_names = list(json.loads(manifest[0]['annotations'][0]['annotationData']['content'])['disease'].keys())
    
for i, j in enumerate(manifest):
    label_dict = json.loads(json.loads(manifest[i]['annotations'][0]['annotationData']['content'])['labels'])
    image_url_list.extend([label_dict['imageurl']])
    image_label_list.extend([class_names.index(label_dict['label'][0])])

これで、DICOMのURL が image_url_list に、対応するラベルが image_label_list にあるので、SageMaker のトレーニングのために Orthanc DICOM サーバーから Amazon S3 に直接DICOMファイルをダウンロードできます。

import urllib3
import requests
import os
from io import BytesIO
import contextlib;

image_file_list = []

#Load DICOM images to S3
for i, j in enumerate(image_url_list):
    file_name = image_url_list[i].split("/file")[0].split("instances/")[1] + '.dcm'
    response = requests.get(image_url_list[i], auth=(user, password), stream=True, verify=False)
    fp = BytesIO(response.content)
    s3.upload_fileobj(fp, bucket, file_name)   
    image_file_list.append(file_name)

S3 バケットに画像をロードした後、MONAI フレームワークを使用して、パースされた JSON ファイルのラベル付きの画像のサンプルを表示できます。

import monai
from monai.transforms import Compose, LoadImage, Resize, SqueezeDim
import matplotlib.pyplot as plt

#Display sample of DICOM Images
trans = Compose([LoadImage(image_only=True), Resize(spatial_size=(108,96)),SqueezeDim()])
plt.subplots(1, 3, figsize=(8, 8))
for i in range(0,3):
    s3.download_file(bucket, image_file_list[i], datadir+'/'+image_file_list[i])
    img = trans(datadir+'/'+image_file_list[i])
    plt.subplot(1, 3, i + 1)
    plt.xlabel(class_names[image_label_list[i]])
    plt.imshow(img, cmap='gray')
plt.tight_layout()
plt.show()

次の図は、ラベル付きの DICOM画像の出力例を示しています。

モデルトレーニング中に MONAI 変換を使用して、DICOM ファイルを直接ロードして前処理します。MONAIには、辞書と配列形式の両方をサポートする変換があり、DICOM医用画像の高次元に特化しています。変換には、くり抜きと余白、輝度、I/O、後処理、空間、ユーティリティなど、いくつかのカテゴリが含まれます。次の抜粋では、Compose クラスが一連のイメージ変換をチェーンし、イメージの単一のテンソルを返します。

#Load and transform DICOM images
class DICOMDataset(Dataset):

    def __init__(self, image_files, labels, transforms):
        self.image_files = image_files
        self.labels = labels
        self.transforms = transforms

    def __len__(self):
        return len(self.image_files)

    def __getitem__(self, index):
        return self.transforms(self.image_files[index]), self.labels[index]

train_transforms = Compose([
    LoadImage(image_only=True),
    ScaleIntensity(),
    RandRotate(range_x=15, prob=0.5, keep_size=True),
    RandFlip(spatial_axis=0, prob=0.5),
    RandZoom(min_zoom=0.9, max_zoom=1.1, prob=0.5, keep_size=True),
    Resize(spatial_size=(108,96)),
    ToTensor()
])
    
dataset = DICOMDataset(trainX, trainY, train_transforms)

train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) if is_distributed else None

train_loader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=train_sampler is None,
                                       sampler=train_sampler, **kwargs)
…

モデルトレーニング

MONAIには、U-Net、DenseNetやGANなのディープニューラルネットワークが含まれており、大量の医用画像に対してスライディングウィンドウ推論を提供します。DICOM 画像分類モデルでは、前のステップでDataLoader クラスを使用してロードおよび変換された DICOM 画像を使って、損失を測定しながら、MONAI DenseNet モデルを10エポック分トレーニングします。次のコードを参照してください。

#Instantiate model	
device = torch.device("cuda")
model = densenet121(
    spatial_dims=spatial_dims_num,
    in_channels=in_channels_num,
    out_channels=out_channels_num
).to(device)
loss_function = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), 1e-5)

#Train DICOM model
for epoch in range(epoch_num):
    
    model.train()
    epoch_loss = 0
    step = 0
    for batch_data in train_loader:
        step += 1
        inputs, labels = batch_data[0].to(device), batch_data[1].to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = loss_function(outputs, labels)
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
        
        epoch_len = len(train_loader.dataset) // train_loader.batch_size        
    epoch_loss /= step
    epoch_loss_values.append(epoch_loss)

次の例は、Jupyter ノートブックで SageMaker Python SDK を使用してトレーニングジョブをインスタンス化し、DICOM モデルトレーニングスクリプトを実行する方法を示しています。

inputs = sagemaker_session.upload_data(path=datadir, bucket=bucket)

from sagemaker.pytorch import PyTorch

estimator = PyTorch(entry_point='monai_dicom.py',
                    source_dir='source',
                    role=role,
                    framework_version='1.5.0',
                    py_version='py3',
                    instance_count=1,
                    instance_type='ml.m5.xlarge',
                    hyperparameters={
                        'backend': 'gloo',
                        'epochs': 10
                    })

estimator.fit({'train': inputs})

この例の fit メソッドを呼び出すと、 instance_type パラメーターに基づく計算機サイズでトレーニングインスタンスを起動し、組み込みの PyTorch ディープラーニングコンテナをインスタンス化し、requirements.txtの中にある MONAI 依存パッケージをインストールします。そして、 entry_point='monai_dicom.py'パラメータで参照されるトレーニングスクリプトを実行します。

SageMaker 内で MONAI フレームワークを使用して医用画像モデルを構築およびデプロイする方法の詳細については、「MONAI フレームワークを使用して Amazon SageMaker で医用画像解析パイプラインを構築する」を参照してください。その他のカスタムデータラベリングワークフローの詳細については、「Amazon SageMaker Ground Truth を使用したカスタムデータラベリングワークフローの構築」を参照してください。

まとめ

この記事は、Ground Truth を使用して DICOM カスタムラベリングワークフローを構築する方法を説明しました。さらに、ラベリングワークフローから生成された出力マニフェストファイルを取得し、それをラベル付きデータセットとして使用し、MONAI フレームワークを使用して DenseNet 画像分類モデルを構築する方法を説明しました。

この投稿について何かコメントや質問がある場合は、コメントセクションを使用してください。このソリューションの最新の開発を見つけるには、 GitHub リポジトリをチェックしてください。

翻訳は Solutions Architect 今井と窪田が担当しました。原文はこちらです。