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

조회 수: 7 (최근 30일)
Kaneko
Kaneko 2020년 1월 31일
댓글: Kenta 2020년 2월 3일
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
Kenta
Kenta 2020년 2월 1일
ご返信ありがとうございます。それでは
「学習データと評価データとは別の画像の判別を行おうとしたらどの画像を判別しても、同じ方に判別されてしまい」に関しては、その別の画像の評価自体が難しかったということですね。おそらく2つ問題があると思います。
1)学習・検証データ以外の画像に関してはうまく推論ができない
2)grad-camがうまくいかない
1)に関しては、ひとまずあまり問題ないと考えて進めてよいということですね?
2)に関してはこちらでも見てみます。net2のmatファイルと、上で使った画像1枚を添付いただけると試しやすいです。よろしくお願いいたします。
Kaneko
Kaneko 2020년 2월 1일
承知しました。ありがとうございます。それでは使用した画像の一枚とmatファイルを添付します。
よろしくお願いいたします。5.jpg

댓글을 달려면 로그인하십시오.

채택된 답변

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

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

Community Treasure Hunt

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

Start Hunting!