Main Content

勾配属性の手法を使用した分類判定の調査

この例では、勾配属性マップを使用して、深層ニューラル ネットワークによって分類の判定が行われる際にイメージのどの部分が最も重要かを調査する方法を説明します。

深層ニューラル ネットワークはブラック ボックスの意思決定者のように見えることがあります。複雑な問題に対して素晴らしい成果が得られますが、ネットワークが特定の出力を返す理由を理解するのが難しいことがあります。深層ネットワークの用途が広がるにつれ、説明可能性はますます重要になります。ネットワークを説明可能であると見なすには、ネットワークが入力データのどの部分を使用して決定を下し、そのデータがネットワークの出力にどれだけ寄与したかが明確でなければなりません。

さまざまな可視化の手法によって、分類の判定に入力データの妥当な部分がネットワークで使用されたかどうかを判断することができます。この例で示される勾配属性の手法に加えて、勾配加重クラス活性化マッピング (Grad-CAM) やオクルージョン感度のような手法を使用できます。以下の例を参照してください。

この例で説明する勾配属性手法では、ネットワークの分類にとってどのピクセルが最も重要かを示すピクセル解像度マップを使用します。マップは入力ピクセルに対するクラス スコアの勾配を計算します。マップにより、変更時にどのピクセルがクラス スコアに最も影響を与えるかを直感的に理解できます。勾配属性手法は Grad-CAM やオクルージョン感度よりも高解像度のマップを作成しますが、ノイズが多くなる傾向にあります。これは、適切に学習された深層ネットワークは特定のピクセルの正確な値に強く依存しないためです。勾配属性手法を使用して、イメージの中で分類に重要な範囲を探します。

最もシンプルな勾配属性マップは、入力イメージの各ピクセルに対する予測クラスのクラス スコアの勾配です [1]。これは、どのピクセルがクラス スコアに最も大きく影響するかを示し、したがってどのピクセルが分類に最も重要かがわかります。この例では、勾配属性と 2 つの拡張手法 (ガイド付き逆伝播 [2] と積分勾配 [3]) の使用方法を示します。これらの拡張がモデルに提供できる洞察の量が明確でないため、これらの手法の使用については議論されています [4]。

事前学習済みのネットワークとイメージの読み込み

事前学習済みの GoogLeNet ネットワークを読み込みます。

net = googlenet;

イメージの入力サイズとネットワークの出力クラスを抽出します。

inputSize = net.Layers(1).InputSize(1:2);
classes = net.Layers(end).Classes;

イメージを読み込みます。イメージは Laika という名前の犬です。イメージのサイズをネットワークの入力サイズに変更します。

img = imread("laika_grass.jpg");
img = imresize(img,inputSize);

イメージを分類して、予測クラスと分類スコアを表示します。

[YPred, scores] = classify(net, img);
[score, classIdx] = max(scores);

predClass = classes(classIdx);

imshow(img);
title(sprintf("%s (%.2f)",string(predClass),score));

ネットワークによって Laika はミニチュア プードルと分類されました。これは妥当な推測です。彼女はプードルとコッカー スパニエルの雑種です。

自動微分を使用した勾配属性マップの計算

勾配属性の手法は、入力イメージに対する予測スコアの勾配の判定に依存します。勾配属性マップは次の式で計算されます。

Wxyc=ScIxy

ここで、Wxyc はクラス c の予測における位置 (x,y) のピクセルの重要度、Sc はそのクラスのソフトマックス スコア、Ixy は位置 (x,y) のピクセルのイメージをそれぞれ表します [1]。

ネットワークを dlnetwork に変換し、自動微分を使用して勾配を計算できるようにします。

lgraph = layerGraph(net);
lgraph = removeLayers(lgraph,lgraph.Layers(end).Name);

dlnet = dlnetwork(lgraph);

ソフトマックス層の名前 'prob' を指定します。

softmaxName = 'prob';

自動微分を使用するには、Laika のイメージを dlarray に変換します。

dlImg = dlarray(single(img),'SSC');

