独自で作成した学習モデルを用いたGrad-CAM

resnet101を転移学習させたモデルを使って3クラス分類をしています。
その際に画像のどの部分に着目しているかを調べるためにGrad-CAMの実装を、
ドキュメンテーション(Grad-CAMでの深層学習による判定の理由を解明)を見ながら試みたのですが
以下のエラーが出てしまい原因がわかりません。
エラー: nnet.internal.cnn.dlnetwork/predict (line 198)
層 'bn2a_branch2a': 入力データが無効です。 'Variance' の値は無効です。 入力は正にする必要があります。
エラー: dlnetwork/predict (line 205)
[varargout{1:nargout}] = predict(net.PrivateNetwork, x, layerIndices, layerOutputIndices);
エラー: gradcam (line 2)
[scores,convMap] = predict(dlnet, dlImg, 'Outputs', {softmaxName, convLayerName});
エラー: deep.internal.dlfeval (line 18)
[varargout{1:nout}] = fun(x{:});
エラー: dlfeval (line 40)
[varargout{1:nout}] = deep.internal.dlfeval(fun,varargin{:});
エラー: G_CAM (line 34)
[convMap, dScoresdMap] = dlfeval(@gradcam, dlnet, dlImg, softmaxName, convLayerName, classfn);
最初のネットワークの読み込み部分と最終畳み込み層の名前を
ConvLayerName = 'res5c_relu'にした以外は基本的に変えていません。
6/29追記
lgraphとdlnetのプロパティを調べたところ、以下のようになりました。
lgraph =
LayerGraph のプロパティ:
Layers: [346×1 nnet.cnn.layer.Layer]
Connections: [378×2 table]
InputNames: {'data'}
OutputNames: {1×0 cell}
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
dlnet =
dlnetwork のプロパティ:
Layers: [346×1 nnet.cnn.layer.Layer]
Learnables: [418×3 table]
State: [208×3 table]
dlnetworkに変換したときにConnectionsとInputNamesとOutputNamesが消えていました。
これがエラーの原因になっているかはわかりませんが、
調べた感じではdlnetworkオブジェクトに変換しただけでこれらが消える事例はなかったので気になりました。
消えてしまう原因もわからずじまいで、手詰まりになっています。
%3クラス分類のネットワークの読み込み
net = load('classification.mat');
net = net.net
%イメージサイズの読み取り
inputSize = net.Layers(1).InputSize(1:2);
%画像の読み込み
img = imread("IMG_4257.JPG");
%画像サイズの変更
img = imresize(img,inputSize);
%イメージを分類して、分類結果及びスコアを表示
[classfn,score] = classify(net,img);
imshow(img);
title(sprintf("%s (%.2f)", classfn, score(classfn)));
type gradcam.m
analyzeNetwork(net)
%Grad-Camを使用するためにdlnetworkを作成する。ネットワークから層グラフを作成する。
lgraph = layerGraph(net);
%分類に使用されるデータにアクセスするため、最終分類層を削除
lgraph = removeLayers(lgraph, lgraph.Layers(end).Name);
%層グラフからdlnetworkを作成
dlnet = dlnetwork(lgraph);
%ソフトマックス層の名前を'prob'に指定。最終畳み込み層の名前を'res5c_relu'に指定
softmaxName = 'prob';
convLayerName = 'res5c_relu';
analyzeNetwork(lgraph)
%自動微分を使用するために、画像をdlarrayに変換
dlImg = dlarray(single(img),'SSC');
%関数gradcamでdlfevalを呼び出すことによって画像のGrad-CAM勾配を計算
[convMap, dScoresdMap] = dlfeval(@gradcam, dlnet, dlImg, softmaxName, convLayerName, classfn);
%
gradcamMap = sum(convMap .* sum(dScoresdMap, [1 2]), 3);
gradcamMap = extractdata(gradcamMap);
gradcamMap = rescale(gradcamMap);
gradcamMap = imresize(gradcamMap, inputSize, 'Method', 'bicubic');
%'AlphaData'の値として、0.5を使用して、イメージの上にGrad-CAMレベルを表示する。'jet'カラーマップでは、濃い青が最低値、濃い赤が最高値
imshow(img);
hold on;
imagesc(gradcamMap,'AlphaData', 0.5);
colormap jet
hold off;
title("Grad-CAM");

