function [model,cost,O3] = tunelssvm(model, varargin)
% Tune the hyperparameters of the model with respect to the given performance measure
%
% 1. Using the functional interface:
%
% >> [gam, sig2, cost] = tunelssvm({X,Y,type,[],[],kernel,preprocess}, optfun, costfun, costargs)
%
% Outputs
% gam : Optimal regularization parameter
% sig2 : Optimal kernel parameter(s)
% cost(*) : Estimated cost of the optimal hyperparameters
% Inputs
% X : N x d matrix with the inputs of the training data
% Y : N x 1 vector with the outputs of the training data
% type : 'function estimation' ('f') or 'classifier' ('c')
% kernel(*) : Kernel type (by default 'RBF_kernel')
% preprocess(*) : 'preprocess'(*) or 'original'
% optfun : Optimization function: 'simplex' or 'gridsearch'
% costfun : Function estimating the cost-criterion: 'crossvalidatelssvm', 'leaveoneoutlssvm', 'gcrossvalidatelssvm'
% costargs(*) : Cell with extra cost function arguments
%
% 2. Using the object oriented interface:
%
% >> model = tunelssvm(model, optfun, costfun, costargs)
%
% Outputs
% model : Object oriented representation of the LS-SVM model with optimal hyperparameters
% Inputs
% model : Object oriented representation of the LS-SVM model with initial hyperparameters
% optfun(*) : Optimization function (by default 'gridsearch')
% costfun : Function estimating the cost-criterion: 'crossvalidatelssvm', 'leaveoneoutlssvm', 'gcrossvalidatelssvm'
% optfun(*) : Cell with extra cost function arguments
%
% See also:
% trainlssvm, crossvalidate, gridsearch, linesearch, simplex, csa
% Copyright (c) 2011, KULeuven-ESAT-SCD, License & help @ http://www.esat.kuleuven.be/sista/lssvmlab
if iscell(model),
model = initlssvm(model{:});
func=1;
else
func=0;
end
%
% defaults
%
if length(varargin)>=1, optfun = varargin{1}; else optfun='gridsearch';end
if length(varargin)>=2, costfun = varargin{2}; else costfun ='crossvalidatelssvm'; end
if length(varargin)>=3, costargs = varargin{3}; else costargs ={}; end
if strcmp(costfun,'crossvalidatelssvm') || strcmp(costfun,'crossvalidateoneclasslssvm')...
|| strcmp(costfun,'rcrossvalidatelssvm') || strcmp(costfun,'crossvalidatesparselssvm')
if size(costargs,2)==1, error('Specify the number of folds for CV'); end
[Y,omega] = helpkernel(model.xtrain,model.ytrain,model.kernel_type,costargs{2},0);
costargs = {Y,costargs{1},omega,costargs{2}};
end
if strcmp(costfun,'crossvalidatelssnd')
if size(costargs,2)==1, error('Specify the number of folds for CV'); end
costargs = {costargs{1},costargs{2}};
end
if strcmp(costfun,'crossvalidate2lp1')
fprintf('\n')
disp('-->> Cross-Validation for Correlated Errors: Determine optimal ''l'' for leave (2l+1) out CV')
% if user specifies 'l'
if numel(costargs)==1, luser = NaN; else luser = costargs{2};end
[l,index] = cvl(model.xtrain,model.ytrain,luser); % First determine the 'l' for the CV
fprintf(['\n -->> Optimal l = ' num2str(l)]);
fprintf('\n')
[Y,omega] = helpkernel(model.xtrain,model.ytrain,model.kernel_type,[],1);
costargs = {Y,index,omega,costargs{1}};
end
if strcmp(costfun,'gcrossvalidatelssvm') || strcmp(costfun,'leaveoneoutlssvm')
[Y,omega] = helpkernel(model.xtrain,model.ytrain,model.kernel_type,[],0);
costargs = {Y,omega,costargs{1}};
end
if strcmp(costfun,'rcrossvalidatelssvm')
eval('model.weights = varargin{4};','model.weights = ''wmyriad''; ')
end
if strcmp(costfun,'crossvalidatelssvm_SIM')
[Y,omega] = helpkernel(model.xtrain,model.ytrain,model.kernel_type,[],1);
costargs = {model.xtrain,Y,costargs{1},omega,costargs{2}};
end
% change the coding type for multiclass and set default 'OneVsOne' if no
% coding type specified
%if length(varargin)>=5 && ~isempty(varargin{5})
if model.type(1) =='c' && ~(sum(unique(model.ytrain))==1 || sum(unique(model.ytrain))==0)
eval('coding = varargin{4};','coding = ''code_OneVsOne''; ')
varargin{5}= coding;
model = changelssvm(model,'codetype',coding);
[yc,cb,oldcb] = code(model.ytrain,coding);
y_dimold = model.y_dim;
model.ytrain = yc; model.y_dim = size(yc,2);
varargin{end} = []; clear yc
end
%
% multiple outputs
if (model.y_dim>1)% & (size(model.kernel_pars,1)==model.y_dim |size(model.gam,1)==model.y_dim |prod(size(model.kernel_type,1))==model.y_dim))
disp('-->> tune individual outputs');
if model.type(1) == 'c'
fprintf('\n')
disp(['-->> Encoding scheme: ',coding]);
end
costs = zeros(model.y_dim,1); gamt = zeros(1,model.y_dim);
for d=1:model.y_dim,
sel = ~isnan(model.ytrain(:,d));
fprintf(['\n\n -> dim ' num2str(d) '/' num2str(model.y_dim) ':\n']);
try kernel = model.kernel_type{d}; catch, kernel=model.kernel_type;end
[g,s,c] = tunelssvm({model.xtrain(sel,:),model.ytrain(sel,d),model.type,[],[],kernel,model.global_opt,'original'},varargin{:});
gamt(:,d) = g;
try kernel_part(:,d) = s; catch, kernel_part = [];end
costs(d) = c;
end
model.gam = gamt;
model.kernel_pars = kernel_part;
if func,
O3 = costs;
cost = model.kernel_pars;
model = model.gam;
end
% decode to the original model.yfull
if model.code(1) == 'c', % changed
model.ytrain = code(model.ytrain, oldcb, [], cb, 'codedist_hamming');
model.y_dim = y_dimold;
end
return
end
% change type of coding for LSSND model
if model.type(1) =='s',
coding = 'code_OneVsAll';
model = changelssvm(model,'codetype',coding);
[yc,cb,ocb] = code(model.ytrain,coding);
model.ytrain = yc; model.y_dim = size(yc,2);
model.codebook1 = ocb;
model.codebook2 = cb;
model.code = 'changed';
clear yc
end
if strcmp(model.global_opt, 'ds')
method = 'Directional Search (DFO) ';
else
method = 'Coupled Simulated Annealing';
end
%-------------------------------------------------------------------------%
if strcmp(model.kernel_type,'lin_kernel'),
if model.type(1) =='s',
[par,fval] = csa(rand(2,5),@(x)simanncostfun1(x,model,costfun,costargs));
model.nu = exp(par(2));
elseif strcmp(model.global_opt,'ds'),
[par,fval] = dsp(rand(1,5),@(x)simanncostfun1(x,model,costfun,costargs));
elseif ~strcmp(model.weights,'wmyriad') && ~strcmp(model.weights,'whuber')
[par,fval] = csa(rand(1,5),@(x)simanncostfun1(x,model,costfun,costargs));
else
[par,fval] = csa(rand(2,5),@(x)simanncostfun1(x,model,costfun,costargs));
model.delta = exp(par(2));
end
model = changelssvm(changelssvm(model,'gam',exp(par(1))),'kernel_pars',[]); clear par
fprintf('\n')
disp([' 1. ' method ' results: [gam] ' num2str(model.gam)]);
if model.type(1) =='s',
disp([' [nu] ' num2str(model.nu)]);
end
disp([' F(X)= ' num2str(fval)]);
disp(' ')
elseif strcmp(model.kernel_type,'RBF_kernel') || strcmp(model.kernel_type,'sinc_kernel') || strcmp(model.kernel_type,'RBF4_kernel')
if model.type(1) =='s',
[par,fval] = csa(rand(3,5),@(x)simanncostfun2(x,model,costfun,costargs));
model.nu = exp(par(3));
elseif strcmp(model.global_opt,'ds'),
[par,fval] = dsp(rand(2,5),@(x)simanncostfun2(x,model,costfun,costargs));
elseif ~strcmp(model.weights,'wmyriad') && ~strcmp(model.weights,'whuber')
[par,fval] = csa(rand(2,5),@(x)simanncostfun2(x,model,costfun,costargs));
else
[par,fval] = csa(rand(3,5),@(x)simanncostfun2(x,model,costfun,costargs));
model.del