Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

大きな多重解像度イメージの深層学習による分類

この例では、Inception-v3 深層ニューラル ネットワークに学習させて、メモリに収まらない多重解像度のスライド ガラス標本全体のイメージ (WSI) を分類する方法を説明します。

この例では、Inception-v3 腫瘍分類ネットワークに学習させる方法を説明し、さらに事前学習済みの Inception-v3 ネットワークも示します。Inception-v3 ネットワークの学習を選択した場合、Compute Capability 3.0 以上の CUDA 対応 NVIDIA™ GPU を使用します。GPU を使用するには Parallel Computing Toolbox™ が必要です。

はじめに

乳癌を診断するための唯一の決定的な方法は、生体組織検査または外科手術において収集した組織サンプルの検査です。サンプルは、組織内の構造のコントラストを高めるために、一般にヘマトキシリンとエオシン (H&E) による染色で処理されます。従来から、病理学者は、スライド ガラスに載せた組織を顕微鏡で検査して、腫瘍組織を検出しています。病理学者はスライド全体を大きな倍率で入念に検査しなければならないため、診断には時間がかかります。さらに、病理学者が小さい腫瘍を見落とす場合があります。深層学習の手法は、腫瘍組織の検出の自動化により、検出時間の短縮と小さい腫瘍の検出率向上を目的としています。

腫瘍分類のための深層学習の手法は、組織を載せたスライド全体を撮像してデジタル化するデジタル病理学に依存しています。結果として得られる WSI は非常に高解像度です。WSI は、イメージの表示、ナビゲーション、処理を容易にするために、多重解像度ファイルに頻繁に格納されます。

WSI では、イメージ全体をメモリに読み込むことができないため、読み取りが困難であり、アウトオブコアのイメージ処理手法が必要です。Image Processing Toolbox™ の bigimage オブジェクトでは、このタイプの大きな多重解像度イメージを格納および処理できます。bigimageDatastore オブジェクトを使用すると、ニューラル ネットワークに供給する学習パッチを bigimage から準備できます。

この例では、bigimagebigimageDatastore を使用して、深層学習ネットワークに学習させ、非常に大きな多重解像度イメージ内の腫瘍を分類する方法を説明します。この例では、分類結果を、局所的な組織が腫瘍性である確率を示すヒートマップとして表示します。腫瘍領域の位置推定により、病理学者は特定の領域を調査して、イメージ内の任意サイズの腫瘍を迅速に識別できます。

学習データのダウンロード

この例では Camelyon16 チャレンジの WSI を使用します [1]。このチャレンジのデータには、2 つの独立したソースによるリンパ節の WSI が合計 400 個含まれており、270 個の学習イメージと 130 個のテスト イメージに分かれています。WSI は、11 レベルのピラミッド構造をもつストリップ形式の TIF ファイルとして格納されています。

ストリップ形式では処理速度が低下するため、イメージにこの形式が含まれる場合、bigimage オブジェクトによって警告が表示されます。コマンド ウィンドウに警告が表示されるのを避けるには、この例の実行中は警告をオフにし、完了時に警告状態を元に戻します。

warningState = warning('off','images:bigimage:singleStripTiff');
c = onCleanup(@()warning(warningState));

学習データセットは、正常なリンパ節の 159 個の WSI と、腫瘍組織と正常組織を含むリンパ節の 111 個の WSI で構成されています。通常、腫瘍組織の割合は正常組織に比べるとごくわずかです。腫瘍イメージには病変境界のグラウンド トゥルース座標が付属しています。

各学習ファイルのサイズは約 2 GB です。学習データセットをダウンロードしない、またはネットワークに学習させない場合、この例のテスト データのダウンロードと前処理の節に進みます。

学習データセットを格納するディレクトリを作成します。

trainingImageDir = fullfile(tempdir,'Camelyon16','training');
if ~exist(trainingImageDir,'dir')
    mkdir(trainingImageDir);
    mkdir(fullfile(trainingImageDir,'normal'));
    mkdir(fullfile(trainingImageDir,'tumor'));
    mkdir(fullfile(trainingImageDir,'lesion_annotations'));
end

trainNormalDataDir = fullfile(trainingImageDir,'normal');
trainTumorDataDir = fullfile(trainingImageDir,'tumor');
trainTumorAnnotationDir = fullfile(trainingImageDir,'lesion_annotations');

学習データをダウンロードするには、Camelyon17 の Web サイトに移動し、最初の [CAMELYON16 data set] リンクをクリックします。"training" ディレクトリを開き、以下の手順に従います。

  • "lesion_annotations.zip" ファイルをダウンロードします。変数 trainTumorAnnotationDir で指定されたディレクトリにファイルを解凍します。

  • "normal" ディレクトリを開きます。変数 trainNormalDataDir で指定されたディレクトリにイメージをダウンロードします。

  • "tumor" ディレクトリを開きます。変数 trainTumorDataDir で指定されたディレクトリにイメージをダウンロードします。

学習イメージの数を指定します。正常組織の学習イメージの 1 つ 'normal_144.tif' には、bigimage オブジェクトで読み取ることができないメタデータが含まれているので注意してください。この例では、残りの 158 個の学習ファイルを使用します。

