function result = demo_svm(action,hfigure,varargin)
% DEMO_SVM Demo on Support Vector Machines.
%
% Synopsis:
% demo_svm
%
% Description:
% DEMO_SVM demonstrates algorithms training the binary
% SVM classifier L1-soft and L2-soft margin [Vapnik95]
% [Cris00]. The input training vectors must be 2-dimensional
% and can be interactively created by the user.
%
% Following algorithms can be tested:
%
% - Sequential Minimal Optimizer (SMO) for L1-norm soft margin.
% - QP solver (quadprog) used to train SVM with L2-norm soft margin.
% - Kernel Perceptron for separable hyperplane.
%
% Control:
% Algorithm - algorithm for testing.
% Kernel - non-linear kernel.
% Kernel argument - argument of the non-linear kernel.
% C-constant - trade-off (regularization) constant.
% parameters - parameters of the selected algorithm.
% background - if selected then the background color
% denotes the sign and the intenzity denotes the value
% of the found decision function.
%
% FIG2EPS - exports screen to the PostScript file.
% Load data - loads input training sets from file.
% Create data - calls program for creating point sets.
% Reset - clears the screen.
% Train SVM - trains and displays the SVM classifer.
% Info - calls the info box.
% Close - close the program.
%
% See also
% SMO, SVMQUADPROG, KPERCEPTR.
%
% About: Statistical Pattern Recognition Toolbox
% (C) 1999-2003, Written by Vojtech Franc and Vaclav Hlavac
% <a href="http://www.cvut.cz">Czech Technical University Prague</a>
% <a href="http://www.feld.cvut.cz">Faculty of Electrical Engineering</a>
% <a href="http://cmp.felk.cvut.cz">Center for Machine Perception</a>
% Modifications:
% 2-june-2004, VF
% 18-July-2003, VF
% 6-march-2002, V.Franc
% 23-oct-2001, V.Franc
BORDER=0.2;
DATA_IDENT='Finite sets, Enumeration';
ALGOS=['SMO (L1) ';...
'QUADPROG (L2) ';...
'Kernel-Perceptron '];
KERNELS=['Linear ';...
'Polynomial';...
'RBF '];
SMO_PARAM = 'epsilon,tolerance';
DEF_SMO_PARAM = '1e-3,1e-3';
KERNELSK_PARAM = 'epsilon,iter_limit';
DEF_KERNELSK_PARAM = '1e-3,inf';
KPERCEPTR_PARAM = 'tmax';
DEF_KPERCEPTR_PARAM = 'inf';
if nargin < 1,
action = 'initialize';
end
switch lower(action)
case 'initialize'
left=0.1;
width=0.8;
bottom=0.1;
height=0.8;
hfigure=figure('Name','Support Vector Machines', ...
'Visible','off',...
'NumberTitle','off', ...
'Units','normalized', ...
'Position',[left bottom width height],...
'Units','normalized', ...
'tag','demo_svm');
left=0.1;
width=0.65;
bottom=0.35;
height=0.60;
haxes=axes(...
'Units','normalized', ...
'UserData',[],...
'Position',[left bottom width height]);
xlabel('feature x');
ylabel('feature y');
bottom=0.05;
height=0.2;
uicontrol( ...
'Style','frame', ...
'Units','normalized', ...
'Position',[left bottom width height], ...
'BackgroundColor',[0.5 0.5 0.5]);
uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left height-0.01 width 0.05], ...
'BackgroundColor',[0.5 0.5 0.5], ...
'ForegroundColor',[1 1 1], ...
'String','Comment Window');
border=0.01;
hconsole=uicontrol( ...
'Style','edit', ...
'HorizontalAlignment','left', ...
'Units','normalized', ...
'Max',10, ...
'BackgroundColor',[1 1 1], ...
'Position',[left+border bottom width-2*border height-0.05], ...
'Enable','inactive',...
'String','');
width=0.1;
left=0.75-width;
bottom=0.95;
height=0.04;
hbt_close = uicontrol(...
'Units','Normalized', ...
'Callback','fig2eps(gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','FIG2EPS');
left=0.8;
bottom=0.05;
height=0.045;
width=0.15;
hbt_close = uicontrol(...
'Units','Normalized', ...
'Callback','close(gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Close');
bottom=bottom+1.5*height;
hbt_info = uicontrol(...
'Units','Normalized', ...
'Callback','demo_svm(''info'',gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Info');
bottom=bottom+1.5*height;
hbt_train = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Train SVM', ...
'Callback','demo_svm(''train'',gcf)');
bottom=bottom+height;
hbt_reset = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Reset', ...
'Callback','demo_svm(''reset'',gcf)');
bottom=bottom+1.5*height;
hbt_creat = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Create data', ...
'Callback','demo_svm(''creatdata'',gcf)');
bottom=bottom+1*height;
hbt_load = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Load data', ...
'Callback','demo_svm(''getfile'',gcf)');
bottom=0.95-height;
htx_algo=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width height], ...
'String','Algorithm');
bottom=bottom-height*0.8;
hpu_algo=uicontrol( ...
'Style','popup', ...
'Units','normalized', ...
'CallBack','demo_svm(''algo_handler'',gcf)',...
'Position',[left bottom width height], ...
'String',ALGOS);
bottom=bottom-height*1.2;
htx_kernel=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width height], ...
'String','Kernel');
bottom=bottom-height*.8;
hpu_kernel=uicontrol( ...
'Style','popup', ...
'Units','normalized', ...
'CallBack','demo_svm(''kernel_handler'',gcf)',...
'Position',[left bottom width height], ...
'String',KERNELS);
bottom=bottom-1.2*height;
htx_arg=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width 0.9*height], ...
'Enable','off',...
'String','Kernel argument');
bottom=bottom-height*.8;
hed_arg = uicontrol(...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'Style','edit',...
'Enable','off',...
'CallBack','demo_svm(''arg_handler'',gcf)',...
'String','1');
bottom=bottom-1.2*height;
htx_cconst=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width 0.9*height], ...
'Enable','on',...
'String','C-constant');
bottom=bottom-height*.8;
hed_cconst = uicontrol(...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'Style','edit',...
'Enable','on',...
'CallBack','demo_svm(''cconst_handler'',gcf)',...
'String','100');
bottom=bottom-1.2*height;
htx_param=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width 0.9*height], ...
'Enable','on',...
'String',SMO_PARAM);
bottom=bottom-height*.8;
hed_param = uicontrol(...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'Style','edit',...
'Enable','on',...
'CallBack','demo_svm(''param_handler'',gcf)',...
'String',DEF_SMO_PARAM);
bottom=bottom-height*1.2;
hxb_background = uicontrol(...
'Style','checkbox', ...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Background');
data=struct(...
'bt_close',hbt_close,...
'bt_train',hbt_train,...
'bt_reset',hbt_reset,...
'bt_info',hbt_info,...
'bt_load',hbt_load,...
'bt_creat',hbt_creat,...
'pu_algo',hpu_algo,...
'pu_kernel', hpu_kernel,...
'ed_arg', hed_arg,...
'tx_arg', htx_arg,...
'tx_cconst', htx_cconst,...
'ed_cconst', hed_cconst,...
'tx_param', htx_param,...
'ed_param', hed_param,...
'console',hconsole,...
'axes',haxes,...
'xb_background',hxb_background);
set(hfigure,'UserData',data );
demo_svm('reset',hfigure);
set(hfigure,'Visible','on');
drawnow;
case 'train'
data = get( hfigure, 'UserData');
trn = get( data.axes, 'UserData' );
if isempty( trn ),
return;
end
C = str2num(get( data.ed_cconst, 'String' ));
ker_inx = get( data.pu_kernel, 'Value' );
if ker_inx == 1,
ker = 'linear';
elseif ker_inx == 2;
ker = 'poly';
else
ker = 'rbf';
end
arg = str2num(get( data.ed_arg, 'String' ));
[Alpha,bias] = svm_train( data, trn, ker, arg, C );
axes( data.axes );
clrchild( data.axes);
options.background = get( data.xb_background, 'Value');
model.sv.X = trn.X;
model.sv.y = trn.I;
ppatterns(model.sv);
inx=find( Alpha ~= 0 );
model.sv.X = trn.X(:,inx);
model.sv.y = trn.I(:,inx);
model.Alpha = Alpha(:,inx)';
model.b = bias;
model.options.ker = ker;
model.options.arg = arg;
psvm( model, options );
case 'algo_handler'
data=get(hfigure,'UserData');
switch get(data.pu_algo, 'Value' )
case 1
set(data.tx_cconst,'Enable','on');
set(data.ed_cconst,'Enable','on');
set(data.tx_param,'Enable','on');
set(data.tx_param,'String',SMO_PARAM);
set(data.ed_param,'Enable','on');
set(data.ed_param,'String',DEF_SMO_PARAM);
case 2
set(data.tx_cconst,'Enable','on');
set(data.ed_cconst,'Enable','on');
set(data.tx_param,'Enable','on');
set(data.ed_param,'Enable','on');
set(data.tx_param,'String',KERNELSK_PARAM);
set(data.ed_param,'String',DEF_KERNELSK_PARAM);
case 3
set(data.tx_cconst,'Enable','off');
set(data.ed_cconst,'Enable','off');
set(data.tx_param,'Enable','on');
set(data.ed_param,'Enable','on');
set(data.tx_param,'String',KPERCEPTR_PARAM);
set(data.ed_param,'String',DEF_KPERCEPTR_PARAM);
end
case 'cconst_handler'
data=get(hfigure,'UserData');
C = str2num(get(data.ed_cconst,'String'));
if C <= 0,
C = 100;
end
set( data.ed_cconst,'String',num2str(C));
case 'arg_handler'
data=get(hfigure,'UserData');
arg = str2num(get(data.ed_arg,'String'));
if arg < 0,
arg = 1;
end
set( data.ed_arg, 'String',num2str( arg));
case 'kernel_handler'
data=get(hfigure,'UserData');
ker_inx = get( data.pu_kernel,'Value');
if ker_inx >= 2,
set( data.ed_arg,'Enable','on');
set( data.tx_arg,'Enable','on');
else
set( data.ed_arg,'Enable','off');
set( data.tx_arg,'Enable','off');
end
case 'creatdata'
createdata('finite',2,'demo_svm','created',hfigure);
case 'created'
figure(hfigure);
data = get(hfigure,'UserData');
path=varargin{1};
name=varargin{2};
pathname=strcat(path,name);
if check2ddata(pathname),
file.pathname=pathname;
file.path=path;
file.name=name;
set(data.bt_load,'UserData',file);
demo_svm('loadsets',hfigure);
demo_svm('reset',hfigure);
else
errordlg('This file does not contain required data.','Bad file','modal');
end
case 'getfile'
data=get(hfigure,'UserData');
[name,path]=uigetfile('*.mat','Open file');
if name~=0,
file.pathname=strcat(path,name);
file.path=path;
file.name=name;
if check2ddata( file.pathname ),
set(data.bt_load,'UserData',file);
demo_svm('loadsets',hfigure);
demo_svm('reset',hfigure);
else
errordlg('This file does not contain required data.','Bad file','modal');
end
end
case 'loadsets'
data = get( hfigure,'UserData' );
clrchild( data.axes);
xlabel('feature x');
ylabel('feature y');
file=get( data.bt_load,'UserData');
trn = load(file.pathname );
trn.I=trn.y;
trn.N= 2;
trn.K = [length( find(trn.y==1)),length(find(trn.y==2))];
set( data.axes,'UserData', trn);
axes( data.axes );
ppatterns( trn );
drawnow;
case 'reset'
data = get(hfigure,'UserData');
clrchild( data.axes);
trn = get( data.axes, 'UserData');
file = get( data.bt_load,'UserData');
if isempty( trn ) == 0,
consoletext=sprintf('Data loaded.\nSelect algorithm and press Train SVM button.\n');
titletext=sprintf('File: %s, # of points K = %d', file.name , size(trn.X,2));
set( data.axes, 'XLimMode','auto', 'YLimMode','auto');
ppatterns( trn);
else
consoletext=sprintf(['No data loaded.\n' ...
'Press Create data button to create your own data.\n'...
'Press Load data button to load data.\n' ...
'Load sample data from ../data/binary/']);
titletext='';
pos=get( data.axes,'Position');
fsize=min(pos(3),pos(4))/10;
setaxis( data.axes,[-1 1 -1 1]);
builtin('text',0,0,'Press ''Load data'' button.',...
'HorizontalAlignment','center',...
'FontUnits','normalized',...
'Clipping','on',...
'FontSize',fsize);
end
set( data.console,'String',consoletext );
pos=get( data.axes,'Position');
fsize=(1-pos(2)-pos(4))*1;
title(titletext,...
'Parent', data.axes,...
'VerticalAlignment','bottom',...
'HorizontalAlignment','left',...
'FontUnits','normalized',...
'Units','normalized',...
'Position',[0 1 0],...
'FontSize',fsize);
case 'info'
helpwin(mfilename);
end
return;
function [Alpha,bias] = svm_train( data, trn, ker, arg, C )
if strcmpi( ker, 'linear'),
strarg = '-';
else
strarg = num2str( arg);
end
param = str2num( get( data.ed_param,'String'));
switch get( data.pu_algo, 'Value' ),
case 1
options.ker = ker;
options.arg = arg;
options.C = C;
options.eps = param(1);
options.tol = param(2);
model = smo( trn, options);
Alpha = zeros(1,size(trn.X,2));
Alpha(model.sv.inx) = model.Alpha(:)';
bias = model.b;
nsv = model.nsv;
kercnt=model.kercnt;
trn_err = model.trnerr;
margin = model.margin;
text = sprintf(...
['SVM (L1) by Sequential Minimal Optimizer\n',...
'Kernel: %s (%s), C: %.4f\n',...
'Kernel evaluations: %d\n',...
'Number of Support Vectors: %d\n',...
'Margin: %.4f\n',...
'Training error: %.2f%%'],...
ker, strarg, C, kercnt, nsv, margin, 100*trn_err );
case 2
model=svmquadprog(trn, {'ker',ker,'arg',arg,'C',C,...
'tolabs',param(1),'tolrel',0,'tmax',param(2) });
Alpha = zeros(1,size(trn.X,2));
Alpha(model.sv.inx) = model.Alpha(:)';
bias = model.b;
nsv = model.nsv;
kercnt=model.kercnt;
trn_err = model.trnerr;
margin = model.margin;
exitflag=model.exitflag;
if( exitflag == 1), exitflag = 'found'; else exitflag = 'not found'; end
text = sprintf(...
['SVM (L2) by Kernel Schlesinger-Kozinec`s algorithm\n',...
'Kernel: %s (%s), C: %.4f\n',...
'Solution: %s\n', ...
'Number of Support Vectors: %d\n',...
'Kernel evaluations: %d\n',...
'Margin: %.4f\n',...
'Training error: %.2f%%'],...
ker, strarg, C, exitflag, nsv, kercnt, margin, trn_err*100 );
case 3
model=kperceptr(trn, {'ker',ker,'arg',arg,'tmax',param(1)});
Alpha = zeros(1,size(trn.X,2));
Alpha(model.sv.inx) = model.Alpha;
bias = model.b;
nsv = model.nsv;
kercnt=model.kercnt;
trn_err = model.trnerr;
exitflag=model.exitflag;
text = sprintf(...
['Kernel Perceptron\n',...
'Kernel: %s (%s)\n',...
'Exitflag: %d\n',...
'Kernel evaluations: %d\n',...
'Number of Support Vectors: %d\n',...
'Training error: %.2f%%'],...
ker, strarg, exitflag, kercnt, nsv, 100*trn_err);
end
set( data.console,'String', text );
return;
function []=clrchild(handle)
delete(get(handle,'Children'));
return;
function []=setaxis(handle,rect)
set(handle,'XLim',rect(1:2));
set(handle,'YLim',rect(3:4));
if size(rect,2)>=6,
set(handle,'ZLim',rect(5:6));
end
return;