交差検証を用いた画像の判別について

14 views (last 30 days)
Kaneko
Kaneko on 27 Aug 2020
Commented: Kaneko on 29 Aug 2020
交差検証を用いた画像の判別を行っています。まず,2種類の画像を100枚ずつ,合計200枚を以下のコードで交差検証を行い,誤分類率を出します。以下は,データを10分割して,交差検証を行った結果です。
imds = imageDatastore('train_data', ...
'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([28 28 1],'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に保存すると,net10.matというmatファイルができます。これを使用して,以下のコードを使って,交差検証に使用していない画像を判別し,ヒートマップで,判別要因をみようとしています。
load net10
%% Autodiffにかけられるようにdlnetworkに変更
lgraph = layerGraph(net10.Layers); %
Outputlayer = lgraph.Layers(end);
newlgraph = removeLayers(lgraph,lgraph.Layers(end).Name); % calssificationの層だけ取る
net0 = dlnetwork(newlgraph); % dlnetworkに変更
softmaxlayer = 'softmax' ; % 予測確率が出てくる最後のレイヤを指定
activationlayer = 'relu3'; % MAPを適用するレイヤを指定
%% 画像の読み込み
labeltbl = {'4test';'9test'};
colortbl = [255 255 102; 73 6 248];
img = imread(fullfile('test_data','4test','5796.jpg'));% 画像の取り込み
img = imresize(img,[28 28]); % ネットワークと同じサイズに変更
[class,score] = classify(net10,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, [28 28], 'Method', 'bicubic'); % 画像サイズに合わせる
HeatMap = map2jpg(gradcam, [], 'jet'); % ヒートマップ表示の画像データに変換する
HeatMap = uint8((im2double(img)*0.3+HeatMap*0.5)*255); % 元画像と重ね合わせる
out2 = [img HeatMap]; % 元画像と結果を横方向に結合する
imshow(out2);shg
%%
function [conv_output,gradients] = Gradient_function(net10,I2,softmaxlayer,activationlayer,class)
[scores,conv_output] = predict(net10, 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._
しかし,以下のようなエラーが出ました。
エラー: horzcat
連結する配列の次元が一致しません。
エラー: kasika (line 28)
out2 = [img HeatMap]; % 元画像と結果を横方向に結合する。
以前,別の画像を判別したときは,うまくいったので,同じものを使用してみましたが,このようなエラーがでてしまいました。
どこがおかしいか教えていただけますでしょうか。よろしくお願い致します。

Accepted Answer

Kenta
Kenta on 27 Aug 2020
imgとHeatMapの縦の長さが違うのだと思います。imresizeなどで調整してみてください
  3 Comments
Kenta
Kenta on 29 Aug 2020
連結する配列の次元が一致しません。
エラー: kasika (line 28)
out2 = [img HeatMap]; % 元画像と結果を横方向に結合する。
というエラーがあるので、ここの、out2を出力するコードに問題がありそうです。このimgとHeatMapの高さがちがうのではないでしょうか?コードのほうは、imresizeのドキュメントが参考になりそうです
Kaneko
Kaneko on 29 Aug 2020
ありがとうございます。解決いたしました。

Sign in to comment.

More Answers (0)

Categories

Find more on Modify Image Colors 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!