numNormalFiles = 158;
numTumorFiles = 111; 

学習データの可視化

学習データをより深く理解するために、1 つの学習イメージを表示します。最も細かい解像度でイメージ全体をメモリに読み込むことはできないため、imshow などの通常のイメージ表示関数は使用できません。イメージ データを表示および処理するには、bigimage オブジェクトを使用します。

腫瘍の学習イメージから bigimage オブジェクトを作成します。

tumorFileName = fullfile(trainTumorDataDir,'tumor_001.tif');
tumorImage = bigimage(tumorFileName);

各解像度レベルで bigimage の次元を検査します。レベル 1 には最も多くのピクセルが含まれており、これは最も細かい解像度レベルです。レベル 10 は、含まれているピクセルの数が最も少なく、最も粗い解像度レベルです。縦横比には一貫性がありません。これは、レベル間で、広がるワールド領域が異なることを示します。

levelSizeInfo = table((1:length(tumorImage.LevelSizes))', ...
    tumorImage.LevelSizes(:,1), ...
    tumorImage.LevelSizes(:,2), ...
    tumorImage.LevelSizes(:,1)./tumorImage.LevelSizes(:,2), ...
    'VariableNames',["Resolution Level" "Image Width" "Image Height" "Aspect Ratio"])
levelSizeInfo=11×4 table
    Resolution Level    Image Width    Image Height    Aspect Ratio
    ________________    ___________    ____________    ____________

            1           2.2118e+05        97792           2.2618   
            2           1.1059e+05        49152             2.25   
            3                55296        24576             2.25   
            4                27648        12288             2.25   
            5                13824         6144             2.25   
            6                 7168         3072           2.3333   
            7                 3584         1536           2.3333   
            8                 2048         1024                2   
            9                 1024          512                2   
           10                  512          512                1   
           11                 1577         3629          0.43455   

関数 bigimageshow を使用して、粗い解像度レベルで bigimage を表示します。bigimageshow オブジェクトのハンドルを返します。このハンドルを使用して表示を調整できます。このイメージには、空の白色の領域が多数含まれています。この組織は、イメージのごく一部のみを占めています。

h = bigimageshow(tumorImage,'ResolutionLevel',7);

最も細かい解像度レベルに対して水平方向と垂直方向の空間範囲を設定して、イメージの一部分を拡大します。この解像度レベルは非常に粗いため、イメージは不鮮明に見えます。

xlim([29471,29763]);
ylim([117450,118110]);

詳細を確認するには、解像度レベルをより細かいレベルに変更します。

h.ResolutionLevel = 1;

マスクの作成

関心領域 (ROI) のみを処理して、計算量を減らすことができます。マスクを使用して ROI を定義します。マスクは、true ピクセルが ROI を表す論理イメージです。

計算量をさらに減らすには、ブロック単位で処理する代わりに、全体をメモリ内で処理できる粗い解像度レベルのマスクを作成します。粗い解像度レベルの空間参照が、より細かい解像度レベルの空間参照に一致する場合、粗いレベルの位置は、細かいレベルの位置に対応します。この場合、粗いマスクを使用して、より細かいレベルで処理するブロックを選択できます。詳細については、大きなイメージの空間参照の設定マスクを使用した大きなイメージの効率的な処理を参照してください。

マスクの作成に使用する解像度レベルを指定します。この例では、粗く、メモリに収まる解像度レベル 7 を使用します。

resolutionLevel = 7;

正常イメージのマスクの作成

正常イメージでは、ROI は正常組織で構成されています。正常組織の色は背景の色と異なるので、色のしきい値処理を使用して、イメージをセグメント化し、ROI を作成します。L*a*b* 色空間はセグメンテーションの色分離に最適です。イメージを L*a*b* 色空間に変換してから、a* チャネルにしきい値処理を行い、組織マスクを作成します。

補助関数 createMaskForNormalTissue を使用することにより、色のしきい値処理を使用してマスクを作成できます。この補助関数は、この例にサポート ファイルとして添付されています。

この補助関数は、正常組織の各学習イメージに対して以下の操作を実行します。

  • TIF イメージ ファイルから bigimage オブジェクトを作成します。

  • イメージ メタデータから、すべての解像度レベルの空間参照を設定します。

  • 粗い解像度レベルのイメージを取得します。

  • 粗いイメージを L*a*b* 色空間に変換し、a* チャネルを抽出します。

  • 黒と白のピクセルの間の級内分散を最小にする Otsu 法を使用してイメージをしきい値処理することにより、バイナリ イメージを作成します。

  • マスクから単一解像度の bigimage オブジェクトを作成し、入力イメージの空間参照と一致するようにマスクの空間参照を設定します。

  • マスクの bigimage をメモリに書き込みます。この bigimage オブジェクトのみがメモリ内にあります。logical マスク イメージに対応する個々のイメージ ブロックは、一時ディレクトリにあります。ディレクトリへの書き込みにより、カスタムの空間参照は維持されます。そのため、正常イメージとそれらに対応するマスク イメージの空間参照が同じであることが保証されます。

trainNormalMaskDir = fullfile(trainNormalDataDir,['normal_mask_level' num2str(resolutionLevel)]);
createMaskForNormalTissue(trainNormalDataDir,trainNormalMaskDir,resolutionLevel)

