├── BPS_Training.m ├── CNN_Data_Cir.mat ├── CNN_ISP.pdf ├── Data_generate_Circle_BP.m ├── Data_generate_Circle_BP_S1.m ├── Display_Results_all_Results.m ├── Display_Results_your_example.m ├── Forward_Circ1.mat ├── README.md ├── accumulate_gradients_test.m ├── add_block_convt_test.m ├── add_block_test.m ├── add_pool_test.m ├── add_reg_concat_test.m ├── add_reg_toss_test.m ├── annulus_gen_exa.m ├── annulus_gen_rand.m ├── basic_para.mat ├── check_results.m ├── computeRegressedSNR.m ├── data_generate_Circle_Es.m ├── data_generate_Circle_Es_S1.m ├── dev_fun.m ├── displayImg_test.m ├── displayImg_test_final.m ├── error_euclideanloss_test.m ├── findLastCheckpoint_test.m ├── getBatch_test.m ├── getSimpleNNBatch_test.m ├── init_weight_test.m ├── process_epoch_test.m ├── struct_para_test.m ├── switchfigure_test.m ├── vl_euclideanloss.m ├── vl_simplenn_fbpconvnet.m ├── vl_simplenn_fbpconvnet_eval.m └── vl_simplenn_para_test.m /BPS_Training.m: -------------------------------------------------------------------------------- 1 | %% CNN for inverse problem of Cricle reconstruction; 2 | % The input is the results reconstructed by Bp with 5% noise, and output is groundtruth; 3 | % Wirtten by Wei Zhun at ECE NUS on 20th, Nov, 2017; 4 | 5 | clc;clear all;close all; 6 | % data_generate_Circle_Es; % generate scattering field 7 | % Data_generate_Circle_BP; % Backpropogation field 8 | run ./matconvnet-1.0-beta23/matlab/vl_setupnn 9 | run ./matconvnet-1.0-beta23/matlab/vl_compilenn 10 | load CNN_Data_Cir.mat; 11 | 12 | %% 13 | % ----------------------------------------------------------------------------------------------------------------------------- 14 | % Basic parameters 15 | % ----------------------------------------------------------------------------------------------------------------------------- 16 | % input 17 | W = 64; % size of patch 18 | Nimg= 500; % # of train + test set 19 | Nimg_test= fix(Nimg*0.05); 20 | Coef=10; 21 | 22 | id_tmp = ones(Nimg,1); 23 | id_tmp(Nimg-Nimg_test+1:end)=2; % the test indx is 2, training is 1 24 | 25 | imdb.images.set=id_tmp; % train set : 1 , test set : 2 26 | imdb.images.noisy=single((epsil_bp-1)*Coef); % input : H x W x C x N (X,Y,channel,batch) 27 | imdb.images.orig=single((epsil_exa-1)*Coef); % output : H x W x C x N (X,Y,channel,batch) 28 | 29 | % opts 30 | opts.channel_in = 1; 31 | opts.channel_out=1; 32 | opts.useGpu = 'false'; %'false' 33 | opts.gpus = [] ; % [] 34 | opts.patchSize = W; 35 | opts.batchSize = 1; 36 | opts.gradMax = 1e-2; 37 | opts.numEpochs = 203 ; 38 | opts.momentum = 0.99 ; 39 | opts.imdb=imdb; 40 | opts.expDir='./training_result_1'; 41 | opts.weightInitMethod = 'gaussian' ; 42 | opts.networkType = 'simplenn' ; 43 | opts.batchNormalization = true ; 44 | opts.contrastNormalization = false ; 45 | opts.waveLevel = 6; 46 | opts.waveName = 'vk'; 47 | opts.train = struct() ; 48 | opts.weight='none'; 49 | opts.plotDiagnostics = false ; 50 | opts.plotStatistics = true; 51 | opts.scale = 1 ; 52 | opts.weightDecay = 1e-6; 53 | opts.cudnnWorkspaceLimit = 1024*1024*1204*1 ; % 1GB 54 | opts.lambda = 1e-4; 55 | opts.continue = true ; 56 | opts.numSubBatches = 1 ; 57 | opts.train = find(imdb.images.set==1) ; 58 | opts.val = find(imdb.images.set == 2) ; 59 | opts.prefetch = false ; 60 | opts.memoryMapFile = fullfile(tempdir, 'matconvnet.bin') ; 61 | opts.profile = false ; 62 | opts.conserveMemory = true ; 63 | opts.backPropDepth = +inf ; 64 | opts.sync = false ; 65 | opts.cudnn = true ; 66 | opts.errorFunction = 'euclideanloss' ; 67 | opts.errorLabels = {} ; 68 | 69 | %% 70 | % -------------------------------------------------------------------------------------------------------------------------- 71 | % Build net 72 | % -------------------------------------------------------------------------------------------------------------------------- 73 | % net para 74 | ch_length=opts.channel_in; 75 | net=[]; 76 | net.meta.normalization.imageSize = [opts.patchSize,opts.patchSize,ch_length] ; 77 | net.layers = {} ; 78 | ch_length = opts.channel_in; 79 | ch_length_out = opts.channel_out; 80 | KerenlSize = 3; % conv size 81 | zeroPad = floor(KerenlSize/2); % padding size equal =(k-1)/2 considering k is odd value; 82 | 83 | net = add_block_test(net, opts, '0', KerenlSize, KerenlSize, ch_length, 64, 1, zeroPad,1,1) ; 84 | net = add_block_test(net, opts, '0', KerenlSize, KerenlSize, 64, 64, 1, zeroPad,1,1) ; 85 | net = add_block_test(net, opts, '0', KerenlSize, KerenlSize, 64, 64, 1, zeroPad,1,1) ; 86 | net = add_reg_toss_test(net, '0',1); 87 | net = add_pool_test(net, opts,'0', 2, 0); 88 | 89 | 90 | 91 | % net = add_block_test(net, opts, '1_1', KerenlSize, KerenlSize, 64, 128, 1, zeroPad,1,1) ; 92 | % net = add_block_test(net, opts, '1_2', KerenlSize, KerenlSize, 128, 128, 1, zeroPad,1,1) ; 93 | % net = add_reg_toss_test(net, '1',2); 94 | % net = add_pool_test(net, opts,'1', 2, 0); 95 | 96 | 97 | net = add_block_test(net, opts, '1_1', KerenlSize, KerenlSize, 64, 128, 1, zeroPad,1,1) ; 98 | net = add_block_test(net, opts, '1_2', KerenlSize, KerenlSize, 128, 128, 1, zeroPad,1,1) ; 99 | net = add_reg_toss_test(net,'1',2); 100 | net = add_pool_test(net, opts,'1', 2, 0); 101 | 102 | 103 | % net = add_block_test(net, opts, '3_1', KerenlSize, KerenlSize, 256, 512, 1, zeroPad,1,1) ; 104 | % net = add_block_test(net, opts, '3_2', KerenlSize, KerenlSize, 512, 512, 1, zeroPad,1,1) ; 105 | % net = add_reg_toss_test(net,'3',4); 106 | % net = add_pool_test(net, opts,'3',2,0); 107 | 108 | 109 | net = add_block_test(net, opts, '2_1', KerenlSize, KerenlSize, 128, 256, 1, zeroPad,1,1) ; 110 | net = add_block_test(net, opts, '2_2', KerenlSize, KerenlSize, 256, 256, 1, zeroPad,1,1) ; 111 | net = add_block_convt_test(net, opts, '2_3', KerenlSize, KerenlSize, 256, 128, 2, [0 1 0 1],1,1) ; 112 | 113 | net = add_reg_concat_test(net, '3_0',2); 114 | net = add_block_test(net, opts, '3_1', KerenlSize, KerenlSize, 256, 128, 1, zeroPad,1,1) ; 115 | net = add_block_test(net, opts, '3_2', KerenlSize, KerenlSize, 128, 128, 1, zeroPad,1,1) ; 116 | net = add_block_convt_test(net, opts, '3_3', KerenlSize, KerenlSize, 128, 64, 2, [0 1 0 1],1,1) ; 117 | 118 | 119 | % net = add_reg_concat_test(net, '6_0',3); 120 | % net = add_block_test(net, opts, '6_1', KerenlSize, KerenlSize, 512, 256, 1, zeroPad,1,1) ; 121 | % net = add_block_test(net, opts, '6_2', KerenlSize, KerenlSize, 256, 256, 1, zeroPad,1,1) ; 122 | % net = add_block_convt_test(net, opts, '6_3', KerenlSize, KerenlSize, 256, 128, 2, [0 1 0 1],1,1) ; 123 | 124 | 125 | % net = add_reg_concat_test(net, '5_0',2); 126 | % net = add_block_test(net, opts, '5_1', KerenlSize, KerenlSize, 256, 128, 1, zeroPad,1,1) ; 127 | % net = add_block_test(net, opts, '5_2', KerenlSize, KerenlSize, 128, 128, 1, zeroPad,1,1) ; 128 | % net = add_block_convt_test(net, opts, '5_3', KerenlSize, KerenlSize, 128, 64, 2, [0 1 0 1],1,1) ; 129 | 130 | net = add_reg_concat_test(net, '4_0',1); 131 | net = add_block_test(net, opts, '4_1', KerenlSize, KerenlSize, 128, 64, 1, zeroPad,1,1) ; 132 | net = add_block_test(net, opts, '4_2', KerenlSize, KerenlSize, 64, 64, 1, zeroPad,1,1) ; 133 | net = add_block_test(net, opts, '4_3', 1, 1, 64, ch_length_out, 1, 0,0,0) ; 134 | 135 | 136 | info = vl_simplenn_display(net); 137 | vl_simplenn_display(net) 138 | net.meta.regNum = 3; 139 | net.meta.regSize = [info.dataSize(1,end),info.dataSize(2,end),info.dataSize(3,end)]; 140 | 141 | % final touches 142 | switch lower(opts.weightInitMethod) 143 | case {'xavier', 'xavierimproved'} 144 | net.layers{end}.weights{1} = net.layers{end}.weights{1} / 10 ; 145 | end 146 | net.layers{end+1} = struct('type', 'euclideanloss', 'name', 'loss') ; 147 | net.meta.inputSize = net.meta.normalization.imageSize ; 148 | net.meta.augmentation.rgbVariance = zeros(0,3) ; 149 | net.meta.augmentation.transformation = 'stretch' ; 150 | 151 | if ~opts.batchNormalization 152 | lr = 1*logspace(-5.5, -7.5, 20) ; % generate 20 points between 10^-2 and 10^-3 153 | else 154 | lr = logspace(-5.5, -7.5, 20) ; 155 | end 156 | net.meta.trainOpts.learningRate = lr ; 157 | 158 | % Fill in default values; fill in missing default values in NET. 159 | net = vl_simplenn_tidy(net) ; 160 | 161 | % Switch to DagNN if requested 162 | switch lower(opts.networkType) 163 | case 'simplenn' 164 | % done 165 | case 'dagnn' 166 | net = dagnn.DagNN.fromSimpleNN(net, 'canonicalNames', true) ; 167 | net.addLayer('top1err', dagnn.Loss('loss', 'classerror'), ... 168 | {'prediction','label'}, 'top1err') ; 169 | net.addLayer('top5err', dagnn.Loss('loss', 'topkerror', ... 170 | 'opts', {'topK',5}), ... 171 | {'prediction','label'}, 'top5err') ; 172 | otherwise 173 | assert(false) ; 174 | end 175 | 176 | % ----------------------------------------------------------------------------------------------------------------------------- 177 | % Prepare data for training 178 | % ----------------------------------------------------------------------------------------------------------------------------- 179 | if isempty(opts.imdb) 180 | imdb = load(opts.imdbPath) ; 181 | else 182 | imdb = opts.imdb; 183 | end 184 | % get batch 185 | patchSize=opts.patchSize; 186 | opts.learningRate = net.meta.trainOpts.learningRate ; 187 | 188 | if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end 189 | if isempty(opts.train), opts.train = find(imdb.images.set==1) ; end % set the training size; 190 | if isempty(opts.val), opts.val = find(imdb.images.set==2) ; end 191 | if isnan(opts.train), opts.train = [] ; end 192 | if isnan(opts.val), opts.val = [] ; end 193 | 194 | % ----------------------------------------------------------------------------------------------------------------------------- 195 | % Network initialization 196 | % ----------------------------------------------------------------------------------------------------------------------------- 197 | 198 | net = vl_simplenn_tidy(net); % fill in some eventually missing values 199 | net.layers{end-1}.precious = 1; % do not remove predictions, used for error 200 | vl_simplenn_display(net, 'batchSize', opts.batchSize) ; 201 | 202 | evaluateMode = isempty(opts.train) ; 203 | 204 | if ~evaluateMode 205 | for i=1:numel(net.layers) 206 | if isfield(net.layers{i}, 'weights') 207 | J = numel(net.layers{i}.weights) ; 208 | for j=1:J 209 | net.layers{i}.momentum{j} = zeros(size(net.layers{i}.weights{j}), 'single') ; 210 | end 211 | if ~isfield(net.layers{i}, 'learningRate') 212 | net.layers{i}.learningRate = ones(1, J, 'single') ; 213 | end 214 | if ~isfield(net.layers{i}, 'weightDecay') 215 | net.layers{i}.weightDecay = ones(1, J, 'single') ; 216 | end 217 | end 218 | end 219 | end 220 | 221 | % setup GPUs 222 | numGpus = numel(opts.gpus) ; 223 | if numGpus > 1 224 | if isempty(gcp('nocreate')), 225 | parpool('local',numGpus) ; 226 | spmd, gpuDevice(opts.gpus(labindex)), end 227 | end 228 | elseif numGpus == 1 229 | gpuDevice(opts.gpus) 230 | end 231 | if exist(opts.memoryMapFile), delete(opts.memoryMapFile) ; end 232 | 233 | % setup error calculation function 234 | hasError = true ; 235 | if isstr(opts.errorFunction) 236 | switch opts.errorFunction 237 | case 'none' 238 | opts.errorFunction = @error_none ; 239 | hasError = false ; 240 | case 'multiclass' 241 | opts.errorFunction = @error_multiclass ; 242 | if isempty(opts.errorLabels), opts.errorLabels = {'top1err', 'top5err'} ; end 243 | case 'binary' 244 | opts.errorFunction = @error_binary ; 245 | if isempty(opts.errorLabels), opts.errorLabels = {'binerr'} ; end 246 | case 'euclideanloss' 247 | opts.errorFunction = @error_euclideanloss_test ; 248 | if isempty(opts.errorLabels), opts.errorLabels = {'mse'} ; end 249 | case 'euclideansparseloss' 250 | opts.errorFunction = @error_euclideanloss ; 251 | if isempty(opts.errorLabels), opts.errorLabels = {'mse'} ; end 252 | otherwise 253 | error('Unknown error function ''%s''.', opts.errorFunction) ; 254 | end 255 | end 256 | 257 | %% 258 | % ----------------------------------------------------------------------------------------------------------------------------- 259 | % Train and validate 260 | % ----------------------------------------------------------------------------------------------------------------------------- 261 | 262 | modelPath = @(ep) fullfile(opts.expDir, sprintf('net-epoch-%d.mat', ep)); 263 | modelFigPath = fullfile(opts.expDir, 'net-train.pdf') ; 264 | 265 | start_e = opts.continue * findLastCheckpoint_test(opts.expDir) ; 266 | if start_e >= 1 267 | fprintf('%s: resuming by loading epoch %d\n', mfilename, start_e) ; 268 | load(modelPath(start_e), 'net', 'info') ; 269 | net = vl_simplenn_tidy(net) ; % just in case MatConvNet was updated 270 | end 271 | 272 | 273 | for epoch=start_e+1:opts.numEpochs % loop for epoch 274 | 275 | % train one epoch and validate 276 | learningRate = opts.learningRate(min(epoch, numel(opts.learningRate))) ; 277 | train = opts.train(randperm(numel(opts.train))) ; % shuffle 278 | val = opts.val ; 279 | 280 | if numGpus <= 1 281 | [net,stats.train,prof] = process_epoch_test(opts, patchSize, epoch, train, learningRate, imdb, net,Coef) ; 282 | [~,stats.val] = process_epoch_test(opts, patchSize, epoch, val, 0, imdb, net,Coef) ; 283 | if opts.profile 284 | profile('viewer') ; 285 | keyboard ; 286 | end 287 | else 288 | fprintf('%s: sending model to %d GPUs\n', mfilename, numGpus) ; 289 | spmd(numGpus) 290 | [net_, stats_train_,prof_] = process_epoch_test(opts, patchSize, epoch, train, learningRate, imdb, net,Coef) ; 291 | [~, stats_val_] = process_epoch_test(opts, patchSize, epoch, val, 0, imdb, net_,Coef) ; 292 | end 293 | net = net_{1} ; 294 | stats.train = sum([stats_train_{:}],2) ; 295 | stats.val = sum([stats_val_{:}],2) ; 296 | if opts.profile 297 | mpiprofile('viewer', [prof_{:,1}]) ; 298 | keyboard ; 299 | end 300 | clear net_ stats_train_ stats_val_ ; 301 | end 302 | 303 | % save 304 | if evaluateMode, sets = {'val'} ; else sets = {'train', 'val'} ; end 305 | for f = sets 306 | f = char(f); 307 | n = numel(eval(f)); 308 | info.(f).speed(epoch) = n / stats.(f)(1) * max(1, numGpus) ; 309 | info.(f).objective(epoch) = stats.(f)(2) / n ; 310 | info.(f).error(:,epoch) = stats.(f)(3:end) / n ; 311 | end 312 | if ~evaluateMode 313 | fprintf('%s: saving model for epoch %d\n', mfilename, epoch) ; 314 | tic ; 315 | if mod(epoch,20)==1 316 | save(modelPath(epoch), 'net', 'info') ; 317 | elseif epoch==1 318 | save(modelPath(epoch), 'net', 'info','opts') ; 319 | end 320 | fprintf('%s: model saved in %.2g s\n', mfilename, toc) ; 321 | end 322 | 323 | if opts.plotStatistics 324 | switchfigure_test(1) ; clf ; 325 | subplot(1,1+hasError,1) ; 326 | if ~evaluateMode 327 | semilogy(max(1,epoch-2000):epoch, info.train.objective(max(1,epoch-2000):end), '.-', 'linewidth', 2) ; 328 | hold on ; 329 | end 330 | semilogy(max(1,epoch-2000):epoch, info.val.objective(max(1,epoch-2000):end), '.--') ; 331 | xlabel('training epoch') ; ylabel('energy') ; 332 | grid on ; 333 | h=legend(sets) ; 334 | set(h,'color','none'); 335 | title('objective') ; 336 | if hasError 337 | subplot(1,2,2) ; leg = {} ; 338 | if ~evaluateMode 339 | plot(max(1,epoch-2000):epoch, info.train.error(max(1,epoch-2000):end)', '.-', 'linewidth', 2) ; 340 | hold on ; 341 | leg = horzcat(leg, strcat('train ', opts.errorLabels)) ; 342 | end 343 | plot(max(1,epoch-2000):epoch, info.val.error(max(1,epoch-2000):end)', '.--') ; 344 | leg = horzcat(leg, strcat('val ', opts.errorLabels)) ; 345 | set(legend(leg{:}),'color','none') ; 346 | grid on ; 347 | xlabel('training epoch') ; ylabel('error') ; 348 | title('error') ; 349 | end 350 | drawnow ; 351 | print(1, modelFigPath, '-dpdf') ; 352 | end 353 | 354 | %} 355 | end 356 | 357 | 358 | %% check and plot evaluate figure; 359 | % Display_Results; 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | -------------------------------------------------------------------------------- /CNN_Data_Cir.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/CNN_Data_Cir.mat -------------------------------------------------------------------------------- /CNN_ISP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/CNN_ISP.pdf -------------------------------------------------------------------------------- /Data_generate_Circle_BP.m: -------------------------------------------------------------------------------- 1 | % This code is used to produce ground truth pattern and backprojection 2 | % initializations; 3 | % Written by Wei Zhun at ECE, NUS, 20th, Nov, 2017. 4 | 5 | clc; clear all; 6 | close all; 7 | 8 | load('basic_para.mat'); 9 | load('Forward_Circ1.mat'); 10 | N_t=size(Pro_Para,2); 11 | MAX = 1; Mx = 64; % discretization parameter 12 | epsil_exa=zeros(Mx,Mx,1,N_t,'single'); 13 | epsil_bp=zeros(Mx,Mx,1,N_t,'single'); 14 | NS_L=0.05; % noise level; 15 | % NS_L=0.2; % noise level; 16 | %% discritization 17 | tmp_domain = linspace(-MAX,MAX,Mx); 18 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 19 | N_cell_dom = size(x_dom,1)*size(x_dom,2); 20 | x0 = x_dom; y0 = y_dom; 21 | step_size = 2*MAX/(Mx-1); 22 | cell_area = step_size^2; % the area of the sub-domain 23 | a_eqv = sqrt(cell_area/pi); % the equivalent radius of the sub-domain for the circle approximatio 24 | 25 | %% reciver and incidence 26 | % reciver 27 | N_rec = 32; % Nb. of Receiver 28 | theta_tmp = linspace(0, 2*pi, N_rec+1); theta_tmp(end) = []; theta_tmp = theta_tmp(:); 29 | [theta,rho] = meshgrid(theta_tmp,3); theta = theta(:); rho = rho(:); 30 | [x,y] = pol2cart(theta,rho); 31 | % Incident field 32 | if bool_plane ==1 33 | %Plane wave incidence 34 | E_inc_dom = exp(i*x_dom*k_x.' +i*y_dom*k_y.'); % N_cell_dom x N_inc 35 | else 36 | %Line source incidence 37 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 38 | [theta_t,rho_t] = meshgrid(theta_inc,3); theta_t = theta_t(:); rho_t = rho_t(:); 39 | [x_t,y_t] = pol2cart(theta_t,rho_t); 40 | % Point source incidence 41 | [x_dom_tmp_t, x_tmp_t] = meshgrid(x_dom,x_t); 42 | [y_dom_tmp_t, y_tmp_t] = meshgrid(y_dom,y_t); 43 | rho_dom_mat_t = sqrt((x_dom_tmp_t-x_tmp_t).^2 +(y_dom_tmp_t-y_tmp_t).^2); % N_inc x N_cell_dom 44 | T_mat_dom = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_dom_mat_t); % N_inc x N_cell_dom 45 | E_inc_dom = T_mat_dom.'; % N_cell_dom x N_inc 46 | clear x_dom_tmp_t x_tmp_t y_dom_tmp_t y_tmp_t rho_dom_mat_t T_mat_dom 47 | end 48 | 49 | %% Gs matrix 50 | x_dom = x_dom(:); 51 | y_dom = y_dom(:); 52 | [x_dom_tmp, x_tmp] = meshgrid(x_dom,x); 53 | [y_dom_tmp, y_tmp] = meshgrid(y_dom,y); 54 | rho_dom_mat = sqrt((x_dom_tmp-x_tmp).^2 +(y_dom_tmp-y_tmp).^2); % N_rec x N_cell_dom 55 | R_dom_mat = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_dom_mat); % N_rec x N_cell_dom 56 | 57 | %% GD matrix 58 | [x_dom_cell, x_dom_cell_2] = meshgrid(x_dom,x_dom); 59 | x_dist_tmp = (x_dom_cell-x_dom_cell_2).^2; 60 | clear x_dom_cell x_dom_cell_2 61 | [y_dom_cell, y_dom_cell_2] = meshgrid(y_dom,y_dom); 62 | y_dist_tmp = (y_dom_cell-y_dom_cell_2).^2; 63 | clear y_dom_cell y_dom_cell_2 64 | dist_tmp = x_dist_tmp + y_dist_tmp; 65 | clear x_dist_tmp y_dist_tmp 66 | dist_dom_cell = sqrt(dist_tmp); 67 | clear dist_tmp 68 | dist_dom_cell = dist_dom_cell+ eye(N_cell_dom); 69 | Phi_mat_dom = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*dist_dom_cell); 70 | clear dist_dom_cell 71 | diag_zero = ones(N_cell_dom)-eye(N_cell_dom); 72 | Phi_mat_dom = Phi_mat_dom .*diag_zero; % Diagonal is set to zero 73 | I2=(i/4)*(2/(k_0*a_eqv)*besselh(1,1,k_0*a_eqv)+4*1i/(k_0^2*cell_area)); % diagonal integral of Green's function; 74 | S1=Coef*I2; % Analytical sigular value for self-cell integral(exclude cell area); 75 | Phi_mat_dom=Phi_mat_dom+S1*eye(N_cell_dom); % Add the self-contribution. 76 | clear diag_zero 77 | 78 | for nn=1:N_t 79 | 80 | %% grondtruth pattern 81 | epsil_exa(:,:,1,nn)= annulus_gen_exa(MAX,Mx,Pro_Para{nn}); 82 | 83 | %% BP pattern 84 | % adding noise 85 | E_sG=E_s(:,:,nn); % no noise signal 86 | rand_real = randn(N_rec,N_inc); 87 | rand_imag = randn(N_rec,N_inc); 88 | E_Gaussian = 1/sqrt(2) *sqrt(1/N_rec/N_inc)*norm(E_sG(:)) *NS_L*(rand_real +i*rand_imag); 89 | E_sN = E_sG +E_Gaussian; 90 | 91 | % Back propagation initial guess 92 | J_init = zeros(N_cell_dom,N_inc); 93 | for ii = 1:N_inc 94 | gamma_tmp = (R_dom_mat*(R_dom_mat'*E_sN(:,ii)))\E_sN(:,ii); %scalar 95 | J_init(:,ii) = gamma_tmp*(R_dom_mat'*E_sN(:,ii)); 96 | end 97 | E_tot_init = E_inc_dom +Phi_mat_dom*J_init; % N_cell_dom x N_inc 98 | up_tmp = sum(conj(E_tot_init).*J_init,2); 99 | clear J_init 100 | down_tmp = sum(conj(E_tot_init).*E_tot_init,2); 101 | clear E_tot_init 102 | x_int = imag(up_tmp./down_tmp); 103 | clear up_tmp down_tmp 104 | x_int = x_int/(-omega*eps_0*step_size^2)+1; % change to epsilon 105 | epsil_bp(:,:,1,nn) = reshape(x_int, Mx, Mx); 106 | nn 107 | end 108 | 109 | %% display a rand one parameter 110 | Indx=round(1+(N_t-1)*rand); % produce a rand integer between 1 and N_t; 111 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 112 | figure 113 | pcolor(x_dom,y_dom,epsil_bp(:,:,1,Indx)); axis square; axis tight; shading flat; 114 | title('BP Results'); 115 | colorbar 116 | figure 117 | pcolor(x_dom,y_dom,epsil_exa(:,:,1,Indx)); axis square; axis tight; shading flat; 118 | colorbar 119 | title('Ground Truth Results'); 120 | 121 | clearvars -except epsil_bp epsil_exa; 122 | save('CNN_Data_Cir.mat') 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /Data_generate_Circle_BP_S1.m: -------------------------------------------------------------------------------- 1 | % This code is used to produce ground truth pattern and backprojection 2 | % initializations; 3 | % Written by Wei Zhun at ECE, NUS, 20th, Nov, 2017. 4 | 5 | clc; clear all; 6 | close all; 7 | 8 | load('basic_para.mat'); 9 | load('Forward_Circ2_S1.mat'); 10 | N_t=500; 11 | MAX = 1; Mx = 64; % discretization parameter 12 | 13 | NS_L=0.2; % noise level; 14 | %% discritization 15 | tmp_domain = linspace(-MAX,MAX,Mx); 16 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 17 | N_cell_dom = size(x_dom,1)*size(x_dom,2); 18 | x0 = x_dom; y0 = y_dom; 19 | step_size = 2*MAX/(Mx-1); 20 | cell_area = step_size^2; % the area of the sub-domain 21 | a_eqv = sqrt(cell_area/pi); % the equivalent radius of the sub-domain for the circle approximatio 22 | 23 | %% reciver and incidence 24 | % reciver 25 | N_rec = 32; % Nb. of Receiver 26 | theta_tmp = linspace(0, 2*pi, N_rec+1); theta_tmp(end) = []; theta_tmp = theta_tmp(:); 27 | [theta,rho] = meshgrid(theta_tmp,3); theta = theta(:); rho = rho(:); 28 | [x,y] = pol2cart(theta,rho); 29 | % Incident field 30 | if bool_plane ==1 31 | %Plane wave incidence 32 | E_inc_dom = exp(i*x_dom*k_x.' +i*y_dom*k_y.'); % N_cell_dom x N_inc 33 | else 34 | %Line source incidence 35 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 36 | [theta_t,rho_t] = meshgrid(theta_inc,3); theta_t = theta_t(:); rho_t = rho_t(:); 37 | [x_t,y_t] = pol2cart(theta_t,rho_t); 38 | % Point source incidence 39 | [x_dom_tmp_t, x_tmp_t] = meshgrid(x_dom,x_t); 40 | [y_dom_tmp_t, y_tmp_t] = meshgrid(y_dom,y_t); 41 | rho_dom_mat_t = sqrt((x_dom_tmp_t-x_tmp_t).^2 +(y_dom_tmp_t-y_tmp_t).^2); % N_inc x N_cell_dom 42 | T_mat_dom = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_dom_mat_t); % N_inc x N_cell_dom 43 | E_inc_dom = T_mat_dom.'; % N_cell_dom x N_inc 44 | clear x_dom_tmp_t x_tmp_t y_dom_tmp_t y_tmp_t rho_dom_mat_t T_mat_dom 45 | end 46 | 47 | %% Gs matrix 48 | x_dom = x_dom(:); 49 | y_dom = y_dom(:); 50 | [x_dom_tmp, x_tmp] = meshgrid(x_dom,x); 51 | [y_dom_tmp, y_tmp] = meshgrid(y_dom,y); 52 | rho_dom_mat = sqrt((x_dom_tmp-x_tmp).^2 +(y_dom_tmp-y_tmp).^2); % N_rec x N_cell_dom 53 | R_dom_mat = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_dom_mat); % N_rec x N_cell_dom 54 | 55 | %% GD matrix 56 | [x_dom_cell, x_dom_cell_2] = meshgrid(x_dom,x_dom); 57 | x_dist_tmp = (x_dom_cell-x_dom_cell_2).^2; 58 | clear x_dom_cell x_dom_cell_2 59 | [y_dom_cell, y_dom_cell_2] = meshgrid(y_dom,y_dom); 60 | y_dist_tmp = (y_dom_cell-y_dom_cell_2).^2; 61 | clear y_dom_cell y_dom_cell_2 62 | dist_tmp = x_dist_tmp + y_dist_tmp; 63 | clear x_dist_tmp y_dist_tmp 64 | dist_dom_cell = sqrt(dist_tmp); 65 | clear dist_tmp 66 | dist_dom_cell = dist_dom_cell+ eye(N_cell_dom); 67 | Phi_mat_dom = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*dist_dom_cell); 68 | clear dist_dom_cell 69 | diag_zero = ones(N_cell_dom)-eye(N_cell_dom); 70 | Phi_mat_dom = Phi_mat_dom .*diag_zero; % Diagonal is set to zero 71 | I2=(i/4)*(2/(k_0*a_eqv)*besselh(1,1,k_0*a_eqv)+4*1i/(k_0^2*cell_area)); % diagonal integral of Green's function; 72 | S1=Coef*I2; % Analytical sigular value for self-cell integral(exclude cell area); 73 | Phi_mat_dom=Phi_mat_dom+S1*eye(N_cell_dom); % Add the self-contribution. 74 | clear diag_zero 75 | 76 | for nn=N_t:N_t 77 | 78 | %% grondtruth pattern 79 | 80 | %% BP pattern 81 | % adding noise 82 | E_sG=E_s; % no noise signal 83 | rand_real = randn(N_rec,N_inc); 84 | rand_imag = randn(N_rec,N_inc); 85 | E_Gaussian = 1/sqrt(2) *sqrt(1/N_rec/N_inc)*norm(E_sG(:)) *NS_L*(rand_real +i*rand_imag); 86 | E_sN = E_sG +E_Gaussian; 87 | 88 | % Back propagation initial guess 89 | J_init = zeros(N_cell_dom,N_inc); 90 | for ii = 1:N_inc 91 | gamma_tmp = (R_dom_mat*(R_dom_mat'*E_sN(:,ii)))\E_sN(:,ii); %scalar 92 | J_init(:,ii) = gamma_tmp*(R_dom_mat'*E_sN(:,ii)); 93 | end 94 | E_tot_init = E_inc_dom +Phi_mat_dom*J_init; % N_cell_dom x N_inc 95 | up_tmp = sum(conj(E_tot_init).*J_init,2); 96 | clear J_init 97 | down_tmp = sum(conj(E_tot_init).*E_tot_init,2); 98 | clear E_tot_init 99 | x_int = imag(up_tmp./down_tmp); 100 | clear up_tmp down_tmp 101 | x_int = x_int/(-omega*eps_0*step_size^2)+1; % change to epsilon 102 | epsil_bpS1 = reshape(x_int, Mx, Mx); 103 | nn 104 | end 105 | 106 | %% display a rand one parameter 107 | Indx=round(1+(N_t-1)*rand); % produce a rand integer between 1 and N_t; 108 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 109 | figure 110 | pcolor(x_dom,y_dom,epsil_bpS1); axis square; axis tight; shading flat; 111 | title('BP Results'); 112 | colorbar 113 | figure 114 | pcolor(x_dom,y_dom,epsil_exaS1); axis square; axis tight; shading flat; 115 | colorbar 116 | title('Ground Truth Results'); 117 | 118 | clearvars -except epsil_bpS1 epsil_exaS1; 119 | save('CNN_Data_Cir_S1_N20.mat') 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Display_Results_all_Results.m: -------------------------------------------------------------------------------- 1 | clc; clear all;close all; 2 | load ('./training_result/net-epoch-201.mat'); 3 | load CNN_Data_Cir.mat; 4 | 5 | % load ('./training_result_S300/net-epoch-201.mat'); 6 | % load CNN_Data_Cir.mat; 7 | 8 | % run D:/Software/Matlab/Neural_Network/5_CNN_test/FBPConvNet-master/matconvnet-1.0-beta23/matlab/vl_setupnn 9 | % run D:/Software/Matlab/Neural_Network/5_CNN_test/FBPConvNet-master/matconvnet-1.0-beta23/matlab/vl_compilenn 10 | %% opts 11 | W = 64; % size of patch 12 | Nimg= 500; % # of train + test set 13 | Nimg_test= fix(Nimg*0.05); 14 | Coef=10; 15 | 16 | id_tmp = ones(Nimg,1); 17 | id_tmp(Nimg-Nimg_test+1:end)=2; % the test indx is 2, training is 1 18 | 19 | imdb.images.set=id_tmp; % train set : 1 , test set : 2 20 | imdb.images.noisy=single((epsil_bp-1)*Coef); % input : H x W x C x N (X,Y,channel,batch) 21 | imdb.images.orig=single((epsil_exa-1)*Coef); % output : H x W x C x N (X,Y,channel,batch) 22 | % opts 23 | opts.channel_in = 1; 24 | opts.channel_out=1; 25 | opts.useGpu = 'false'; %'false' 26 | opts.gpus = [] ; % [] 27 | patchSize = W; 28 | %% 29 | tic 30 | for t=1:25 31 | batch=t+475; 32 | [im, labels, lowRes] = getSimpleNNBatch_test(imdb, batch, patchSize); 33 | dzdy=[];res=[];s=1; evalMode = 'val' ; 34 | opts.conserveMemory = true ; 35 | opts.backPropDepth = +inf ; 36 | opts.sync = false ; 37 | opts.cudnn = true ; 38 | [res, reg] = vl_simplenn_fbpconvnet(net, im, dzdy, res, ... 39 | 'accumulate', s ~= 1, ... 40 | 'mode', evalMode, ... 41 | 'conserveMemory', opts.conserveMemory, ... 42 | 'backPropDepth', opts.backPropDepth, ... 43 | 'sync', opts.sync, ... 44 | 'cudnn', opts.cudnn) ; 45 | 46 | [epsil_exa,epsil_bp,epsil_rec]=displayImg_test_final(labels,im,res,lowRes,Coef); 47 | toc 48 | err_bp(t)=norm(reshape(epsil_bp,[],1)-reshape(epsil_exa,[],1))/norm(reshape(epsil_exa,[],1)); 49 | err_rec(t)=norm(reshape(epsil_rec,[],1)-reshape(epsil_exa,[],1))/norm(reshape(epsil_exa,[],1)); 50 | 51 | end 52 | err_rec 53 | mean(err_rec) 54 | 55 | mean(err_rec) 56 | MAX = 1; Mx = 64; % discretization parameter 57 | tmp_domain = linspace(-MAX,MAX,Mx); 58 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 59 | figure 60 | set(0,'DefaultaxesFontSize',22); 61 | set(0,'DefaulttextFontSize',22); 62 | xlabel('x (m)'); 63 | ylabel('y (m)'); 64 | pcolor(x_dom,y_dom,epsil_exa); axis square; axis tight; shading flat;colorbar;colormap(jet); 65 | xlabel('x (m)'); 66 | ylabel('y (m)'); 67 | print('-djpeg','-r200','-painters','Fig11'); 68 | figure 69 | pcolor(x_dom,y_dom,epsil_bp); axis square; axis tight; shading flat;colorbar;colormap(jet); 70 | set(0,'DefaultaxesFontSize',22); 71 | set(0,'DefaulttextFontSize',22); 72 | xlabel('x (m)'); 73 | ylabel('y (m)'); 74 | print('-djpeg','-r200','-painters','Fig12'); 75 | % title('BP Results'); 76 | figure 77 | pcolor(x_dom,y_dom,epsil_rec); axis square; axis tight; shading flat;colorbar;colormap(jet); 78 | set(0,'DefaultaxesFontSize',22); 79 | set(0,'DefaulttextFontSize',22); 80 | 81 | xlabel('x (m)'); 82 | ylabel('y (m)'); 83 | print('-djpeg','-r200','-painters','Fig13'); 84 | -------------------------------------------------------------------------------- /Display_Results_your_example.m: -------------------------------------------------------------------------------- 1 | clc; clear all;close all; 2 | load ('./training_result/net-epoch-201.mat'); 3 | load CNN_Data_Cir.mat; 4 | 5 | load CNN_Data_Cir_S1_N20.mat; 6 | 7 | % load ('./training_result/net-epoch-201.mat'); 8 | % load CNN_Data_Cir_N20.mat; 9 | 10 | % run D:/Software/Matlab/Neural_Network/5_CNN_test/FBPConvNet-master/matconvnet-1.0-beta23/matlab/vl_setupnn 11 | % run D:/Software/Matlab/Neural_Network/5_CNN_test/FBPConvNet-master/matconvnet-1.0-beta23/matlab/vl_compilenn 12 | %% opts 13 | W = 64; % size of patch 14 | Nimg= 500; % # of train + test set 15 | Nimg_test= fix(Nimg*0.05); 16 | Coef=10; 17 | 18 | id_tmp = ones(Nimg,1); 19 | id_tmp(Nimg-Nimg_test+1:end)=2; % the test indx is 2, training is 1 20 | 21 | imdb.images.set=id_tmp; % train set : 1 , test set : 2 22 | imdb.images.noisy=single((epsil_bp-1)*Coef); % input : H x W x C x N (X,Y,channel,batch) 23 | imdb.images.orig=single((epsil_exa-1)*Coef); % output : H x W x C x N (X,Y,channel,batch) 24 | imdb.images.noisy(:,:,1,500)=single((epsil_bpS1-1)*Coef); % input : H x W x C x N (X,Y,channel,batch) 25 | imdb.images.orig(:,:,1,500)=single((epsil_exaS1-1)*Coef); % output : H x W x C x N (X,Y,channel,batch) 26 | % opts 27 | opts.channel_in = 1; 28 | opts.channel_out=1; 29 | opts.useGpu = 'false'; %'false' 30 | opts.gpus = [] ; % [] 31 | patchSize = W; 32 | %% 33 | tic 34 | for t=500 35 | batch=500; 36 | [im, labels, lowRes] = getSimpleNNBatch_test(imdb, batch, patchSize); 37 | dzdy=[];res=[];s=1; evalMode = 'val' ; 38 | opts.conserveMemory = true ; 39 | opts.backPropDepth = +inf ; 40 | opts.sync = false ; 41 | opts.cudnn = true ; 42 | [res, reg] = vl_simplenn_fbpconvnet(net, im, dzdy, res, ... 43 | 'accumulate', s ~= 1, ... 44 | 'mode', evalMode, ... 45 | 'conserveMemory', opts.conserveMemory, ... 46 | 'backPropDepth', opts.backPropDepth, ... 47 | 'sync', opts.sync, ... 48 | 'cudnn', opts.cudnn) ; 49 | 50 | [epsil_exa,epsil_bp,epsil_rec]=displayImg_test_final(labels,im,res,lowRes,Coef); 51 | toc 52 | err_bp=norm(reshape(epsil_bp,[],1)-reshape(epsil_exa,[],1))/norm(reshape(epsil_exa,[],1)); 53 | err_rec=norm(reshape(epsil_rec,[],1)-reshape(epsil_exa,[],1))/norm(reshape(epsil_exa,[],1)); 54 | 55 | end 56 | err_rec 57 | mean(err_rec) 58 | 59 | mean(err_rec) 60 | MAX = 1; Mx = 64; % discretization parameter 61 | tmp_domain = linspace(-MAX,MAX,Mx); 62 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 63 | figure 64 | set(0,'DefaultaxesFontSize',22); 65 | set(0,'DefaulttextFontSize',22); 66 | xlabel('x (m)'); 67 | ylabel('y (m)'); 68 | pcolor(x_dom,y_dom,epsil_exa); axis square; axis tight; shading flat;colorbar;colormap(jet); 69 | xlabel('x (m)'); 70 | ylabel('y (m)'); 71 | print('-djpeg','-r200','-painters','Fig11'); 72 | figure 73 | pcolor(x_dom,y_dom,epsil_bp); axis square; axis tight; shading flat;colorbar;colormap(jet); 74 | set(0,'DefaultaxesFontSize',22); 75 | set(0,'DefaulttextFontSize',22); 76 | xlabel('x (m)'); 77 | ylabel('y (m)'); 78 | print('-djpeg','-r200','-painters','Fig12'); 79 | % title('BP Results'); 80 | figure 81 | pcolor(x_dom,y_dom,epsil_rec); axis square; axis tight; shading flat;colorbar;colormap(jet); 82 | set(0,'DefaultaxesFontSize',22); 83 | set(0,'DefaulttextFontSize',22); 84 | 85 | xlabel('x (m)'); 86 | ylabel('y (m)'); 87 | print('-djpeg','-r200','-painters','Fig13'); 88 | -------------------------------------------------------------------------------- /Forward_Circ1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/Forward_Circ1.mat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solving full-wave-nonlinear-inverse-scattering-problems with back-propagation-scheme 2 | This Matlab code is used to solve inverse scattering problem with convolutional neural network by BPS. 3 | Zhun Wei. weizhun1010@gmail.com 4 | 5 | More information, please welcome to visist: https://person.zju.edu.cn/0020060 6 | (更多信息欢迎访问: https://person.zju.edu.cn/0020060) 7 | 8 | Please first download matconvnet 1.0-beta23 : http://www.vlfeat.org/matconvnet/ remember to upzip it. To use mex, you also need visual studio installed. 9 | 10 | (1) The Matlab code is used to implement back-propagation scheme (BPS) in 11 | Z. Wei and X. Chen, “Deep learning schemes for full-wave nonlinear inverse scattering problems,” IEEE Transactions on Geoscience and Remote Sensing, 57 (4), pp. 1849-1860, 2019. 12 | This Matlab code is used to solve inverse scattering problem with convolutional neural network by BPS, which is written by Zhun WEI (weizhun1010@gmail. com). 13 | Please feel free to contact if you have any question. Only CPU is required, and you can easily adapt it into GPU version or Python version. 14 | 15 | (2) After training, you can simply test the trained network by running “Display_Results_all_Results” for 25 examples. 16 | If you want to test it on a profile defined by yourself, you can define your profile in “data_generate_Circle_Es_S1” , run it, and then run “Data_generate_Circle_BP_S1” to generate BP inputs, and at last run “Display_Results_your_example” 17 | 18 | (3) To start a new training: You can start your training by simple run “BPS_Training”, it consists of “data_generate_Circle_Es” (generate training scattering field) , “Data_generate_Circle_BP” (generate BP inputs), and training process. 19 | To test your trained network, please refer to (2). 20 | 21 | If you find this code is useful for you, please cite the following references: 22 | 23 | Z. Wei and X. Chen, “Deep learning schemes for full-wave nonlinear inverse scattering problems,” IEEE Transactions on Geoscience and Remote Sensing, 57 (4), pp. 1849-1860, 2019. 24 | 25 | Z. Wei# and X. Chen, “Uncertainty Quantification in Inverse Scattering Problems with Bayesian Convolutional Neural Networks” IEEE Transactions on Antennas and Propagation, 10.1109/TAP.2020.3030974, 2020. 26 | 27 | K. H. Jin, M. T. McCann, E. Froustey, and M. Unser, “Deep convolutional neural network for inverse problems in imaging,” IEEE Transactions on Image Processing, vol. 26, no. 9, pp. 4509–4522, 2017. 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /accumulate_gradients_test.m: -------------------------------------------------------------------------------- 1 | function [net,res] = accumulate_gradients_test(opts, lr, batchSize, net, res, mmap) 2 | % ------------------------------------------------------------------------- 3 | if nargin >= 6 4 | numGpus = numel(mmap.Data) ; 5 | else 6 | numGpus = 1 ; 7 | end 8 | 9 | for l=numel(net.layers):-1:1 10 | for j=1:numel(res(l).dzdw) 11 | 12 | % accumualte gradients from multiple labs (GPUs) if needed 13 | if numGpus > 1 14 | tag = sprintf('l%d_%d',l,j) ; 15 | tmp = zeros(size(mmap.Data(labindex).(tag)), 'single') ; 16 | for g = setdiff(1:numGpus, labindex) 17 | tmp = tmp + mmap.Data(g).(tag) ; 18 | end 19 | res(l).dzdw{j} = res(l).dzdw{j} + tmp ; 20 | end 21 | 22 | if j == 3 && strcmp(net.layers{l}.type, 'bnorm') 23 | % special case for learning bnorm moments 24 | thisLR = net.layers{l}.learningRate(j) ; 25 | net.layers{l}.weights{j} = ... 26 | (1-thisLR) * net.layers{l}.weights{j} + ... 27 | (thisLR/batchSize) * res(l).dzdw{j} ; 28 | else 29 | % standard gradient training 30 | thisDecay = opts.weightDecay * net.layers{l}.weightDecay(j) ; 31 | thisLR = lr * net.layers{l}.learningRate(j) ; 32 | net.layers{l}.momentum{j} = ... 33 | opts.momentum * net.layers{l}.momentum{j} ... 34 | - thisDecay * net.layers{l}.weights{j} ... 35 | - (1 / batchSize) * res(l).dzdw{j} ; 36 | 37 | net.layers{l}.weights{j} = net.layers{l}.weights{j} + ... 38 | min(max(thisLR * net.layers{l}.momentum{j},-opts.gradMax),opts.gradMax) ; 39 | end 40 | 41 | % if requested, collect some useful stats for debugging 42 | if opts.plotDiagnostics 43 | variation = [] ; 44 | label = '' ; 45 | switch net.layers{l}.type 46 | case {'conv','convt'} 47 | variation = thisLR * mean(abs(net.layers{l}.momentum{j}(:))) ; 48 | if j == 1 % fiters 49 | base = mean(abs(net.layers{l}.weights{j}(:))) ; 50 | label = 'filters' ; 51 | else % biases 52 | base = mean(abs(res(l+1).x(:))) ; 53 | label = 'biases' ; 54 | end 55 | variation = variation / base ; 56 | label = sprintf('%s_%s', net.layers{l}.name, label) ; 57 | end 58 | res(l).stats.variation(j) = variation ; 59 | res(l).stats.label{j} = label ; 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /add_block_convt_test.m: -------------------------------------------------------------------------------- 1 | function net = add_block_convt_test(net, opts, id, h, w, in, out, upsample, crop,batchOn,ReluOn) 2 | % -------------------------------------------------------------------- 3 | % crop=[2 3 2 3]; 4 | info = vl_simplenn_display(net) ; 5 | fc = (h == info.dataSize(1,end) && w == info.dataSize(2,end)) ; 6 | if fc 7 | name = 'fc' ; 8 | else 9 | name = 'convt' ; 10 | end 11 | convOpts = {'CudnnWorkspaceLimit', opts.cudnnWorkspaceLimit} ; 12 | net.layers{end+1} = struct('type', 'convt', 'name', sprintf('%s%s', name, id), ... 13 | 'weights', {{init_weight_test(opts, h, w, out, in, 'single'), zeros(out, 1, 'single')}}, ... 14 | 'upsample', upsample, ... 15 | 'crop', crop, ... 16 | 'learningRate', [1 2], ... 17 | 'weightDecay', [opts.weightDecay 0], ... 18 | 'opts', {convOpts}) ; 19 | if (opts.batchNormalization)&&batchOn 20 | net.layers{end+1} = struct('type', 'bnorm', 'name', sprintf('bn%s',id), ... 21 | 'weights', {{ones(out, 1, 'single'), zeros(out, 1, 'single'), zeros(out, 2, 'single')}}, ... 22 | 'learningRate', [2 1 0.05], ... 23 | 'weightDecay', [0 0]) ; 24 | end 25 | if ReluOn 26 | net.layers{end+1} = struct('type', 'relu', 'name', sprintf('relu%s',id)) ; 27 | end -------------------------------------------------------------------------------- /add_block_test.m: -------------------------------------------------------------------------------- 1 | function net = add_block_test(net, opts, id, h, w, in, out, stride, pad,batchOn,ReluOn) 2 | % -------------------------------------------------------------------- 3 | info = vl_simplenn_display(net) ; 4 | fc = (h == info.dataSize(1,end) && w == info.dataSize(2,end)) ; 5 | if fc 6 | name = 'fc' ; 7 | else 8 | name = 'conv' ; 9 | end 10 | convOpts = {'CudnnWorkspaceLimit', opts.cudnnWorkspaceLimit} ; 11 | net.layers{end+1} = struct('type', 'conv', 'name', sprintf('%s%s', name, id), ... 12 | 'weights', {{init_weight_test(opts, h, w, in, out, 'single'), zeros(out, 1, 'single')}}, ... 13 | 'stride', stride, ... 14 | 'pad', pad, ... 15 | 'dilate', 1, ... 16 | 'learningRate', [1 2], ... 17 | 'weightDecay', [opts.weightDecay 0], ... 18 | 'opts', {convOpts}) ; 19 | if (opts.batchNormalization)&&batchOn 20 | net.layers{end+1} = struct('type', 'bnorm', 'name', sprintf('bn%s',id), ... 21 | 'weights', {{ones(out, 1, 'single'), zeros(out, 1, 'single'), zeros(out, 2, 'single')}}, ... 22 | 'learningRate', [2 1 0.05], ... 23 | 'weightDecay', [0 0]) ; 24 | end 25 | if ReluOn 26 | net.layers{end+1} = struct('type', 'relu', 'name', sprintf('relu%s',id)) ; 27 | end -------------------------------------------------------------------------------- /add_pool_test.m: -------------------------------------------------------------------------------- 1 | function net = add_pool_test(net, opts,id, stride, pad) 2 | % -------------------------------------------------------------------- 3 | convOpts = {'CudnnWorkspaceLimit', opts.cudnnWorkspaceLimit} ; 4 | net.layers{end+1} = struct('type', 'pool', 'name', sprintf('pool%s', id), ... 5 | 'pool',stride,... 6 | 'stride', stride, ... 7 | 'pad', pad, ... 8 | 'method','max',... 9 | 'opts', {convOpts}) ; -------------------------------------------------------------------------------- /add_reg_concat_test.m: -------------------------------------------------------------------------------- 1 | function net = add_reg_concat_test(net, id, regSet) 2 | % -------------------------------------------------------------------- 3 | net.layers{end+1} = struct('type', 'reg_concat', ... 4 | 'name', sprintf('reg%s', id),... 5 | 'regSet', regSet) ; -------------------------------------------------------------------------------- /add_reg_toss_test.m: -------------------------------------------------------------------------------- 1 | function net = add_reg_toss_test(net, id, regNum) 2 | % -------------------------------------------------------------------- 3 | net.layers{end+1} = struct('type', 'reg_toss', ... 4 | 'name', sprintf('reg%s', id),... 5 | 'regNum', regNum) ; -------------------------------------------------------------------------------- /annulus_gen_exa.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/annulus_gen_exa.m -------------------------------------------------------------------------------- /annulus_gen_rand.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/annulus_gen_rand.m -------------------------------------------------------------------------------- /basic_para.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleweiz/Solving-full-wave-nonlinear-inverse-scattering-problems-with-back-propagation-scheme/41a6b614bbcda7656eff45a1a57df2ebdc0bcbb9/basic_para.mat -------------------------------------------------------------------------------- /check_results.m: -------------------------------------------------------------------------------- 1 | function [net_cpu,stats,prof] = check_results(opts, patchSize, epoch, subset, learningRate, imdb, net_cpu) 2 | % ------------------------------------------------------------------------- 3 | 4 | % move the CNN to GPU (if needed) 5 | numGpus = numel(opts.gpus) ; 6 | if numGpus >= 1 7 | net = vl_simplenn_move(net_cpu, 'gpu') ; 8 | one = gpuArray(single(1)) ; 9 | else 10 | net = net_cpu ; 11 | net_cpu = [] ; 12 | one = single(1) ; 13 | end 14 | 15 | % assume validation mode if the learning rate is zero 16 | training = learningRate > 0 ; 17 | if training 18 | mode = 'train' ; 19 | evalMode = 'normal' ; 20 | else 21 | mode = 'val' ; 22 | evalMode = 'val' ; 23 | end 24 | 25 | % turn on the profiler (if needed) 26 | if opts.profile 27 | if numGpus <= 1 28 | prof = profile('info') ; 29 | profile clear ; 30 | profile on ; 31 | else 32 | prof = mpiprofile('info') ; 33 | mpiprofile reset ; 34 | mpiprofile on ; 35 | end 36 | end 37 | 38 | res = [] ; 39 | mmap = [] ; 40 | stats = [] ; 41 | start = tic ; 42 | 43 | for t=1:opts.batchSize:numel(subset) 44 | fprintf('%s: epoch %02d: %3d/%3d: ', mode, epoch, ... 45 | fix(t/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize)) ; 46 | batchSize = min(opts.batchSize, numel(subset) - t + 1) ; 47 | numDone = 0 ; 48 | error = [] ; 49 | for s=1:opts.numSubBatches 50 | % get this image batch and prefetch the next 51 | batchStart = t + (labindex-1) + (s-1) * numlabs ; 52 | batchEnd = min(t+opts.batchSize-1, numel(subset)) ; 53 | batch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ; 54 | [im, labels, lowRes] = getSimpleNNBatch_test(imdb, batch, patchSize); 55 | 56 | if opts.prefetch 57 | if s==opts.numSubBatches 58 | batchStart = t + (labindex-1) + opts.batchSize ; 59 | batchEnd = min(t+2*opts.batchSize-1, numel(subset)) ; 60 | else 61 | batchStart = batchStart + numlabs ; 62 | end 63 | nextBatch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ; 64 | getSimpleNNBatch_test(imdb, nextBatch, patchSize); 65 | end 66 | 67 | if numGpus >= 1 68 | im = gpuArray(im) ; 69 | end 70 | 71 | % evaluate the CNN 72 | net.layers{end}.class = labels ; 73 | net.layers{end}.lambda = opts.lambda ; 74 | if training, dzdy = one; else, dzdy = [] ; end 75 | 76 | [res, reg] = vl_simplenn_fbpconvnet(net, im, dzdy, res, ... 77 | 'accumulate', s ~= 1, ... 78 | 'mode', evalMode, ... 79 | 'conserveMemory', opts.conserveMemory, ... 80 | 'backPropDepth', opts.backPropDepth, ... 81 | 'sync', opts.sync, ... 82 | 'cudnn', opts.cudnn) ; 83 | 84 | 85 | 86 | if (mod(t,5) == 1)%&&(rand>0.95) 87 | displayImg_test_final(labels,im,res,lowRes,opts); 88 | end 89 | 90 | % accumulate training errors 91 | error = sum([error, [... 92 | sum(double(gather(res(end).x))) ; 93 | reshape(opts.errorFunction(opts, labels, res),[],1) ; ]],2) ; 94 | numDone = numDone + numel(batch) ; 95 | end % next sub-batch 96 | 97 | % gather and accumulate gradients across labs 98 | if training 99 | if numGpus <= 1 100 | [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res) ; 101 | else 102 | if isempty(mmap) 103 | mmap = map_gradients(opts.memoryMapFile, net, res, numGpus) ; 104 | end 105 | write_gradients(mmap, net, res) ; 106 | labBarrier() ; 107 | [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res, mmap) ; 108 | end 109 | end 110 | 111 | % collect and print learning statistics 112 | time = toc(start) ; 113 | stats = sum([stats,[0 ; error]],2); % works even when stats=[] 114 | stats(1) = time ; 115 | n = t + batchSize - 1 ; % number of images processed overall 116 | speed = n/time ; 117 | fprintf('%.1f Hz%s\n', speed) ; 118 | 119 | m = n / max(1,numlabs) ; % num images processed on this lab only 120 | fprintf(' obj:%.3g', stats(2)/m) ; 121 | for i=1:numel(opts.errorLabels) 122 | fprintf(' %s:%.3e', opts.errorLabels{i}, stats(i+2)/m) ; 123 | % fprintf(' %s:%.3g', opts.errorLabels{i}, stats(i+2)/m) ; 124 | end 125 | fprintf(' [%d/%d]', numDone, batchSize); 126 | fprintf('\n') ; 127 | 128 | % collect diagnostic statistics 129 | if training & opts.plotDiagnostics 130 | switchfigure_test(2) ; clf ; 131 | diag = [res.stats] ; 132 | barh(horzcat(diag.variation)) ; 133 | set(gca,'TickLabelInterpreter', 'none', ... 134 | 'YTickLabel',horzcat(diag.label), ... 135 | 'YDir', 'reverse', ... 136 | 'XScale', 'log', ... 137 | 'XLim', [1e-5 1]) ; 138 | drawnow ; 139 | end 140 | 141 | end 142 | 143 | % switch off the profiler 144 | if opts.profile 145 | if numGpus <= 1 146 | prof = profile('info') ; 147 | profile off ; 148 | else 149 | prof = mpiprofile('info'); 150 | mpiprofile off ; 151 | end 152 | else 153 | prof = [] ; 154 | end 155 | 156 | % bring the network back to CPU 157 | if numGpus >= 1 158 | net_cpu = vl_simplenn_move(net, 'cpu') ; 159 | else 160 | net_cpu = net ; 161 | end 162 | 163 | 164 | 165 | % ------------------------------------------------------------------------- 166 | function [net,res] = accumulate_gradients(opts, lr, batchSize, net, res, mmap) 167 | % ------------------------------------------------------------------------- 168 | if nargin >= 6 169 | numGpus = numel(mmap.Data) ; 170 | else 171 | numGpus = 1 ; 172 | end 173 | 174 | for l=numel(net.layers):-1:1 175 | for j=1:numel(res(l).dzdw) 176 | 177 | % accumualte gradients from multiple labs (GPUs) if needed 178 | if numGpus > 1 179 | tag = sprintf('l%d_%d',l,j) ; 180 | tmp = zeros(size(mmap.Data(labindex).(tag)), 'single') ; 181 | for g = setdiff(1:numGpus, labindex) 182 | tmp = tmp + mmap.Data(g).(tag) ; 183 | end 184 | res(l).dzdw{j} = res(l).dzdw{j} + tmp ; 185 | end 186 | 187 | if j == 3 && strcmp(net.layers{l}.type, 'bnorm') 188 | % special case for learning bnorm moments 189 | thisLR = net.layers{l}.learningRate(j) ; 190 | net.layers{l}.weights{j} = ... 191 | (1-thisLR) * net.layers{l}.weights{j} + ... 192 | (thisLR/batchSize) * res(l).dzdw{j} ; 193 | else 194 | % standard gradient training 195 | thisDecay = opts.weightDecay * net.layers{l}.weightDecay(j) ; 196 | thisLR = lr * net.layers{l}.learningRate(j) ; 197 | net.layers{l}.momentum{j} = ... 198 | opts.momentum * net.layers{l}.momentum{j} ... 199 | - thisDecay * net.layers{l}.weights{j} ... 200 | - (1 / batchSize) * res(l).dzdw{j} ; 201 | 202 | net.layers{l}.weights{j} = net.layers{l}.weights{j} + ... 203 | min(max(thisLR * net.layers{l}.momentum{j},-opts.gradMax),opts.gradMax) ; 204 | end 205 | 206 | % if requested, collect some useful stats for debugging 207 | if opts.plotDiagnostics 208 | variation = [] ; 209 | label = '' ; 210 | switch net.layers{l}.type 211 | case {'conv','convt'} 212 | variation = thisLR * mean(abs(net.layers{l}.momentum{j}(:))) ; 213 | if j == 1 % fiters 214 | base = mean(abs(net.layers{l}.weights{j}(:))) ; 215 | label = 'filters' ; 216 | else % biases 217 | base = mean(abs(res(l+1).x(:))) ; 218 | label = 'biases' ; 219 | end 220 | variation = variation / base ; 221 | label = sprintf('%s_%s', net.layers{l}.name, label) ; 222 | end 223 | res(l).stats.variation(j) = variation ; 224 | res(l).stats.label{j} = label ; 225 | end 226 | end 227 | end 228 | 229 | % ------------------------------------------------------------------------- 230 | function mmap = map_gradients(fname, net, res, numGpus) 231 | % ------------------------------------------------------------------------- 232 | format = {} ; 233 | for i=1:numel(net.layers) 234 | for j=1:numel(res(i).dzdw) 235 | format(end+1,1:3) = {'single', size(res(i).dzdw{j}), sprintf('l%d_%d',i,j)} ; 236 | end 237 | end 238 | format(end+1,1:3) = {'double', [3 1], 'errors'} ; 239 | if ~exist(fname) && (labindex == 1) 240 | f = fopen(fname,'wb') ; 241 | for g=1:numGpus 242 | for i=1:size(format,1) 243 | fwrite(f,zeros(format{i,2},format{i,1}),format{i,1}) ; 244 | end 245 | end 246 | fclose(f) ; 247 | end 248 | labBarrier() ; 249 | mmap = memmapfile(fname, 'Format', format, 'Repeat', numGpus, 'Writable', true) ; 250 | 251 | % ------------------------------------------------------------------------- 252 | function write_gradients(mmap, net, res) 253 | % ------------------------------------------------------------------------- 254 | for i=1:numel(net.layers) 255 | for j=1:numel(res(i).dzdw) 256 | mmap.Data(labindex).(sprintf('l%d_%d',i,j)) = gather(res(i).dzdw{j}) ; 257 | end 258 | end 259 | 260 | -------------------------------------------------------------------------------- /computeRegressedSNR.m: -------------------------------------------------------------------------------- 1 | function [SNR, rec, c] = computeRegressedSNR(rec,oracle) 2 | 3 | sumP = sum(oracle(:)) ; 4 | sumI = sum(rec(:)) ; 5 | sumIP = sum( oracle(:) .* rec(:) ) ; 6 | sumI2 = sum(rec(:).^2) ; 7 | A = [sumI2, sumI; sumI, numel(oracle)]; 8 | b = [sumIP;sumP] ; 9 | c = (A)\b ; 10 | rec = c(1)*rec+c(2) ; 11 | err = sum((oracle(:)-rec(:)).^2) ; 12 | SNR = 10*log10(sum(oracle(:).^2)/err) ; -------------------------------------------------------------------------------- /data_generate_Circle_Es.m: -------------------------------------------------------------------------------- 1 | %% save forward data including Profile parameters and scattered field; 2 | % Wirtten by Wei Zhun at NUS on 18 Nov, 2017 3 | 4 | 5 | clc; clear all;close all; 6 | %% basic paramters 7 | eta_0 = 120*pi; 8 | c = 3e8; 9 | eps_0 = 8.85e-12; 10 | lam_0 = 0.75; % lambda: 0.75 m is for 400 MHz 11 | k_0 = 2*pi/lam_0; 12 | omega = k_0*c; 13 | bool_plane = 0; % 1: Plane wave incidence; 0: Line source incidence 14 | Coef=i*k_0*eta_0; 15 | N_rec = 32; % Nb. of Receiver 16 | N_inc = 16; % Nb. of Incidence 17 | % save('basic_para.mat') 18 | % return 19 | % discritization 20 | MAX = 1; Mx = 64; 21 | step_size = 2*MAX/(Mx-1); 22 | cell_area = step_size^2; % the area of the sub-domain 23 | a_eqv = sqrt(cell_area/pi); % the equivalent radius of the sub-domain for the circle approximation 24 | Mnr=0.15; Mxr=0.4; % radius range, center range will be decided by specific radius value; 25 | Ep_s=1+1e-3; Ep_l=1.5; % permittivity range 26 | N_t=500; % total data number; 27 | E_s=zeros(N_rec,N_inc,N_t); 28 | Pro_Para=cell(1,N_t); 29 | 30 | for nn=1:N_t 31 | 32 | %% generate total profile 33 | tmp_domain = linspace(-MAX,MAX,Mx); 34 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 35 | N_cell_dom = size(x_dom,1)*size(x_dom,2); 36 | x0 = x_dom; y0 = y_dom; 37 | 38 | %% generate perturbations 39 | N_cir=ceil((3*rand)+1e-2); 40 | [epsil,Para] = annulus_gen_rand(MAX,Mx,N_cir,[Mnr,Mxr],[Ep_s,Ep_l]); 41 | Pro_Para{1,nn}=Para; 42 | 43 | xi_all = -i*omega*(epsil-1)*eps_0*cell_area; 44 | bool_eps = epsil==1; in_anulus = find(bool_eps==0); in_anulus = in_anulus(:); 45 | x0(bool_eps) = []; y0(bool_eps) = []; 46 | x0 = x0(:); y0 = y0(:); 47 | xi_forward = xi_all; xi_forward(bool_eps) =[]; xi_forward = xi_forward(:); 48 | N_cell = length(x0); 49 | 50 | epsil_t=epsil; 51 | epsil_t(bool_eps)=[];epsil_t=epsil_t(:); 52 | 53 | % reciver 54 | 55 | theta_tmp = linspace(0, 2*pi, N_rec+1); theta_tmp(end) = []; theta_tmp = theta_tmp(:); 56 | [theta,rho] = meshgrid(theta_tmp,3); theta = theta(:); rho = rho(:); 57 | [x,y] = pol2cart(theta,rho); 58 | 59 | if bool_plane == 1 60 | %Plane wave incidence 61 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 62 | k_x = k_0*cos(theta_inc); k_y = k_0*sin(theta_inc); 63 | E_inc = exp(i*x0*k_x.' +i*y0*k_y.'); % N_cell x N_inc 64 | else 65 | %Line source incidence 66 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 67 | [theta_t,rho_t] = meshgrid(theta_inc,3); theta_t = theta_t(:); rho_t = rho_t(:); 68 | [x_t,y_t] = pol2cart(theta_t,rho_t); 69 | 70 | [x0_tmp_t, x_tmp_t] = meshgrid(x0,x_t); 71 | [y0_tmp_t, y_tmp_t] = meshgrid(y0,y_t); 72 | rho_mat_t = sqrt((x0_tmp_t-x_tmp_t).^2 +(y0_tmp_t-y_tmp_t).^2); % N_inc x N_cell 73 | T_mat = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_mat_t); % N_inc x N_cell 74 | E_inc = T_mat.'; % N_cell x N_inc 75 | 76 | clear x0_tmp_t x_tmp_t y0_cell_t y0_cell_2_t rho_mat_t T_mat 77 | end 78 | 79 | % MOM results ----------------------------------------- 80 | Phi_mat = zeros(N_cell); % GD matrix 81 | [x0_cell, x0_cell_2] = meshgrid(x0,x0); 82 | [y0_cell, y0_cell_2] = meshgrid(y0,y0); 83 | dist_cell = sqrt((x0_cell-x0_cell_2).^2 +(y0_cell-y0_cell_2).^2); 84 | dist_cell = dist_cell + eye(N_cell); 85 | I1=(i/4)*besselh(0,1,k_0*dist_cell); % off-diagonal integral of Green's function; 86 | Phi_mat = Coef * I1; 87 | Phi_mat = Phi_mat .*(ones(N_cell)-eye(N_cell)); % Diagonal is set to zero 88 | I2=(i/4)*(2/(k_0*a_eqv)*besselh(1,1,k_0*a_eqv)+4*1i/(k_0^2*cell_area)); % diagonal integral of Green's function; 89 | S1=Coef*I2; % Analytical sigular value for self-cell integral(exclude cell area); 90 | Phi_mat=Phi_mat+S1*eye(N_cell); % Add the self-contribution. 91 | E_tot = (eye(N_cell)-Phi_mat*diag(xi_forward))\E_inc; % E_tot = E_inside for 2D % N_cell x N_inc 92 | 93 | [x0_tmp, x_tmp] = meshgrid(x0,x); 94 | [y0_tmp, y_tmp] = meshgrid(y0,y); 95 | rho_mat = sqrt((x0_tmp-x_tmp).^2 +(y0_tmp-y_tmp).^2); % N_rec x N_cell 96 | R_mat = Coef *(i/4)*besselh(0,1,k_0*rho_mat); % N_rec x N_cell 97 | E_CDM = R_mat *diag(xi_forward) *E_tot; % N_rec x N_inc 98 | E_s(:,:,nn)=E_CDM; 99 | nn 100 | end 101 | clearvars -except E_s Pro_Para; 102 | save('Forward_Circ1.mat') 103 | 104 | 105 | -------------------------------------------------------------------------------- /data_generate_Circle_Es_S1.m: -------------------------------------------------------------------------------- 1 | %% save forward data including Profile parameters and scattered field; 2 | % Wirtten by Wei Zhun at NUS on 18 Nov, 2017 3 | 4 | 5 | clc; clear all;close all; 6 | load Forward_Circ1.mat; % Make Sure it is the same profile as in Previous traning 7 | clear E_s 8 | %% basic paramters 9 | eta_0 = 120*pi; 10 | c = 3e8; 11 | eps_0 = 8.85e-12; 12 | lam_0 = 0.75; % lambda: 0.75 m is for 400 MHz 13 | k_0 = 2*pi/lam_0; 14 | omega = k_0*c; 15 | bool_plane = 0; % 1: Plane wave incidence; 0: Line source incidence 16 | Coef=i*k_0*eta_0; 17 | N_rec = 32; % Nb. of Receiver 18 | N_inc = 16; % Nb. of Incidence 19 | % save('basic_para.mat') 20 | % return 21 | % discritization 22 | MAX = 1; Mx = 64; 23 | step_size = 2*MAX/(Mx-1); 24 | cell_area = step_size^2; % the area of the sub-domain 25 | a_eqv = sqrt(cell_area/pi); % the equivalent radius of the sub-domain for the circle approximation 26 | Mnr=0.15; Mxr=0.4; % radius range, center range will be decided by specific radius value; 27 | Ep_s=1+1e-3; Ep_l=1.5; % permittivity range 28 | N_t=500; % total data number; 29 | E_s=zeros(N_rec,N_inc,N_t); 30 | % Pro_Para=cell(1,N_t); 31 | Ep1=1.5; 32 | for nn=N_t:N_t 33 | 34 | %% generate total profile 35 | tmp_domain = linspace(-MAX,MAX,Mx); 36 | [x_dom,y_dom] = meshgrid(tmp_domain, -tmp_domain); 37 | N_cell_dom = size(x_dom,1)*size(x_dom,2); 38 | x0 = x_dom; y0 = y_dom; 39 | 40 | %% generate perturbations 41 | N_cir=ceil((3*rand)+1e-2); 42 | AA=[4,0.6,0,-0.2,Ep1;4,0.3,0,-0.2,1+1e-3;4,0.2,0.3,0.6,Ep1;4,0.2,-0.3,0.6,Ep1]; %% total number of circle, radius, xcenter, ycenter,epr; 43 | 44 | epsil= annulus_gen_exa(MAX,Mx,AA); 45 | epsil_exaS1=epsil; 46 | % Pro_Para{1,nn}=Para; 47 | 48 | xi_all = -i*omega*(epsil-1)*eps_0*cell_area; 49 | bool_eps = epsil==1; in_anulus = find(bool_eps==0); in_anulus = in_anulus(:); 50 | x0(bool_eps) = []; y0(bool_eps) = []; 51 | x0 = x0(:); y0 = y0(:); 52 | xi_forward = xi_all; xi_forward(bool_eps) =[]; xi_forward = xi_forward(:); 53 | N_cell = length(x0); 54 | 55 | epsil_t=epsil; 56 | epsil_t(bool_eps)=[];epsil_t=epsil_t(:); 57 | 58 | % reciver 59 | 60 | theta_tmp = linspace(0, 2*pi, N_rec+1); theta_tmp(end) = []; theta_tmp = theta_tmp(:); 61 | [theta,rho] = meshgrid(theta_tmp,3); theta = theta(:); rho = rho(:); 62 | [x,y] = pol2cart(theta,rho); 63 | 64 | if bool_plane == 1 65 | %Plane wave incidence 66 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 67 | k_x = k_0*cos(theta_inc); k_y = k_0*sin(theta_inc); 68 | E_inc = exp(i*x0*k_x.' +i*y0*k_y.'); % N_cell x N_inc 69 | else 70 | %Line source incidence 71 | theta_inc = linspace(0, 2*pi, N_inc+1); theta_inc(end) = []; theta_inc = theta_inc(:); 72 | [theta_t,rho_t] = meshgrid(theta_inc,3); theta_t = theta_t(:); rho_t = rho_t(:); 73 | [x_t,y_t] = pol2cart(theta_t,rho_t); 74 | 75 | [x0_tmp_t, x_tmp_t] = meshgrid(x0,x_t); 76 | [y0_tmp_t, y_tmp_t] = meshgrid(y0,y_t); 77 | rho_mat_t = sqrt((x0_tmp_t-x_tmp_t).^2 +(y0_tmp_t-y_tmp_t).^2); % N_inc x N_cell 78 | T_mat = i*k_0*eta_0 *(i/4)*besselh(0,1,k_0*rho_mat_t); % N_inc x N_cell 79 | E_inc = T_mat.'; % N_cell x N_inc 80 | 81 | clear x0_tmp_t x_tmp_t y0_cell_t y0_cell_2_t rho_mat_t T_mat 82 | end 83 | 84 | % MOM results ----------------------------------------- 85 | Phi_mat = zeros(N_cell); % GD matrix 86 | [x0_cell, x0_cell_2] = meshgrid(x0,x0); 87 | [y0_cell, y0_cell_2] = meshgrid(y0,y0); 88 | dist_cell = sqrt((x0_cell-x0_cell_2).^2 +(y0_cell-y0_cell_2).^2); 89 | dist_cell = dist_cell + eye(N_cell); 90 | I1=(i/4)*besselh(0,1,k_0*dist_cell); % off-diagonal integral of Green's function; 91 | Phi_mat = Coef * I1; 92 | Phi_mat = Phi_mat .*(ones(N_cell)-eye(N_cell)); % Diagonal is set to zero 93 | I2=(i/4)*(2/(k_0*a_eqv)*besselh(1,1,k_0*a_eqv)+4*1i/(k_0^2*cell_area)); % diagonal integral of Green's function; 94 | S1=Coef*I2; % Analytical sigular value for self-cell integral(exclude cell area); 95 | Phi_mat=Phi_mat+S1*eye(N_cell); % Add the self-contribution. 96 | E_tot = (eye(N_cell)-Phi_mat*diag(xi_forward))\E_inc; % E_tot = E_inside for 2D % N_cell x N_inc 97 | 98 | [x0_tmp, x_tmp] = meshgrid(x0,x); 99 | [y0_tmp, y_tmp] = meshgrid(y0,y); 100 | rho_mat = sqrt((x0_tmp-x_tmp).^2 +(y0_tmp-y_tmp).^2); % N_rec x N_cell 101 | R_mat = Coef *(i/4)*besselh(0,1,k_0*rho_mat); % N_rec x N_cell 102 | E_CDM = R_mat *diag(xi_forward) *E_tot; % N_rec x N_inc 103 | E_s=E_CDM; 104 | nn 105 | end 106 | clearvars -except E_s epsil_exaS1; 107 | save('Forward_Circ2_S1.mat') 108 | 109 | 110 | -------------------------------------------------------------------------------- /dev_fun.m: -------------------------------------------------------------------------------- 1 | function [out]=dev_fun(img) 2 | 3 | img_dx=padarray(diff(img,[],2),[0 1],'post'); 4 | img_dy=padarray(diff(img,[],1),[1 0],'post'); 5 | img_hes=padarray(diff(diff(img,[],1),[],2),[1 1],'post'); 6 | 7 | img_dx2=padarray(diff(img_dx,[],2),[0 1],'post'); 8 | img_dy2=padarray(diff(img_dy,[],1),[1 0],'post'); 9 | img_hes2=padarray(diff(diff(img_hes,[],1),[],2),[1 1],'post'); 10 | 11 | out=cat(3,img,img_dx,img_dy,img_hes,img_dx2,img_dy2,img_hes2); -------------------------------------------------------------------------------- /displayImg_test.m: -------------------------------------------------------------------------------- 1 | function displayImg_test(labels,im,res,lowRes,opts,Coef) 2 | 3 | 4 | imTemp = im(:,:,:,1); 5 | labelsTemp = labels(:,:,:,1); 6 | labelsTemp(:,:,1,:) = labelsTemp(:,:,1,:) +lowRes(:,:,1); 7 | recTemp = res(end-1).x(:,:,:,1); 8 | recTemp(:,:,1,:) = recTemp(:,:,1,:) +lowRes(:,:,1); 9 | 10 | 11 | figure(12); 12 | subplot(1,3,1); imagesc((labelsTemp/Coef)+1); colormap(gray); axis off image;title('original'); 13 | subplot(1,3,2); imagesc((imTemp/Coef)+1); colormap(gray); axis off image; title('BP'); 14 | subplot(1,3,3); imagesc((recTemp/Coef)+1); colormap(gray); axis off image;title('Reconstruction'); 15 | drawnow; 16 | pause(.1); -------------------------------------------------------------------------------- /displayImg_test_final.m: -------------------------------------------------------------------------------- 1 | function [x1,x2,x3]=displayImg_test_final(labels,im,res,lowRes,Coef) 2 | 3 | 4 | imTemp = im(:,:,:,1); 5 | labelsTemp = labels(:,:,:,1); 6 | labelsTemp(:,:,1,:) = labelsTemp(:,:,1,:) +lowRes(:,:,1); 7 | recTemp = res(end-1).x(:,:,:,1); 8 | recTemp(:,:,1,:) = recTemp(:,:,1,:) +lowRes(:,:,1); 9 | 10 | 11 | x1=(labelsTemp/Coef)+1;x2=(imTemp/Coef)+1;x3=(recTemp/Coef)+1; 12 | figure; 13 | subplot(1,3,1); imagesc(x1); colormap(gray); axis off image;title('original'); 14 | subplot(1,3,2); imagesc(x2); colormap(gray); axis off image; title('BP'); 15 | subplot(1,3,3); imagesc(x3); colormap(gray); axis off image;title('CNN'); 16 | drawnow; 17 | pause(.1); -------------------------------------------------------------------------------- /error_euclideanloss_test.m: -------------------------------------------------------------------------------- 1 | function err = error_euclideanloss_test(opts, labels, res) 2 | % ------------------------------------------------------------------------- 3 | errTemp = res(end-1).x - labels ; 4 | err = sum(errTemp(:).^2)/numel(errTemp); -------------------------------------------------------------------------------- /findLastCheckpoint_test.m: -------------------------------------------------------------------------------- 1 | function epoch = findLastCheckpoint_test(modelDir) 2 | % ------------------------------------------------------------------------- 3 | list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ; 4 | tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ; 5 | epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ; 6 | epoch = max([epoch 0]) ; -------------------------------------------------------------------------------- /getBatch_test.m: -------------------------------------------------------------------------------- 1 | function fn = getBatch_test(opts) 2 | % ------------------------------------------------------------------------- 3 | fn = @(x,y) getSimpleNNBatch(x,y,opts.patchSize) ; 4 | 5 | 6 | % ------------------------------------------------------------------------- 7 | function [images, labels, lowRes] = getSimpleNNBatch(imdb, batch, patchSize) 8 | % ------------------------------------------------------------------------- 9 | Ny = size(imdb.images.noisy,1); 10 | Nx = size(imdb.images.noisy,2); 11 | pos_x = round(rand(1)*(Nx-patchSize)); 12 | pos_y = round(rand(1)*(Ny-patchSize)); 13 | images = single(imdb.images.noisy(pos_y+(1:patchSize),pos_x+(1:patchSize),:,batch)) ; 14 | labels = single(imdb.images.orig(pos_y+(1:patchSize),pos_x+(1:patchSize),:,batch)) ; 15 | if rand > 0.5 16 | labels=fliplr(labels); % left right rotate 17 | images=fliplr(images); 18 | end 19 | if rand > 0.5 20 | labels=flipud(labels); % up down rotate 21 | images=flipud(images); 22 | end 23 | lowRes = images(:,:,1,:); 24 | labels(:,:,1,:) = labels(:,:,1,:) - lowRes; -------------------------------------------------------------------------------- /getSimpleNNBatch_test.m: -------------------------------------------------------------------------------- 1 | function [images, labels, lowRes] = getSimpleNNBatch_test(imdb, batch, patchSize) 2 | % ------------------------------------------------------------------------- 3 | Ny = size(imdb.images.noisy,1); 4 | Nx = size(imdb.images.noisy,2); 5 | pos_x = round(rand(1)*(Nx-patchSize)); 6 | pos_y = round(rand(1)*(Ny-patchSize)); 7 | images = single(imdb.images.noisy(pos_y+(1:patchSize),pos_x+(1:patchSize),:,batch)) ; 8 | labels = single(imdb.images.orig(pos_y+(1:patchSize),pos_x+(1:patchSize),:,batch)) ; 9 | % if rand > 0.5 10 | % labels=fliplr(labels); % left right rotate 11 | % images=fliplr(images); 12 | % end 13 | % if rand > 0.5 14 | % labels=flipud(labels); % up down rotate 15 | % images=flipud(images); 16 | % end 17 | lowRes = images(:,:,1,:); 18 | labels(:,:,1,:) = labels(:,:,1,:) - lowRes; 19 | -------------------------------------------------------------------------------- /init_weight_test.m: -------------------------------------------------------------------------------- 1 | function weights = init_weight_test(opts, h, w, in, out, type) 2 | % ------------------------------------------------------------------------- 3 | % See K. He, X. Zhang, S. Ren, and J. Sun. Delving deep into 4 | % rectifiers: Surpassing human-level performance on imagenet 5 | % classification. CoRR, (arXiv:1502.01852v1), 2015. 6 | 7 | switch lower(opts.weightInitMethod) % lower: transfer capital letter to lower letter; 8 | case 'gaussian' 9 | sc = 0.01/opts.scale ; 10 | weights = randn(h, w, in, out, type)*sc; 11 | case 'xavier' 12 | sc = sqrt(3/(h*w*in)) ; 13 | weights = (rand(h, w, in, out, type)*2 - 1)*sc ; 14 | case 'xavierimproved' 15 | sc = sqrt(2/(h*w*out)) ; 16 | weights = randn(h, w, in, out, type)*sc ; 17 | otherwise 18 | error('Unknown weight initialization method''%s''', opts.weightInitMethod) ; 19 | end -------------------------------------------------------------------------------- /process_epoch_test.m: -------------------------------------------------------------------------------- 1 | function [net_cpu,stats,prof] = process_epoch_test(opts, patchSize, epoch, subset, learningRate, imdb, net_cpu,Coef) 2 | % ------------------------------------------------------------------------- 3 | 4 | % move the CNN to GPU (if needed) 5 | numGpus = numel(opts.gpus) ; 6 | if numGpus >= 1 7 | net = vl_simplenn_move(net_cpu, 'gpu') ; 8 | one = gpuArray(single(1)) ; 9 | else 10 | net = net_cpu ; 11 | net_cpu = [] ; 12 | one = single(1) ; 13 | end 14 | 15 | % assume validation mode if the learning rate is zero 16 | training = learningRate > 0 ; 17 | if training 18 | mode = 'train' ; 19 | evalMode = 'normal' ; 20 | else 21 | mode = 'val' ; 22 | evalMode = 'val' ; 23 | end 24 | 25 | % turn on the profiler (if needed) 26 | if opts.profile 27 | if numGpus <= 1 28 | prof = profile('info') ; 29 | profile clear ; 30 | profile on ; 31 | else 32 | prof = mpiprofile('info') ; 33 | mpiprofile reset ; 34 | mpiprofile on ; 35 | end 36 | end 37 | 38 | res = [] ; 39 | mmap = [] ; 40 | stats = [] ; 41 | start = tic ; 42 | 43 | for t=1:opts.batchSize:numel(subset) 44 | fprintf('%s: epoch %02d: %3d/%3d: ', mode, epoch, ... 45 | fix(t/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize)) ; 46 | batchSize = min(opts.batchSize, numel(subset) - t + 1) ; 47 | numDone = 0 ; 48 | error = [] ; 49 | for s=1:opts.numSubBatches 50 | % get this image batch and prefetch the next 51 | batchStart = t + (labindex-1) + (s-1) * numlabs ; 52 | batchEnd = min(t+opts.batchSize-1, numel(subset)) ; 53 | batch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ; 54 | [im, labels, lowRes] = getSimpleNNBatch_test(imdb, batch, patchSize); 55 | 56 | if opts.prefetch 57 | if s==opts.numSubBatches 58 | batchStart = t + (labindex-1) + opts.batchSize ; 59 | batchEnd = min(t+2*opts.batchSize-1, numel(subset)) ; 60 | else 61 | batchStart = batchStart + numlabs ; 62 | end 63 | nextBatch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ; 64 | getSimpleNNBatch_test(imdb, nextBatch, patchSize); 65 | end 66 | 67 | if numGpus >= 1 68 | im = gpuArray(im) ; 69 | end 70 | 71 | % evaluate the CNN 72 | net.layers{end}.class = labels ; 73 | net.layers{end}.lambda = opts.lambda ; 74 | if training, dzdy = one; else, dzdy = [] ; end 75 | 76 | [res, reg] = vl_simplenn_fbpconvnet(net, im, dzdy, res, ... 77 | 'accumulate', s ~= 1, ... 78 | 'mode', evalMode, ... 79 | 'conserveMemory', opts.conserveMemory, ... 80 | 'backPropDepth', opts.backPropDepth, ... 81 | 'sync', opts.sync, ... 82 | 'cudnn', opts.cudnn) ; 83 | 84 | 85 | if training 86 | if (mod(t,20) == 1)%&&(rand>0.95) 87 | displayImg_test(labels,im,res,lowRes,opts,Coef); 88 | end 89 | else 90 | if (mod(t,5) == 1)%&&(rand>0.95) 91 | displayImg_test(labels,im,res,lowRes,opts,Coef); 92 | end 93 | end 94 | 95 | % accumulate training errors 96 | error = sum([error, [... 97 | sum(double(gather(res(end).x))) ; 98 | reshape(opts.errorFunction(opts, labels, res),[],1) ; ]],2) ; 99 | numDone = numDone + numel(batch) ; 100 | end % next sub-batch 101 | 102 | % gather and accumulate gradients across labs 103 | if training 104 | if numGpus <= 1 105 | [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res) ; 106 | else 107 | if isempty(mmap) 108 | mmap = map_gradients(opts.memoryMapFile, net, res, numGpus) ; 109 | end 110 | write_gradients(mmap, net, res) ; 111 | labBarrier() ; 112 | [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res, mmap) ; 113 | end 114 | end 115 | 116 | % collect and print learning statistics 117 | time = toc(start) ; 118 | stats = sum([stats,[0 ; error]],2); % works even when stats=[] 119 | stats(1) = time ; 120 | n = t + batchSize - 1 ; % number of images processed overall 121 | speed = n/time ; 122 | fprintf('%.1f Hz%s\n', speed) ; 123 | 124 | m = n / max(1,numlabs) ; % num images processed on this lab only 125 | fprintf(' obj:%.3g', stats(2)/m) ; 126 | for i=1:numel(opts.errorLabels) 127 | fprintf(' %s:%.3e', opts.errorLabels{i}, stats(i+2)/m) ; 128 | % fprintf(' %s:%.3g', opts.errorLabels{i}, stats(i+2)/m) ; 129 | end 130 | fprintf(' [%d/%d]', numDone, batchSize); 131 | fprintf('\n') ; 132 | 133 | % collect diagnostic statistics 134 | if training && opts.plotDiagnostics 135 | switchfigure_test(2) ; clf ; 136 | diag = [res.stats] ; 137 | barh(horzcat(diag.variation)) ; 138 | set(gca,'TickLabelInterpreter', 'none', ... 139 | 'YTickLabel',horzcat(diag.label), ... 140 | 'YDir', 'reverse', ... 141 | 'XScale', 'log', ... 142 | 'XLim', [1e-5 1]) ; 143 | drawnow ; 144 | end 145 | 146 | end 147 | 148 | % switch off the profiler 149 | if opts.profile 150 | if numGpus <= 1 151 | prof = profile('info') ; 152 | profile off ; 153 | else 154 | prof = mpiprofile('info'); 155 | mpiprofile off ; 156 | end 157 | else 158 | prof = [] ; 159 | end 160 | 161 | % bring the network back to CPU 162 | if numGpus >= 1 163 | net_cpu = vl_simplenn_move(net, 'cpu') ; 164 | else 165 | net_cpu = net ; 166 | end 167 | 168 | 169 | 170 | % ------------------------------------------------------------------------- 171 | function [net,res] = accumulate_gradients(opts, lr, batchSize, net, res, mmap) 172 | % ------------------------------------------------------------------------- 173 | if nargin >= 6 174 | numGpus = numel(mmap.Data) ; 175 | else 176 | numGpus = 1 ; 177 | end 178 | 179 | for l=numel(net.layers):-1:1 180 | for j=1:numel(res(l).dzdw) 181 | 182 | % accumualte gradients from multiple labs (GPUs) if needed 183 | if numGpus > 1 184 | tag = sprintf('l%d_%d',l,j) ; 185 | tmp = zeros(size(mmap.Data(labindex).(tag)), 'single') ; 186 | for g = setdiff(1:numGpus, labindex) 187 | tmp = tmp + mmap.Data(g).(tag) ; 188 | end 189 | res(l).dzdw{j} = res(l).dzdw{j} + tmp ; 190 | end 191 | 192 | if j == 3 && strcmp(net.layers{l}.type, 'bnorm') 193 | % special case for learning bnorm moments 194 | thisLR = net.layers{l}.learningRate(j) ; 195 | net.layers{l}.weights{j} = ... 196 | (1-thisLR) * net.layers{l}.weights{j} + ... 197 | (thisLR/batchSize) * res(l).dzdw{j} ; 198 | else 199 | % standard gradient training 200 | thisDecay = opts.weightDecay * net.layers{l}.weightDecay(j) ; 201 | thisLR = lr * net.layers{l}.learningRate(j) ; 202 | net.layers{l}.momentum{j} = ... 203 | opts.momentum * net.layers{l}.momentum{j} ... 204 | - thisDecay * net.layers{l}.weights{j} ... 205 | - (1 / batchSize) * res(l).dzdw{j} ; 206 | 207 | net.layers{l}.weights{j} = net.layers{l}.weights{j} + ... 208 | min(max(thisLR * net.layers{l}.momentum{j},-opts.gradMax),opts.gradMax) ; 209 | end 210 | 211 | % if requested, collect some useful stats for debugging 212 | if opts.plotDiagnostics 213 | variation = [] ; 214 | label = '' ; 215 | switch net.layers{l}.type 216 | case {'conv','convt'} 217 | variation = thisLR * mean(abs(net.layers{l}.momentum{j}(:))) ; 218 | if j == 1 % fiters 219 | base = mean(abs(net.layers{l}.weights{j}(:))) ; 220 | label = 'filters' ; 221 | else % biases 222 | base = mean(abs(res(l+1).x(:))) ; 223 | label = 'biases' ; 224 | end 225 | variation = variation / base ; 226 | label = sprintf('%s_%s', net.layers{l}.name, label) ; 227 | end 228 | res(l).stats.variation(j) = variation ; 229 | res(l).stats.label{j} = label ; 230 | end 231 | end 232 | end 233 | 234 | % ------------------------------------------------------------------------- 235 | function mmap = map_gradients(fname, net, res, numGpus) 236 | % ------------------------------------------------------------------------- 237 | format = {} ; 238 | for i=1:numel(net.layers) 239 | for j=1:numel(res(i).dzdw) 240 | format(end+1,1:3) = {'single', size(res(i).dzdw{j}), sprintf('l%d_%d',i,j)} ; 241 | end 242 | end 243 | format(end+1,1:3) = {'double', [3 1], 'errors'} ; 244 | if ~exist(fname) && (labindex == 1) 245 | f = fopen(fname,'wb') ; 246 | for g=1:numGpus 247 | for i=1:size(format,1) 248 | fwrite(f,zeros(format{i,2},format{i,1}),format{i,1}) ; 249 | end 250 | end 251 | fclose(f) ; 252 | end 253 | labBarrier() ; 254 | mmap = memmapfile(fname, 'Format', format, 'Repeat', numGpus, 'Writable', true) ; 255 | 256 | % ------------------------------------------------------------------------- 257 | function write_gradients(mmap, net, res) 258 | % ------------------------------------------------------------------------- 259 | for i=1:numel(net.layers) 260 | for j=1:numel(res(i).dzdw) 261 | mmap.Data(labindex).(sprintf('l%d_%d',i,j)) = gather(res(i).dzdw{j}) ; 262 | end 263 | end 264 | 265 | -------------------------------------------------------------------------------- /struct_para_test.m: -------------------------------------------------------------------------------- 1 | function [opts]=struct_para_test(varargin) 2 | % replace structure paarameters 3 | 4 | opts.expDir = fullfile('data','exp') ; 5 | opts.continue = true ; 6 | opts.batchSize = 256 ; 7 | opts.numSubBatches = 1 ; 8 | opts.train = [] ; 9 | opts.val = [] ; 10 | opts.gpus = [] ; 11 | opts.prefetch = false ; 12 | opts.numEpochs = 300 ; 13 | opts.learningRate = 0.001 ; 14 | opts.weightDecay = 0.0005 ; 15 | opts.momentum = 0.9 ; 16 | opts.memoryMapFile = fullfile(tempdir, 'matconvnet.bin') ; 17 | opts.profile = false ; 18 | 19 | opts.conserveMemory = true ; 20 | opts.backPropDepth = +inf ; 21 | opts.sync = false ; 22 | opts.cudnn = true ; 23 | opts.errorFunction = 'euclideanloss' ; 24 | opts.errorLabels = {} ; 25 | opts.plotDiagnostics = false ; 26 | opts.plotStatistics = true; 27 | opts.lambda = 0; 28 | opts.waveLevel = [1 2 3]; 29 | opts.waveName = 'vk'; 30 | opts.gradMax = 1e-2; 31 | opts.weight = 'none'; 32 | opts = vl_argparse(opts, varargin) ; 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /switchfigure_test.m: -------------------------------------------------------------------------------- 1 | function switchfigure_test(n) 2 | % ------------------------------------------------------------------------- 3 | if get(0,'CurrentFigure') ~= n 4 | try 5 | set(0,'CurrentFigure',n) ; 6 | catch 7 | figure(n) ; 8 | end 9 | end -------------------------------------------------------------------------------- /vl_euclideanloss.m: -------------------------------------------------------------------------------- 1 | function Y = vl_euclideanloss(X, c, dzdy) 2 | 3 | assert(numel(X) == numel(c)); 4 | d = size(X); 5 | 6 | % assert(all(d == size(c))); 7 | c = reshape(c, size(X)); 8 | % X = reshape(X, size(c, 1), size(c, 2)); 9 | 10 | if nargin == 2 || (nargin == 3 && isempty(dzdy)) 11 | Y = sqrt(sum(subsref((X - c) .^ 2, substruct('()', {':'})))); 12 | elseif nargin == 3 && ~isempty(dzdy) 13 | assert(numel(dzdy) == 1); 14 | Y = dzdy * (X - c); 15 | end 16 | 17 | end -------------------------------------------------------------------------------- /vl_simplenn_fbpconvnet.m: -------------------------------------------------------------------------------- 1 | function [res, reg] = vl_simplenn_fbpconvnet(net, x, dzdy, res, varargin) 2 | %VL_SIMPLENN Evaluate a SimpleNN network. 3 | % RES = VL_SIMPLENN(NET, X) evaluates the convnet NET on data X. 4 | % RES = VL_SIMPLENN(NET, X, DZDY) evaluates the convnent NET and its 5 | % derivative on data X and output derivative DZDY (foward+bacwkard pass). 6 | % RES = VL_SIMPLENN(NET, X, [], RES) evaluates the NET on X reusing the 7 | % structure RES. 8 | % RES = VL_SIMPLENN(NET, X, DZDY, RES) evaluates the NET on X and its 9 | % derivatives reusing the structure RES. 10 | % 11 | % This function process networks using the SimpleNN wrapper 12 | % format. Such networks are 'simple' in the sense that they consist 13 | % of a linear sequence of computational layers. You can use the 14 | % `dagnn.DagNN` wrapper for more complex topologies, or write your 15 | % own wrapper around MatConvNet computational blocks for even 16 | % greater flexibility. 17 | % 18 | % The format of the network structure NET and of the result 19 | % structure RES are described in some detail below. Most networks 20 | % expect the input data X to be standardized, for example by 21 | % rescaling the input image(s) and subtracting a mean. Doing so is 22 | % left to the user, but information on how to do this is usually 23 | % contained in the `net.meta` field of the NET structure (see 24 | % below). 25 | % 26 | % The NET structure needs to be updated as new features are 27 | % introduced in MatConvNet; use the `VL_SIMPLENN_TIDY()` function 28 | % to make an old network current, as well as to cleanup and check 29 | % the structure of an existing network. 30 | % 31 | % Networks can run either on the CPU or GPU. Use VL_SIMPLENN_MOVE() 32 | % to move the network parameters between these devices. 33 | % 34 | % To print or obtain summary of the network structure, use the 35 | % VL_SIMPLENN_DISPLAY() function. 36 | % 37 | % VL_SIMPLENN(NET, X, DZDY, RES, 'OPT', VAL, ...) takes the following 38 | % options: 39 | % 40 | % `Mode`:: `normal` 41 | % Specifies the mode of operation. It can be either `'normal'` or 42 | % `'test'`. In test mode, dropout and batch-normalization are 43 | % bypassed. Note that, when a network is deployed, it may be 44 | % preferable to *remove* such blocks altogether. 45 | % 46 | % `ConserveMemory`:: `true` 47 | % Aggressively delete intermediate results. This in practice has 48 | % a very small performance hit and allows training much larger 49 | % models. However, it can be useful to disable it for 50 | % debugging. It is also possible to preserve individual layer outputs 51 | % by setting `net.layers{...}.precious` to `true`. 52 | % 53 | % `CuDNN`:: `true` 54 | % Use CuDNN when available. 55 | % 56 | % `Accumulate`:: `false` 57 | % Accumulate gradients in back-propagation instead of rewriting 58 | % them. This is useful to break the computation in sub-batches. 59 | % The gradients are accumulated to the provided RES structure 60 | % (i.e. to call VL_SIMPLENN(NET, X, DZDY, RES, ...). 61 | % 62 | % `SkipForward`:: `false` 63 | % Reuse the output values from the provided RES structure and compute 64 | % only the derivatives (bacward pass). 65 | % 66 | % ## The result format 67 | % 68 | % SimpleNN returns the result of its calculations in the RES 69 | % structure array. RES(1) contains the input to the network, while 70 | % RES(2), RES(3), ... contain the output of each layer, from first 71 | % to last. Each entry has the following fields: 72 | % 73 | % - `res(i+1).x`: the output of layer `i`. Hence `res(1).x` is the 74 | % network input. 75 | % 76 | % - `res(i+1).aux`: any auxiliary output data of layer i. For example, 77 | % dropout uses this field to store the dropout mask. 78 | % 79 | % - `res(i+1).dzdx`: the derivative of the network output relative 80 | % to the output of layer `i`. In particular `res(1).dzdx` is the 81 | % derivative of the network output with respect to the network 82 | % input. 83 | % 84 | % - `res(i+1).dzdw`: a cell array containing the derivatives of the 85 | % network output relative to the parameters of layer `i`. It can 86 | % be a cell array for multiple parameters. 87 | % 88 | % ## The network format 89 | % 90 | % The network is represented by the NET structure, which contains 91 | % two fields: 92 | % 93 | % - `net.layers` is a cell array with the CNN layers. 94 | % 95 | % - `net.meta` is a grab-bag of auxiliary application-dependent 96 | % information, including for example details on how to normalize 97 | % input data, the class names for a classifiers, or details of 98 | % the learning algorithm. The content of this field is ignored by 99 | % VL_SIMPLENN(). 100 | % 101 | % SimpleNN is aware of the following layers: 102 | % 103 | % Convolution layer:: 104 | % The convolution layer wraps VL_NNCONV(). It has fields: 105 | % 106 | % - `layer.type` contains the string `'conv'`. 107 | % - `layer.weights` is a cell array with filters and biases. 108 | % - `layer.stride` is the sampling stride (e.g. 1). 109 | % - `layer.pad` is the padding (e.g. 0). 110 | % 111 | % Convolution transpose layer:: 112 | % The convolution transpose layer wraps VL_NNCONVT(). It has fields: 113 | % 114 | % - `layer.type` contains the string `'convt'`. 115 | % - `layer.weights` is a cell array with filters and biases. 116 | % - `layer.upsample` is the upsampling factor (e.g. 1). 117 | % - `layer.crop` is the amount of output cropping (e.g. 0). 118 | % 119 | % Max pooling layer:: 120 | % The max pooling layer wraps VL_NNPOOL(). It has fields: 121 | % 122 | % - `layer.type` contains the string `'pool'`. 123 | % - `layer.method` is the pooling method (either 'max' or 'avg'). 124 | % - `layer.pool` is the pooling size (e.g. 3). 125 | % - `layer.stride` is the sampling stride (usually 1). 126 | % - `layer.pad` is the padding (usually 0). 127 | % 128 | % Normalization (LRN) layer:: 129 | % The normalization layer wraps VL_NNNORMALIZE(). It has fields: 130 | % 131 | % - `layer.type` contains the string `'normalize'` or `'lrn'`. 132 | % - `layer.param` contains the normalization parameters (see VL_NNNORMALIZE()). 133 | % 134 | % Spatial normalization layer:: 135 | % The spatial normalization layer wraps VL_NNSPNORM(). It has fields: 136 | % 137 | % - `layer.type` contains the string `'spnorm'`. 138 | % - `layer.param` contains the normalization parameters (see VL_NNSPNORM()). 139 | % 140 | % Batch normalization layer:: 141 | % This layer wraps VL_NNBNORM(). It has fields: 142 | % 143 | % - `layer.type` contains the string `'bnorm'`. 144 | % - `layer.weights` contains is a cell-array with, multiplier and 145 | % biases, and moments parameters 146 | % 147 | % Note that moments are used only in `'test'` mode to bypass batch 148 | % normalization. 149 | % 150 | % ReLU and Sigmoid layers:: 151 | % The ReLU layer wraps VL_NNRELU(). It has fields: 152 | % 153 | % - `layer.type` contains the string `'relu'`. 154 | % - `layer.leak` is the leak factor (e.g. 0). 155 | % 156 | % The sigmoid layer is the same, but for the sigmoid function, 157 | % with `relu` replaced by `sigmoid` and no leak factor. 158 | % 159 | % Dropout layer:: 160 | % The dropout layer wraps VL_NNDROPOUT(). It has fields: 161 | % 162 | % - `layer.type` contains the string `'dropout'`. 163 | % - `layer.rate` is the dropout rate (e.g. 0.5). 164 | % 165 | % Note that the block is bypassed in `test` mode. 166 | % 167 | % Softmax layer:: 168 | % The softmax layer wraps VL_NNSOFTMAX(). It has fields 169 | % 170 | % - `layer.type` contains the string`'softmax'`. 171 | % 172 | % Log-loss layer and softmax-log-loss:: 173 | % The log-loss layer wraps VL_NNLOSS(). It has fields: 174 | % 175 | % - `layer.type` contains `'loss'`. 176 | % - `layer.class` contains the ground-truth class labels. 177 | % 178 | % The softmax-log-loss layer wraps VL_NNSOFTMAXLOSS() instead. it 179 | % has the same parameters, but `type` contains the `'softmaxloss'` 180 | % string. 181 | % 182 | % P-dist layer:: 183 | % The p-dist layer wraps VL_NNPDIST(). It has fields: 184 | % 185 | % - `layer.type` contains the string `'pdist'`. 186 | % - `layer.p` is the P parameter of the P-distance (e.g. 2). 187 | % - `layer.noRoot` it tells whether to raise the distance to 188 | % the P-th power (e.g. `false`). 189 | % - `layer.epsilon` is the regularization parameter for the derivatives. 190 | % 191 | % Custom layer:: 192 | % This can be used to specify custom layers. 193 | % 194 | % - `layer.type` contains the string `'custom'`. 195 | % - `layer.forward` is a function handle computing the block. 196 | % - `layer.backward` is a function handle computing the block derivative. 197 | % 198 | % The first function is called as 199 | % 200 | % res(i+1) = layer.forward(layer, res(i), res(i+1)) 201 | % 202 | % where RES is the structure array specified before. The second function is 203 | % called as 204 | % 205 | % res(i) = layer.backward(layer, res(i), res(i+1)) 206 | % 207 | % Note that the `layer` structure can contain additional custom 208 | % fields if needed. 209 | % 210 | % See also: dagnn.DagNN, VL_SIMPLENN_TIDY(), 211 | % VL_SIMPLENN_DISPLAY(), VL_SIMPLENN_MOVE(). 212 | 213 | % Copyright (C) 2014-15 Andrea Vedaldi. 214 | % All rights reserved. 215 | % 216 | % This file is part of the VLFeat library and is made available under 217 | % the terms of the BSD license (see the COPYING file). 218 | 219 | opts.conserveMemory = false ; 220 | opts.sync = false ; 221 | opts.mode = 'normal' ; 222 | opts.accumulate = false ; 223 | opts.cudnn = true ; 224 | opts.backPropDepth = +inf ; 225 | opts.skipForward = false; 226 | opts = vl_argparse(opts, varargin); 227 | 228 | n = numel(net.layers) ; 229 | 230 | backPropLim = max(n - opts.backPropDepth + 1, 1); 231 | 232 | if (nargin <= 2) || isempty(dzdy) 233 | doder = false ; 234 | if opts.skipForward 235 | error('simplenn:skipForwardNoBackwPass', ... 236 | '`skipForward` valid only when backward pass is computed.'); 237 | end 238 | else 239 | doder = true ; 240 | end 241 | 242 | if opts.cudnn 243 | cudnn = {'CuDNN'} ; 244 | else 245 | cudnn = {'NoCuDNN'} ; 246 | end 247 | 248 | switch lower(opts.mode) 249 | case 'normal' 250 | testMode = false ; 251 | case 'val' 252 | testMode = false ; 253 | case 'test' 254 | testMode = true ; 255 | otherwise 256 | error('Unknown mode ''%s''.', opts. mode) ; 257 | end 258 | 259 | gpuMode = isa(x, 'gpuArray') ; 260 | 261 | if nargin <= 3 || isempty(res) 262 | if opts.skipForward 263 | error('simplenn:skipForwardEmptyRes', ... 264 | 'RES structure must be provided for `skipForward`.'); 265 | end 266 | res = struct(... 267 | 'x', cell(1,n+1), ... 268 | 'dzdx', cell(1,n+1), ... 269 | 'dzdw', cell(1,n+1), ... 270 | 'aux', cell(1,n+1), ... 271 | 'stats', cell(1,n+1), ... 272 | 'time', num2cell(zeros(1,n+1)), ... 273 | 'backwardTime', num2cell(zeros(1,n+1))) ; 274 | end 275 | 276 | if ~opts.skipForward 277 | res(1).x = x ; 278 | end 279 | 280 | 281 | reg = struct('name', 'registers', ... 282 | 'x', cell(1,net.meta.regNum),... 283 | 'dzdx', cell(1,net.meta.regNum)) ; 284 | 285 | regConcatTemp = []; 286 | 287 | 288 | 289 | 290 | % ------------------------------------------------------------------------- 291 | % Forward pass 292 | % ------------------------------------------------------------------------- 293 | 294 | 295 | 296 | for i=1:n 297 | if opts.skipForward, break; end; 298 | l = net.layers{i} ; 299 | res(i).time = tic ; 300 | switch l.type 301 | case 'conv' 302 | res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ... 303 | 'pad', l.pad, ... 304 | 'stride', l.stride, ... 305 | l.opts{:}, ... 306 | cudnn{:}) ; 307 | 308 | case 'convt' 309 | res(i+1).x = vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, ... 310 | 'crop', l.crop, ... 311 | 'upsample', l.upsample, ... 312 | 'numGroups', l.numGroups, ... 313 | l.opts{:}, ... 314 | cudnn{:}) ; 315 | 316 | case 'pool' 317 | res(i+1).x = vl_nnpool(res(i).x, l.pool, ... 318 | 'pad', l.pad, 'stride', l.stride, ... 319 | 'method', l.method) ; 320 | case 'upconv' 321 | res(i+1).x=vl_nnupconv(res(i).x,l.pad,l.stride); 322 | 323 | case {'normalize', 'lrn'} 324 | res(i+1).x = vl_nnnormalize(res(i).x, l.param) ; 325 | 326 | case 'softmax' 327 | res(i+1).x = vl_nnsoftmax(res(i).x) ; 328 | 329 | case 'loss' 330 | res(i+1).x = vl_nnloss(res(i).x, l.class) ; 331 | 332 | case 'softmaxloss' 333 | res(i+1).x = vl_nnsoftmaxloss(res(i).x, l.class) ; 334 | 335 | case 'relu' 336 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 337 | res(i+1).x = vl_nnrelu(res(i).x,[],leak{:}) ; 338 | 339 | case 'sigmoid' 340 | res(i+1).x = vl_nnsigmoid(res(i).x) ; 341 | 342 | case 'noffset' 343 | res(i+1).x = vl_nnnoffset(res(i).x, l.param) ; 344 | 345 | case 'spnorm' 346 | res(i+1).x = vl_nnspnorm(res(i).x, l.param) ; 347 | 348 | case 'dropout' 349 | if testMode 350 | res(i+1).x = res(i).x ; 351 | else 352 | [res(i+1).x, res(i+1).aux] = vl_nndropout(res(i).x, 'rate', l.rate) ; 353 | end 354 | 355 | case 'bnorm' 356 | if testMode 357 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}) ; 358 | else 359 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}) ; 360 | end 361 | 362 | case 'pdist' 363 | res(i+1).x = vl_nnpdist(res(i).x, l.class, l.p, ... 364 | 'noRoot', l.noRoot, ... 365 | 'epsilon', l.epsilon, ... 366 | 'aggregate', l.aggregate) ; 367 | 368 | case 'custom' 369 | res(i+1) = l.forward(l, res(i), res(i+1)) ; 370 | 371 | case 'reg_catch' 372 | res(i+1).x = res(i).x + reg(l.regNum).x; 373 | 374 | case 'reg_toss' 375 | res(i+1).x = res(i).x; 376 | reg(l.regNum).x = res(i).x; 377 | 378 | case 'reg_concat' % combine with the left side (contracting path); 379 | % if isempty(regConcatTemp) 380 | regConcatTemp = zeros(size(reg(l.regSet(1)).x,1),size(reg(l.regSet(1)).x,2),size(res(i).x,3)*(length(l.regSet)+1),size(res(i).x,4),'single'); 381 | if gpuMode 382 | regConcatTemp = gpuArray(regConcatTemp); 383 | end 384 | % end 385 | for ii = 1:length(l.regSet) 386 | regConcatTemp(:,:,(ii-1)*size(res(i).x,3) + (1:size(res(i).x,3)),:) = ... 387 | reg(l.regSet(ii)).x; 388 | end 389 | dif_dim=size(reg(l.regSet(1)).x) -size(res(i).x); 390 | if mod(dif_dim(1),2)==0 391 | tmp= padarray(res(i).x,[dif_dim(1)/2 0 0]); 392 | else 393 | tmp= padarray(res(i).x,[fix(dif_dim(1)/2) 0 0]); 394 | tmp= padarray(tmp,[1 0 0],'pre'); 395 | end 396 | 397 | if mod(dif_dim(2),2)==0 398 | tmp= padarray(tmp,[0 dif_dim(2)/2 0]); 399 | else 400 | tmp= padarray(tmp,[0 fix(dif_dim(2)/2) 0]); 401 | tmp= padarray(tmp,[0 1 0],'pre'); 402 | end 403 | 404 | regConcatTemp(:,:,(ii)*size(res(i).x,3) + (1:size(res(i).x,3)),:) = tmp; 405 | res(i+1).x = regConcatTemp; 406 | 407 | 408 | 409 | case 'euclideanloss' 410 | if testMode 411 | res(i+1).x = res(i).x; 412 | else 413 | res(i+1).x = vl_euclideanloss(res(i).x, l.class) ; 414 | end 415 | 416 | otherwise 417 | error('Unknown layer type ''%s''.', l.type) ; 418 | end 419 | 420 | % optionally forget intermediate results 421 | forget = opts.conserveMemory & ~(doder & n >= backPropLim) ; 422 | if i > 1 423 | lp = net.layers{i-1} ; 424 | % forget RELU input, even for BPROP 425 | forget = forget & (~doder | (strcmp(l.type, 'relu') & ~lp.precious)) ; 426 | forget = forget & ~(strcmp(lp.type, 'loss') || strcmp(lp.type, 'softmaxloss')) ; 427 | forget = forget & ~lp.precious ; 428 | end 429 | if forget 430 | res(i).x = [] ; 431 | end 432 | 433 | if gpuMode && opts.sync 434 | wait(gpuDevice) ; 435 | end 436 | res(i).time = toc(res(i).time) ; 437 | end 438 | 439 | % ------------------------------------------------------------------------- 440 | % Backward pass 441 | % ------------------------------------------------------------------------- 442 | 443 | if doder 444 | res(n+1).dzdx = dzdy ; 445 | for i=n:-1:max(1, n-opts.backPropDepth+1) 446 | l = net.layers{i} ; 447 | res(i).backwardTime = tic ; 448 | switch l.type 449 | 450 | 451 | case 'conv' 452 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 453 | vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 454 | 'pad', l.pad, ... 455 | 'stride', l.stride, ... 456 | l.opts{:}, ... 457 | cudnn{:}) ; 458 | 459 | case 'convt' 460 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 461 | vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 462 | 'crop', l.crop, ... 463 | 'upsample', l.upsample, ... 464 | 'numGroups', l.numGroups, ... 465 | l.opts{:}, ... 466 | cudnn{:}) ; 467 | 468 | case 'pool' 469 | res(i).dzdx = vl_nnpool(res(i).x, l.pool, res(i+1).dzdx, ... 470 | 'pad', l.pad, 'stride', l.stride, ... 471 | 'method', l.method) ; 472 | case 'upconv' 473 | %(x,pad,stride,dzdy) 474 | res(i).dzdx = vl_nnupconv(res(i).x, l.pad,l.stride, res(i+1).dzdx) ; 475 | 476 | case {'normalize', 'lrn'} 477 | res(i).dzdx = vl_nnnormalize(res(i).x, l.param, res(i+1).dzdx) ; 478 | 479 | case 'softmax' 480 | res(i).dzdx = vl_nnsoftmax(res(i).x, res(i+1).dzdx) ; 481 | 482 | case 'loss' 483 | res(i).dzdx = vl_nnloss(res(i).x, l.class, res(i+1).dzdx) ; 484 | 485 | case 'softmaxloss' 486 | res(i).dzdx = vl_nnsoftmaxloss(res(i).x, l.class, res(i+1).dzdx) ; 487 | 488 | case 'relu' 489 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 490 | if ~isempty(res(i).x) 491 | res(i).dzdx = vl_nnrelu(res(i).x, res(i+1).dzdx, leak{:}) ; 492 | else 493 | % if res(i).x is empty, it has been optimized away, so we use this 494 | % hack (which works only for ReLU): 495 | res(i).dzdx = vl_nnrelu(res(i+1).x, res(i+1).dzdx, leak{:}) ; 496 | end 497 | 498 | case 'sigmoid' 499 | res(i).dzdx = vl_nnsigmoid(res(i).x, res(i+1).dzdx) ; 500 | 501 | case 'noffset' 502 | res(i).dzdx = vl_nnnoffset(res(i).x, l.param, res(i+1).dzdx) ; 503 | 504 | case 'spnorm' 505 | res(i).dzdx = vl_nnspnorm(res(i).x, l.param, res(i+1).dzdx) ; 506 | 507 | case 'dropout' 508 | if testMode 509 | res(i).dzdx = res(i+1).dzdx ; 510 | else 511 | res(i).dzdx = vl_nndropout(res(i).x, res(i+1).dzdx, ... 512 | 'mask', res(i+1).aux) ; 513 | end 514 | 515 | case 'bnorm' 516 | [res(i).dzdx, dzdw{1}, dzdw{2}, dzdw{3}] = ... 517 | vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx) ; 518 | % multiply the moments update by the number of images in the batch 519 | % this is required to make the update additive for subbatches 520 | % and will eventually be normalized away 521 | dzdw{3} = dzdw{3} * size(res(i).x,4) ; 522 | 523 | case 'pdist' 524 | res(i).dzdx = vl_nnpdist(res(i).x, l.class, ... 525 | l.p, res(i+1).dzdx, ... 526 | 'noRoot', l.noRoot, ... 527 | 'epsilon', l.epsilon, ... 528 | 'aggregate', l.aggregate) ; 529 | 530 | case 'custom' 531 | res(i) = l.backward(l, res(i), res(i+1)) ; 532 | 533 | 534 | case 'reg_catch' 535 | 536 | res(i).dzdx = res(i+1).dzdx; 537 | reg(l.regNum).dzdx = res(i).dzdx; 538 | 539 | 540 | case 'reg_toss' 541 | res(i).dzdx = res(i+1).dzdx + reg(l.regNum).dzdx; 542 | 543 | 544 | case 'reg_concat' 545 | for ii = 1:length(l.regSet) 546 | reg(l.regSet(ii)).dzdx = res(i+1).dzdx(:,:,(ii-1)*size(res(i).x,3) + (1:size(res(i).x,3)),:); 547 | end 548 | res(i).dzdx = res(i+1).dzdx(:,:,(ii)*size(res(i).x,3) + (1:size(res(i).x,3)),:); 549 | 550 | case 'euclideanloss' 551 | res(i).dzdx = vl_euclideanloss(res(i).x, l.class,res(i+1).dzdx) ; 552 | 553 | 554 | end % layers 555 | 556 | switch l.type 557 | case {'conv', 'convt', 'bnorm'} 558 | if ~opts.accumulate 559 | res(i).dzdw = dzdw ; 560 | else 561 | for j=1:numel(dzdw) 562 | res(i).dzdw{j} = res(i).dzdw{j} + dzdw{j} ; 563 | end 564 | end 565 | dzdw = [] ; 566 | end 567 | if opts.conserveMemory && ~net.layers{i}.precious && i ~= n 568 | res(i+1).dzdx = [] ; 569 | res(i+1).x = [] ; 570 | end 571 | if gpuMode && opts.sync 572 | wait(gpuDevice) ; 573 | end 574 | res(i).backwardTime = toc(res(i).backwardTime) ; 575 | end 576 | end 577 | -------------------------------------------------------------------------------- /vl_simplenn_fbpconvnet_eval.m: -------------------------------------------------------------------------------- 1 | function [res, reg] = vl_simplenn_fbpconvnet_eval(net, x, dzdy, res, varargin) 2 | %VL_SIMPLENN Evaluate a SimpleNN network. 3 | % RES = VL_SIMPLENN(NET, X) evaluates the convnet NET on data X. 4 | % RES = VL_SIMPLENN(NET, X, DZDY) evaluates the convnent NET and its 5 | % derivative on data X and output derivative DZDY (foward+bacwkard pass). 6 | % RES = VL_SIMPLENN(NET, X, [], RES) evaluates the NET on X reusing the 7 | % structure RES. 8 | % RES = VL_SIMPLENN(NET, X, DZDY, RES) evaluates the NET on X and its 9 | % derivatives reusing the structure RES. 10 | % 11 | % This function process networks using the SimpleNN wrapper 12 | % format. Such networks are 'simple' in the sense that they consist 13 | % of a linear sequence of computational layers. You can use the 14 | % `dagnn.DagNN` wrapper for more complex topologies, or write your 15 | % own wrapper around MatConvNet computational blocks for even 16 | % greater flexibility. 17 | % 18 | % The format of the network structure NET and of the result 19 | % structure RES are described in some detail below. Most networks 20 | % expect the input data X to be standardized, for example by 21 | % rescaling the input image(s) and subtracting a mean. Doing so is 22 | % left to the user, but information on how to do this is usually 23 | % contained in the `net.meta` field of the NET structure (see 24 | % below). 25 | % 26 | % The NET structure needs to be updated as new features are 27 | % introduced in MatConvNet; use the `VL_SIMPLENN_TIDY()` function 28 | % to make an old network current, as well as to cleanup and check 29 | % the structure of an existing network. 30 | % 31 | % Networks can run either on the CPU or GPU. Use VL_SIMPLENN_MOVE() 32 | % to move the network parameters between these devices. 33 | % 34 | % To print or obtain summary of the network structure, use the 35 | % VL_SIMPLENN_DISPLAY() function. 36 | % 37 | % VL_SIMPLENN(NET, X, DZDY, RES, 'OPT', VAL, ...) takes the following 38 | % options: 39 | % 40 | % `Mode`:: `normal` 41 | % Specifies the mode of operation. It can be either `'normal'` or 42 | % `'test'`. In test mode, dropout and batch-normalization are 43 | % bypassed. Note that, when a network is deployed, it may be 44 | % preferable to *remove* such blocks altogether. 45 | % 46 | % `ConserveMemory`:: `true` 47 | % Aggressively delete intermediate results. This in practice has 48 | % a very small performance hit and allows training much larger 49 | % models. However, it can be useful to disable it for 50 | % debugging. It is also possible to preserve individual layer outputs 51 | % by setting `net.layers{...}.precious` to `true`. 52 | % 53 | % `CuDNN`:: `true` 54 | % Use CuDNN when available. 55 | % 56 | % `Accumulate`:: `false` 57 | % Accumulate gradients in back-propagation instead of rewriting 58 | % them. This is useful to break the computation in sub-batches. 59 | % The gradients are accumulated to the provided RES structure 60 | % (i.e. to call VL_SIMPLENN(NET, X, DZDY, RES, ...). 61 | % 62 | % `SkipForward`:: `false` 63 | % Reuse the output values from the provided RES structure and compute 64 | % only the derivatives (bacward pass). 65 | % 66 | % ## The result format 67 | % 68 | % SimpleNN returns the result of its calculations in the RES 69 | % structure array. RES(1) contains the input to the network, while 70 | % RES(2), RES(3), ... contain the output of each layer, from first 71 | % to last. Each entry has the following fields: 72 | % 73 | % - `res(i+1).x`: the output of layer `i`. Hence `res(1).x` is the 74 | % network input. 75 | % 76 | % - `res(i+1).aux`: any auxiliary output data of layer i. For example, 77 | % dropout uses this field to store the dropout mask. 78 | % 79 | % - `res(i+1).dzdx`: the derivative of the network output relative 80 | % to the output of layer `i`. In particular `res(1).dzdx` is the 81 | % derivative of the network output with respect to the network 82 | % input. 83 | % 84 | % - `res(i+1).dzdw`: a cell array containing the derivatives of the 85 | % network output relative to the parameters of layer `i`. It can 86 | % be a cell array for multiple parameters. 87 | % 88 | % ## The network format 89 | % 90 | % The network is represented by the NET structure, which contains 91 | % two fields: 92 | % 93 | % - `net.layers` is a cell array with the CNN layers. 94 | % 95 | % - `net.meta` is a grab-bag of auxiliary application-dependent 96 | % information, including for example details on how to normalize 97 | % input data, the class names for a classifiers, or details of 98 | % the learning algorithm. The content of this field is ignored by 99 | % VL_SIMPLENN(). 100 | % 101 | % SimpleNN is aware of the following layers: 102 | % 103 | % Convolution layer:: 104 | % The convolution layer wraps VL_NNCONV(). It has fields: 105 | % 106 | % - `layer.type` contains the string `'conv'`. 107 | % - `layer.weights` is a cell array with filters and biases. 108 | % - `layer.stride` is the sampling stride (e.g. 1). 109 | % - `layer.pad` is the padding (e.g. 0). 110 | % 111 | % Convolution transpose layer:: 112 | % The convolution transpose layer wraps VL_NNCONVT(). It has fields: 113 | % 114 | % - `layer.type` contains the string `'convt'`. 115 | % - `layer.weights` is a cell array with filters and biases. 116 | % - `layer.upsample` is the upsampling factor (e.g. 1). 117 | % - `layer.crop` is the amount of output cropping (e.g. 0). 118 | % 119 | % Max pooling layer:: 120 | % The max pooling layer wraps VL_NNPOOL(). It has fields: 121 | % 122 | % - `layer.type` contains the string `'pool'`. 123 | % - `layer.method` is the pooling method (either 'max' or 'avg'). 124 | % - `layer.pool` is the pooling size (e.g. 3). 125 | % - `layer.stride` is the sampling stride (usually 1). 126 | % - `layer.pad` is the padding (usually 0). 127 | % 128 | % Normalization (LRN) layer:: 129 | % The normalization layer wraps VL_NNNORMALIZE(). It has fields: 130 | % 131 | % - `layer.type` contains the string `'normalize'` or `'lrn'`. 132 | % - `layer.param` contains the normalization parameters (see VL_NNNORMALIZE()). 133 | % 134 | % Spatial normalization layer:: 135 | % The spatial normalization layer wraps VL_NNSPNORM(). It has fields: 136 | % 137 | % - `layer.type` contains the string `'spnorm'`. 138 | % - `layer.param` contains the normalization parameters (see VL_NNSPNORM()). 139 | % 140 | % Batch normalization layer:: 141 | % This layer wraps VL_NNBNORM(). It has fields: 142 | % 143 | % - `layer.type` contains the string `'bnorm'`. 144 | % - `layer.weights` contains is a cell-array with, multiplier and 145 | % biases, and moments parameters 146 | % 147 | % Note that moments are used only in `'test'` mode to bypass batch 148 | % normalization. 149 | % 150 | % ReLU and Sigmoid layers:: 151 | % The ReLU layer wraps VL_NNRELU(). It has fields: 152 | % 153 | % - `layer.type` contains the string `'relu'`. 154 | % - `layer.leak` is the leak factor (e.g. 0). 155 | % 156 | % The sigmoid layer is the same, but for the sigmoid function, 157 | % with `relu` replaced by `sigmoid` and no leak factor. 158 | % 159 | % Dropout layer:: 160 | % The dropout layer wraps VL_NNDROPOUT(). It has fields: 161 | % 162 | % - `layer.type` contains the string `'dropout'`. 163 | % - `layer.rate` is the dropout rate (e.g. 0.5). 164 | % 165 | % Note that the block is bypassed in `test` mode. 166 | % 167 | % Softmax layer:: 168 | % The softmax layer wraps VL_NNSOFTMAX(). It has fields 169 | % 170 | % - `layer.type` contains the string`'softmax'`. 171 | % 172 | % Log-loss layer and softmax-log-loss:: 173 | % The log-loss layer wraps VL_NNLOSS(). It has fields: 174 | % 175 | % - `layer.type` contains `'loss'`. 176 | % - `layer.class` contains the ground-truth class labels. 177 | % 178 | % The softmax-log-loss layer wraps VL_NNSOFTMAXLOSS() instead. it 179 | % has the same parameters, but `type` contains the `'softmaxloss'` 180 | % string. 181 | % 182 | % P-dist layer:: 183 | % The p-dist layer wraps VL_NNPDIST(). It has fields: 184 | % 185 | % - `layer.type` contains the string `'pdist'`. 186 | % - `layer.p` is the P parameter of the P-distance (e.g. 2). 187 | % - `layer.noRoot` it tells whether to raise the distance to 188 | % the P-th power (e.g. `false`). 189 | % - `layer.epsilon` is the regularization parameter for the derivatives. 190 | % 191 | % Custom layer:: 192 | % This can be used to specify custom layers. 193 | % 194 | % - `layer.type` contains the string `'custom'`. 195 | % - `layer.forward` is a function handle computing the block. 196 | % - `layer.backward` is a function handle computing the block derivative. 197 | % 198 | % The first function is called as 199 | % 200 | % res(i+1) = layer.forward(layer, res(i), res(i+1)) 201 | % 202 | % where RES is the structure array specified before. The second function is 203 | % called as 204 | % 205 | % res(i) = layer.backward(layer, res(i), res(i+1)) 206 | % 207 | % Note that the `layer` structure can contain additional custom 208 | % fields if needed. 209 | % 210 | % See also: dagnn.DagNN, VL_SIMPLENN_TIDY(), 211 | % VL_SIMPLENN_DISPLAY(), VL_SIMPLENN_MOVE(). 212 | 213 | % Copyright (C) 2014-15 Andrea Vedaldi. 214 | % All rights reserved. 215 | % 216 | % This file is part of the VLFeat library and is made available under 217 | % the terms of the BSD license (see the COPYING file). 218 | 219 | opts.conserveMemory = true ; 220 | opts.sync = false ; 221 | opts.mode = 'normal' ; 222 | opts.accumulate = false ; 223 | opts.cudnn = true ; 224 | opts.backPropDepth = +inf ; 225 | opts.skipForward = false; 226 | opts = vl_argparse(opts, varargin); 227 | 228 | n = numel(net.layers) ; 229 | 230 | backPropLim = max(n - opts.backPropDepth + 1, 1); 231 | 232 | % if (nargin <= 2) || isempty(dzdy) 233 | doder = false ; 234 | if opts.skipForward 235 | error('simplenn:skipForwardNoBackwPass', ... 236 | '`skipForward` valid only when backward pass is computed.'); 237 | end 238 | % else 239 | % doder = true ; 240 | % end 241 | 242 | if opts.cudnn 243 | cudnn = {'CuDNN'} ; 244 | else 245 | cudnn = {'NoCuDNN'} ; 246 | end 247 | 248 | switch lower(opts.mode) 249 | case 'normal' 250 | testMode = false ; 251 | case 'val' 252 | testMode = false ; 253 | case 'test' 254 | testMode = true ; 255 | otherwise 256 | error('Unknown mode ''%s''.', opts. mode) ; 257 | end 258 | 259 | gpuMode = isa(x, 'gpuArray') ; 260 | 261 | if nargin <= 3 || isempty(res) 262 | if opts.skipForward 263 | error('simplenn:skipForwardEmptyRes', ... 264 | 'RES structure must be provided for `skipForward`.'); 265 | end 266 | res = struct(... 267 | 'x', cell(1,n+1), ... 268 | 'dzdx', cell(1,n+1), ... 269 | 'dzdw', cell(1,n+1), ... 270 | 'aux', cell(1,n+1), ... 271 | 'stats', cell(1,n+1), ... 272 | 'time', num2cell(zeros(1,n+1)), ... 273 | 'backwardTime', num2cell(zeros(1,n+1))) ; 274 | end 275 | 276 | if ~opts.skipForward 277 | res(1).x = x ; 278 | end 279 | 280 | 281 | reg = struct('name', 'registers', ... 282 | 'x', cell(1,net.meta.regNum),... 283 | 'dzdx', cell(1,net.meta.regNum)) ; 284 | 285 | regConcatTemp = []; 286 | 287 | 288 | 289 | 290 | % ------------------------------------------------------------------------- 291 | % Forward pass 292 | % ------------------------------------------------------------------------- 293 | 294 | 295 | 296 | % th = 20; 297 | % x_repository = max(abs(x_repository)-th,0).*sign(x_repository); 298 | 299 | % x_repository = 0; 300 | for i=1:n 301 | if opts.skipForward, break; end; 302 | l = net.layers{i} ; 303 | res(i).time = tic ; 304 | switch l.type 305 | case 'conv' 306 | res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ... 307 | 'pad', l.pad, ... 308 | 'stride', l.stride, ... 309 | l.opts{:}, ... 310 | cudnn{:}) ; 311 | 312 | case 'convt' 313 | res(i+1).x = vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, ... 314 | 'crop', l.crop, ... 315 | 'upsample', l.upsample, ... 316 | 'numGroups', l.numGroups, ... 317 | l.opts{:}, ... 318 | cudnn{:}) ; 319 | 320 | case 'pool' 321 | res(i+1).x = vl_nnpool(res(i).x, l.pool, ... 322 | 'pad', l.pad, 'stride', l.stride, ... 323 | 'method', l.method) ; 324 | case 'upconv' 325 | res(i+1).x=vl_nnupconv(res(i).x,l.pad,l.stride); 326 | 327 | case {'normalize', 'lrn'} 328 | res(i+1).x = vl_nnnormalize(res(i).x, l.param) ; 329 | 330 | case 'softmax' 331 | res(i+1).x = vl_nnsoftmax(res(i).x) ; 332 | 333 | case 'loss' 334 | res(i+1).x = vl_nnloss(res(i).x, l.class) ; 335 | 336 | case 'softmaxloss' 337 | res(i+1).x = vl_nnsoftmaxloss(res(i).x, l.class) ; 338 | 339 | case 'relu' 340 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 341 | res(i+1).x = vl_nnrelu(res(i).x,[],leak{:}) ; 342 | 343 | case 'sigmoid' 344 | res(i+1).x = vl_nnsigmoid(res(i).x) ; 345 | 346 | case 'noffset' 347 | res(i+1).x = vl_nnnoffset(res(i).x, l.param) ; 348 | 349 | case 'spnorm' 350 | res(i+1).x = vl_nnspnorm(res(i).x, l.param) ; 351 | 352 | case 'dropout' 353 | if testMode 354 | res(i+1).x = res(i).x ; 355 | else 356 | [res(i+1).x, res(i+1).aux] = vl_nndropout(res(i).x, 'rate', l.rate) ; 357 | end 358 | 359 | case 'bnorm' 360 | if testMode 361 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, 'moments', l.weights{3}) ; 362 | else 363 | res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}) ; 364 | end 365 | 366 | case 'pdist' 367 | res(i+1).x = vl_nnpdist(res(i).x, l.class, l.p, ... 368 | 'noRoot', l.noRoot, ... 369 | 'epsilon', l.epsilon, ... 370 | 'aggregate', l.aggregate) ; 371 | 372 | case 'custom' 373 | res(i+1) = l.forward(l, res(i), res(i+1)) ; 374 | 375 | case 'reg_catch' 376 | res(i+1).x = res(i).x + reg(l.regNum).x; 377 | 378 | case 'reg_toss' 379 | res(i+1).x = res(i).x; 380 | reg(l.regNum).x = res(i).x; 381 | 382 | case 'reg_concat' 383 | % if isempty(regConcatTemp) 384 | regConcatTemp = zeros(size(res(i).x,1),size(res(i).x,2),size(res(i).x,3)*(length(l.regSet)+1),size(res(i).x,4),'single'); 385 | if gpuMode 386 | regConcatTemp = gpuArray(regConcatTemp); 387 | end 388 | % end 389 | for ii = 1:length(l.regSet) 390 | regConcatTemp(:,:,(ii-1)*size(res(i).x,3) + (1:size(res(i).x,3)),:) = ... 391 | reg(l.regSet(ii)).x; 392 | end 393 | regConcatTemp(:,:,(ii)*size(res(i).x,3) + (1:size(res(i).x,3)),:) = res(i).x; 394 | res(i+1).x = regConcatTemp; 395 | 396 | 397 | 398 | case 'euclideanloss' 399 | if testMode 400 | res(i+1).x = res(i).x; 401 | else 402 | res(i+1).x = vl_euclideanloss(res(i).x, l.class) ; 403 | end 404 | 405 | otherwise 406 | error('Unknown layer type ''%s''.', l.type) ; 407 | end 408 | 409 | % optionally forget intermediate results 410 | forget = opts.conserveMemory & ~(doder & n >= backPropLim) ; 411 | if i > 1 412 | lp = net.layers{i-1} ; 413 | % forget RELU input, even for BPROP 414 | forget = forget & (~doder | (strcmp(l.type, 'relu') & ~lp.precious)) ; 415 | forget = forget & ~(strcmp(lp.type, 'loss') || strcmp(lp.type, 'softmaxloss')) ; 416 | forget = forget & ~lp.precious ; 417 | end 418 | if forget 419 | res(i).x = [] ; 420 | end 421 | 422 | if gpuMode && opts.sync 423 | wait(gpuDevice) ; 424 | end 425 | res(i).time = toc(res(i).time) ; 426 | end 427 | 428 | % ------------------------------------------------------------------------- 429 | % Backward pass 430 | % ------------------------------------------------------------------------- 431 | 432 | if doder 433 | res(n+1).dzdx = dzdy ; 434 | for i=n:-1:max(1, n-opts.backPropDepth+1) 435 | l = net.layers{i} ; 436 | res(i).backwardTime = tic ; 437 | switch l.type 438 | 439 | 440 | case 'conv' 441 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 442 | vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 443 | 'pad', l.pad, ... 444 | 'stride', l.stride, ... 445 | l.opts{:}, ... 446 | cudnn{:}) ; 447 | 448 | case 'convt' 449 | [res(i).dzdx, dzdw{1}, dzdw{2}] = ... 450 | vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ... 451 | 'crop', l.crop, ... 452 | 'upsample', l.upsample, ... 453 | 'numGroups', l.numGroups, ... 454 | l.opts{:}, ... 455 | cudnn{:}) ; 456 | 457 | case 'pool' 458 | res(i).dzdx = vl_nnpool(res(i).x, l.pool, res(i+1).dzdx, ... 459 | 'pad', l.pad, 'stride', l.stride, ... 460 | 'method', l.method) ; 461 | case 'upconv' 462 | %(x,pad,stride,dzdy) 463 | res(i).dzdx = vl_nnupconv(res(i).x, l.pad,l.stride, res(i+1).dzdx) ; 464 | 465 | case {'normalize', 'lrn'} 466 | res(i).dzdx = vl_nnnormalize(res(i).x, l.param, res(i+1).dzdx) ; 467 | 468 | case 'softmax' 469 | res(i).dzdx = vl_nnsoftmax(res(i).x, res(i+1).dzdx) ; 470 | 471 | case 'loss' 472 | res(i).dzdx = vl_nnloss(res(i).x, l.class, res(i+1).dzdx) ; 473 | 474 | case 'softmaxloss' 475 | res(i).dzdx = vl_nnsoftmaxloss(res(i).x, l.class, res(i+1).dzdx) ; 476 | 477 | case 'relu' 478 | if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end 479 | if ~isempty(res(i).x) 480 | res(i).dzdx = vl_nnrelu(res(i).x, res(i+1).dzdx, leak{:}) ; 481 | else 482 | % if res(i).x is empty, it has been optimized away, so we use this 483 | % hack (which works only for ReLU): 484 | res(i).dzdx = vl_nnrelu(res(i+1).x, res(i+1).dzdx, leak{:}) ; 485 | end 486 | 487 | case 'sigmoid' 488 | res(i).dzdx = vl_nnsigmoid(res(i).x, res(i+1).dzdx) ; 489 | 490 | case 'noffset' 491 | res(i).dzdx = vl_nnnoffset(res(i).x, l.param, res(i+1).dzdx) ; 492 | 493 | case 'spnorm' 494 | res(i).dzdx = vl_nnspnorm(res(i).x, l.param, res(i+1).dzdx) ; 495 | 496 | case 'dropout' 497 | if testMode 498 | res(i).dzdx = res(i+1).dzdx ; 499 | else 500 | res(i).dzdx = vl_nndropout(res(i).x, res(i+1).dzdx, ... 501 | 'mask', res(i+1).aux) ; 502 | end 503 | 504 | case 'bnorm' 505 | [res(i).dzdx, dzdw{1}, dzdw{2}, dzdw{3}] = ... 506 | vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx) ; 507 | % multiply the moments update by the number of images in the batch 508 | % this is required to make the update additive for subbatches 509 | % and will eventually be normalized away 510 | dzdw{3} = dzdw{3} * size(res(i).x,4) ; 511 | 512 | case 'pdist' 513 | res(i).dzdx = vl_nnpdist(res(i).x, l.class, ... 514 | l.p, res(i+1).dzdx, ... 515 | 'noRoot', l.noRoot, ... 516 | 'epsilon', l.epsilon, ... 517 | 'aggregate', l.aggregate) ; 518 | 519 | case 'custom' 520 | res(i) = l.backward(l, res(i), res(i+1)) ; 521 | 522 | 523 | case 'reg_catch' 524 | 525 | res(i).dzdx = res(i+1).dzdx; 526 | reg(l.regNum).dzdx = res(i).dzdx; 527 | 528 | 529 | case 'reg_toss' 530 | res(i).dzdx = res(i+1).dzdx + reg(l.regNum).dzdx; 531 | 532 | 533 | case 'reg_concat' 534 | for ii = 1:length(l.regSet) 535 | reg(l.regSet(ii)).dzdx = res(i+1).dzdx(:,:,(ii-1)*size(res(i).x,3) + (1:size(res(i).x,3)),:); 536 | end 537 | res(i).dzdx = res(i+1).dzdx(:,:,(ii)*size(res(i).x,3) + (1:size(res(i).x,3)),:); 538 | 539 | case 'euclideanloss' 540 | res(i).dzdx = vl_euclideanloss(res(i).x, l.class,res(i+1).dzdx) ; 541 | 542 | end % layers 543 | 544 | switch l.type 545 | case {'conv', 'convt', 'bnorm'} 546 | if ~opts.accumulate 547 | res(i).dzdw = dzdw ; 548 | else 549 | for j=1:numel(dzdw) 550 | res(i).dzdw{j} = res(i).dzdw{j} + dzdw{j} ; 551 | end 552 | end 553 | dzdw = [] ; 554 | end 555 | if opts.conserveMemory && ~net.layers{i}.precious && i ~= n 556 | res(i+1).dzdx = [] ; 557 | res(i+1).x = [] ; 558 | end 559 | if gpuMode && opts.sync 560 | wait(gpuDevice) ; 561 | end 562 | res(i).backwardTime = toc(res(i).backwardTime) ; 563 | end 564 | end 565 | -------------------------------------------------------------------------------- /vl_simplenn_para_test.m: -------------------------------------------------------------------------------- 1 | function [opts] = vl_simplenn_para_test(varargin) 2 | %VL_SIMPLENN Evaluate a SimpleNN network. 3 | % RES = VL_SIMPLENN(NET, X) evaluates the convnet NET on data X. 4 | % RES = VL_SIMPLENN(NET, X, DZDY) evaluates the convnent NET and its 5 | % derivative on data X and output derivative DZDY (foward+bacwkard pass). 6 | % RES = VL_SIMPLENN(NET, X, [], RES) evaluates the NET on X reusing the 7 | % structure RES. 8 | % RES = VL_SIMPLENN(NET, X, DZDY, RES) evaluates the NET on X and its 9 | % derivatives reusing the structure RES. 10 | % 11 | % This function process networks using the SimpleNN wrapper 12 | % format. Such networks are 'simple' in the sense that they consist 13 | % of a linear sequence of computational layers. You can use the 14 | % `dagnn.DagNN` wrapper for more complex topologies, or write your 15 | % own wrapper around MatConvNet computational blocks for even 16 | % greater flexibility. 17 | % 18 | % The format of the network structure NET and of the result 19 | % structure RES are described in some detail below. Most networks 20 | % expect the input data X to be standardized, for example by 21 | % rescaling the input image(s) and subtracting a mean. Doing so is 22 | % left to the user, but information on how to do this is usually 23 | % contained in the `net.meta` field of the NET structure (see 24 | % below). 25 | % 26 | % The NET structure needs to be updated as new features are 27 | % introduced in MatConvNet; use the `VL_SIMPLENN_TIDY()` function 28 | % to make an old network current, as well as to cleanup and check 29 | % the structure of an existing network. 30 | % 31 | % Networks can run either on the CPU or GPU. Use VL_SIMPLENN_MOVE() 32 | % to move the network parameters between these devices. 33 | % 34 | % To print or obtain summary of the network structure, use the 35 | % VL_SIMPLENN_DISPLAY() function. 36 | % 37 | % VL_SIMPLENN(NET, X, DZDY, RES, 'OPT', VAL, ...) takes the following 38 | % options: 39 | % 40 | % `Mode`:: `normal` 41 | % Specifies the mode of operation. It can be either `'normal'` or 42 | % `'test'`. In test mode, dropout and batch-normalization are 43 | % bypassed. Note that, when a network is deployed, it may be 44 | % preferable to *remove* such blocks altogether. 45 | % 46 | % `ConserveMemory`:: `true` 47 | % Aggressively delete intermediate results. This in practice has 48 | % a very small performance hit and allows training much larger 49 | % models. However, it can be useful to disable it for 50 | % debugging. It is also possible to preserve individual layer outputs 51 | % by setting `net.layers{...}.precious` to `true`. 52 | % 53 | % `CuDNN`:: `true` 54 | % Use CuDNN when available. 55 | % 56 | % `Accumulate`:: `false` 57 | % Accumulate gradients in back-propagation instead of rewriting 58 | % them. This is useful to break the computation in sub-batches. 59 | % The gradients are accumulated to the provided RES structure 60 | % (i.e. to call VL_SIMPLENN(NET, X, DZDY, RES, ...). 61 | % 62 | % `SkipForward`:: `false` 63 | % Reuse the output values from the provided RES structure and compute 64 | % only the derivatives (bacward pass). 65 | % 66 | % ## The result format 67 | % 68 | % SimpleNN returns the result of its calculations in the RES 69 | % structure array. RES(1) contains the input to the network, while 70 | % RES(2), RES(3), ... contain the output of each layer, from first 71 | % to last. Each entry has the following fields: 72 | % 73 | % - `res(i+1).x`: the output of layer `i`. Hence `res(1).x` is the 74 | % network input. 75 | % 76 | % - `res(i+1).aux`: any auxiliary output data of layer i. For example, 77 | % dropout uses this field to store the dropout mask. 78 | % 79 | % - `res(i+1).dzdx`: the derivative of the network output relative 80 | % to the output of layer `i`. In particular `res(1).dzdx` is the 81 | % derivative of the network output with respect to the network 82 | % input. 83 | % 84 | % - `res(i+1).dzdw`: a cell array containing the derivatives of the 85 | % network output relative to the parameters of layer `i`. It can 86 | % be a cell array for multiple parameters. 87 | % 88 | % ## The network format 89 | % 90 | % The network is represented by the NET structure, which contains 91 | % two fields: 92 | % 93 | % - `net.layers` is a cell array with the CNN layers. 94 | % 95 | % - `net.meta` is a grab-bag of auxiliary application-dependent 96 | % information, including for example details on how to normalize 97 | % input data, the class names for a classifiers, or details of 98 | % the learning algorithm. The content of this field is ignored by 99 | % VL_SIMPLENN(). 100 | % 101 | % SimpleNN is aware of the following layers: 102 | % 103 | % Convolution layer:: 104 | % The convolution layer wraps VL_NNCONV(). It has fields: 105 | % 106 | % - `layer.type` contains the string `'conv'`. 107 | % - `layer.weights` is a cell array with filters and biases. 108 | % - `layer.stride` is the sampling stride (e.g. 1). 109 | % - `layer.pad` is the padding (e.g. 0). 110 | % 111 | % Convolution transpose layer:: 112 | % The convolution transpose layer wraps VL_NNCONVT(). It has fields: 113 | % 114 | % - `layer.type` contains the string `'convt'`. 115 | % - `layer.weights` is a cell array with filters and biases. 116 | % - `layer.upsample` is the upsampling factor (e.g. 1). 117 | % - `layer.crop` is the amount of output cropping (e.g. 0). 118 | % 119 | % Max pooling layer:: 120 | % The max pooling layer wraps VL_NNPOOL(). It has fields: 121 | % 122 | % - `layer.type` contains the string `'pool'`. 123 | % - `layer.method` is the pooling method (either 'max' or 'avg'). 124 | % - `layer.pool` is the pooling size (e.g. 3). 125 | % - `layer.stride` is the sampling stride (usually 1). 126 | % - `layer.pad` is the padding (usually 0). 127 | % 128 | % Normalization (LRN) layer:: 129 | % The normalization layer wraps VL_NNNORMALIZE(). It has fields: 130 | % 131 | % - `layer.type` contains the string `'normalize'` or `'lrn'`. 132 | % - `layer.param` contains the normalization parameters (see VL_NNNORMALIZE()). 133 | % 134 | % Spatial normalization layer:: 135 | % The spatial normalization layer wraps VL_NNSPNORM(). It has fields: 136 | % 137 | % - `layer.type` contains the string `'spnorm'`. 138 | % - `layer.param` contains the normalization parameters (see VL_NNSPNORM()). 139 | % 140 | % Batch normalization layer:: 141 | % This layer wraps VL_NNBNORM(). It has fields: 142 | % 143 | % - `layer.type` contains the string `'bnorm'`. 144 | % - `layer.weights` contains is a cell-array with, multiplier and 145 | % biases, and moments parameters 146 | % 147 | % Note that moments are used only in `'test'` mode to bypass batch 148 | % normalization. 149 | % 150 | % ReLU and Sigmoid layers:: 151 | % The ReLU layer wraps VL_NNRELU(). It has fields: 152 | % 153 | % - `layer.type` contains the string `'relu'`. 154 | % - `layer.leak` is the leak factor (e.g. 0). 155 | % 156 | % The sigmoid layer is the same, but for the sigmoid function, 157 | % with `relu` replaced by `sigmoid` and no leak factor. 158 | % 159 | % Dropout layer:: 160 | % The dropout layer wraps VL_NNDROPOUT(). It has fields: 161 | % 162 | % - `layer.type` contains the string `'dropout'`. 163 | % - `layer.rate` is the dropout rate (e.g. 0.5). 164 | % 165 | % Note that the block is bypassed in `test` mode. 166 | % 167 | % Softmax layer:: 168 | % The softmax layer wraps VL_NNSOFTMAX(). It has fields 169 | % 170 | % - `layer.type` contains the string`'softmax'`. 171 | % 172 | % Log-loss layer and softmax-log-loss:: 173 | % The log-loss layer wraps VL_NNLOSS(). It has fields: 174 | % 175 | % - `layer.type` contains `'loss'`. 176 | % - `layer.class` contains the ground-truth class labels. 177 | % 178 | % The softmax-log-loss layer wraps VL_NNSOFTMAXLOSS() instead. it 179 | % has the same parameters, but `type` contains the `'softmaxloss'` 180 | % string. 181 | % 182 | % P-dist layer:: 183 | % The p-dist layer wraps VL_NNPDIST(). It has fields: 184 | % 185 | % - `layer.type` contains the string `'pdist'`. 186 | % - `layer.p` is the P parameter of the P-distance (e.g. 2). 187 | % - `layer.noRoot` it tells whether to raise the distance to 188 | % the P-th power (e.g. `false`). 189 | % - `layer.epsilon` is the regularization parameter for the derivatives. 190 | % 191 | % Custom layer:: 192 | % This can be used to specify custom layers. 193 | % 194 | % - `layer.type` contains the string `'custom'`. 195 | % - `layer.forward` is a function handle computing the block. 196 | % - `layer.backward` is a function handle computing the block derivative. 197 | % 198 | % The first function is called as 199 | % 200 | % res(i+1) = layer.forward(layer, res(i), res(i+1)) 201 | % 202 | % where RES is the structure array specified before. The second function is 203 | % called as 204 | % 205 | % res(i) = layer.backward(layer, res(i), res(i+1)) 206 | % 207 | % Note that the `layer` structure can contain additional custom 208 | % fields if needed. 209 | % 210 | % See also: dagnn.DagNN, VL_SIMPLENN_TIDY(), 211 | % VL_SIMPLENN_DISPLAY(), VL_SIMPLENN_MOVE(). 212 | 213 | % Copyright (C) 2014-15 Andrea Vedaldi. 214 | % All rights reserved. 215 | % 216 | % This file is part of the VLFeat library and is made available under 217 | % the terms of the BSD license (see the COPYING file). 218 | 219 | opts.conserveMemory = false ; 220 | opts.sync = false ; 221 | opts.mode = 'normal' ; 222 | opts.accumulate = false ; 223 | opts.cudnn = true ; 224 | opts.backPropDepth = +inf ; 225 | opts.skipForward = false; 226 | opts = vl_argparse(opts, varargin); 227 | 228 | 229 | --------------------------------------------------------------------------------