dlfeval 関数および gradientMap 関数 (この例のサポート関数セクションで定義) を使用して微分 ScIxy を計算します。関数 gradientMap はネットワークにイメージを渡し、クラス スコアを取得し、dlgradient を呼び出してそのイメージに対するスコアの勾配を評価します。

dydI = dlfeval(@gradientMap,dlnet,dlImg,softmaxName,classIdx);

属性マップ dydI は 227 x 227 x 3 の配列です。各チャネルの各要素は、元の RGB イメージのそのチャネルについて、入力イメージに対するクラス スコアの勾配に対応します。

このマップを可視化する方法はいくつかあります。マップは一般にノイズを多く含むため、勾配属性マップを直接 RGB イメージとしてプロットすると不明瞭になる可能性があります。代わりに、チャネル次元に沿って各ピクセルの絶対値を合計し、01 の間に再スケーリングします。255 色のカスタム カラーマップを使用して 0 の値を白に、1 の値を黒にマッピングし、勾配属性マップを表示します。

map = sum(abs(extractdata(dydI)),3);
map = rescale(map);

cmap = [linspace(1,0,255)' linspace(1,0,255)' linspace(1,0,255)'];

imshow(map, "Colormap", cmap);
title("Gradient Attribution Map (" + string(predClass) + ")");

マップで最も暗いのは犬を中心とする部分です。このマップは非常に多くのノイズを含みますが、ネットワークがイメージ内の適切な情報を使って分類を実行していることを示唆しています。犬の部分のピクセルは、背景の芝生のピクセルよりも分類スコアにより大きな影響を与えています。

ガイド付き逆伝播を使用した勾配属性マップのシャープ化

ReLU 層を経由するネットワークのバックワード パスを変更して、ゼロ未満の勾配要素およびゼロ未満の ReLU 層への入力要素をそれぞれゼロに設定することで、勾配属性マップをシャープにすることができます。これはガイド付き逆伝播と呼ばれます [2]。

ガイド付き逆伝播の逆方向関数は次のとおりです。

dLdZ=(X>0)*(dLdZ>0)*dLdZ

ここで、L は損失、X は ReLU 層への入力、Z は出力です。

非標準のバックワード パスをもつカスタム層を作成し、自動微分と共に使用することができます。この変更が実装されたカスタム層クラス CustomBackpropReluLayer は、この例のサポート ファイルに含まれています。自動微分逆伝播が CustomBackpropReluLayer オブジェクトを経由する際、カスタム層で定義された変更済みのガイド付き逆伝播関数が使用されます。

サポート関数 replaceLayersOfType (この例のサポート関数の節で定義) を使用して、ネットワーク内にある reluLayer のすべてのインスタンスを CustomBackpropReluLayer のインスタンスに置き換えます。各 CustomBackpropReluLayerBackpropMode プロパティを "guided-backprop" に設定します。

customRelu = CustomBackpropReluLayer();
customRelu.BackpropMode = "guided-backprop";

lgraphGB = replaceLayersOfType(lgraph, ...
    "nnet.cnn.layer.ReLULayer",customRelu);

CustomBackpropReluLayers を含む層グラフを dlnetwork に変換します。

dlnetGB = dlnetwork(lgraphGB);

ガイド付き逆伝播を使用して、ネットワークの勾配属性マップを計算してプロットします。

dydIGB = dlfeval(@gradientMap,dlnetGB,dlImg,softmaxName,classIdx);

mapGB = sum(abs(extractdata(dydIGB)),3);
mapGB = rescale(mapGB);

imshow(mapGB, "Colormap", cmap);
title("Guided Backpropagation (" + string(predClass) + ")");

ガイド付き逆伝播の手法の方が、犬の目や鼻のようなさまざまな部分をより明瞭に強調表示していることがわかります。

ReLU 層を経由する逆伝播に Zeiler-Fergus 手法を使用することも可能です [5]。Zeiler-Fergus 手法では、逆方向関数は次で与えられます。

dLdZ=(dLdZ>0)*dLdZ

CustomBackpropReluLayer インスタンスの BackpropMode プロパティを "zeiler-fergus" に設定します。

customReluZF = CustomBackpropReluLayer();
customReluZF.BackpropMode = "zeiler-fergus";

lgraphZF = replaceLayersOfType(lgraph, ...
    "nnet.cnn.layer.ReLULayer",customReluZF);

dlnetZF = dlnetwork(lgraphZF);

dydIZF = dlfeval(@gradientMap,dlnetZF,dlImg,softmaxName,classIdx);


mapZF = sum(abs(extractdata(dydIZF)),3);
mapZF = rescale(mapZF);

imshow(mapZF,"Colormap", cmap);
title("Zeiler-Fergus (" + string(predClass) + ")");

Zeiler-Fergus の逆伝播手法を使って計算した勾配属性マップは、ガイド付き逆伝播を使って計算したマップよりも不明瞭です。

積分勾配を使用したイメージの変化に対する感度の評価

積分勾配のアプローチでは、ベースライン イメージと対象の元のイメージの間に線形に内挿されたイメージの集合全体にわたる、イメージ ピクセルに対するクラス スコアの勾配の積分を計算します [3]。積分勾配の手法は、積分全体でのピクセル値の変化の影響を受けるように設計されています。そのため、ピクセル値の変更がクラス スコアに影響を与える場合、そのピクセルはマップにおいて非ゼロの値をもちます。ReLU 層のようなネットワーク内の非線形要素は、よりシンプルな勾配属性の手法でこの感度を抑制することが可能です。

積分勾配属性マップは次の式で計算されます。

Wxyc=(Ixy-Ixy0)α=01dαSc(Ixy(α))Ixy(α),

ここで Wxyc は位置 (x,y) のピクセルにおけるクラス c のマップの値、Ixy0 はベースライン イメージ、Ixy(α) はベースライン イメージと入力イメージの間のパスに沿った距離 α にあるイメージです。

Ixy(α)=Ixy0+α(Ixy-Ixy0).

この例では、α にわたって積分するのではなく、離散インデックス n を加算することで、積分勾配の式を単純化します。

Wxyc=(Ixy-Ixy0)n=0NSc(Ixyn)Ixyn,

ここで

Ixyn=Ixy0+nN(Ixy-Ixy0).

イメージ データの場合、ベースライン イメージにゼロの黒いイメージを選択します。元のイメージとベースライン イメージの差分となるイメージを見つけます。ここでは、ベースライン イメージがゼロであるため、differenceImg は元のイメージと同じです。

baselineImg = zeros([inputSize, 3]);
differenceImg = single(img) - baselineImg;

ベースライン イメージから元の入力イメージへの線形パスに沿った離散のステップに対応するイメージの配列を作成します。イメージ数が多いほど結果は滑らかになりますが、計算に時間がかかります。

numPathImages = 25;

pathImgs = zeros([inputSize 3 numPathImages-1]);
for n=0:numPathImages-1
    pathImgs(:,:,:,n+1) = baselineImg + (n)/(numPathImages-1) * differenceImg;
end

figure;
imshow(imtile(rescale(pathImgs)));
title("Images Along Integration Path");

パス イメージのミニバッチを dlarray に変換します。データを 2 つの空間次元、1 つのチャネル次元、そして 1 つのバッチ次元から成る 'SSCB' フォーマットに変換します。各パス イメージはミニバッチの 1 つの観測値です。パスに沿って結果のイメージのバッチの勾配マップを計算します。

dlPathImgs = dlarray(pathImgs, 'SSCB');
dydIIG = dlfeval(@gradientMap, dlnet, dlPathImgs, softmaxName, classIdx);

チャネルごとに、ミニバッチ内のすべての観測値の勾配を加算します。

dydIIGSum = sum(dydIIG,4);

加算した勾配属性マップの各要素に、differenceImg の対応する要素を乗算します。積分勾配属性マップを計算するには、それぞれのチャネルを加算して再スケーリングします。

dydIIGSum = differenceImg .* dydIIGSum;

mapIG = sum(extractdata(abs(dydIIGSum)),3);
mapIG = rescale(mapIG);

imshow(mapIG, "Colormap", cmap);
title("Integrated Gradients (" + string(predClass) + ")");

計算されたマップは、ネットワークがクラスを決定する手段として、犬の顔により強く焦点を当てていることを示しています。

ここで説明した勾配属性の手法は、分類を行うときにイメージの適切な部分にネットワークが焦点を当てているかどうかを確認するために使用できます。モデルの動作に関する優れた洞察を得て分類の判定を説明するには、これらの手法を一定範囲のイメージに対して実行し、特定クラスに強く寄与する具体的な特徴を探します。多くの場合、変更されていない勾配属性の手法の方が、ネットワークの判定を説明する手法として優れた信頼性を提供します。ガイド付き逆伝播と積分勾配の手法では非常に明瞭な勾配マップを作成できますが、これらの手法によってモデルの動作に関してどれくらいの洞察を得られるかは明確ではありません [4]。

サポート関数

勾配マップ関数

関数 gradientMap は、指定のクラスについて、イメージに対するスコアの勾配を計算します。この関数は、単一のイメージまたはイメージのミニバッチを受け取ります。この例では、関数 gradientMap について自動微分を使用した勾配属性マップの計算の節で紹介されています。

function dydI = gradientMap(dlnet, dlImgs, softmaxName, classIdx)
% Compute the gradient of a class score with respect to one or more input
% images.

dydI = dlarray(zeros(size(dlImgs)));

for i=1:size(dlImgs,4)
    I = dlImgs(:,:,:,i);
    scores = predict(dlnet,I,'Outputs',{softmaxName});
    classScore = scores(classIdx);
    dydI(:,:,:,i) = dlgradient(classScore,I);
end
end

層の置換関数

関数 replaceLayersOfType は、指定したクラスのすべての層を新しい層のインスタンスに置き換えます。新しい層の名前は、元の層と同じ名前になります。この例において、関数 replaceLayersOfType については、ガイド付き逆伝播を使用した勾配属性マップのシャープ化の節で説明されています。

function lgraph = replaceLayersOfType(lgraph, layerType, newLayer)
% Replace layers in the layerGraph lgraph of the type specified by
% layerType with copies of the layer newLayer.

for i=1:length(lgraph.Layers)
    if isa(lgraph.Layers(i), layerType)
        % Match names between old and new layer.
        layerName = lgraph.Layers(i).Name;
        newLayer.Name = layerName;
        
        lgraph = replaceLayer(lgraph, layerName, newLayer);
    end
end
end

参考文献

[1] Simonyan, Karen, Andrea Vedaldi, and Andrew Zisserman. “Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps.” ArXiv:1312.6034 [Cs], April 19, 2014. http://arxiv.org/abs/1312.6034.

[2] Springenberg, Jost Tobias, Alexey Dosovitskiy, Thomas Brox, and Martin Riedmiller. “Striving for Simplicity: The All Convolutional Net.” ArXiv:1412.6806 [Cs], April 13, 2015. http://arxiv.org/abs/1412.6806.

[3] Sundararajan, Mukund, Ankur Taly, and Qiqi Yan. "Axiomatic Attribution for Deep Networks." Proceedings of the 34th International Conference on Machine Learning (PMLR) 70 (2017): 3319-3328

[4] Adebayo, Julius, Justin Gilmer, Michael Muelly, Ian Goodfellow, Moritz Hardt, and Been Kim. “Sanity Checks for Saliency Maps.” ArXiv:1810.03292 [Cs, Stat], October 27, 2018. http://arxiv.org/abs/1810.03292.

[5] Zeiler, Matthew D. and Rob Fergus. "Visualizing and Understanding Convolutional Networks." In Computer Vision – ECCV 2014. Lecture Notes in Computer Science 8689, edited by D. Fleet, T. Pajdla, B. Schiele, T. Tuytelaars. Springer, Cham, 2014.

参考

| | | | | | | | |

関連するトピック