9 Comments

Kenta
Kenta on 26 Jun 2020
こんにちは、classification.matと対象画像を添付いただけると考えやすいのですが、添付いただくことは可能でしょうか。ご検討宜しくお願い致します。
Takuma Hashimoto
Takuma Hashimoto on 29 Jun 2020
Kentaさん
お返事ありがとうございます。
classification.matの容量が大きすぎて添付できませんでした。
パブリックなドライブ等も用意できない状態で、お渡しができない状況かと思います。
ご対応いただいたのに申し訳ありません。
Kenta
Kenta on 29 Jun 2020
上のコードで、もともとのresnet101と、サンプル画像でやってみましたが、こちらではエラーは返さず、うまく走りました。おそらく、そちらのネットワーク固有の問題なのではと思います。ちなみに、dlfeval(@gradcam...
の直前まで実行してから
lgraph.Layers(19, 1).TrainedVariance
と打つとどのような値がでますか?エラー文ではこの値におそらく0が含まれているとあります。
Takuma Hashimoto
Takuma Hashimoto on 30 Jun 2020
Edited: Takuma Hashimoto on 30 Jun 2020
私もresnet101をそのまま用いたらエラーを返さずに走りました。
lgraph.Layers(19, 1).TrainedVariance
を実行してみましたところ、1*1*64の配列が返されました。
ans(:,:,1)~ans(:,:,64)まで中身の値を確認しましたが、全て正の値で0は存在しませんでした。(限りなく0に近い値はありましたが。)
※Layers(19,1)ではなくLayers(7,1)のような気がして、出力したところ、
ans(:,:,41) = -1.1468e-12と負の値が1つ入っていました。
Kentaさんのご指摘通りですと、これがエラーの元かと思いますが
なぜ負の値が入っているのか、どのようにすれば改善されるかがわかりません。
もしご存知であれば教えていただけないでしょうか。
重ね重ね質問をして申し訳ありませんがよろしくお願いいたします。
Kenta
Kenta on 30 Jun 2020
詳細をありがとうございます。resnet用にリサイズ(224×224など)した画像を添付してもらえることは可能ですか?
Takuma Hashimoto
Takuma Hashimoto on 1 Jul 2020
申し訳ありません。
諸事情により実物を添付することはできません。
マスキング処理をし、224*224*3にリサイズしたpng画像を学習に用いています。
Kenta
Kenta on 2 Jul 2020
わかりました。教えていただきありがとうございます。
resnet101以外で行ってみてはいかがでしょうか。もしかしたらネットワークを変更したらうまく走るかもしれません。
Kenta
Kenta on 2 Jul 2020
あと少し思い出したことがあるのですが、gradcam関数の中のpredictをforwardとsoftmax関数で書き直すと良いかもしれません。こちらの勘違いかもしれませんが、カスタムループ形式の深層学習のときにpredict関数のかわりに、上のように書き直すとうまくいった経験があります。
Takuma Hashimoto
Takuma Hashimoto on 2 Jul 2020
ありがとうございます。
私の技術不足で恐縮ですが、どのように書き直せばよいか
具体的にコードを見せていただくことは可能でしょうか。

Sign in to comment.

 Accepted Answer

Kenta
Kenta on 3 Jul 2020

0 votes

[featureMap,scores]=forward(dlnet,dlImg,'Outputs',{convLayerName,'prob'});
こんにちは、コメントのほう、返信ありがとうございます。
predict関数ではなく、forward関数で行ってはいかがでしょうか。詳細は添付のファイルをご覧ください。

1 Comment

Takuma Hashimoto
Takuma Hashimoto on 5 Jul 2020
動かせました!
ありがとうございます。

Sign in to comment.

More Answers (0)

Categories

Find more on Deep Learning Toolbox in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!