畳み込みニューラルネ​ットワークで交差検証​後にgrad-cam​を使用した画像の判別​について

28 views (last 30 days)
Kaneko
Kaneko on 31 Jan 2020
Commented: Kenta on 3 Feb 2020
MATLAB初心者です。畳み込みニューラルネットワークで放電の画像を二種類「sioari」、「sionasi」として判別しようと考えてます。まず、200枚の画像を学習データ及び評価データとして使い、以下の交差検証のコードを使って、誤分類率を出します。
imds = imageDatastore('houdenmatlab1', ...
'IncludeSubfolders',true, ...
'LabelSource','foldernames');
figure;
perm = randperm(200,20);
for i = 1:20
subplot(4,5,i);
imshow(imds.Files{perm(i)});
end
labelCount = countEachLabel(imds)
img = readimage(imds,1);
size(img)
numTrainFiles = 80;
[imdsTrain,imdsValidation] = splitEachLabel(imds,numTrainFiles,'randomize');
%% ダミーのトレーニングインデックスを生成
X = (1:imds.numpartitions)';
y = imds.Labels;
%% 交差検定にCNNの予測ラベル関数のポインタを渡す
cp = cvpartition(y,'k',10); % Stratified cross-validation
mcr = crossval('mcr',X,y,'Predfun',@(xtrain,ytrain,xtest)myCNNPredict(xtrain,ytrain,xtest,imds),'partition',cp)
%% CNNを学習し、予測ラベルを出力する関数
function ypred = myCNNPredict(xtrain,ytrain,xtest,imds)
% 結果が一意になるように乱数シードをデフォルト値に設定
rng('default');
% ダミーの変数ベクトルを受けてimageDatastoreを学習用とテスト用に分割
imdsTrain = imageDatastore(imds.Files(xtrain));
imdsTrain.Labels = ytrain;
imdsValidation = imageDatastore(imds.Files(xtest));
% レイヤーの設定
layers = [
imageInputLayer([150 200 3],'Name','input')
convolution2dLayer(3,8,'Padding','same','Name','conv1')
batchNormalizationLayer('Name','BN1')
reluLayer('Name','relu1')
crossChannelNormalizationLayer(5)
maxPooling2dLayer(2,'Stride',2,'Name','pool1')
convolution2dLayer(3,16,'Padding','same','Name','conv2')
batchNormalizationLayer('Name','BN2')
reluLayer('Name','relu2')
crossChannelNormalizationLayer(5)
maxPooling2dLayer(2,'Stride',2,'Name','pool2')
convolution2dLayer(3,32,'Padding','same','Name','conv3')
batchNormalizationLayer('Name','BN3')
reluLayer('Name','relu3')
dropoutLayer('probability',0.5,'Name','drop6')
fullyConnectedLayer(2,'Name','fc')
softmaxLayer('Name','softmax')
classificationLayer('Name','classoutput')];
options = trainingOptions('sgdm', ...
'InitialLearnRate',0.01, ...
'MaxEpochs',5, ...
'Shuffle','every-epoch', ...
'Verbose',false);
net10 = trainNetwork(imdsTrain,layers,options);
ypred = classify(net10,imdsValidation);
save net10
end
誤分類率を出したら保存したネットワークであるnet10を以下のコードに読み込んで学習データと評価データとは別の画像の判別を行おうとしたらどの画像を判別しても、同じ方に判別されてしまい、ans = signal 1(100%)となってしまいます。
load net2
%% Autodiffにかけられるようにdlnetworkに変更
lgraph = layerGraph(net2.Layers); %
Outputlayer = lgraph.Layers(end);
newlgraph = removeLayers(lgraph,lgraph.Layers(end).Name); % calssificationの層だけ取る
net0 = dlnetwork(newlgraph); % dlnetworkに変更
softmaxlayer = 'softmax' ; % 予測確率が出てくる最後のレイヤを指定
activationlayer = 'relu3'; % MAPを適用するレイヤを指定
%% 画像の読み込み
labeltbl = {'sioaritest';'sionasitest'};
colortbl = [255 255 102; 73 6 248];
img = imread(fullfile('houdentestdata','sionasitest','houden_190807_0005 (1).jpg'));% 画像の取り込み
img = imresize(img,[150 200]); % ネットワークと同じサイズに変更
[class,score] = classify(net2,img); % 推論
class
max(score)
img2 = dlarray(single(img),'SSC');
% 指定レイヤの出力とGradientをとる
[conv_output,gradients] = dlfeval(@Gradient_function,net0,img2,softmaxlayer,activationlayer,class);
% 得られた出力から演算でヒートマップを作製
gradcam = sum(conv_output .* mean(gradients, [1 2]), 3); % GradientのGlobal average poolingし出力とかけ和をとる
gradcam = extractdata(gradcam); % single型で取り出し。
gradcam = max(gradcam,0); % relu関数を適用
gradcam = imresize(gradcam, [150 200], 'Method', 'bicubic'); % 画像サイズに合わせる
HeatMap = map2jpg(gradcam, [150 200], 'jet'); % ヒートマップ表示の画像データに変換する
HeatMap = uint8((im2double(img)*0.3+HeatMap*0.5)*255); % 元画像と重ね合わせる
out2 = [img HeatMap]; % 元画像と結果を横方向に結合する
imshow(out2);shg
%%
function [conv_output,gradients] = Gradient_function(net0,I2,softmaxlayer,activationlayer,class)
[scores,conv_output] = predict(net0, I2, 'Outputs', {softmaxlayer, activationlayer}); % 予測確率とMAPを作る層までの出力を得る
loss = scores(class); % 指定したクラスのスコアをとる
gradients = dlgradient(loss,conv_output); % MAPを作る層でのgradientをとる
gradients = gradients / (sqrt(mean(gradients.^2,'all')) + 1e-5); % 正規化する
end
% ヒートマップに変換する関数
function img = map2jpg(imgmap, range, colorMap)
imgmap = double(imgmap);
if(~exist('range', 'var') || isempty(range))
range = [min(imgmap(:)) max(imgmap(:))];
end
heatmap_gray = mat2gray(imgmap, range);
heatmap_x = gray2ind(heatmap_gray, 256);
heatmap_x(isnan(imgmap)) = 0;
if(~exist('colorMap', 'var'))
img = ind2rgb(heatmap_x, jet(256));
else
img = ind2rgb(heatmap_x, eval([colorMap '(256)']));
end
end
%%
% _Copyright 2018-2019 The MathWorks, Inc._
また、grad-camを使った判別要因の可視化をしても、ヒートマップが画像のように判別要因がでないというような状態です。どこかコードでおかしな所があるから、ダメなのでしょうか。それとも、そもそも私がやってる、交差検証をつかって、誤分類率を出した後に、grad-camで判別すること自体、不可能な事なのでしょうか。
ちなみに交差検証のコードはこちら、grad-camのコードは、ディープラーニング評価キットD2_2_3_mygradcam_alexnet.mを参考にしています。
よろしくお願いいたします。
  6 Comments
