畳み込みニューラルネットワークで交差検証後にgrad-camを使用した画像の判別について
1 view (last 30 days)
Show older comments
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._
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/269273/image.jpeg)
また、grad-camを使った判別要因の可視化をしても、ヒートマップが画像のように判別要因がでないというような状態です。どこかコードでおかしな所があるから、ダメなのでしょうか。それとも、そもそも私がやってる、交差検証をつかって、誤分類率を出した後に、grad-camで判別すること自体、不可能な事なのでしょうか。
よろしくお願いいたします。
6 Comments
Kenta
on 1 Feb 2020
ご返信ありがとうございます。それでは
「学習データと評価データとは別の画像の判別を行おうとしたらどの画像を判別しても、同じ方に判別されてしまい」に関しては、その別の画像の評価自体が難しかったということですね。おそらく2つ問題があると思います。
1)学習・検証データ以外の画像に関してはうまく推論ができない
2)grad-camがうまくいかない
1)に関しては、ひとまずあまり問題ないと考えて進めてよいということですね?
2)に関してはこちらでも見てみます。net2のmatファイルと、上で使った画像1枚を添付いただけると試しやすいです。よろしくお願いいたします。
Accepted Answer
Kenta
on 1 Feb 2020
![result.JPG](https://www.mathworks.com/matlabcentral/answers/uploaded_files/269383/result.jpeg)
HeatMap = map2jpg(gradcam, [], 'jet');
HeatMapの計算をこのように変更するとできます。教えていただいたURLでのコードは正しかったのですが、質問者様のほうで、まちがって変更されていたようです。
変数gradcamを150by200に変更する際に2つ目の変数で、スケーリングの範囲を決めますが、[]とすると、
minmaxスケーリングをしてくれます。詳しくは補助関数map2jpgをご覧ください。
3 Comments
More Answers (0)
See Also
Categories
Find more on イメージのセグメンテーション 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!