https://github.com/Klimmasch/AEC
Tip revision: 96e9ae2336937469a8f1602c178ea5e0cb8564b6 authored by Lukas Klimmasch on 13 August 2021, 14:16:04 UTC
Merge branch 'alternateRearing' of https://github.com/Klimmasch/AEC into alternateRearing
Merge branch 'alternateRearing' of https://github.com/Klimmasch/AEC into alternateRearing
Tip revision: 96e9ae2
OESDiscrete.m
%%% 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