正常イメージとマスクがどちらもディスク上にあるので、bigimage オブジェクトを作成し、補助関数 createBigImageAndMaskArrays を使用してそれらのデータを管理します。この関数は正常イメージから bigimage オブジェクトの配列を作成し、正常マスク イメージから対応する bigimage オブジェクトの配列を作成します。この補助関数は、この例にサポート ファイルとして添付されています。

[bigNormalImages,bigNormalMasks] = createBigImageAndMaskArrays(trainNormalDataDir,trainNormalMaskDir);

サンプルの正常イメージとマスクを選択します。マスクの空間ワールド範囲が、最も細かい解像度レベルのイメージの範囲に一致することを確認します。空間ワールド範囲は XWorldLimits プロパティと YWorldLimits プロパティによって指定されます。

idx = 2;
bigNormalImages(idx).SpatialReferencing(1)
ans = 
  imref2d with properties:

           XWorldLimits: [0 97792]
           YWorldLimits: [0 221184]
              ImageSize: [221184 97792]
    PixelExtentInWorldX: 1
    PixelExtentInWorldY: 1
    ImageExtentInWorldX: 97792
    ImageExtentInWorldY: 221184
       XIntrinsicLimits: [0.5000 9.7793e+04]
       YIntrinsicLimits: [0.5000 2.2118e+05]

bigNormalMasks(idx).SpatialReferencing(1)
ans = 
  imref2d with properties:

           XWorldLimits: [0 97792]
           YWorldLimits: [0 221184]
              ImageSize: [3456 1527]
    PixelExtentInWorldX: 64.0419
    PixelExtentInWorldY: 64
    ImageExtentInWorldX: 97792
    ImageExtentInWorldY: 221184
       XIntrinsicLimits: [0.5000 1.5275e+03]
       YIntrinsicLimits: [0.5000 3.4565e+03]

マスクに正しい ROI と空間参照が含まれていることを確認します。関数 bigimageshow を使用してサンプル イメージを表示します。この表示を含む座標軸を取得します。

figure
hBigNormal = bigimageshow(bigNormalImages(idx));
hNormalAxes = hBigNormal.Parent;

表示された bigimage の上に新しい座標軸を作成します。新しい座標軸で、部分的に透明な対応するマスク イメージを表示します。このマスクは、正常組織を含む領域を強調表示します。

hMaskAxes = axes;
hBigMask = bigimageshow(bigNormalMasks(idx),'Parent',hMaskAxes, ...
    'Interpolation','nearest','AlphaData',0.5);
hMaskAxes.Visible = 'off';

イメージの座標軸とマスクの座標軸をリンクさせます。ズームやパンを行うと、両方の座標軸がまったく同じように更新されます。

linkaxes([hNormalAxes,hMaskAxes]);

水平方向と垂直方向の空間範囲を設定して、イメージの一部分を拡大します。マスクは正常組織に適切に重なります。

xlim([45000 80000]);
ylim([130000 165000]);

腫瘍イメージのマスクの作成

腫瘍イメージの場合、ROI は腫瘍組織で構成されています。腫瘍組織の色は正常組織の色と似ているため、色のセグメンテーション手法を使用できません。代わりに、腫瘍イメージに付属している病変境界のグラウンド トゥルース座標を使用して ROI を作成します。

補助関数 createMaskForTumorTissue を使用すると、ROI を使用してマスクを作成できます。この補助関数は、この例にサポート ファイルとして添付されています。

この補助関数は、腫瘍組織の各学習イメージに対して以下の操作を実行します。

  • TIF イメージ ファイルから bigimage オブジェクトを作成します。

  • イメージ メタデータから空間参照を設定します。

  • XML ファイル内の対応する病変注釈を読み取り、注釈を多角形 (Polygon オブジェクト) に変換します。

  • 各イメージ ブロックごとに、多角形データを使用して対応するブロックのマスクを作成します。腫瘍領域を含むイメージの中に、正常領域が含まれている可能性があります。正常組織の注釈を使用して、それらの領域を除外します。

  • 粗い解像度レベルで出力用の logical マスク bigimage オブジェクトを作成します。関数 setBlock を使用してブロック単位でマスク イメージを書き込みます。

  • マスク bigimage オブジェクトをメモリ内のディレクトリに書き込みます。この bigimage オブジェクトのみがメモリ内にあります。logical マスク イメージに対応する個々のイメージ ブロックは、一時ディレクトリにあります。ディレクトリへの書き込みにより、カスタムの空間参照は維持されます。そのため、腫瘍イメージとそれらに対応するマスク イメージの空間参照が同じであることが保証されます。

trainTumorMaskDir = fullfile(trainTumorDataDir,['tumor_mask_level' num2str(resolutionLevel)]);
createMaskForTumorTissue(trainTumorDataDir,trainTumorAnnotationDir, ...
    trainTumorMaskDir,resolutionLevel);

腫瘍イメージとマスクがどちらもディスク上にあるので、bigimage オブジェクトを作成し、補助関数 createBigImageAndMaskArrays を使用してそれらのデータを管理します。この関数は腫瘍イメージから bigimage オブジェクトの配列を作成し、腫瘍マスク イメージから対応する bigimage オブジェクトの配列を作成します。この補助関数は、この例にサポート ファイルとして添付されています。

