基于卷积神经⽹络的数字重建-UnetMatlab代码
两年前写论⽂时,发过⼀篇在MATLAB上⽤神经⽹络实现数字重建的帖⼦。当时是想着⽅便⽇后⾃⼰复习,没想到收到了不少⼩伙伴的私信,希望能把Unet的代码分享⼀下。其实,在发帖时⾃⼰也忽略了这⼀点,所以现在专门写⼀篇帖⼦把代码分享给⼤家。*代码好像是从MATLAB官⽹论坛上下载,⾮原创
代码
话不多说,先上代码。
function lgraph = createUnet_regression()
% EDIT: modify these parameters for your application.
% encoderDepth 决定了对称⽹络的深度,即先 encode (N次)后再decode(N次)
% 注意输⼊图⽚的尺⼨。由于加⼊了MaxPooling, 所以图⽚的尺⼨会递减32->16->8-&
encoderDepth =4;
initialEncoderNumChannels =32;
%inputTileSize =[2562561];
%inputTileSize =[1281281];
% 输⼊图⽚的尺⼨
inputTileSize =[32321];
convFilterSize =[33];
%inputNumChannels =3;
inputNumChannels =1;
inputlayer = imageInputLayer(inputTileSize,'Name','ImageInputLayer');
[encoder, finalNumChannels]= iCreateEncoder(encoderDepth, convFilterSize, initialEncoderNumChannels, inputNumChannels);
firstConv = createAndInitializeConvLayer(convFilterSize, finalNumChannels, ...
2*finalNumChannels, 'Bridge-Conv-1');
firstReLU = reluLayer('Name','Bridge-ReLU-1');
secondConv = createAndInitializeConvLayer(convFilterSize, 2*finalNumChannels, ...
2*finalNumChannels, 'Bridge-Conv-2');
secondReLU = reluLayer('Name','Bridge-ReLU-2');
encoderDecoderBridge =[firstConv; firstReLU; secondConv; secondReLU];
dropOutLayer = dropoutLayer(0.5,'Name','Bridge-DropOut');
encoderDecoderBridge =[encoderDecoderBridge; dropOutLayer];
initialDecoderNumChannels = finalNumChannels;
upConvFilterSize =2;
[decoder, finalDecoderNumChannels]= iCreateDecoder(encoderDepth, upConvFilterSize, convFilterSize, initialDecoderNumChannels);
layers =[inputlayer; encoder; encoderDecoderBridge; decoder];
finalConv = convolution2dLayer(1,1,...
'BiasL2Factor',0,...
'Name','Final-ConvolutionLayer');
%finalConv.Weights = randn(1,1,finalDecoderNumChannels,initialEncoderNumChannels);
%finalConv.Bias = zeros(1,1,initialEncoderNumChannels);
%smLayer = softmaxLayer('Name','Softmax-Layer');
%pixelClassLayer = pixelClassificationLayer('Name','Segmentation-Layer');
%layers =[layers; finalConv; smLayer; pixelClassLayer];
finalregressionLayer= regressionLayer('name','Reg.Layer');
layers =[layers; finalConv;finalregressionLayer];
lgraph = layerGraph(layers);
for depth =1:encoderDepth
startLayer = sprintf('Encoder-Stage-%d-ReLU-2',depth);
endLayer = sprintf('Decoder-Stage-%d-DepthConcatenation/in2',encoderDepth-depth + 1);
lgraph = connectLayers(lgraph,startLayer, endLayer);
end
enddecoder
%--------------------------------------------------------------------------
function[encoder, finalNumChannels]= iCreateEncoder(encoderDepth, convFilterSize, initialEncoderNumChannels, inputNumChannels)
encoder =[];
for stage =1:encoderDepth
% Double the layer number of channels at each stage of the encoder.
encoderNumChannels = initialEncoderNumChannels * 2^(stage-1);
if stage ==1
firstConv = createAndInitializeConvLayer(convFilterSize, inputNumChannels, encoderNumChannels, ['Encoder-Stage-' num2str(stage)'-Conv-1']); else
firstConv = createAndInitializeConvLayer(convFilterSize, encoderNumChannels/2, encoderNumChannels, ['Encoder-Stage-' num2str(stage)'-Conv-1'] );
end
firstReLU = reluLayer('Name',['Encoder-Stage-' num2str(stage)'-ReLU-1']);
secondConv = createAndInitializeConvLayer(convFilterSize, encoderNumChannels, encoderNumChannels, ['Encoder-Stage-' num2str(stage)'-Conv-2']) ;
secondReLU = reluLayer('Name',['Encoder-Stage-' num2str(stage)'-ReLU-2']);
encoder =[encoder;firstConv; firstReLU; secondConv; secondReLU];
if stage == encoderDepth
dropOutLayer = dropoutLayer(0.5,'Name',['Encoder-Stage-' num2str(stage)'-DropOut']);
encoder =[encoder; dropOutLayer];
end
maxPoolLayer = maxPooling2dLayer(2, 'Stride', 2, 'Name',['Encoder-Stage-' num2str(stage)'-MaxPool']);
encoder =[encoder; maxPoolLayer];
end
finalNumChannels = encoderNumChannels;
end
%--------------------------------------------------------------------------
function[decoder, finalDecoderNumChannels]= iCreateDecoder(encoderDepth, upConvFilterSize, convFilterSize, initialDecoderNumChannels)
decoder =[];
for stage =1:encoderDepth
% Half the layer number of channels at each stage of the decoder.
decoderNumChannels = initialDecoderNumChannels / 2^(stage-1);
upConv = createAndInitializeUpConvLayer(upConvFilterSize, 2*decoderNumChannels, decoderNumChannels, ['Decoder-Stage-' num2str(stage)'-UpCo nv']);
upReLU = reluLayer('Name',['Decoder-Stage-' num2str(stage)'-UpReLU']);
% Input feature channels are concatenated with deconvolved features within the decoder.
depthConcatLayer = depthConcatenationLayer(2, 'Name', ['Decoder-Stage-' num2str(stage)'-DepthConcatenation']);
firstConv = createAndInitializeConvLayer(convFilterSize, 2*decoderNumChannels, decoderNumChannels, ['Decoder-Stage-' num2str(stage)'-Conv-1']);    firstReLU = reluLayer('Name',['Decoder-Stage-' num2str(stage)'-ReLU-1']);
secondConv = createAndInitializeConvLayer(convFilterSize, decoderNumChannels, decoderNumChannels, ['Decoder-Stage-' num2str(stage)'-Conv-2'])
;
secondReLU = reluLayer('Name',['Decoder-Stage-' num2str(stage)'-ReLU-2']);
decoder =[decoder; upConv; upReLU; depthConcatLayer; firstConv; firstReLU; secondConv; secondReLU];
end
finalDecoderNumChannels = decoderNumChannels;
end
%--------------------------------------------------------------------------
function convLayer = createAndInitializeConvLayer(convFilterSize, inputNumChannels, outputNumChannels, layerName)
convLayer = convolution2dLayer(convFilterSize,outputNumChannels,...
'Padding', 'same',...
'BiasL2Factor',0,...
'Name',layerName);
% He initialization is used
convLayer.Weights = sqrt(2/((convFilterSize(1)*convFilterSize(2))*inputNumChannels))...
* randn(convFilterSize(1),convFilterSize(2), inputNumChannels, outputNumChannels);
convLayer.Bias = zeros(1,1,outputNumChannels);
convLayer.BiasLearnRateFactor =2;
end
%--------------------------------------------------------------------------
function upConvLayer = createAndInitializeUpConvLayer(UpconvFilterSize, inputNumChannels, outputNumChannels, layerName)
upConvLayer = transposedConv2dLayer(UpconvFilterSize, outputNumChannels,...
'Stride',2,...
'BiasL2Factor',0,...
'Name',layerName);
% The transposed conv filter size is a scalar
upConvLayer.Weights = sqrt(2/((UpconvFilterSize^2)*inputNumChannels))...
* randn(UpconvFilterSize,UpconvFilterSize,outputNumChannels,inputNumChannels);
upConvLayer.Bias = zeros(1,1,outputNumChannels);
upConvLayer.BiasLearnRateFactor =2;
end
这⾥附上⼀张⽣成的Unet结构图。 顺便解释⼏句,希望能减少初学者的学习成本。
Unet本来是⽤来做图像分割的,但是为了⽤了实现图像的重建,最后的输出层应改为regression layer,这也是我的命名⽅法。在之前帖⼦⾥提到的 其实去掉了前后的连接,并改⽤了LeakyReLu激活函数的变种。去掉前后的桥接并不复杂,想尝试的朋友可以注销encoderDecoderBridge 相关代码。
最后,希望⼤家多尝试,多思考,多交流,多分享。有什么问题,欢迎留⾔讨论。