frontend.py
and template/index.html
.
7 | User requests are indexed by UUIDs and the source (original images) and result files (hacked images and logs) are named correspondingly.
8 | While source and resultant images are directly served in static/
, logs are placed in backend/log/
.
9 | ### Configuration
10 | Except for the secret keys for Flask and Flask-WTF reCAPTCHA (i.e. SECRET_KEY
, RECAPTCHA_PUBLIC_KEY
and RECAPTCHA_PRIVATE_KEY
, which in our case, are put in keys.py
), to run the backend locally or distributedly (i.e. without or with a job queue) should be the only thing which needs to be configured here.
11 | Frontend.py
by default is using a Celery plus Redis job queue for requests.
12 | However, users can easily comment/uncomment blocks in frontend.py
to make it run locally following instructions in the file.
13 | ### Deployment
14 | Simply executing python frontend.py
can launch the Flask frontend with gevent WSGI server.
15 | However, other combinations (e.g. Flask with uWSGI and Nginx, as used by the demo site) may be more favorable.
16 |
17 | ## Backend
18 | The backend of Ostrichinator is a compiled executable which directly takes input images from the static/
directory and parameters from the command line arguments.
19 | When the backend is running, log files stating the execution progresses and the final results are generated inside backend/log/
, and when it finishes, result images are written into the static/
directory as well.
20 | The log files are structurally defined with the first lines describing the tasks, the fourth- and third-to-the-last lines the original and final class labels, the second-to-the-last lines the exit flags, and the final lines "DONE".
21 | For now, there's no explicit mechanism for pushing results to the users implemented yet.
22 | ### Configuration
23 | Configuring the backend of Ostrichinator would involve compiling MATLAB codes located in backend/src/
into an executable.
24 | We used MATLAB R2014b, while any MATLAB version after R2013a should be fine as well.
25 | First thing the users need to do would be installing and setting up [MatConvNet](http://www.vlfeat.org/matconvnet/), which is fairly simple and quick.
26 | While MatConvNet v1.0 beta-7 is used and included in this project, newer versions should work as well.
27 | The main MATLAB file is backend/src/demo.m
, which should be ready to run after MatConvNet is correctly installed, and both MatConvNet and backend/src/minConf
are in MATLAB’s search path.
28 | Please follow demo.m
to compile the executable, and place the generated demo
and run_demo.sh
under backend/
.
29 | If installing MATLAB is not an option, users can check out our [precompiled executables](https://drive.google.com/folderview?id=0B8LpM_21I0tYfmtjdHFoenByeVhnTkZaRWRDUkZneHQzWDVZUi1VdTFxcVRxaDQ2UnFzWnM&usp=sharing) as well.
30 | After obtaining the executable, users also need to specify the path to MATLAB runtime libraries in backend/MCR/
.
31 | If users have a full MATLAB installation, a symbolic link, e.g. backend/MCR/v84 -> /usr/local/MATLAB/R2014b/
, can be created to do this.
32 | If users don’t have a full MATALB and decide to use our precompiled executable, please download and install the [MATLAB Compiler Runtime](http://www.mathworks.com/products/compiler/mcr/) into backend/MCR/
.
33 | Also remember to download the pretrained deep learning networks [[1](http://www.vlfeat.org/matconvnet/models/imagenet-caffe-ref.mat),[2](http://www.vlfeat.org/matconvnet/models/imagenet-vgg-s.mat),[3](http://www.vlfeat.org/matconvnet/models/imagenet-vgg-verydeep-19.mat)] into backend/networks/
.
34 | Lastly, adjust backend/run.py
and backend/info.py
for running locally or distributedly as well.
35 | ### Deployment
36 | If users decided to run the backend distributedly, simply remember to start Redis and Celery by e.g. redis-server
and celery worker -A backend.run --loglevel=info
(for Celery, under the main directory, not backend/
).
37 | Otherwise, nothing needs to be done.
38 |
39 |
--------------------------------------------------------------------------------
/backend/MCR/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/backend/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coxlab/ostrichinator/24a7626b57895fa40172a922110306da4f20be3c/backend/__init__.py
--------------------------------------------------------------------------------
/backend/info.py:
--------------------------------------------------------------------------------
1 | WORKER_NUM = 128
2 |
--------------------------------------------------------------------------------
/backend/log/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !example*
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/backend/networks/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/backend/run.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | # See src/demo.m for definitions
4 | run_inst = 'backend/run_demo.sh backend/MCR/v84/ static/{0}.png backend/networks/ 0 50 1 1 {1} {4} {2} {4} {3} {4} >> backend/log/{0}.txt 2>&1'
5 |
6 | # Comment out for running locally
7 | from celery import Celery
8 | from keys import UPLOAD_PATH
9 |
10 | backend = Celery('run', broker='redis://localhost:6379/1'); backend.conf.update(CELERYD_PREFETCH_MULTIPLIER=1)
11 |
12 | @backend.task
13 | def run_backend(taskpar):
14 | os.system('wget -q -P static http://localhost:8080/static/{0}.png'.format(taskpar[0]))
15 | os.system(run_inst.format(*taskpar))
16 | os.system('curl -s -X POST -F data=@static/{0}-out.png "http://localhost:8080/{1}"'.format(taskpar[0],UPLOAD_PATH))
17 | os.system('curl -s -X POST -F data=@static/{0}-sal.png "http://localhost:8080/{1}"'.format(taskpar[0],UPLOAD_PATH))
18 | os.system('curl -s -X POST -F data=@static/{0}-dff.png "http://localhost:8080/{1}"'.format(taskpar[0],UPLOAD_PATH))
19 | os.system('curl -s -X POST -F data=@backend/log/{0}.txt "http://localhost:8080/{1}"'.format(taskpar[0],UPLOAD_PATH))
20 | return None
21 | # ----------
22 |
23 | # Uncomment for running locally
24 | #def run_backend(taskpar):
25 | # run_inst_async = '(' + run_inst + ' &)'
26 | # os.system(run_inst_async.format(*taskpar))
27 | # return None
28 | # ----------
29 |
30 |
--------------------------------------------------------------------------------
/backend/src/demo.m:
--------------------------------------------------------------------------------
1 | function demo(imgfile, netpath, allwgpu, iter, faststp, stpthrs, varargin)
2 |
3 | % INPUT VARIABLES
4 | % imgfile, path and filename to the target image, which must be PNG sized 227x227.
5 | % netpath, path to the pretrained networks' mat files.
6 | % allwgpu, enable GPU mode or not.
7 | % iter, maximally allowed running iterations; set to 1 for recognition only mode.
8 | % faststp, 1 for fast stop (stopping after score of the target class becomes highest) and 0 for slow stop (stopping after probability of the target class reaches 'stpthrs').
9 | % stpthrs, stopping threshold for probability of the target class when faststp is set to 0.
10 | % varargin{1}, enable 'imagenet-caffe-ref' or not.
11 | % varargin{2}, target class for 'imagenet-caffe-ref'.
12 | % varargin{3}, enable 'imagenet-vgg-s' or not.
13 | % varargin{4}, target class for 'imagenet-vgg-s'.
14 | % varargin{5}, enable 'imagenet-vgg-verydeep-19' or not.
15 | % varargin{6}, target class for 'imagenet-vgg-verydeep-19'.
16 |
17 | % EXAMPLE: HACK TEST.PNG INTO CLASS 1 FOR ALL NETWORKS
18 | % demo('static/test.png','backend/networks','0','50','1','1.0','1','1','1','1','1','1');
19 |
20 | % EXAMPLE: COMPILE DEMO.M INTO EXECUTABLE
21 | % mcc -m -R -nojvm -R -nodisplay -R -singleCompThread -v demo.m;
22 |
23 | % -------------------------------------------------------------------------
24 |
25 | netfile = {'imagenet-caffe-ref.mat', ...
26 | 'imagenet-vgg-s.mat', ...
27 | 'imagenet-vgg-verydeep-19.mat'};
28 |
29 | try
30 | % PROCESS PARAMETERS
31 | [allwgpu, iter, faststp, stpthrs, varargin{:}] = cell2double(allwgpu, iter, faststp, stpthrs, varargin{:});
32 |
33 | % LOAD IMAGE (SHOULD BE PNG)
34 | img = double(imread(imgfile));
35 | switch size(img,3)
36 | case 1, img = repmat(img, [1 1 3]);
37 | case 3, % NOTHING
38 | otherwise, error('IMREAD ERROR');
39 | end
40 |
41 | % LOAD NETWORK(S)
42 | tic;
43 | net = {}; tc = {};
44 | for i = 1:2:numel(varargin)
45 | if (varargin{i} == 1)
46 | net(end+1) = {load(fullfile(netpath, netfile{(i-1)/2+1}), 'layers')};
47 | tc(end+1) = {[(varargin{i+1}) 1000]};
48 |
49 | temp = load(fullfile(netpath, netfile{(i-1)/2+1}), 'classes');
50 | [~,tempidx] = sortrows(temp.classes.name');
51 | net{end}.layers{end-1}.filters = net{end}.layers{end-1}.filters(:,:,:,tempidx);
52 | end
53 | end
54 | toc;
55 |
56 | % RUN DEMO
57 | alg = @ostrichinator_lite;
58 |
59 | tic;
60 | try
61 | [xmin, xsal, flag, ~, ~, chist] = alg(net, img, tc, allwgpu, iter, faststp, stpthrs);
62 | catch ERR % RETRY CPU MODE IF GPU MODE ERROR
63 | if (allwgpu == 0), rethrow(ERR);
64 | else [xmin, xsal, flag, ~, ~, chist] = alg(net, img, tc, 0, iter, faststp, stpthrs); end
65 | end
66 | toc;
67 |
68 | % PROCESS RESULTS
69 | for i = 1:numel(xsal)
70 | xsal{i} = sum(abs(xsal{i}), 3);
71 | xsal{i} = xsal{i} - min(xsal{i}(:));
72 | xsal{i} = xsal{i} / max(max(xsal{i}(:)), eps);
73 | end
74 | xsal = cat(3, xsal{:});
75 | xsal = min(sum(xsal, 3), 1);
76 |
77 | xdff = xmin - img;
78 | xdff = xdff - min(xdff(:));
79 | xdff = xdff / max(max(xdff(:)), eps);
80 | xdff = round(xdff * 255);
81 |
82 | chist = [chist{:}];
83 |
84 | % WRITE RESULTS
85 | [imgpath,imgname,~] = fileparts(imgfile);
86 |
87 | imwrite(uint8(xmin), fullfile(imgpath, [imgname '-out.png']));
88 |
89 | xsal = gray2ind(xsal, 256);
90 | if (exist('parula','file') > 0), cm = @parula; else cm = @gray; end
91 | imwrite(xsal, cm(256), fullfile(imgpath, [imgname '-sal.png']));
92 |
93 | imwrite(uint8(xdff), fullfile(imgpath, [imgname '-dff.png']));
94 |
95 | fprintf('%s\n', num2str(chist(:,1)' ));
96 | fprintf('%s\n', num2str(chist(:,end)'));
97 | catch ERR
98 | fprintf('%s\n', ERR.getReport);
99 | flag = -1;
100 | end
101 |
102 | % 1 = SUCCESSFUL FINISH; 0 = UNSUCCESSFUL FINISH; -1 = ERROR
103 | fprintf('%d\n', flag);
104 | fprintf('DONE');
105 |
106 | % -------------------------------------------------------------------------
107 |
108 | function varargout = cell2double(varargin)
109 |
110 | varargout = cell(size(varargin));
111 |
112 | for c = 1:numel(varargin)
113 | if isa(varargin{c}, 'char'), varargout{c} = str2double(varargin{c});
114 | else varargout{c} = double(varargin{c}); end
115 | end
116 | end
117 |
118 | end
119 |
120 |
--------------------------------------------------------------------------------
/backend/src/matconvnet-1.0-beta7.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coxlab/ostrichinator/24a7626b57895fa40172a922110306da4f20be3c/backend/src/matconvnet-1.0-beta7.tar.gz
--------------------------------------------------------------------------------
/backend/src/minConf/isLegal.m:
--------------------------------------------------------------------------------
1 | function [legal] = isLegal(v)
2 | legal = sum(any(imag(v(:))))==0 & sum(isnan(v(:)))==0 & sum(isinf(v(:)))==0;
--------------------------------------------------------------------------------
/backend/src/minConf/lbfgs.m:
--------------------------------------------------------------------------------
1 | function [d] = lbfgs(g,s,y,Hdiag)
2 | % BFGS Search Direction
3 | %
4 | % This function returns the (L-BFGS) approximate inverse Hessian,
5 | % multiplied by the gradient
6 | %
7 | % If you pass in all previous directions/sizes, it will be the same as full BFGS
8 | % If you truncate to the k most recent directions/sizes, it will be L-BFGS
9 | %
10 | % s - previous search directions (p by k)
11 | % y - previous step sizes (p by k)
12 | % g - gradient (p by 1)
13 | % Hdiag - value of initial Hessian diagonal elements (scalar)
14 |
15 | [p,k] = size(s);
16 |
17 | for i = 1:k
18 | ro(i,1) = 1/(y(:,i)'*s(:,i));
19 | end
20 |
21 | q = zeros(p,k+1);
22 | r = zeros(p,k+1);
23 | al =zeros(k,1);
24 | be =zeros(k,1);
25 |
26 | q(:,k+1) = g;
27 |
28 | for i = k:-1:1
29 | al(i) = ro(i)*s(:,i)'*q(:,i+1);
30 | q(:,i) = q(:,i+1)-al(i)*y(:,i);
31 | end
32 |
33 | % Multiply by Initial Hessian
34 | r(:,1) = Hdiag*q(:,1);
35 |
36 | for i = 1:k
37 | be(i) = ro(i)*y(:,i)'*r(:,i);
38 | r(:,i+1) = r(:,i) + s(:,i)*(al(i)-be(i));
39 | end
40 | d=r(:,k+1);
--------------------------------------------------------------------------------
/backend/src/minConf/lbfgsHvFunc2.m:
--------------------------------------------------------------------------------
1 | function Hv = lbfgsHvFunc2(v,Hdiag,N,M)
2 | Hv = v/Hdiag - N*(M\(N'*v));
--------------------------------------------------------------------------------
/backend/src/minConf/lbfgsUpdate.m:
--------------------------------------------------------------------------------
1 | function [old_dirs,old_stps,Hdiag] = lbfgsUpdate(y,s,corrections,debug,old_dirs,old_stps,Hdiag)
2 | ys = y'*s;
3 | if ys > 1e-10
4 | numCorrections = size(old_dirs,2);
5 | if numCorrections < corrections
6 | % Full Update
7 | old_dirs(:,numCorrections+1) = s;
8 | old_stps(:,numCorrections+1) = y;
9 | else
10 | % Limited-Memory Update
11 | old_dirs = [old_dirs(:,2:corrections) s];
12 | old_stps = [old_stps(:,2:corrections) y];
13 | end
14 |
15 | % Update scale of initial Hessian approximation
16 | Hdiag = ys/(y'*y);
17 | else
18 | if debug
19 | fprintf('Skipping Update\n');
20 | end
21 | end
--------------------------------------------------------------------------------
/backend/src/minConf/minConf_PQN.m:
--------------------------------------------------------------------------------
1 | function [x,f,funEvals] = minConf_PQN(funObj,x,funProj,options,ckpntFun)
2 | % function [x,f] = minConf_PQN(funObj,funProj,x,options)
3 | %
4 | % Function for using a limited-memory projected quasi-Newton to solve problems of the form
5 | % min funObj(x) s.t. x in C
6 | %
7 | % The projected quasi-Newton sub-problems are solved the spectral projected
8 | % gradient algorithm
9 | %
10 | % @funObj(x): function to minimize (returns gradient as second argument)
11 | % @funProj(x): function that returns projection of x onto C
12 | %
13 | % options:
14 | % verbose: level of verbosity (0: no output, 1: final, 2: iter (default), 3:
15 | % debug)
16 | % optTol: tolerance used to check for optimality (default: 1e-5)
17 | % progTol: tolerance used to check for progress (default: 1e-9)
18 | % maxIter: maximum number of calls to funObj (default: 500)
19 | % maxProject: maximum number of calls to funProj (default: 100000)
20 | % numDiff: compute derivatives numerically (0: use user-supplied
21 | % derivatives (default), 1: use finite differences, 2: use complex
22 | % differentials)
23 | % suffDec: sufficient decrease parameter in Armijo condition (default: 1e-4)
24 | % corrections: number of lbfgs corrections to store (default: 10)
25 | % adjustStep: use quadratic initialization of line search (default: 0)
26 | % bbInit: initialize sub-problem with Barzilai-Borwein step (default: 1)
27 | % SPGoptTol: optimality tolerance for SPG direction finding (default: 1e-6)
28 | % SPGiters: maximum number of iterations for SPG direction finding (default:10)
29 |
30 | nVars = length(x);
31 |
32 | % Set Parameters
33 | if nargin < 4
34 | options = [];
35 | end
36 | [verbose,numDiff,optTol,progTol,maxIter,maxProject,suffDec,corrections,adjustStep,bbInit,...
37 | SPGoptTol,SPGprogTol,SPGiters,SPGtestOpt] = ...
38 | myProcessOptions(...
39 | options,'verbose',3,'numDiff',0,'optTol',1e-5,'progTol',1e-9,'maxIter',100,'maxProject',100000,'suffDec',1e-4,...
40 | 'corrections',10,'adjustStep',0,'bbInit',0,'SPGoptTol',1e-6,'SPGprogTol',1e-10,'SPGiters',10,'SPGtestOpt',0);
41 |
42 | % Output Parameter Settings
43 | % if verbose >= 3
44 | % fprintf('Running PQN...\n');
45 | % fprintf('Number of L-BFGS Corrections to store: %d\n',corrections);
46 | % fprintf('Spectral initialization of SPG: %d\n',bbInit);
47 | % fprintf('Maximum number of SPG iterations: %d\n',SPGiters);
48 | % fprintf('SPG optimality tolerance: %.2e\n',SPGoptTol);
49 | % fprintf('SPG progress tolerance: %.2e\n',SPGprogTol);
50 | % fprintf('PQN optimality tolerance: %.2e\n',optTol);
51 | % fprintf('PQN progress tolerance: %.2e\n',progTol);
52 | % fprintf('Quadratic initialization of line search: %d\n',adjustStep);
53 | % fprintf('Maximum number of function evaluations: %d\n',maxIter);
54 | % fprintf('Maximum number of projections: %d\n',maxProject);
55 | % end
56 |
57 | % Output Log
58 | if verbose >= 2
59 | fprintf('%10s %10s %10s %15s %15s %15s\n','Iteration','FunEvals','Projections','Step Length','Function Val','Opt Cond');
60 | end
61 |
62 | % Make objective function (if using numerical derivatives)
63 | funEvalMultiplier = 1;
64 | if numDiff
65 | if numDiff == 2
66 | useComplex = 1;
67 | else
68 | useComplex = 0;
69 | end
70 | funObj = @(x)autoGrad(x,useComplex,funObj);
71 | funEvalMultiplier = nVars+1-useComplex;
72 | end
73 |
74 | % Project initial parameter vector
75 | x = funProj(x);
76 | projects = 1;
77 |
78 | % Evaluate initial parameters
79 | [f,g] = funObj(x);
80 | funEvals = 1;
81 |
82 | % Plot Progress
83 | if (nargin == 5)
84 | [stop, dispstr] = ckpntFun(x);
85 | fprintf('\b %s\n', dispstr);
86 | if stop, fprintf('Early termination condition(s) reached\n'); return; end
87 | end
88 |
89 | % Check Optimality of Initial Point
90 | projects = projects+1;
91 | if max(abs(funProj(x-g)-x)) < optTol
92 | if verbose >= 1
93 | fprintf('First-Order Optimality Conditions Below optTol at Initial Point\n');
94 | end
95 | return;
96 | end
97 |
98 | i = 1;
99 | while funEvals <= maxIter
100 |
101 | % Compute Step Direction
102 | if i == 1
103 | p = funProj(x-g);
104 | projects = projects+1;
105 | S = zeros(nVars,0);
106 | Y = zeros(nVars,0);
107 | Hdiag = 1;
108 | else
109 | y = g-g_old;
110 | s = x-x_old;
111 | [S,Y,Hdiag] = lbfgsUpdate(y,s,corrections,verbose==3,S,Y,Hdiag);
112 |
113 | % Make Compact Representation
114 | k = size(Y,2);
115 | L = zeros(k);
116 | for j = 1:k
117 | L(j+1:k,j) = S(:,j+1:k)'*Y(:,j);
118 | end
119 | N = [S/Hdiag Y];
120 | M = [S'*S/Hdiag L;L' -diag(diag(S'*Y))];
121 | HvFunc = @(v)lbfgsHvFunc2(v,Hdiag,N,M);
122 |
123 | if bbInit
124 | % Use Barzilai-Borwein step to initialize sub-problem
125 | alpha = (s'*s)/(s'*y);
126 | if alpha <= 1e-10 || alpha > 1e10
127 | alpha = min(1,1/sum(abs(g)));
128 | end
129 |
130 | % Solve Sub-problem
131 | xSubInit = x-alpha*g;
132 | feasibleInit = 0;
133 | else
134 | xSubInit = x;
135 | feasibleInit = 1;
136 | end
137 | % Solve Sub-problem
138 | [p,subProjects] = solveSubProblem(x,g,HvFunc,funProj,SPGoptTol,SPGprogTol,SPGiters,SPGtestOpt,feasibleInit,xSubInit);
139 | projects = projects+subProjects;
140 | end
141 | d = p-x;
142 | g_old = g;
143 | x_old = x;
144 |
145 | % Check that Progress can be made along the direction
146 | gtd = g'*d;
147 | if gtd > -progTol
148 | if verbose >= 1
149 | fprintf('Directional Derivative below progTol\n');
150 | end
151 | break;
152 | end
153 |
154 | % Select Initial Guess to step length
155 | if i == 1 || adjustStep == 0
156 | t = 1;
157 | else
158 | t = min(1,2*(f-f_old)/gtd);
159 | end
160 |
161 | % Bound Step length on first iteration
162 | if i == 1
163 | t = min(1,1/sum(abs(g)));
164 | end
165 |
166 | % Evaluate the Objective and Gradient at the Initial Step
167 | if t == 1
168 | x_new = p;
169 | else
170 | x_new = x + t*d;
171 | end
172 | [f_new,g_new] = funObj(x_new);
173 | funEvals = funEvals+1;
174 |
175 | % Backtracking Line Search
176 | f_old = f;
177 | while f_new > f + suffDec*g'*(x_new-x) || ~isLegal(f_new)
178 | temp = t;
179 |
180 | % Backtrack to next trial value
181 | if ~isLegal(f_new) || ~isLegal(g_new)
182 | if verbose == 3
183 | fprintf('Halving Step Size\n');
184 | end
185 | t = t/2;
186 | else
187 | if verbose == 3
188 | fprintf('Cubic Backtracking\n');
189 | end
190 | t = polyinterp([0 f gtd; t f_new g_new'*d]);
191 | end
192 |
193 | % Adjust if change is too small/large
194 | if t < temp*1e-3
195 | if verbose == 3
196 | fprintf('Interpolated value too small, Adjusting\n');
197 | end
198 | t = temp*1e-3;
199 | elseif t > temp*0.6
200 | if verbose == 3
201 | fprintf('Interpolated value too large, Adjusting\n');
202 | end
203 | t = temp*0.6;
204 | end
205 |
206 | % Check whether step has become too small
207 | if sum(abs(t*d)) < progTol || t == 0
208 | if verbose == 3
209 | fprintf('Line Search failed\n');
210 | end
211 | t = 0;
212 | f_new = f;
213 | g_new = g;
214 | break;
215 | end
216 |
217 | % Evaluate New Point
218 | f_prev = f_new;
219 | t_prev = temp;
220 | x_new = x + t*d;
221 | [f_new,g_new] = funObj(x_new);
222 | funEvals = funEvals+1;
223 |
224 | end
225 |
226 | % Take Step
227 | x = x_new;
228 | f = f_new;
229 | g = g_new;
230 |
231 | optCond = max(abs(funProj(x-g)-x));
232 | projects = projects+1;
233 |
234 | % Output Log
235 | if verbose >= 2
236 | fprintf('%10d %10d %10d %15.5e %15.5e %15.5e\n',i,funEvals*funEvalMultiplier,projects,t,f,optCond);
237 | end
238 |
239 | % Plot Progress
240 | if (nargin == 5)
241 | [stop, dispstr] = ckpntFun(x);
242 | fprintf('\b %s\n', dispstr);
243 | if stop, fprintf('Early termination condition(s) reached\n'); break; end
244 | end
245 |
246 | % Check optimality
247 | if optCond < optTol
248 | fprintf('First-Order Optimality Conditions Below optTol\n');
249 | break;
250 | end
251 |
252 | if max(abs(t*d)) < progTol
253 | if verbose >= 1
254 | fprintf('Step size below progTol\n');
255 | end
256 | break;
257 | end
258 |
259 | if abs(f-f_old) < progTol
260 | if verbose >= 1
261 | fprintf('Function value changing by less than progTol\n');
262 | end
263 | break;
264 | end
265 |
266 | if funEvals*funEvalMultiplier > maxIter
267 | if verbose >= 1
268 | fprintf('Function Evaluations exceeds maxIter\n');
269 | end
270 | break;
271 | end
272 |
273 | if projects > maxProject
274 | if verbose >= 1
275 | fprintf('Number of projections exceeds maxProject\n');
276 | end
277 | break;
278 | end
279 |
280 | i = i + 1;
281 | % pause
282 | end
283 | end
284 |
285 |
286 | function [p,subProjects] = solveSubProblem(x,g,H,funProj,optTol,progTol,maxIter,testOpt,feasibleInit,x_init)
287 | % Uses SPG to solve for projected quasi-Newton direction
288 | options.verbose = 0;
289 | options.optTol = optTol;
290 | options.progTol = progTol;
291 | options.maxIter = maxIter;
292 | options.testOpt = testOpt;
293 | options.feasibleInit = feasibleInit;
294 |
295 | funObj = @(p)subHv(p,x,g,H);
296 | [p,f,funEvals,subProjects] = minConf_SPG(funObj,x_init,funProj,options);
297 | end
298 |
299 | function [f,g] = subHv(p,x,g,HvFunc)
300 | d = p-x;
301 | Hd = HvFunc(d);
302 | f = g'*d + (1/2)*d'*Hd;
303 | g = g + Hd;
304 | end
--------------------------------------------------------------------------------
/backend/src/minConf/minConf_SPG.m:
--------------------------------------------------------------------------------
1 | function [x,f,funEvals,projects] = minConf_SPG(funObj,x,funProj,options)
2 | % function [x,f] = minConF_SPG(funObj,x,funProj,options)
3 | %
4 | % Function for using Spectral Projected Gradient to solve problems of the form
5 | % min funObj(x) s.t. x in C
6 | %
7 | % @funObj(x): function to minimize (returns gradient as second argument)
8 | % @funProj(x): function that returns projection of x onto C
9 | %
10 | % options:
11 | % verbose: level of verbosity (0: no output, 1: final, 2: iter (default), 3:
12 | % debug)
13 | % optTol: tolerance used to check for optimality (default: 1e-5)
14 | % progTol: tolerance used to check for lack of progress (default: 1e-9)
15 | % maxIter: maximum number of calls to funObj (default: 500)
16 | % numDiff: compute derivatives numerically (0: use user-supplied
17 | % derivatives (default), 1: use finite differences, 2: use complex
18 | % differentials)
19 | % suffDec: sufficient decrease parameter in Armijo condition (default
20 | % : 1e-4)
21 | % interp: type of interpolation (0: step-size halving, 1: quadratic,
22 | % 2: cubic)
23 | % memory: number of steps to look back in non-monotone Armijo
24 | % condition
25 | % useSpectral: use spectral scaling of gradient direction (default:
26 | % 1)
27 | % curvilinear: backtrack along projection Arc (default: 0)
28 | % testOpt: test optimality condition (default: 1)
29 | % feasibleInit: if 1, then the initial point is assumed to be
30 | % feasible
31 | % bbType: type of Barzilai Borwein step (default: 1)
32 | %
33 | % Notes:
34 | % - if the projection is expensive to compute, you can reduce the
35 | % number of projections by setting testOpt to 0
36 |
37 |
38 | nVars = length(x);
39 |
40 | % Set Parameters
41 | if nargin < 4
42 | options = [];
43 | end
44 | [verbose,numDiff,optTol,progTol,maxIter,suffDec,interp,memory,useSpectral,curvilinear,feasibleInit,testOpt,bbType] = ...
45 | myProcessOptions(...
46 | options,'verbose',2,'numDiff',0,'optTol',1e-5,'progTol',1e-9,'maxIter',500,'suffDec',1e-4,...
47 | 'interp',2,'memory',10,'useSpectral',1,'curvilinear',0,'feasibleInit',0,...
48 | 'testOpt',1,'bbType',1);
49 |
50 | % Output Log
51 | if verbose >= 2
52 | if testOpt
53 | fprintf('%10s %10s %10s %15s %15s %15s\n','Iteration','FunEvals','Projections','Step Length','Function Val','Opt Cond');
54 | else
55 | fprintf('%10s %10s %10s %15s %15s\n','Iteration','FunEvals','Projections','Step Length','Function Val');
56 | end
57 | end
58 |
59 | % Make objective function (if using numerical derivatives)
60 | funEvalMultiplier = 1;
61 | if numDiff
62 | if numDiff == 2
63 | useComplex = 1;
64 | else
65 | useComplex = 0;
66 | end
67 | funObj = @(x)autoGrad(x,useComplex,funObj);
68 | funEvalMultiplier = nVars+1-useComplex;
69 | end
70 |
71 | % Evaluate Initial Point
72 | if ~feasibleInit
73 | x = funProj(x);
74 | end
75 | [f,g] = funObj(x);
76 | projects = 1;
77 | funEvals = 1;
78 |
79 | % Optionally check optimality
80 | if testOpt
81 | projects = projects+1;
82 | if max(abs(funProj(x-g)-x)) < optTol
83 | if verbose >= 1
84 | fprintf('First-Order Optimality Conditions Below optTol at Initial Point\n');
85 | end
86 | return;
87 | end
88 | end
89 |
90 | i = 1;
91 | while funEvals <= maxIter
92 |
93 | % Compute Step Direction
94 | if i == 1 || ~useSpectral
95 | alpha = 1;
96 | else
97 | y = g-g_old;
98 | s = x-x_old;
99 | if bbType == 1
100 | alpha = (s'*s)/(s'*y);
101 | else
102 | alpha = (s'*y)/(y'*y);
103 | end
104 | if alpha <= 1e-10 || alpha > 1e10
105 | alpha = 1;
106 | end
107 | end
108 | d = -alpha*g;
109 | f_old = f;
110 | x_old = x;
111 | g_old = g;
112 |
113 | % Compute Projected Step
114 | if ~curvilinear
115 | d = funProj(x+d)-x;
116 | projects = projects+1;
117 | end
118 |
119 | % Check that Progress can be made along the direction
120 | gtd = g'*d;
121 | if gtd > -progTol
122 | if verbose >= 1
123 | fprintf('Directional Derivative below progTol\n');
124 | end
125 | break;
126 | end
127 |
128 | % Select Initial Guess to step length
129 | if i == 1
130 | t = min(1,1/sum(abs(g)));
131 | else
132 | t = 1;
133 | end
134 |
135 | % Compute reference function for non-monotone condition
136 |
137 | if memory == 1
138 | funRef = f;
139 | else
140 | if i == 1
141 | old_fvals = repmat(-inf,[memory 1]);
142 | end
143 |
144 | if i <= memory
145 | old_fvals(i) = f;
146 | else
147 | old_fvals = [old_fvals(2:end);f];
148 | end
149 | funRef = max(old_fvals);
150 | end
151 |
152 | % Evaluate the Objective and Gradient at the Initial Step
153 | if curvilinear
154 | x_new = funProj(x + t*d);
155 | projects = projects+1;
156 | else
157 | x_new = x + t*d;
158 | end
159 | [f_new,g_new] = funObj(x_new);
160 | funEvals = funEvals+1;
161 |
162 | % Backtracking Line Search
163 | lineSearchIters = 1;
164 | while f_new > funRef + suffDec*g'*(x_new-x) || ~isLegal(f_new)
165 | temp = t;
166 | if interp == 0 || ~isLegal(f_new)
167 | if verbose == 3
168 | fprintf('Halving Step Size\n');
169 | end
170 | t = t/2;
171 | elseif interp == 2 && isLegal(g_new)
172 | if verbose == 3
173 | fprintf('Cubic Backtracking\n');
174 | end
175 | t = polyinterp([0 f gtd; t f_new g_new'*d]);
176 | elseif lineSearchIters < 2 || ~isLegal(f_prev)
177 | if verbose == 3
178 | fprintf('Quadratic Backtracking\n');
179 | end
180 | t = polyinterp([0 f gtd; t f_new sqrt(-1)]);
181 | else
182 | if verbose == 3
183 | fprintf('Cubic Backtracking on Function Values\n');
184 | end
185 | t = polyinterp([0 f gtd; t f_new sqrt(-1);t_prev f_prev sqrt(-1)]);
186 | end
187 |
188 | % Adjust if change is too small
189 | if t < temp*1e-3
190 | if verbose == 3
191 | fprintf('Interpolated value too small, Adjusting\n');
192 | end
193 | t = temp*1e-3;
194 | elseif t > temp*0.6
195 | if verbose == 3
196 | fprintf('Interpolated value too large, Adjusting\n');
197 | end
198 | t = temp*0.6;
199 | end
200 |
201 | % Check whether step has become too small
202 | if max(abs(t*d)) < progTol || t == 0
203 | if verbose == 3
204 | fprintf('Line Search failed\n');
205 | end
206 | t = 0;
207 | f_new = f;
208 | g_new = g;
209 | break;
210 | end
211 |
212 | % Evaluate New Point
213 | f_prev = f_new;
214 | t_prev = temp;
215 | if curvilinear
216 | x_new = funProj(x + t*d);
217 | projects = projects+1;
218 | else
219 | x_new = x + t*d;
220 | end
221 | [f_new,g_new] = funObj(x_new);
222 | funEvals = funEvals+1;
223 | lineSearchIters = lineSearchIters+1;
224 |
225 | end
226 |
227 | % Take Step
228 | x = x_new;
229 | f = f_new;
230 | g = g_new;
231 |
232 | if testOpt
233 | optCond = max(abs(funProj(x-g)-x));
234 | projects = projects+1;
235 | end
236 |
237 | % Output Log
238 | if verbose >= 2
239 | if testOpt
240 | fprintf('%10d %10d %10d %15.5e %15.5e %15.5e\n',i,funEvals*funEvalMultiplier,projects,t,f,optCond);
241 | else
242 | fprintf('%10d %10d %10d %15.5e %15.5e\n',i,funEvals*funEvalMultiplier,projects,t,f);
243 | end
244 | end
245 |
246 | % Check optimality
247 | if testOpt
248 | if optCond < optTol
249 | if verbose >= 1
250 | fprintf('First-Order Optimality Conditions Below optTol\n');
251 | end
252 | break;
253 | end
254 | end
255 |
256 | if max(abs(t*d)) < progTol
257 | if verbose >= 1
258 | fprintf('Step size below progTol\n');
259 | end
260 | break;
261 | end
262 |
263 | if abs(f-f_old) < progTol
264 | if verbose >= 1
265 | fprintf('Function value changing by less than progTol\n');
266 | end
267 | break;
268 | end
269 |
270 | if funEvals*funEvalMultiplier > maxIter
271 | if verbose >= 1
272 | fprintf('Function Evaluations exceeds maxIter\n');
273 | end
274 | break;
275 | end
276 |
277 | i = i + 1;
278 | end
279 | end
--------------------------------------------------------------------------------
/backend/src/minConf/minConf_TMP.m:
--------------------------------------------------------------------------------
1 | function [x,f,funEvals] = minConf_TMP(funObj,x,LB,UB,options,ckpntFun)
2 | % function [x,f] = minConF_BC(funObj,x,LB,UB,options)
3 | %
4 | % Function for using Two-Metric Projection to solve problems of the form:
5 | % min funObj(x)
6 | % s.t. LB_i <= x_i <= UB_i
7 | %
8 | % @funObj(x): function to minimize (returns gradient as second argument)
9 | %
10 | % options:
11 | % verbose: level of verbosity (0: no output, 1: final, 2: iter (default), 3:
12 | % debug)
13 | % optTol: tolerance used to check for progress (default: 1e-7)
14 | % maxIter: maximum number of calls to funObj (default: 250)
15 | % numDiff: compute derivatives numerically (0: use user-supplied
16 | % derivatives (default), 1: use finite differences, 2: use complex
17 | % differentials)
18 | % method: 'sd', 'lbfgs', 'newton'
19 |
20 | nVars = length(x);
21 |
22 | % Set Parameters
23 | if nargin < 5
24 | options = [];
25 | end
26 | [verbose,numDiff,optTol,maxIter,suffDec,interp,method,corrections,damped] = ...
27 | myProcessOptions(...
28 | options,'verbose',3,'numDiff',0,'optTol',1e-6,'maxIter',100,'suffDec',1e-4,...
29 | 'interp',1,'method','lbfgs','corrections',10,'damped',0);
30 |
31 | % Output Log
32 | if verbose >= 3
33 | fprintf('%10s %10s %15s %15s %15s\n','Iteration','FunEvals','Step Length','Function Val','Opt Cond');
34 | end
35 |
36 | % Make objective function (if using numerical derivatives)
37 | funEvalMultiplier = 1;
38 | if numDiff
39 | if numDiff == 2
40 | useComplex = 1;
41 | else
42 | useComplex = 0;
43 | end
44 | funObj = @(x)autoGrad(x,useComplex,funObj);
45 | funEvalMultiplier = nVars+1-useComplex;
46 | end
47 |
48 | % Evaluate Initial Point
49 | x = projectBounds(x,LB,UB);
50 | if strcmp(method,'newton')
51 | [f,g,H] = funObj(x);
52 | secondOrder = 1;
53 | else
54 | [f,g] = funObj(x);
55 | secondOrder = 0;
56 | end
57 | funEvals = 1;
58 |
59 | % Plot Progress
60 | if (nargin == 6)
61 | [stop, dispstr] = ckpntFun(x);
62 | fprintf('\b %s\n', dispstr);
63 | if stop, fprintf('Early termination condition(s) reached\n'); return; end
64 | end
65 |
66 | % Compute Working Set
67 | working = ones(nVars,1);
68 | working((x < LB+optTol*2) & g >= 0) = 0;
69 | working((x > UB-optTol*2) & g <= 0) = 0;
70 | working = find(working);
71 |
72 | % Check Optimality
73 | if isempty(working)
74 | if verbose >= 1
75 | fprintf('All variables are at their bound and no further progress is possible at initial point\n');
76 | end
77 | return;
78 | elseif norm(g(working)) <= optTol
79 | if verbose >=1
80 | fprintf('All working variables satisfy optimality condition at initial point\n');
81 | end
82 | return;
83 | end
84 |
85 | if verbose >= 3
86 | switch method
87 | case 'sd'
88 | fprintf('Steepest Descent\n');
89 | case 'lbfgs'
90 | fprintf('L-BFGS\n');
91 | case 'bfgs'
92 | fprintf('BFGS\n');
93 | case 'newton'
94 | fprintf('Newton\n');
95 | end
96 | end
97 |
98 | i = 1;
99 | while funEvals <= maxIter
100 |
101 | % Compute Step Direction
102 | d = zeros(nVars,1);
103 | switch(method)
104 | case 'sd'
105 | d(working) = -g(working);
106 | case 'lbfgs'
107 | if i == 1
108 | d(working) = -g(working);
109 | old_dirs = zeros(nVars,0);
110 | old_stps = zeros(nVars,0);
111 | Hdiag = 1;
112 | else
113 | if damped
114 | [old_dirs,old_stps,Hdiag] = dampedUpdate(g-g_old,x-x_old,corrections,verbose==3,old_dirs,old_stps,Hdiag);
115 | else
116 | [old_dirs,old_stps,Hdiag] = lbfgsUpdate(g-g_old,x-x_old,corrections,verbose==3,old_dirs,old_stps,Hdiag);
117 | end
118 | curvSat = sum(old_dirs(working,:).*old_stps(working,:)) > 1e-10;
119 | d(working) = lbfgs(-g(working),old_dirs(working,curvSat),old_stps(working,curvSat),Hdiag);
120 | end
121 | g_old = g;
122 | x_old = x;
123 | case 'bfgs'
124 | if i == 1
125 | d(working) = -g(working);
126 | B = eye(nVars);
127 | else
128 | y = g-g_old;
129 | s = x-x_old;
130 |
131 | ys = y'*s;
132 |
133 | if i == 2
134 | if ys > 1e-10
135 | B = ((y'*y)/(y'*s))*eye(nVars);
136 | end
137 | end
138 | if ys > 1e-10
139 | B = B + (y*y')/(y'*s) - (B*s*s'*B)/(s'*B*s);
140 | else
141 | if verbose == 2
142 | fprintf('Skipping Update\n');
143 | end
144 | end
145 | d(working) = -B(working,working)\g(working);
146 | end
147 | g_old = g;
148 | x_old = x;
149 |
150 | case 'newton'
151 | [R,posDef] = chol(H(working,working));
152 |
153 | if posDef == 0
154 | d(working) = -R\(R'\g(working));
155 | else
156 | if verbose == 3
157 | fprintf('Adjusting Hessian\n');
158 | end
159 | H(working,working) = H(working,working) + eye(length(working)) * max(0,1e-12 - min(real(eig(H(working,working)))));
160 | d(working) = -H(working,working)\g(working);
161 | end
162 | otherwise
163 | fprintf('Unrecognized Method: %s\n',method);
164 | break;
165 | end
166 |
167 | % Check that Progress can be made along the direction
168 | f_old = f;
169 | gtd = g'*d;
170 | if gtd > -optTol
171 | if verbose >= 2
172 | fprintf('Directional Derivative below optTol\n');
173 | end
174 | break;
175 | end
176 |
177 | % Select Initial Guess to step length
178 | if i == 1 && ~secondOrder
179 | t = min(1,1/sum(abs(g(working))));
180 | else
181 | t = 1;
182 | end
183 |
184 | % Evaluate the Objective and Projected Gradient at the Initial Step
185 | x_new = projectBounds(x+t*d,LB,UB);
186 | if secondOrder
187 | [f_new,g_new,H] = funObj(x_new);
188 | else
189 | [f_new,g_new] = funObj(x_new);
190 | end
191 | funEvals = funEvals+1;
192 |
193 | % Backtracking Line Search
194 | lineSearchIters = 1;
195 | while f_new > f + suffDec*g'*(x_new-x) || ~isLegal(f_new)
196 | temp = t;
197 | if interp == 0 || ~isLegal(f_new) || ~isLegal(g_new)
198 | if verbose == 3
199 | fprintf('Halving Step Size\n');
200 | end
201 | t = .5*t;
202 | else
203 | if verbose == 3
204 | fprintf('Cubic Backtracking\n');
205 | end
206 | t = polyinterp([0 f gtd; t f_new g_new'*d]);
207 | end
208 |
209 | % Adjust if change is too small
210 | if t < temp*1e-3
211 | if verbose == 3
212 | fprintf('Interpolated value too small, Adjusting\n');
213 | end
214 | t = temp*1e-3;
215 | elseif t > temp*0.6
216 | if verbose == 3
217 | fprintf('Interpolated value too large, Adjusting\n');
218 | end
219 | t = temp*0.6;
220 | end
221 |
222 | % Check whether step has become too small
223 | if sum(abs(t*d)) < optTol
224 | if verbose == 3
225 | fprintf('Line Search failed\n');
226 | end
227 | t = 0;
228 | f_new = f;
229 | g_new = g;
230 | break;
231 | end
232 |
233 | % Evaluate New Point
234 | x_new = projectBounds(x+t*d,LB,UB);
235 | [f_new,g_new] = funObj(x_new);
236 | funEvals = funEvals+1;
237 | lineSearchIters = lineSearchIters+1;
238 |
239 | end
240 |
241 | % Take Step
242 | x = x_new;
243 | f = f_new;
244 | g = g_new;
245 |
246 | % Compute Working Set
247 | working = ones(nVars,1);
248 | working((x < LB+optTol*2) & g >= 0) = 0;
249 | working((x > UB-optTol*2) & g <= 0) = 0;
250 | working = find(working);
251 |
252 | % Output Log
253 | if verbose >= 2
254 | fprintf('%10d %10d %15.5e %15.5e %15.5e\n',i,funEvals*funEvalMultiplier,t,f,sum(abs(g(working))));
255 | end
256 |
257 | % Plot Progress
258 | if (nargin == 6)
259 | [stop, dispstr] = ckpntFun(x);
260 | fprintf('\b %s\n', dispstr);
261 | if stop, fprintf('Early termination condition(s) reached\n'); break; end
262 | end
263 |
264 | % Check Optimality
265 | if isempty(working)
266 | if verbose >= 1
267 | fprintf('All variables are at their bound and no further progress is possible\n');
268 | end
269 | break;
270 | elseif norm(g(working)) <= optTol
271 | if verbose >=1
272 | fprintf('All working variables satisfy optimality condition\n');
273 | end
274 | break;
275 | end
276 |
277 | % Check for lack of progress
278 | if sum(abs(t*d)) < optTol
279 | if verbose >= 1
280 | fprintf('Step size below optTol\n');
281 | end
282 | break;
283 | end
284 |
285 | if abs(f-f_old) < optTol
286 | if verbose >= 1
287 | fprintf('Function value changing by less than optTol\n');
288 | end
289 | break;
290 | end
291 |
292 | if funEvals*funEvalMultiplier > maxIter
293 | if verbose >= 1
294 | fprintf('Function Evaluations exceeds maxIter\n');
295 | end
296 | break;
297 | end
298 |
299 | % If necessary, compute Hessian
300 | if secondOrder && lineSearchIters > 1
301 | [f_new,g_new,H] = funObj(x);
302 | end
303 |
304 | i = i + 1;
305 | end
306 | end
307 |
308 | function [x] = projectBounds(x,LB,UB)
309 | x(x < LB) = LB(x < LB);
310 | x(x > UB) = UB(x > UB);
311 | end
--------------------------------------------------------------------------------
/backend/src/minConf/myProcessOptions.m:
--------------------------------------------------------------------------------
1 | function [varargout] = myProcessOptions(options,varargin)
2 | % Similar to processOptions, but case insensitive and
3 | % using a struct instead of a variable length list
4 |
5 | options = toUpper(options);
6 |
7 | for i = 1:2:length(varargin)
8 | if isfield(options,upper(varargin{i}))
9 | v = getfield(options,upper(varargin{i}));
10 | if isempty(v)
11 | varargout{(i+1)/2}=varargin{i+1};
12 | else
13 | varargout{(i+1)/2}=v;
14 | end
15 | else
16 | varargout{(i+1)/2}=varargin{i+1};
17 | end
18 | end
19 |
20 | end
21 |
22 | function [o] = toUpper(o)
23 | if ~isempty(o)
24 | fn = fieldnames(o);
25 | for i = 1:length(fn)
26 | o = setfield(o,upper(fn{i}),getfield(o,fn{i}));
27 | end
28 | end
29 | end
--------------------------------------------------------------------------------
/backend/src/minConf/polyinterp.m:
--------------------------------------------------------------------------------
1 | function [minPos,fmin] = polyinterp(points,doPlot,xminBound,xmaxBound)
2 | % function [minPos] = polyinterp(points,doPlot,xminBound,xmaxBound)
3 | %
4 | % Minimum of interpolating polynomial based on function and derivative
5 | % values
6 | %
7 | % In can also be used for extrapolation if {xmin,xmax} are outside
8 | % the domain of the points.
9 | %
10 | % Input:
11 | % points(pointNum,[x f g])
12 | % doPlot: set to 1 to plot, default: 0
13 | % xmin: min value that brackets minimum (default: min of points)
14 | % xmax: max value that brackets maximum (default: max of points)
15 | %
16 | % set f or g to sqrt(-1) if they are not known
17 | % the order of the polynomial is the number of known f and g values minus 1
18 |
19 | if nargin < 2
20 | doPlot = 0;
21 | end
22 |
23 | nPoints = size(points,1);
24 | order = sum(sum((imag(points(:,2:3))==0)))-1;
25 |
26 | % Code for most common case:
27 | % - cubic interpolation of 2 points
28 | % w/ function and derivative values for both
29 | % - no xminBound/xmaxBound
30 |
31 | if nPoints == 2 && order ==3 && nargin <= 2 && doPlot == 0
32 | % Solution in this case (where x2 is the farthest point):
33 | % d1 = g1 + g2 - 3*(f1-f2)/(x1-x2);
34 | % d2 = sqrt(d1^2 - g1*g2);
35 | % minPos = x2 - (x2 - x1)*((g2 + d2 - d1)/(g2 - g1 + 2*d2));
36 | % t_new = min(max(minPos,x1),x2);
37 | [minVal minPos] = min(points(:,1));
38 | notMinPos = -minPos+3;
39 | d1 = points(minPos,3) + points(notMinPos,3) - 3*(points(minPos,2)-points(notMinPos,2))/(points(minPos,1)-points(notMinPos,1));
40 | d2 = sqrt(d1^2 - points(minPos,3)*points(notMinPos,3));
41 | if isreal(d2)
42 | t = points(notMinPos,1) - (points(notMinPos,1) - points(minPos,1))*((points(notMinPos,3) + d2 - d1)/(points(notMinPos,3) - points(minPos,3) + 2*d2));
43 | minPos = min(max(t,points(minPos,1)),points(notMinPos,1));
44 | else
45 | minPos = mean(points(:,1));
46 | end
47 | return;
48 | end
49 |
50 | xmin = min(points(:,1));
51 | xmax = max(points(:,1));
52 |
53 | % Compute Bounds of Interpolation Area
54 | if nargin < 3
55 | xminBound = xmin;
56 | end
57 | if nargin < 4
58 | xmaxBound = xmax;
59 | end
60 |
61 | % Constraints Based on available Function Values
62 | A = zeros(0,order+1);
63 | b = zeros(0,1);
64 | for i = 1:nPoints
65 | if imag(points(i,2))==0
66 | constraint = zeros(1,order+1);
67 | for j = order:-1:0
68 | constraint(order-j+1) = points(i,1)^j;
69 | end
70 | A = [A;constraint];
71 | b = [b;points(i,2)];
72 | end
73 | end
74 |
75 | % Constraints based on available Derivatives
76 | for i = 1:nPoints
77 | if isreal(points(i,3))
78 | constraint = zeros(1,order+1);
79 | for j = 1:order
80 | constraint(j) = (order-j+1)*points(i,1)^(order-j);
81 | end
82 | A = [A;constraint];
83 | b = [b;points(i,3)];
84 | end
85 | end
86 |
87 | % Find interpolating polynomial
88 | params = A\b;
89 |
90 | % Compute Critical Points
91 | dParams = zeros(order,1);
92 | for i = 1:length(params)-1
93 | dParams(i) = params(i)*(order-i+1);
94 | end
95 |
96 | if any(isinf(dParams))
97 | cp = [xminBound;xmaxBound;points(:,1)].';
98 | else
99 | cp = [xminBound;xmaxBound;points(:,1);roots(dParams)].';
100 | end
101 |
102 | % Test Critical Points
103 | fmin = inf;
104 | minPos = (xminBound+xmaxBound)/2; % Default to Bisection if no critical points valid
105 | for xCP = cp
106 | if imag(xCP)==0 && xCP >= xminBound && xCP <= xmaxBound
107 | fCP = polyval(params,xCP);
108 | if imag(fCP)==0 && fCP < fmin
109 | minPos = real(xCP);
110 | fmin = real(fCP);
111 | end
112 | end
113 | end
114 | % Plot Situation
115 | if doPlot
116 | figure(1); clf; hold on;
117 |
118 | % Plot Points
119 | plot(points(:,1),points(:,2),'b*');
120 |
121 | % Plot Derivatives
122 | for i = 1:nPoints
123 | if isreal(points(i,3))
124 | m = points(i,3);
125 | b = points(i,2) - m*points(i,1);
126 | plot([points(i,1)-.05 points(i,1)+.05],...
127 | [(points(i,1)-.05)*m+b (points(i,1)+.05)*m+b],'c.-');
128 | end
129 | end
130 |
131 | % Plot Function
132 | x = min(xmin,xminBound)-.1:(max(xmax,xmaxBound)+.1-min(xmin,xminBound)-.1)/100:max(xmax,xmaxBound)+.1;
133 | size(x)
134 | for i = 1:length(x)
135 | f(i) = polyval(params,x(i));
136 | end
137 | plot(x,f,'y');
138 | axis([x(1)-.1 x(end)+.1 min(f)-.1 max(f)+.1]);
139 |
140 | % Plot Minimum
141 | plot(minPos,fmin,'g+');
142 | if doPlot == 1
143 | pause(1);
144 | end
145 | end
--------------------------------------------------------------------------------
/backend/src/ostrichinator_lite.m:
--------------------------------------------------------------------------------
1 | function [xmin, xsal, flag, xhist, fhist, chist] = ostrichinator_lite(net, img, tclass, allwgpu, maxiter, faststp, stpthrs)
2 |
3 | % ----------
4 | % Copyright (c) 2015, Chuan-Yung Tsai
5 | % All rights reserved.
6 | %
7 | % Redistribution and use in source and binary forms, with or without
8 | % modification, are permitted provided that the following conditions are met:
9 | %
10 | % 1. Redistributions of source code must retain the above copyright notice, this
11 | % list of conditions and the following disclaimer.
12 | % 2. Redistributions in binary form must reproduce the above copyright notice,
13 | % this list of conditions and the following disclaimer in the documentation
14 | % and/or other materials provided with the distribution.
15 | %
16 | % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | % ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | % WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | % DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | % ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | % (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | % LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | % ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | % (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | % SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | %
27 | % The views and conclusions contained in the software and documentation are those
28 | % of the authors and should not be interpreted as representing official policies,
29 | % either expressed or implied, of the FreeBSD Project.
30 | % ----------
31 |
32 | % PARAMETERS
33 |
34 | dispimg = 0;
35 | erlystp = 1;
36 | disthrs = 5;
37 | bfgshis = 10;
38 | enbalnc = 1;
39 | fulhist = 0;
40 |
41 | if dispimg, clf; subplot(2,2,1); image(img/255); end
42 | if faststp, stpthrs = 1.0; end
43 |
44 | stpcond = @(x)all(x >= stpthrs);
45 | rndmult = 16;
46 |
47 | % SHARED VARS
48 |
49 | fevalnum = 0;
50 | res = []; sal = [];
51 | xhist = []; fhist = []; chist = [];
52 |
53 | % SETUP NETWORKS & TARGET FUNCTION
54 |
55 | for n = 1:numel(net)
56 | net{n}.layers(end) = [];
57 | if allwgpu, net{n} = vl_simplenn_move(net{n}, 'gpu'); end
58 | end
59 |
60 | xshp = [227 227 3];
61 | tfuno = @(x)vl_simplenn_opt(net, reshape(x,xshp), tclass, false); % original
62 | if faststp && enbalnc, tfunn = @(x)vl_simplenn_opt(net, reshape(x,xshp), tclass, numel(net) > 1); % normalized
63 | else tfunn = tfuno; end
64 |
65 | img = img - 128;
66 |
67 | % EARLY TERM.
68 |
69 | tfuno(img);
70 | [iprogress, iclass] = cal_progress(res, tclass); chist = [chist {iclass(:)}];
71 | if fulhist, xhist = [xhist {img}]; fhist = [fhist {res}]; end
72 |
73 | flag = stpcond(iprogress);
74 | if (flag || (maxiter==1)), xmin = img + 128; xsal = sal; return; end
75 |
76 | % RUN SOLVER
77 |
78 | caldis = @(x)norm(x(:)-img(:))/sqrt(prod(xshp));
79 |
80 | lb = -128; ub = 127;
81 | clip = @(x)min(max(x,lb),ub);
82 | xini = img; xini = clip(xini(:));
83 |
84 | lb = repmat(lb, size(xini));
85 | ub = repmat(ub, size(xini));
86 |
87 | rng(0);
88 | fstphse = 1;
89 | rderfix = 0;
90 | rdclean = 0;
91 |
92 | while (fevalnum < maxiter)
93 | if ~rderfix
94 | if fstphse
95 | fprintf('-------------------- First Phase (OPT) --------------------\n');
96 |
97 | options.maxIter = maxiter - fevalnum; options.corrections = bfgshis;
98 | [xmin, ~, fevaltmp] = minConf_TMP(tfunn,xini,lb,ub,options,@plot_progress);
99 | fevalnum = fevalnum + fevaltmp;
100 |
101 | if stpcond(cal_progress(res, tclass))
102 | if rdclean, fstphse = 0; if (caldis(xmin)ONLY in case this is running too long (e.g. over 30 minutes, meaning something may have gone wrong), you are suggested to delete task and resubmit it.
95 | 96 | 97 | {% else %} 98 | 99 | {% endif %} 100 | 101 | {% if not advmode %} 102 | 103 | 109 | {% endif %} 110 | 111 |