[bigTumorImages,bigTumorMasks] = createBigImageAndMaskArrays(trainTumorDataDir,trainTumorMaskDir);

サンプルの腫瘍イメージとマスクを選択します。マスクの空間ワールド範囲が、最も細かい解像度レベルのイメージの範囲に一致することを確認します。空間ワールド範囲は XWorldLimits プロパティと YWorldLimits プロパティによって指定されます。

idx = 5;
bigTumorImages(idx).SpatialReferencing(1)
ans = 
  imref2d with properties:

           XWorldLimits: [0 97792]
           YWorldLimits: [0 219648]
              ImageSize: [219648 97792]
    PixelExtentInWorldX: 1
    PixelExtentInWorldY: 1
    ImageExtentInWorldX: 97792
    ImageExtentInWorldY: 219648
       XIntrinsicLimits: [0.5000 9.7793e+04]
       YIntrinsicLimits: [0.5000 2.1965e+05]

bigTumorMasks(idx).SpatialReferencing(1)
ans = 
  imref2d with properties:

           XWorldLimits: [0 97792]
           YWorldLimits: [0 219648]
              ImageSize: [3432 1527]
    PixelExtentInWorldX: 64.0419
    PixelExtentInWorldY: 64
    ImageExtentInWorldX: 97792
    ImageExtentInWorldY: 219648
       XIntrinsicLimits: [0.5000 1.5275e+03]
       YIntrinsicLimits: [0.5000 3.4325e+03]

マスクに正しい ROI と空間参照が含まれていることを確認します。関数 bigimageshow を使用してサンプル イメージを表示します。この表示を含む座標軸を取得します。

figure
hBigTumor = bigimageshow(bigTumorImages(idx));
hTumorAxes = hBigTumor.Parent;

表示された大きなイメージの上に新しい座標軸を作成します。新しい座標軸で、部分的に透明な対応するマスク イメージを表示します。このマスクは、正常組織を含む領域を強調表示します。

hMaskAxes = axes;
hBigMask = bigimageshow(bigTumorMasks(idx),'Parent',hMaskAxes, ...
    'Interpolation','nearest','AlphaData',0.5);
hMaskAxes.Visible = 'off';

イメージの座標軸とマスクの座標軸をリンクさせます。ズームやパンを行うと、両方の座標軸がまったく同じように更新されます。

linkaxes([hTumorAxes,hMaskAxes]);

水平方向と垂直方向の空間範囲を設定して、イメージの一部分を拡大します。マスクは腫瘍組織に適切に重なります。

xlim([45000 65000]);
ylim([130000 150000]);

学習と検証のための大きなイメージ データストアの作成

bigimage オブジェクトから学習データのパッチを抽出するには、bigimageDatastore を使用します。このデータストアは、単一解像度レベルの bigimage データのパッチを読み取ります。

生の学習パッチの色の不均衡とクラスの不均衡によって、ネットワークにバイアスが生じる可能性があります。色の不均衡は、組織の色の染色が一様でないことに起因します。色の不均衡は、データ内の腫瘍組織と正常組織の量が等しくないことに起因します。これらの不均衡を修正するには、データストアを前処理して拡張します。

この例では、ネットワークに学習させるための腫瘍パッチと正常パッチを抽出する bigimageDatastore を作成する方法を説明します。また、データストアを前処理および拡張して、ネットワークに生じるバイアスを避ける方法も説明します。

読み取る正常組織パッチの場所の選択

正常イメージと対応するマスクを 2 つのセットにランダムに分割します。検証セットには、ランダムに選択された 2 つのイメージと対応するマスクが格納されています。学習セットには、残りのイメージとマスクが格納されています。

normalValidationIdx = randi(numNormalFiles,[1 2]);
normalTrainIdx = setdiff(1:numNormalFiles,normalValidationIdx);

パッチ サイズはイメージ内の特徴のサイズに比べて小さくなります。既定では、bigimageDatastore は重なりや隙間なくパッチを抽出します。これにより、膨大な量の学習パッチが生成されます。パッチのサブセットを指定することによって、学習データの量を減らすことができます。関数 selectBlockLocations を使用してパッチの座標を指定します。名前と値の引数 BlockOffsets を使用して、サンプリングされた学習パッチ間に隙間を追加します。パッチ サイズより大きいオフセットを指定します。比較的一様なパッチでネットワークに学習させるために、包含しきい値を既定値の 0.5 より大きくします。

