-
Notifications
You must be signed in to change notification settings - Fork 1
/
OESDiscrete.m
405 lines (337 loc) · 17.1 KB
/
OESDiscrete.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
%%% Main script for launching experimental procedure
% @param trainTime training time in number of iterations
% @param randomizationSeed randomization seed
% @param fileDescription description of approach used as file name
%%%
function OESDiscrete(trainTime, randomizationSeed, fileDescription)
rng(randomizationSeed);
% useLearnedFile(1): 0 = don't do it
% 1 = use previously learned policy specified in learnedFile
% useLearnedFile(2): 0 = retrain with same/new parameters
% 1 = complete/continue training
%
% If useLearnedFile = [1, 1] and you want to continue training, trainTime must be the overall desired train time,
% i.e. trained at first 100k iterations with useLearnedFile = [0, 0], then decided to continue training for 100k more
% iterations, then the overall train time for the model is 200k and you set useLearnedFile = [1, 1] and execute with
% OES2Muscles(200000, randomizationSeed, fileDescription)
useLearnedFile = [0, 0];
learnedFile = '';
% learnedFile = '/home/lelais/Documents/MATLAB/results/model_20-May-2016_13:10:14_500000_nonhomeo_1_2m_newImplem_highResSmSc_noMF/model.mat';
%%% Stimulus declaration
textureFile = 'Textures_mcgillManMadeTrain(jpg).mat'; % McGill man made database
% textureFile = 'Textures_mcgillFruitsAll.mat'; % McGill fruits database
% textureFile = 'Textures_mcgillFoliageTrain(jpg).mat'; % McGill foliage database
% textureFile = 'Textures_vanHaterenTrain.mat'; % vanHateren database
% textureFile = 'Textures_celine.mat'; % Celine's images
% Sparse coding approach
% sparseCodingType: 0 = non-homeostatic
% 1 = homeostatic
sparseCodingType = uint8(0);
sparseCodingTypeName = cellstr(['nonhomeo'; 'homeo___']);
% Plotting flag
% Whether figures should be generated and saved
% plotIt: [training, testing]
% 0 = don't do it
% 1 = do it
plotIt = [uint8(1), uint8(1)];
% Whether figures should be closed after generation
% closeFigures: 0 = don't do it
% 1 = do it
closeFigures = uint8(1);
% Testing flag
% Whether the testing procedure shall be executed after training
% testIt: 0 = don't do it
% 1 = do it
testIt = uint8(0);
% Load model from file or instantiate and initiate new model object
if (useLearnedFile(1) == 1)
if isempty(learnedFile)
sprintf('could not open the learned file! %s', learnedFile)
return;
else
model = load(learnedFile, 'model');
model = model.model;
model.trainTime = trainTime;
end
else
model = config(textureFile, trainTime, sparseCodingType);
end
% check if main script and model are compatible
if (model.rlModel.continuous == 1)
error('This training/main script is not compatible with continuous action space models!\nPlease execute OES1Muscle.m or OES2Muscles.m instead.');
end
% safety check for plotting functions
if (trainTime <= model.interval)
error('trainTime[%d] must be > model.interval[%d]', trainTime, model.interval);
end
% File management: either complete training with existing folder etc.,
% or create a new one
if ((useLearnedFile(1) == 1) && (useLearnedFile(2) == 1))
timeToTrain = model.trainTime - model.trainedUntil;
else
modelName = sprintf('model_%s_%i_%s_%i_%s', ...
datestr(now, 'dd-mmm-yyyy_HH:MM:SS'), ...
trainTime, ...
sparseCodingTypeName{sparseCodingType + 1}, ...
randomizationSeed, ...
fileDescription);
folder = '../results/';
mkdir(folder, modelName);
model.savePath = strcat(folder, modelName);
% backup all used files
copyfile(strcat(mfilename, '.m'), model.savePath);
copyfile('config.m', model.savePath);
copyfile(strcat(class(model), '.m'), model.savePath);
copyfile(strcat(class(model.rlModel), '.m'), model.savePath);
copyfile('results.ods', model.savePath);
timeToTrain = model.trainTime;
end
% additional notes/infromation to this model/approach
model.notes = [model.notes fileDescription];
% Save model every #saveInterval training iterations
saveInterval = ceil(model.trainTime / 5);
% Track the evolution of all basis functions of the respective sparse coders
trackSCBasisHistory = uint8(0);
% Textures
texture = load(sprintf('config/%s', textureFile));
texture = texture.texture;
nTextures = length(texture);
%%% New renderer
% simulator = OpenEyeSim('create'); % stable renderer
simulator = OpenEyeSimV5('create'); % experimental version
simulator.initRenderer();
% simulator.reinitRenderer(); % for debugging
% load all stimuli into memory for experimental renderer
for i = 1 : nTextures
simulator.add_texture(i, texture{i});
end
imgRawLeft = uint8(zeros(240, 320, 3));
imgRawRight = uint8(zeros(240, 320, 3));
imgGrayLeft = uint8(zeros(240, 320, 3));
imgGrayRight = uint8(zeros(240, 320, 3));
% Image patches cell array (input to model)
currentView = cell(1, length(model.scModel));
%%% Generates two new images for both eyes
% texture: file path of texture input
% eyeAngle: angle of single eye (rotation from offspring)
% objDist: distance of stimulus
% scaleImSize: scaling factor of stimulus plane [m]
function refreshImages(texture, eyeAngle, objDist, scaleImSize)
simulator.add_texture(1, texture);
simulator.set_params(1, eyeAngle, objDist, 0, scaleImSize); % scaling of obj plane size
result1 = simulator.generate_left();
result2 = simulator.generate_right();
imgRawLeft = permute(reshape(result1, ...
[size(imgRawLeft, 3), ...
size(imgRawLeft, 2), ...
size(imgRawLeft, 1)]), ...
[3, 2, 1]);
imgRawRight = permute(reshape(result2, ...
[size(imgRawRight, 3), ...
size(imgRawRight, 2), ...
size(imgRawRight, 1)]), ...
[3, 2, 1]);
% convert images to gray scale
imgGrayLeft = 0.2989 * imgRawLeft(:, :, 1) + 0.5870 * imgRawLeft(:, :, 2) + 0.1140 * imgRawLeft(:, :, 3);
imgGrayRight = 0.2989 * imgRawRight(:, :, 1) + 0.5870 * imgRawRight(:, :, 2) + 0.1140 * imgRawRight(:, :, 3);
end
%%% Generates two new images for both eyes for experimental renderer
% textureNumber: index of stimulus in memory buffer
% eyeAngle: angle of single eye (rotation from offspring)
% objDist: distance of stimulus
% scaleImSize: scaling factor of stimulus plane [m]
function refreshImagesNew(textureNumber, eyeAngle, objDist, scaleImSize)
simulator.set_params(textureNumber, eyeAngle, objDist, 0, scaleImSize); % scaling of obj plane size
result1 = simulator.generate_left();
result2 = simulator.generate_right();
imgRawLeft = permute(reshape(result1, ...
[size(imgRawLeft, 3), ...
size(imgRawLeft, 2), ...
size(imgRawLeft, 1)]), ...
[3, 2, 1]);
imgRawRight = permute(reshape(result2, ...
[size(imgRawRight, 3), ...
size(imgRawRight, 2), ...
size(imgRawRight, 1)]), ...
[3, 2, 1]);
% convert images to gray scale
imgGrayLeft = 0.2989 * imgRawLeft(:, :, 1) + 0.5870 * imgRawLeft(:, :, 2) + 0.1140 * imgRawLeft(:, :, 3);
imgGrayRight = 0.2989 * imgRawRight(:, :, 1) + 0.5870 * imgRawRight(:, :, 2) + 0.1140 * imgRawRight(:, :, 3);
end
%%% Main execution loop
t = model.trainedUntil; % this is zero in newly initiated model
tic; % start time count
for iter1 = 1 : (timeToTrain / model.interval)
% pick random texture every #interval times
% currentTexture = texture{(randi(nTextures, 1))}; % stable renderer
currentTexture = randi(nTextures, 1); % experimental renderer
% random depth
objDist = model.objDistMin + (model.objDistMax - model.objDistMin) * rand(1, 1);
angleDes = 2 * atand(model.baseline / (2 * objDist)); % desired vergence [deg]
% reset vergence to random value
angleNew = randi(fix(model.vergAngleFixMax)); % relax the eyes
for iter2 = 1 : model.interval
t = t + 1;
% update stimuli
% refreshImages(currentTexture, angleNew / 2, objDist, 3); % stable renderer
refreshImagesNew(currentTexture, angleNew / 2, objDist, 3); % experimental renderer
% Generate & save the anaglyph picture
% anaglyph = stereoAnaglyph(imgGrayLeft, imgGrayRight); % only for matlab 2015 or newer
% imwrite(imfuse(imgGrayLeft, imgGrayRight, 'falsecolor'), [model.savePath '/anaglyph.png']); %this one works for all tested matlab
% more advanced functions that generated the anaglyphs of the foveal views
% generateAnaglyphs(imgGrayLeft, imgGrayRight, dsRatioL, dsRatioS, foveaL, foveaS, model.savePath);
% Image patch generation
for i = 1 : length(model.scModel)
model.preprocessImageFilled(imgGrayLeft, i, 1);
model.preprocessImageFilled(imgGrayRight, i, 2);
currentView{i} = vertcat(model.patchesLeft{i}, model.patchesRight{i});
end
% Generate basis function feature vector from current images
[bfFeature, reward, recErrorArray] = model.generateFR(currentView);
%%% Learning
%% Sparse coding models
for i = 1 : length(model.scModel)
model.scModel{i}.stepTrain();
end
relativeCommand = model.rlModel.stepTrain(bfFeature, reward, (iter2 > 1));
% calculate resulting angle which is used for both eyes
angleNew = max(0.01, angleNew + relativeCommand); % command is relative angle - constrain to positive vergence
% safety on control command - RESET TO a new vergence angle
if (angleNew > model.vergAngleFixMax)
angleNew = randi(fix(model.vergAngleFixMax)); % relax the eyes
end
%%%%%%%%%%%%%%%% TRACK ALL PARAMETERS %%%%%%%%%%%%%%%%%%
% compute desired vergence command, disparity and vergence error
fixDepth = (model.baseline / 2) / tand(angleNew / 2); % fixation depth [m]
anglerr = angleDes - angleNew; % vergence error [deg]
disparity = 2 * model.focalLength * tand(anglerr / 2); % current disp [px]
% save state
% model.Z(t) = objDist;
% model.fixZ(t) = fixDepth;
% model.disp_hist(t) = disparity;
model.vergerr_hist(t) = anglerr;
model.recerr_hist(t, :) = recErrorArray;
% model.verge_actual(t) = angleNew;
% model.verge_desired(t) = angleDes;
model.relCmd_hist(t, :) = relativeCommand;
% model.cmd_hist(t, :) = command;
% model.reward_hist(t) = reward;
% model.feature_hist(t, :) = bfFeature;
% model.td_hist(t) = model.rlModel.td;
model.weight_hist(t, 1) = sum(sum(abs(model.rlModel.weightArray{2, 1})));
model.weight_hist(t, 2) = sum(sum(abs(model.rlModel.weightArray{1, 1})));
model.trainedUntil = t;
end
if mod(t, 100) == 0
sprintf('Training Iteration = %d\nAbs Command =\t[%7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f]\nRel Command = \t[%7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f]\nVer Error =\t[%7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f]', ...
t, model.verge_actual(t - model.interval + 1 : t), model.relCmd_hist(t - model.interval + 1 : t), model.vergerr_hist(t - model.interval + 1 : t))
end
% Display per cent completed of training and save model
if (~mod(t, saveInterval))
sprintf('%g%% is finished', (t / timeToTrain * 100))
save(strcat(model.savePath, '/model'), 'model');
% track basis history
if (trackSCBasisHistory == 1)
for i = 1 : length(model.scModel)
model.scModel{i}.saveBasis();
end
end
end
end
elapsedTime = toc;
% Total simulation time
model.simulatedTime = model.simulatedTime + elapsedTime / 60;
sprintf('Time = %.2f [h] = %.2f [min] = %f [sec]\nFrequency = %.4f [iterations/sec]', ...
elapsedTime / 3600, elapsedTime / 60, elapsedTime, timeToTrain / elapsedTime)
% store simulated time
save(strcat(model.savePath, '/model'), 'model');
% plot results
if (plotIt(1) == 1)
model.allPlotSave();
end
%%% Testing procedure
if (testIt == 1)
% testModelContinuous(model, nStim, plotIt, saveTestResults, verbose, simulator, reinitRenderer, folderName)
warning('Testing procedure is currently not supported.');
end
if (closeFigures == 1)
close all;
end
end
% Generates anaglyphs of the large and small scale fovea and
% one of the two unpreprocessed gray scale images
function generateAnaglyphs(leftGray, rightGray, dsRatioL, dsRatioS, foveaL, foveaS, savePath)
anaglyph = imfuse(leftGray, rightGray, 'falsecolor');
imwrite(anaglyph, [savePath '/anaglyph.png']);
%Downsampling Large
imgLeftL = leftGray(:);
imgLeftL = reshape(imgLeftL, size(leftGray));
imgRightL = rightGray(:);
imgRightL = reshape(imgRightL, size(rightGray));
for i = 1:log2(dsRatioL)
imgLeftL = impyramid(imgLeftL, 'reduce');
imgRightL = impyramid(imgRightL, 'reduce');
end
% cut fovea in the center
[h, w, ~] = size(imgLeftL);
imgLeftL = imgLeftL(fix(h / 2 + 1 - foveaL / 2) : fix(h / 2 + foveaL / 2), ...
fix(w / 2 + 1 - foveaL / 2) : fix(w / 2 + foveaL / 2));
imgRightL = imgRightL(fix(h / 2 + 1 - foveaL / 2) : fix(h / 2 + foveaL / 2), ...
fix(w / 2 + 1 - foveaL / 2) : fix(w / 2 + foveaL / 2));
% create an anaglyph of the two pictures, scale it up and save it
anaglyphL = imfuse(imgLeftL, imgRightL, 'falsecolor');
imwrite(imresize(anaglyphL, 20), [savePath '/anaglyphLargeScale.png']);
largeScaleView = imfuse(imgLeftL, imgRightL, 'montage');
imwrite(imresize(largeScaleView, 20), [savePath '/LargeScaleMontage.png']);
% Downsampling Small
imgLeftS = leftGray(:);
imgLeftS = reshape(imgLeftS, size(leftGray));
imgRightS = rightGray(:);
imgRightS = reshape(imgRightS, size(rightGray));
for i = 1:log2(dsRatioS)
imgLeftS = impyramid(imgLeftS, 'reduce');
imgRightS = impyramid(imgRightS, 'reduce');
end
% cut fovea in the center
[h, w, ~] = size(imgLeftS);
imgLeftS = imgLeftS(fix(h / 2 + 1 - foveaS / 2) : fix(h / 2 + foveaS / 2), ...
fix(w / 2 + 1 - foveaS / 2) : fix(w / 2 + foveaS / 2));
imgRightS = imgRightS(fix(h / 2 + 1 - foveaS / 2) : fix(h / 2 + foveaS / 2), ...
fix(w / 2 + 1 - foveaS / 2) : fix(w / 2 + foveaS / 2));
% create an anaglyph of the two pictures, scale it up and save it
anaglyphS = imfuse(imgLeftS, imgRightS, 'falsecolor');
imwrite(imresize(anaglyphS, 8), [savePath '/anaglyphSmallScale.png']);
smallScaleView = imfuse(imgLeftL, imgRightL, 'montage');
imwrite(imresize(smallScaleView, 8), [savePath '/smallScaleMontage.png']);
end
%% Not overlapping Patch generation
% function patchesNoOv = preprocessImageNoOv(img, fovea, downSampling, patchSize)
% img = .2989 * img(:,:,1) + .5870 * img(:,:,2) + .1140 * img(:,:,3);
% for i = 1:log2(downSampling)
% img = impyramid(img, 'reduce');
% end
% % convert to double
% img = double(img);
% % cut fovea in the center
% [h, w, ~] = size(img);
% img = img(fix(h / 2 + 1 - fovea / 2) : fix(h / 2 + fovea / 2), ...
% fix(w / 2 + 1 - fovea / 2) : fix(w / 2 + fovea / 2));
% % cut patches and store them as col vectors
% % no overlapping patches (for display)
% patchesNoOv = im2col(img, [patchSize patchSize], 'distinct');
% end
%% Generation of random vergence angles according to truncated Laplace distribution
% function l = truncLaplacian(diversity, range)
% % see wikipedia for the generation of random numbers according to the
% % LaPlace distribution via the inversion method
% r = rand;
% switch r < 0.5
% case 1
% l = 1 / diversity * log(2 * r);
% case 0
% l = -1 / diversity * log(2 * (1 - r));
% end
% if (abs(l) > range)
% l = 0;
% end
% end