Kenta
Kenta on 1 Feb 2020
ご返信ありがとうございます。それでは
「学習データと評価データとは別の画像の判別を行おうとしたらどの画像を判別しても、同じ方に判別されてしまい」に関しては、その別の画像の評価自体が難しかったということですね。おそらく2つ問題があると思います。
1)学習・検証データ以外の画像に関してはうまく推論ができない
2)grad-camがうまくいかない
1)に関しては、ひとまずあまり問題ないと考えて進めてよいということですね?
2)に関してはこちらでも見てみます。net2のmatファイルと、上で使った画像1枚を添付いただけると試しやすいです。よろしくお願いいたします。
Kaneko
Kaneko on 1 Feb 2020
承知しました。ありがとうございます。それでは使用した画像の一枚とmatファイルを添付します。
よろしくお願いいたします。5.jpg

Sign in to comment.

Accepted Answer

Kenta
Kenta on 1 Feb 2020
result.JPG
HeatMap = map2jpg(gradcam, [], 'jet');
HeatMapの計算をこのように変更するとできます。教えていただいたURLでのコードは正しかったのですが、質問者様のほうで、まちがって変更されていたようです。
変数gradcamを150by200に変更する際に2つ目の変数で、スケーリングの範囲を決めますが、[]とすると、
minmaxスケーリングをしてくれます。詳しくは補助関数map2jpgをご覧ください。
  3 Comments
Kaneko
Kaneko on 2 Feb 2020
すみません、解決しました。それぞれの分割数のネットワークで同じ画像を判別させて、ヒートマップをそれぞれ比較したら、ヒートマップが同じにはならなかったので、これで大丈夫だと判断しました。
この度は本当にありがとうございました。とても助かりました。
Kenta
Kenta on 3 Feb 2020
すいません、返信が遅れました。解決したようでよかったです。

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!