patchSize = [299,299,3];
normalStrideFactor = 10;
blsNormalData = selectBlockLocations(bigNormalImages(normalTrainIdx), ...
    "BlockSize",patchSize(1:2),"BlockOffsets",patchSize(1:2)*normalStrideFactor, ...
    "Masks",bigNormalMasks(normalTrainIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

読み取る検証パッチの場所を選択します。検証イメージは数が少ないため、パッチ間に隙間を追加する必要はありません。

blsNormalDataValidation = selectBlockLocations(bigNormalImages(normalValidationIdx), ...
    "BlockSize",patchSize(1:2), ...
    "Masks",bigNormalMasks(normalValidationIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

正常イメージのデータストアの作成

それぞれ学習と検証のために最も細かい解像度レベルの正常イメージからイメージ パッチを読み取るデータストア dsNormalDatadsNormalDataValidation を作成します。名前と値のペアの引数 BlockLocationSet を使用してパッチの座標を指定します。

dsNormalData = bigimageDatastore(bigNormalImages(normalTrainIdx), ...
    "BlockLocationSet",blsNormalData);
dsNormalDataValidation = bigimageDatastore(bigNormalImages(normalValidationIdx), ...
    "BlockLocationSet",blsNormalDataValidation);

正常部分の学習イメージを含むデータストアからパッチをプレビューします。

imagesToPreview = zeros([patchSize 10],'uint8');
for n = 1:10
    im = read(dsNormalData);
    imagesToPreview(:,:,:,n) = im{1};
end
figure
montage(imagesToPreview,'Size',[2 5],'BorderSize',10,'BackgroundColor','k');
title("Training Patches of Normal Tissue")

読み取る腫瘍組織パッチの場所の選択

腫瘍イメージと対応するマスクを 2 つのセットにランダムに分割します。検証セットには、ランダムに選択された 2 つのイメージと対応するマスクが格納されています。学習セットには、残りのイメージとマスクが格納されています。

tumorValidationIdx = randi(numTumorFiles,[1 2]);
tumorTrainIdx = setdiff(1:numTumorFiles,tumorValidationIdx);

関数 selectBlockLocations を使用して、読み取るパッチの座標を指定します。腫瘍組織は正常組織よりもスパースに分布しているため、通常組織よりも小さいブロック オフセットを指定してサンプリング密度を大きくします。少ない数の学習イメージを使用して学習させる場合、ブロック オフセットをさらに減らして学習セットのサイズを増やすことが必要な場合があることに注意してください。

tumorStrideFactor = 4;
blsTumorData = selectBlockLocations(bigTumorImages(tumorTrainIdx), ...
    "BlockSize",patchSize(1:2),"BlockOffsets",patchSize(1:2)*tumorStrideFactor, ...
    "Masks",bigTumorMasks(tumorTrainIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

読み取る検証パッチの場所を選択します。検証イメージは数が少ないため、パッチ間に隙間を追加する必要はありません。

blsTumorDataValidation = selectBlockLocations(bigTumorImages(tumorValidationIdx), ...
    "BlockSize",patchSize(1:2), ...
    "Masks",bigTumorMasks(tumorValidationIdx),"InclusionThreshold",0.75,"ExcludeIncompleteBlocks",true);

腫瘍イメージのデータストアの作成

学習用の腫瘍イメージとマスクから bigimageDatastore を作成します。データストア dsTumorDatadsTumorDataValidation は、それぞれ学習と検証のために最も細かい解像度レベルの腫瘍イメージからイメージ パッチを読み取ります。

dsTumorData = bigimageDatastore(bigTumorImages(tumorTrainIdx), ...
    "BlockLocationSet",blsTumorData);
dsTumorDataValidation = bigimageDatastore(bigTumorImages(tumorValidationIdx), ...
    "BlockLocationSet",blsTumorDataValidation);

腫瘍の学習イメージを含むデータストアからパッチをプレビューします。

imagesToPreview = zeros([patchSize 10],'uint8');
for n = 1:10
    im = read(dsTumorData);
    imagesToPreview(:,:,:,n) = im{1};
end
montage(imagesToPreview,'Size',[2 5],'BorderSize',10,'BackgroundColor','k');
title("Training Patches of Tumor Tissue")

色の正規化と学習データの拡張

データセットは異なるソースから入手されており、また、同じ色で組織を染色しても染色のされ方はイメージごとに異なるため、学習イメージごとに色の分布は異なります。ネットワークのバイアスを避けるために、追加の前処理が必要です。

色のばらつきを防ぐため、この例では標準的な染色の正規化手法を使用してデータを前処理します。関数 transform を、補助関数 augmentAndLabel によって指定されたカスタム前処理演算と共に使用して、染色の正規化と拡張を適用します。この関数は、この例にサポート ファイルとして添付されています。

関数 augmentAndLabel は以下の操作を実行します。

  • 関数 normalizeStaining.m を使用して染色を正規化します [4]。Macenko の手法を使用して、染色の正規化を実行します。この手法では、固定された行列を使用する色の逆畳み込みによって H&E カラー チャネルを分離し、個別に修正された混合を使用して正規化されたイメージを再作成します。関数は、正規化されたイメージと H&E イメージを返します。

  • 関数 jitterColorHSV を使用してカラー ジッターを追加します。カラー ジッターは、イメージのコントラスト、色相、彩度、および明度に摂動を加えることによって各パッチの色を変化させます。RGB イメージ内の不要な色のアーティファクトを避けるため、カラー ジッターは HSV 色空間で実行します。

  • 90 度回転と垂直方向および水平方向の反転のランダムな組み合わせを適用します。ランダムなアフィン変換により、入力イメージ データの方向がネットワークに反映されなくなります。

  • パッチに 'normal' または 'tumor' のラベルを付けます。

各イメージ パッチから、拡張されてラベルが付けられた 5 つのパッチが生成されます。それらのパッチは、染色が正規化されたパッチ、染色が正規化されカラー ジッターが適用されたパッチ、染色が正規化されカラー ジッターとランダムなアフィン変換が適用されたパッチ、ランダムなアフィン変換が適用されたヘマトキシリン イメージ、およびランダムなアフィン変換が適用されたエオシン イメージです。

正常部分の学習イメージと検証イメージを変換するデータストアを作成し、生成されたパッチに 'normal' のラベルを付けます。

dsLabelledNormalData = transform(dsNormalData, ...
    @(x,info)augmentAndLabel(x,info,'normal'),'IncludeInfo',true);
dsLabelledNormalDataValidation = transform(dsNormalDataValidation, ...
    @(x,info)augmentAndLabel(x,info,'normal'),'IncludeInfo',true);

腫瘍の学習イメージと検証イメージを変換するデータストアを作成し、生成されたパッチに 'tumor' のラベルを付けます。

dsLabelledTumorData = transform(dsTumorData, ...
    @(x,info)augmentAndLabel(x,info,'tumor'),'IncludeInfo',true);
dsLabelledTumorDataValidation = transform(dsTumorDataValidation, ...
    @(x,info)augmentAndLabel(x,info,'tumor'),'IncludeInfo',true);

腫瘍クラスと正常クラスのバランス調整

腫瘍イメージ内の癌組織の量は、正常組織の量に比べて非常に小さくなります。大量の正常組織とごくわずかの腫瘍組織を含む、クラスが不均衡なデータでネットワークに学習させるのを回避するために、追加の前処理が必要です。

クラスの不均衡を防ぐため、この例では、バランスの取れた方法で正常部分の学習パッチと腫瘍の学習パッチをランダムに選択する randomSamplingDatastore という名前のカスタム データストアを定義します。このカスタム データストアを定義するスクリプトは、この例にサポート ファイルとして添付されています。詳細については、カスタム データ ストアの開発を参照してください。

正常部分および腫瘍の学習データストアからカスタムの randomSamplingDatastore を作成します。無作為抽出データストア dsTrain は、エポックの各反復で学習データのミニバッチをネットワークに提供します。

dsTrain = randomSamplingDatastore(dsLabelledTumorData,dsLabelledNormalData);

検証中に使用するパッチの数を制限するため、この例では、各クラスから 5 つの検証パッチを返す validationDatastore という名前のカスタム データストアを定義します。このカスタム データストアを定義するスクリプトは、この例にサポート ファイルとして添付されています。

正常部分および腫瘍の検証データストアからカスタムの validationDatastore を作成します。

numValidationPatchesPerClass = 5;
dsValidation = validationDatastore(dsLabelledTumorDataValidation, ...
    dsLabelledNormalDataValidation,numValidationPatchesPerClass);

Inception-v3 ネットワーク層の設定

この例では、Inception-v3 ネットワークを使用します。このネットワークは、ImageNet データベースの 100 万枚を超えるイメージで学習済みの畳み込みニューラル ネットワークです [3]。このネットワークは、深さが 48 層であり、イメージを 1,000 個のオブジェクト カテゴリ (キーボード、マウス、鉛筆、多くの動物など) に分類できます。このネットワークでは、3 チャネルで 299 行 299 列のイメージ入力サイズを想定しています。

関数 inceptionv3 (Deep Learning Toolbox) は、事前学習済みの Inception-v3 ネットワークを返します。Inception-v3 には、Deep Learning Toolbox™ Model for Inception-v3 Network サポート パッケージが必要です。このサポート パッケージがインストールされていない場合、関数によってダウンロード用リンクが表示されます。

net = inceptionv3;

最後の層の置き換え

ネットワークの畳み込み層は、入力イメージを分類するために、最後の学習可能な層と最終分類層が使用するイメージの特徴を抽出します。これらの 2 つの層は、ネットワークによって抽出された特徴を組み合わせてクラス確率、損失値、および予測ラベルにまとめる方法に関する情報を含んでいます。新しいイメージを分類するために事前学習済みのネットワークを再学習させるには、これら 2 つの層を新しいデータセットに適応させた新しい層に置き換えます。詳細については、新しいイメージを分類するための深層学習ネットワークの学習 (Deep Learning Toolbox)を参照してください。

学習済みのネットワークから層グラフを抽出します。

lgraph = layerGraph(net);

サポート関数 findLayersToReplace を使用して、置き換える 2 つの層の名前を見つけます。この関数は、この例にサポート ファイルとして添付されています。Inception-v3 では、これら 2 つの層の名前は 'predictions''ClassificationLayer_predictions' です。

[learnableLayer,classLayer] = findLayersToReplace(lgraph)
learnableLayer = 
  FullyConnectedLayer with properties:

          Name: 'predictions'

   Hyperparameters
     InputSize: 2048
    OutputSize: 1000

   Learnable Parameters
       Weights: [1000×2048 single]
          Bias: [1000×1 single]

  Show all properties

classLayer = 
  ClassificationOutputLayer with properties:

            Name: 'ClassificationLayer_predictions'
         Classes: [1000×1 categorical]
      OutputSize: 1000

   Hyperparameters
    LossFunction: 'crossentropyex'

この例の目的は、2 つのクラス (腫瘍領域と非腫瘍領域) 間でバイナリ セグメンテーションを実行することです。2 つのクラスの新しい全結合層を作成します。元の最後の全結合層を新しい層に置き換えます。

numClasses = 2;
newLearnableLayer = fullyConnectedLayer(numClasses,'Name','predictions');
lgraph = replaceLayer(lgraph,learnableLayer.Name,newLearnableLayer);

2 つのクラスの新しい分類層を作成します。元の最後の分類層を新しい層に置き換えます。

newClassLayer = classificationLayer('Name','ClassificationLayer_predictions');
lgraph = replaceLayer(lgraph,classLayer.Name,newClassLayer);

学習オプションの指定

rmsprop 最適化ソルバーを使用してネットワークに学習させます。このソルバーは、収束を高速化するために学習率とモーメンタムを自動的に調整します。関数 trainingOptions (Deep Learning Toolbox) を使用して、その他のハイパーパラメーター設定を指定します。大量の学習データによってネットワークがすぐに収束に到達するため、MaxEpochs を小さい値に減らします。Parallel Computing Toolbox™ と、マルチ GPU または並列学習に使用できるハードウェア リソースがある場合、名前と値のペアの引数 ExecutionEnvironment をそれぞれ 'multi-gpu' または 'parallel' に指定して、学習を高速化できます。

checkpointsDir = fullfile(trainingImageDir,'checkpoints');
if ~exist(checkpointsDir,'dir')
    mkdir(checkpointsDir);
end

options = trainingOptions('rmsprop', ...
    'InitialLearnRate',1e-5, ...
    'SquaredGradientDecayFactor',0.99, ...
    'MaxEpochs',3, ...
    'MiniBatchSize',32, ...
    'Plots','training-progress', ...
    'CheckpointPath',checkpointsDir, ... 
    'ValidationData',dsValidation, ...
    'ExecutionEnvironment','auto', ...
    'Shuffle','every-epoch');

テスト データのダウンロードと前処理

Camelyon16 テスト データセットは 130 個の WSI で構成されています。これらのイメージには、正常組織と腫瘍組織の両方が含まれています。この例では Camelyon16 テスト データの 2 つのテスト イメージを使用します。各ファイルのサイズは約 2 GB です。

テスト データを格納するディレクトリを作成します。

testingImageDir = fullfile(tempdir,'Camelyon16','testing');
if ~exist(testingImageDir,'dir')
    mkdir(testingImageDir);
    mkdir(fullfile(testingImageDir,'images'));
    mkdir(fullfile(testingImageDir,'lesion_annotations'));
end

testDataDir = fullfile(testingImageDir,'images');
testTumorAnnotationDir = fullfile(testingImageDir,'lesion_annotations');

テスト データをダウンロードするには、Camelyon17 の Web サイトに移動し、最初の [CAMELYON16 data set] リンクをクリックします。"testing" ディレクトリを開き、以下の手順に従います。

  • "lesion_annotations.zip" ファイルをダウンロードします。変数 testTumorAnnotationDir で指定されたディレクトリに、すべてのファイルを解凍します。

  • "images" ディレクトリを開きます。最初の 2 つのファイル "test_001.tif" と "test_002.tif" をダウンロードします。変数 testDataDir で指定されたディレクトリにファイルを移動します。

テスト イメージの数を指定します。

numTestFiles = 2;

テスト イメージのマスクの作成

テスト イメージには、正常イメージと腫瘍イメージの混合が含まれています。分類中の計算量を減らすために、マスクを作成して ROI を定義します。

マスクの作成に使用する解像度レベルを指定します。この例では、粗く、メモリに収まる解像度レベル 7 を使用します。

resolutionLevel = 7;

組織を含む領域のマスクを作成します。補助関数 createMaskForNormalTissue を使用することにより、色のしきい値処理を使用してマスクを作成できます。この補助関数は、この例にサポート ファイルとして添付されています。この補助関数の詳細については、正常イメージのマスクの作成を参照してください。

testTissueMaskDir = fullfile(testDataDir,['test_tissuemask_level' num2str(resolutionLevel)]);
createMaskForNormalTissue(testDataDir,testTissueMaskDir,resolutionLevel);

腫瘍組織を含むイメージのマスクを作成します。腫瘍組織を含まないイメージをスキップします。補助関数 createMaskForTumorTissue を使用することにより、ROI オブジェクトを使用してマスクを作成できます。この補助関数は、この例にサポート ファイルとして添付されています。この補助関数の詳細については、腫瘍イメージのマスクの作成を参照してください。

testTumorMaskDir = fullfile(testDataDir,['test_tumormask_level' num2str(resolutionLevel)]);
createMaskForTumorTissue(testDataDir,testTumorAnnotationDir,testTumorMaskDir,resolutionLevel);

ネットワークの学習

学習オプションとデータ ソースを構成した後、関数 trainNetwork を使用して Inception-v3 ネットワークに学習させます。既定では、この例は補助関数 downloadTrainedCamelyonNet を使用して、このデータセット用に事前学習済みバージョンの Inception-v3 ネットワークをダウンロードします。この補助関数は、この例にサポート ファイルとして添付されています。この事前学習済みのネットワークを使用することで、学習の完了を待たずに例全体を実行できます。

メモ: NVIDIA™ Titan X での学習には 20 時間を要します。ご使用の GPU ハードウェアによっては、さらに長い時間がかかる可能性もあります。

doTraining = false;
if doTraining
    trainedNet = trainNetwork(dsTrain,lgraph,options);
    save(['trainedCamelyonNet-' datestr(now, 'dd-mmm-yyyy-HH-MM-SS') '.mat'],'trainedNet');
else
    trainedCamelyonNet_url = 'https://www.mathworks.com/supportfiles/vision/data/trainedCamelyonNet.mat';
    netDir = fullfile(tempdir,'Camelyon16');
    downloadTrainedCamelyonNet(trainedCamelyonNet_url,netDir);
    load(fullfile(netDir,'trainedCamelyonNet.mat'));
end
Downloading pretrained Inception-v3 network for Cameylon16 data.
This can take several minutes to download...
Done.

テスト データの分類とヒートマップの作成

テスト イメージの分類には GPU を使用することを強くお勧めします (Parallel Computing Toolbox™ が必要)。

各テスト イメージには、正常組織を示すマスクと腫瘍組織を示すマスクの 2 つのマスクが含まれています。bigimage オブジェクトを作成し、補助関数 createBigImageAndMaskArrays を使用してテスト データとマスクを管理します。この補助関数は、この例にサポート ファイルとして添付されています。

[bigTestImages,bigTestTissueMasks] = createBigImageAndMaskArrays(testDataDir,testTissueMaskDir);
[~,bigTestTumorMasks] = createBigImageAndMaskArrays(testDataDir,testTumorMaskDir);

学習済みの Inception-v3 ネットワークを使用して、テスト イメージ bigTestImages 内の腫瘍パッチを識別します。関数 apply を、補助関数 createHeatMap によって指定されたカスタム処理パイプラインと共に使用して、ブロック単位でテスト イメージを分類します。この補助関数は、この例にサポート ファイルとして添付されています。必要な計算量を減らすために、関数 apply が組織を含むパッチのみを処理するように組織マスク bigTestTissueMask を指定します。Parallel Computing Toolbox™ と GPU がある場合、名前と値のペアの引数 'UseParallel'true に指定して、ブロックを並列に評価できます。

関数 createHeatMap は、各組織ブロックに対して以下の操作を実行します。

  • 関数 predict (Deep Learning Toolbox) を使用して腫瘍確率スコアを計算します。

  • 腫瘍確率スコアに等しいピクセル値を使用して、ヒートマップ イメージ パッチを作成します。

関数 apply は、各ブロックのヒートマップをつなぎ合わせて、テスト イメージの単一のヒートマップを作成します。ヒートマップは、ネットワークが、腫瘍を含む領域を検出した場所を示します。

ヒートマップを可視化するために、元のイメージの上にヒートマップを重ね合わせ、透明度 'AlphaData' プロパティを組織マスクとして設定します。この重ね合わせは、腫瘍がイメージ内でどの程度局在化しているかを示します。腫瘍である確率が高い領域は赤のピクセルで表示されています。腫瘍である確率が低い領域は青のピクセルで表示されています。

patchSize = [299,299,3];

for idx = 1:numTestFiles
    bigTestHeatMaps(idx) = apply(bigTestImages(idx),1,@(x)createHeatMap(x,trainedNet), ...
        'Mask',bigTestTissueMasks(idx),'InclusionThreshold',0, ...
        'BlockSize',patchSize(1:2),'UseParallel',false);
    
    figure
    hBigTest = bigimageshow(bigTestImages(idx));
    hTestAxes = hBigTest.Parent;
    hTestAxes.Visible = 'off';
        
    hMaskAxes = axes;
    hBigMask = bigimageshow(bigTestHeatMaps(idx),'Parent',hMaskAxes, ...
        "Interpolation","nearest","AlphaData",bigTestTissueMasks(idx));
    colormap(jet(255));
    hMaskAxes.Visible = 'off';
    
    linkaxes([hTestAxes,hMaskAxes]);
    title(['Tumor Heatmap of Test Image ',num2str(idx)])
end

参考文献

[1] Ehteshami B. B., et al. "Diagnostic Assessment of Deep Learning Algorithms for Detection of Lymph Node Metastases in Women With Breast Cancer." Journal of the American Medical Association. Vol. 318, No. 22, 2017, pp. 2199–2210. doi:10.1001/jama.2017.14585

[2] Szegedy, C., V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna. "Rethinking the Inception Architecture for Computer Vision." In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, 2818–2826. Las Vegas, NV: IEEE, 2016.

[3] ImageNet. http://www.image-net.org.

[4] Macenko, M., et al. "A Method for Normalizing Histology Slides for Quantitative Analysis." In 2009 IEEE International Symposium on Biomedical Imaging: From Nano to Macro, 1107–1110. Boston, MA: IEEE, 2009.

[5] xml2struct https://www.mathworks.com/matlabcentral/fileexchange/28518-xml2struct.

参考

| | | | (Deep Learning Toolbox) | (Deep Learning Toolbox)

関連するトピック