[libocas] 01/01: Imported Upstream version 0.95
Christian Kastner
chrisk-guest at moszumanska.debian.org
Mon Aug 25 03:36:34 UTC 2014
This is an automated email from the git hooks/post-receive script.
chrisk-guest pushed a commit to annotated tag upstream/0.95
in repository libocas.
commit cdc2a80d2f6a42e0392416b1e6c51c0c6adf9e48
Author: Christian Kastner <debian at kvr.at>
Date: Sat Jun 30 02:02:23 2012 +0200
Imported Upstream version 0.95
---
ChangeLog | 7 +
Contents.m | 40 +-
INSTALL | 48 +-
Makefile | 50 +-
README | 27 +-
compute_auc.m | 15 +
compute_auc.mexa64 | Bin 0 -> 27573 bytes
compute_errors_mex.c => compute_auc_mex.c | 26 +-
data/reference_solution.mat | Bin 0 -> 2424860 bytes
data/refernce_solution.mat | Bin 5824 -> 0 bytes
features_double.c | 372 ++++++++++++++
features_double.h | 37 ++
features_int8.c | 89 ++++
features_int8.h | 20 +
features_single.c | 91 ++++
features_single.h | 20 +
html/ChangeLog | 2 +
html/index.html | 29 +-
lbpfilter_mex.c | 78 ---
lbppyr.m | 59 ---
lbppyr_features.mexa64 | Bin 0 -> 25711 bytes
lbppyr_features_mex.c | 17 +-
lbppyr_mex.c | 134 -----
libocas.so | Bin 0 -> 41123 bytes
libocas_test.m | 348 ++++++++-----
linclassif | Bin 0 -> 17743 bytes
linclass.c => linclassif.c | 12 +-
svmlight_linclass.m => linclassif_light.m | 13 +-
linclassif_light.mexa64 | Bin 0 -> 31853 bytes
svmlight_linclass_mex.c => linclassif_light_mex.c | 62 ++-
msvmocas | Bin 0 -> 78218 bytes
msvmocas.c | 11 +-
msvmocas.m | 38 +-
msvmocas.mexa64 | Bin 0 -> 65734 bytes
msvmocas.m => msvmocas_light.m | 39 +-
msvmocas_light.mexa64 | Bin 0 -> 65780 bytes
msvmocas_test.m => msvmocas_light_example.m | 14 +-
msvmocas_mex.c => msvmocas_light_mex.c | 301 +++++-------
msvmocas_mex.c | 312 +++++-------
ocas_helper.c | 566 +++-------------------
ocas_helper.h | 91 ++--
ocas_lbp_helper.c | 7 +-
svmocas | Bin 0 -> 82262 bytes
svmocas.c | 29 +-
svmocas.m | 51 +-
svmocas.mexa64 | Bin 0 -> 70189 bytes
svmocas_lbp.mexa64 | Bin 0 -> 51481 bytes
svmocas_lbp_mex.c | 79 +--
svmocas.m => svmocas_light.m | 41 +-
svmocas_light.mexa64 | Bin 0 -> 65826 bytes
svmocas_lbp_mex.c => svmocas_light_mex.c | 307 ++++++------
svmocas_mex.c | 502 +++++++++----------
version.h | 2 +-
53 files changed, 1963 insertions(+), 2023 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5e762e3..f20ff02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-02-06 Vojtech Franc
+ * Release of v0.95
+ * Helper functions for different data types put to separate files -
+ * features_double.c/h, features_single.c/h, features_int8.c.h.
+ * Programmed support for data stored in int8 and float single precision.
+ * Separate MEX funtions for training from SVM^light format.
+ * Removed unused functions for computing LBP features.
2010-06-11 Vojtech Franc
* Added functions which implement the COFFIN framework for training
* translation invariant image classifier from virtual example.
diff --git a/Contents.m b/Contents.m
index 9644ca0..deb8ec7 100644
--- a/Contents.m
+++ b/Contents.m
@@ -1,29 +1,27 @@
% OCAS solver for training linear SVM classifiers from large-scale data
%
-% Copyright (C) 2008,2009,2010
+% Copyright (C) 2008,2009,2010,2012
% Vojtech Franc, xfrancv at cmp.felk.cvut.cz
% Soeren Sonnenburg, soeren.sonnenburg at tu-berlin.de
%
-% SVM solvers:
-% svmocas Train linear binary (two-class) SVM classifier using
-% OCAS solver.
-% svmocas_lbp Train linear SVM classifier for images represented by
-% LBP features.
-% msvmocas Train multi-class linear SVM classifier using OCAS solver.
+% SVM solvers for training linear two-class classifiers:
+% svmocas Accepts examples stored in dense double or sparse
+% double or dense single or dense int8 matrix.
+% svmocas_light Loads examples from file in SVM^light format.
+% svmocas_lbp Examples are LBP features computed on a set of
+% given grayscale images.
%
-% Auxciliary functions:
-% svmlight_linclass Classify examples in SVM^light file by linear rule.
-% svmocas_parseout Parsing of text output of SVMOCAS solver.
-%
-% Examples
-% libocas_test This script tests functionality of SVMOCAS and
-% MSVMOCAS solvers.
-% svmocas_lbp_example Example on using SVMOCAS_LBP from training translation
-% invariant image classifiers.
+% SVM solver for training linear multi-class classifiers:
+% msvmocas Accepts examples stored in dense double or
+% sparse double matrix.
+% msvmocas_light Loads examples from file in SVM^light format.
%
-% LBP features for image classification:
-% lbpfilter Computes LBP for each 3x3 subwindow in input image.
-% lbppyr Computes LBP features on scale-pyramid of input image.
-% lbppyr_features Computes pyramid of LBP features for each defined
-% window in input images.
+% Auxciliary functions:
+% compute_auc Computes area under ROC.
+% lbppyr_features Computes LBP feature representation for given images.
+% libocas_test This script tests all SVM solvers in the LIBOCAS.
+% linclassif_light Classifies examples in SVM^light file by linear rule.
+% msvmocas_light_example Example on using multi-class SVM solver.
+% svmocas_lbp_example Example on training translation invariant image classifiers.
+% svmocas_parseout Parsing out text output of SVMOCAS solver.
%
\ No newline at end of file
diff --git a/INSTALL b/INSTALL
index 447497f..c0f1189 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,12 @@
-Issue make
+DEPENDENCES
+===========
+LIBOCAS requires only standard C libraries.
+
+
+INSTALL
+=======
+
+Unpack the library to a folder of your choice, jump to the folder and issue
make
@@ -6,30 +14,42 @@ which should produce
svmocas ... standalone application for training binary linear SVM classifiers
msvmocas ... standalone application for training multi-class linear SVM classifiers
- linclass ... implementation of linear classification rule
+ linclassif ... implementation of linear classification rule
svmocas.so ... Linux library
-In addition, if mex compiler is in path then the following Matlab functions
+In addition, if Matlab mex compiler is in path then the following MEX functions will be generated
msvmocas.mexXXX ... Training multi-class linear SVM classifier
+ msvmocas_light.mexXXX ... Training multi-class linear SVM classifier from SVM^light file
svmocas.mexXXX ... Training two-class linear SVM classifier
- svmlight_linclass.mexXXX ... Linear classifier loading examples directly form SVM^light file
svmocas_lbp.mexXXX ... Training two-class linear SVM classifier for grey-scale images
-
- lbpfilter.mexXXX ... functions computing LBP features on grey-scale images
- lbppyr_features.mexXXX
- lbppyr.mexXXX
+ svmocas_light.mexXXX ... Training two-class linear SVM classifier from SVM^light file
+ linclassif_light.mexXXX ... Linear classifier loading examples directly form SVM^light file
+
+ compute_auc ... Computes area under ROC.
+ lbppyr_features.mexXXX ... Computing LBP feature descriptor for given images.
MATLAB
======
-First, CD to the root folder of OCASLIB and then:
+First, CD to the root folder of LIBOCAS and then:
-To test LIBOCAS library type
+To get list of all implemented functions type
+ help Contents
+
+Each of the implemented SVM solvers has its detailed help together with a simple example of use,
+just try
+ help svmocas
+ help svmocas_light
+ help svmocas_lbp
+ help msvmocas
+ help msvmocas_light
+
+To test all implemented SVM solvers type
libocas_test
-To test SVMOCAS_LBP try
+To test SVMOCAS_LBP for training translation invariant image classifiers try
svmocas_lbp_example
To get help type
@@ -44,3 +64,9 @@ To get help type
./msvmocas
./linclass
+
+TROUBLESHOOTING
+===============
+
+Do not hasitate to send us email
+ xfrancv at cmp.felk.cvut.cz
diff --git a/Makefile b/Makefile
index 2ed4145..6bc4c9a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,30 +4,32 @@ MEXFLAGS := $(shell if uname -m | grep -q x86_64 ; then echo -largeArrayDims ; f
MEXSUFFIX := $(shell if uname -m | grep -q x86_64 ; then echo mexa64 ; else echo mexglx ; fi)
CC := gcc
#CFLAGS := -g -lm -Wall -pthread
-CFLAGS := -lm -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall -pthread
+CFLAGS := -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall -pthread
+CLIBS := -lm
#CFLAGS := -lm -msse -O3 -fPIC -fstrict-aliasing -fomit-frame-pointer -Wall
#CFLAGS := -lm -msse -O3 -fPIC -fopenmp -fstrict-aliasing -fomit-frame-pointer -Wall
ifeq (yes,$(MEXDETECTED))
-all: svmocas.$(MEXSUFFIX) svmlight_linclass.$(MEXSUFFIX) libocas.so svmocas msvmocas linclass msvmocas.$(MEXSUFFIX) compute_errors.$(MEXSUFFIX) lbppyr.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) lbpfilter.$(MEXSUFFIX)
+all: svmocas.$(MEXSUFFIX) svmocas_light.$(MEXSUFFIX) linclassif_light.$(MEXSUFFIX) libocas.so svmocas msvmocas linclassif msvmocas.$(MEXSUFFIX) msvmocas_light.$(MEXSUFFIX) compute_auc.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX)
-compute_errors.$(MEXSUFFIX): compute_errors_mex.c libocas.h ocas_helper.h ocas_helper.c
- $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output compute_errors.$(MEXSUFFIX) compute_errors_mex.c ocas_helper.c lib_svmlight_format.c
+compute_auc.$(MEXSUFFIX): compute_auc_mex.c libocas.h ocas_helper.h ocas_helper.c
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output compute_auc.$(MEXSUFFIX) compute_auc_mex.c ocas_helper.c lib_svmlight_format.c
-svmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
- $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas.$(MEXSUFFIX) svmocas_mex.c lib_svmlight_format.c ocas_helper.c libocas.c libqp_splx.c
-
-
-linclass_light.$(MEXSUFFIX): linclass_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
- $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output linclass_light.$(MEXSUFFIX) linclass_light_mex.c lib_svmlight_format.c ocas_helper.c
+svmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_int8.h features_int8.c features_double.h features_double.c features_single.h features_single.c
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas.$(MEXSUFFIX) svmocas_mex.c lib_svmlight_format.c ocas_helper.c features_int8.c features_double.c features_single.c libocas.c libqp_splx.c
+svmocas_light.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h svmocas_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmocas_light.$(MEXSUFFIX) svmocas_light_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
-svmlight_linclass.$(MEXSUFFIX): svmlight_linclass_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
- $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output svmlight_linclass.$(MEXSUFFIX) svmlight_linclass_mex.c lib_svmlight_format.c ocas_helper.c
-
-msvmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
- $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas.$(MEXSUFFIX) msvmocas_mex.c lib_svmlight_format.c ocas_helper.c libocas.c libqp_splx.c
+linclassif_light.$(MEXSUFFIX): linclassif_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output linclassif_light.$(MEXSUFFIX) linclassif_light_mex.c lib_svmlight_format.c ocas_helper.c
+
+msvmocas.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas.$(MEXSUFFIX) msvmocas_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
+
+msvmocas_light.$(MEXSUFFIX): libocas.c libocas.h libqp_splx.c libqp.h msvmocas_light_mex.c lib_svmlight_format.c lib_svmlight_format.h ocas_helper.c ocas_helper.h features_double.h features_double.c
+ $(MEX) $(MEXFLAGS) -DLIBOCAS_MATLAB -O -output msvmocas_light.$(MEXSUFFIX) msvmocas_light_mex.c lib_svmlight_format.c ocas_helper.c features_double.c libocas.c libqp_splx.c
lbppyr.$(MEXSUFFIX): lbppyr_mex.c
$(MEX) $(MEXFLAGS) -O -output lbppyr.$(MEXSUFFIX) lbppyr_mex.c
@@ -43,21 +45,21 @@ lbpfilter.$(MEXSUFFIX): lbpfilter_mex.c
else
-all: libocas.so svmocas msvmocas
+all: libocas.so svmocas msvmocas linclass
endif
-svmocas: svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c
- $(CC) $(CFLAGS) -o $@ svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c libocas.c libqp_splx.c
+svmocas: svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c features_double.h features_double.c
+ $(CC) $(CFLAGS) -o $@ svmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c features_double.c libocas.c libqp_splx.c $(CLIBS)
-msvmocas: msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c
- $(CC) $(CFLAGS) -o $@ msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c libocas.c libqp_splx.c
+msvmocas: msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c ocas_helper.h libocas.h sparse_mat.h libocas.c features_double.h features_double.c
+ $(CC) $(CFLAGS) -o $@ msvmocas.c lib_svmlight_format.c sparse_mat.c ocas_helper.c features_double.c libocas.c libqp_splx.c $(CLIBS)
-linclass: linclass.c lib_svmlight_format.c libocas.h
- $(CC) $(CFLAGS) -o $@ linclass.c lib_svmlight_format.c
+linclassif: linclassif.c lib_svmlight_format.c libocas.h
+ $(CC) $(CFLAGS) -o $@ linclassif.c lib_svmlight_format.c $(CLIBS)
libocas.so: libocas.c libocas.h libqp_splx.c libqp.h
- $(CC) $(CFLAGS) -shared -o $@ libocas.c libqp_splx.c
+ $(CC) $(CFLAGS) -shared -o $@ libocas.c libqp_splx.c $(CLIBS)
clean:
- rm -f *~ svmocas.$(MEXSUFFIX) svmlight_linclass.$(MEXSUFFIX) svmocas msvmocas linclass libocas.so msvmocas.$(MEXSUFFIX) lbpfilter.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) lbppyr.$(MEXSUFFIX) compute_errors.$(MEXSUFFIX)
+ rm -f *~ svmocas.$(MEXSUFFIX) svmocas_light.$(MEXSUFFIX) linclassif_light.$(MEXSUFFIX) svmocas msvmocas linclassif libocas.so msvmocas.$(MEXSUFFIX) msvmocas_light.$(MEXSUFFIX) lbppyr_features.$(MEXSUFFIX) svmocas_lbp.$(MEXSUFFIX) compute_auc.$(MEXSUFFIX)
diff --git a/README b/README
index da840c9..4cd3837 100644
--- a/README
+++ b/README
@@ -3,15 +3,14 @@ solver for training linear SVM classifiers
FEATURES
- SVM solvers for training linear classifiers from large scale-data.
- - Binary (two-class) and genuine multi-class SVM formulations.
- - Optimized code written in C.
+ - Two-class and genuine multi-class SVM formulations.
- A stand alone application and MEX interface for Matlab.
+ - Optimized for features represented in by different data types:
+ sparse/dense, double/single precision, int8.
- Reads examples from SVM^light format.
- - Optimized for both sparse and dense features.
- - Parallelized version of the binary solver.
- - Allows using different C for each training example (Matlab's interace to binary solver).
- - Tools for classification.
- - Training translation invariant image classifiers from virtual examples.
+ - Parallelized version of the two-class SVM solver.
+ - Allows using different C for each training example (only for Matlab).
+ - Training translation invariant image classifier from virtual examples using LBP features.
- Functions for computing image features based on Local Binary Patterns (LBP).
@@ -22,12 +21,13 @@ SVM classifiers:
1. Binary case: OCAS solves the following unconstrained convex optimization task
- W^*,W0^* = argmin 0.5*(W'*W+W0^2) + C*sum max( 0, 1-y(i)*(W'*X(:,i)+W0*X0) )
+ W^*,W0^* = argmin 0.5*(W'*W+W0^2) + sum C(i)*max( 0, 1-y(i)*(W'*X(:,i)+W0*X0) )
W,W0 i=1:nData
-where C is the regularization constant, X [nDim x nData] are training feature
-vectors and y [nData x 1] are their binary labels (+1/-1). The result are
-parameters W^* [nDim x 1], W0^* [1 x 1] of the linear rule
+where C [nData x 1] is the regularization constant for each example,
+X [nDim x nData] are training feature vectors and y [nData x 1] are their
+binary labels (+1/-1). The result are parameters W^* [nDim x 1], W0^* [1 x 1] of
+the linear rule
f(X) = sign( X'*W + W0 )
@@ -50,8 +50,7 @@ LIBOCAS can be downloaded from
PLATFORMS
-GNU/Linux.
-
+Developed and tested under GNU/Linux.
LICENSE
@@ -71,4 +70,4 @@ V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vect
S. Sonnenburg, V. Franc. COFFIN: A Computational Framework for Linear SVMs.
In Proceedings of the 27nd International Machine Learning Conference (ICML'10).
Haifa 2010.
- http://cmp.felk.cvut.cz/~xfrancv/papers/Sonnenburg-COFFIN-ICML10.pdf
+ http://cmp.felk.cvut.cz/~xfrancv/papers/Sonnenburg-COFFIN-ICML10.pdf
\ No newline at end of file
diff --git a/compute_auc.m b/compute_auc.m
new file mode 100644
index 0000000..a7bc74a
--- /dev/null
+++ b/compute_auc.m
@@ -0,0 +1,15 @@
+% COMPUTE_AUC computes area under ROC.
+%
+% Synopsis:
+% auc = compute_auc(score,trueLabels)
+%
+% Input:
+% score [N x 1 (double)] score of two-class classifier; positive class has
+% score >= 0 while negative class has score < 0
+% trueLabels [N x 1 (double)] positive class 1; negative class ~= 1
+% Output:
+% auc [1x1] Area Under ROC.
+%
+% Example:
+% help svmocas
+%
diff --git a/compute_auc.mexa64 b/compute_auc.mexa64
new file mode 100755
index 0000000..975441d
Binary files /dev/null and b/compute_auc.mexa64 differ
diff --git a/compute_errors_mex.c b/compute_auc_mex.c
similarity index 69%
rename from compute_errors_mex.c
rename to compute_auc_mex.c
index de418d6..417034b 100644
--- a/compute_errors_mex.c
+++ b/compute_auc_mex.c
@@ -1,8 +1,8 @@
/*=================================================================
- * COMPUTE_ERRORS computes classification error and area under ROC.
+ * COMPUTE_AUC computes area under ROC.
*
* Synopsis:
- * [error,auc] = compute_errors(score,true_labels)
+ * auc = compute_auc(score,true_labels)
*
* Input:
* scores [1 x n] scores of binary classifier; the classifier decides
@@ -10,7 +10,6 @@
* true_labels [1 x n] true labels; 1st class label = 1,
* 2nd class label != 1
* Output:
- * error [1x1] number of mis-classifications
* auc [1x1] Area under ROC
*
*=================================================================*/
@@ -39,18 +38,17 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
int *true_labels_int;
uint32_t n1, n2, i;
- double auc, error;
+ double auc; /*, error;*/
double *scores, *true_labels;
if( nrhs != 2 )
mexErrMsgTxt("Two input arguments must be passed.\n"
"\n"
- "[error,auc] = compute_errors(score,true_labels)\n"
- "Inputs: score [N x 1 (double)] positive class score >= 0 otherwise negative class \n"
- " true_labels [N x 1 (double)] positive class 1; negative class ~= 1\n"
- "Outputs: error [1x1] number of misclassifications\n"
- " auc [1x1] Arrea Under ROC\n");
+ "auc = compute_auc(score,trueLabels)\n"
+ "Inputs: score [N x 1 (double)] positive class score >= 0 otherwise negative class \n"
+ " trueLabels [N x 1 (double)] positive class 1; negative class ~= 1\n"
+ "Outputs: auc [1x1] Arrea Under ROC\n");
scores = mxGetPr(prhs[0]);
true_labels = mxGetPr(prhs[1]);
@@ -66,21 +64,21 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(true_labels_int == NULL)
mexErrMsgTxt("Not enough memory.");
- error = 0;
+ /*error = 0;*/
for(i = 0; i < n1; i++)
{
true_labels_int[i] = (int)true_labels[i];
- if((true_labels[i] == 1 && scores[i] <= 0) || (true_labels[i] != 1 && scores[i] > 0))
- error++;
+/* if((true_labels[i] == 1 && scores[i] <= 0) || (true_labels[i] != 1 && scores[i] > 0))
+ error++;*/
}
auc = compute_auc(scores, true_labels_int, n1);
mxFree(true_labels_int);
- plhs[0] = mxCreateDoubleScalar(error);
- plhs[1] = mxCreateDoubleScalar(auc);
+ /*plhs[0] = mxCreateDoubleScalar(error);*/
+ plhs[0] = mxCreateDoubleScalar(auc);
return;
}
diff --git a/data/reference_solution.mat b/data/reference_solution.mat
new file mode 100644
index 0000000..174450d
Binary files /dev/null and b/data/reference_solution.mat differ
diff --git a/data/refernce_solution.mat b/data/refernce_solution.mat
deleted file mode 100644
index ad939e0..0000000
Binary files a/data/refernce_solution.mat and /dev/null differ
diff --git a/features_double.c b/features_double.c
new file mode 100644
index 0000000..9bed263
--- /dev/null
+++ b/features_double.c
@@ -0,0 +1,372 @@
+/*-----------------------------------------------------------------------
+ * features_double.c: Helper functions for the OCAS solver working with
+ * features in double precision.
+ *-------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ocas_helper.h"
+#include "features_double.h"
+
+/*----------------------------------------------------------------------------------
+ sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = zeros(nDim,nY);
+ for i=1:nData
+ if new_cut(i) ~= data_y(i)
+ new_a(:,data_y(i)) = new_a(:,data_y(i)) + X(;,i);
+ new_a(:,new_cut(i)) = new_a(:,new_cut(i)) - X(;,i);
+ end
+ end
+
+ new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ sparse_A(:,nSel+1) = new_a;
+
+ Warning: data_y is 1-based while new_cut is 0-based
+
+ ---------------------------------------------------------------------------------*/
+int msvm_sparse_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t nSel,
+ void* user_data )
+{
+/* double *new_a, */
+ double sq_norm_a;
+ uint32_t i, j, nz_dims, ptr, y;
+
+ memset(new_a, 0, sizeof(double)*nY*nDim);
+
+ for(i=0; i < nData; i++)
+ {
+ y = (uint32_t)(data_y[i]-1);
+ if(new_cut[i] != y)
+ {
+ add_sparse_col(&new_a[nDim*y], data_X, i);
+ subtract_sparse_col(&new_a[nDim*(uint32_t)new_cut[i]], data_X, i);
+ }
+ }
+
+ /* compute new_a'*new_a and count number of non-zero dimensions */
+ nz_dims = 0;
+ sq_norm_a = 0;
+ for(j=0; j < nY*nDim; j++ ) {
+ if(new_a[j] != 0) {
+ nz_dims++;
+ sq_norm_a += new_a[j]*new_a[j];
+ }
+ }
+
+ /* sparsify new_a and insert it to the last column of sparse_A */
+ sparse_A.nz_dims[nSel] = nz_dims;
+ if(nz_dims > 0) {
+ sparse_A.index[nSel] = NULL;
+ sparse_A.value[nSel] = NULL;
+ sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
+ sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
+ if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
+ {
+/* mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
+ mxFree(sparse_A.index[nSel]);
+ mxFree(sparse_A.value[nSel]);
+ return(-1);
+ }
+
+ ptr = 0;
+ for(j=0; j < nY*nDim; j++ ) {
+ if(new_a[j] != 0) {
+ sparse_A.index[nSel][ptr] = j;
+ sparse_A.value[nSel][ptr++] = new_a[j];
+ }
+ }
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = 0;
+
+ for(j=0; j < sparse_A.nz_dims[i]; j++) {
+ tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
+ }
+
+ new_col_H[i] = tmp;
+ }
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------
+ sparse_compute_output( output ) does the follwing:
+
+ output = W'*data_X;
+ ----------------------------------------------------------------------*/
+int msvm_sparse_compute_output( double *output, void* user_data )
+{
+ uint32_t i,y;
+
+ for(i=0; i < nData; i++)
+ {
+ for(y=0; y < nY; y++)
+ {
+ output[LIBOCAS_INDEX(y,i,nY)] = dp_sparse_col(&W[y*nDim], data_X, i);
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------
+ full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+ new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ full_A(:,nSel+1) = new_a;
+
+ ---------------------------------------------------------------------------------*/
+int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data)
+{
+ double sq_norm_a, *ptr;
+ uint32_t i, j, y, y2;
+
+ ptr = mxGetPr(data_X);
+
+ memset(new_a, 0, sizeof(double)*nDim*nY);
+
+ for(i=0; i < nData; i++)
+ {
+ y = (uint32_t)(data_y[i]-1);
+ y2 = (uint32_t)new_cut[i];
+ if(y2 != y)
+ {
+ for(j=0; j < nDim; j++ )
+ {
+ new_a[LIBOCAS_INDEX(j,y,nDim)] += ptr[LIBOCAS_INDEX(j,i,nDim)];
+ new_a[LIBOCAS_INDEX(j,y2,nDim)] -= ptr[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ }
+ }
+
+ /* compute new_a'*new_a and insert new_a to the last column of full_A */
+ sq_norm_a = 0;
+ for(j=0; j < nDim*nY; j++ ) {
+ sq_norm_a += new_a[j]*new_a[j];
+ full_A[LIBOCAS_INDEX(j,nSel,nDim*nY)] = new_a[j];
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = 0;
+
+ for(j=0; j < nDim*nY; j++ ) {
+ tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim*nY)];
+ }
+ new_col_H[i] = tmp;
+ }
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------
+ full_compute_output( output ) does the follwing:
+
+ output = data_X'*W;
+ ----------------------------------------------------------------------*/
+int msvm_full_compute_output( double *output, void* user_data )
+{
+ uint32_t i, j, y;
+ double *ptr, tmp;
+
+ ptr = mxGetPr( data_X );
+
+ for(i=0; i < nData; i++)
+ {
+ for(y=0; y < nY; y++)
+ {
+ tmp = 0;
+
+ for(j=0; j < nDim; j++ )
+ {
+ tmp += W[LIBOCAS_INDEX(j,y,nDim)]*ptr[LIBOCAS_INDEX(j,i,nDim)];
+ }
+
+ output[LIBOCAS_INDEX(y,i,nY)] = tmp;
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------
+ sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+ new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ sparse_A(:,nSel+1) = new_a;
+
+ ---------------------------------------------------------------------------------*/
+int sparse_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data )
+{
+/* double *new_a, */
+ double sq_norm_a;
+ uint32_t i, j, nz_dims, ptr;
+
+ memset(new_a, 0, sizeof(double)*nDim);
+
+ for(i=0; i < cut_length; i++) {
+ add_sparse_col(new_a, data_X, new_cut[i]);
+
+ A0[nSel] += X0*data_y[new_cut[i]];
+ }
+
+ /* compute new_a'*new_a and count number of non-zero dimensions */
+ nz_dims = 0;
+ sq_norm_a = A0[nSel]*A0[nSel];
+ for(j=0; j < nDim; j++ ) {
+ if(new_a[j] != 0) {
+ nz_dims++;
+ sq_norm_a += new_a[j]*new_a[j];
+ }
+ }
+
+ /* sparsify new_a and insert it to the last column of sparse_A */
+ sparse_A.nz_dims[nSel] = nz_dims;
+ if(nz_dims > 0) {
+ sparse_A.index[nSel] = NULL;
+ sparse_A.value[nSel] = NULL;
+ sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
+ sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
+ if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
+ {
+/* mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
+ mxFree(sparse_A.index[nSel]);
+ mxFree(sparse_A.value[nSel]);
+ return(-1);
+ }
+
+ ptr = 0;
+ for(j=0; j < nDim; j++ ) {
+ if(new_a[j] != 0) {
+ sparse_A.index[nSel][ptr] = j;
+ sparse_A.value[nSel][ptr++] = new_a[j];
+ }
+ }
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = A0[nSel]*A0[i];
+
+ for(j=0; j < sparse_A.nz_dims[i]; j++) {
+ tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
+ }
+
+ new_col_H[i] = tmp;
+ }
+
+/* mxFree( new_a );*/
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------------
+ full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+ new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ full_A(:,nSel+1) = new_a;
+
+ ---------------------------------------------------------------------------------*/
+int full_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data)
+{
+/* double *new_a, */
+ double sq_norm_a, *ptr;
+ uint32_t i, j;
+
+ ptr = mxGetPr(data_X);
+
+ memset(new_a, 0, sizeof(double)*nDim);
+
+
+ for(i=0; i < cut_length; i++) {
+ for(j=0; j < nDim; j++ ) {
+ new_a[j] += ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+ }
+
+ A0[nSel] += X0*data_y[new_cut[i]];
+ }
+
+ /* compute new_a'*new_a and insert new_a to the last column of full_A */
+ sq_norm_a = A0[nSel]*A0[nSel];
+ for(j=0; j < nDim; j++ ) {
+ sq_norm_a += new_a[j]*new_a[j];
+ full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = A0[nSel]*A0[i];
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ new_col_H[i] = tmp;
+ }
+
+/* mxFree( new_a );*/
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------
+ sparse_compute_output( output ) does the follwing:
+
+ output = data_X'*W;
+ ----------------------------------------------------------------------*/
+int sparse_compute_output( double *output, void* user_data )
+{
+ uint32_t i;
+
+ for(i=0; i < nData; i++) {
+ output[i] = data_y[i]*X0*W0 + dp_sparse_col(W, data_X, i);
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+ full_compute_output( output ) does the follwing:
+
+ output = data_X'*W;
+ ----------------------------------------------------------------------*/
+int full_compute_output( double *output, void* user_data )
+{
+ uint32_t i, j;
+ double *ptr, tmp;
+
+ ptr = mxGetPr( data_X );
+
+ for(i=0; i < nData; i++) {
+ tmp = data_y[i]*X0*W0;
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += W[j]*ptr[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ output[i] = tmp;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/features_double.h b/features_double.h
new file mode 100644
index 0000000..a44ed60
--- /dev/null
+++ b/features_double.h
@@ -0,0 +1,37 @@
+/*-----------------------------------------------------------------------
+ * features_double.h: Helper functions for the OCAS solver working with
+ * features in double precision.
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_double_h
+#define _features_double_h
+
+#include <stdint.h>
+
+/* dense double features */
+extern int full_compute_output( double *output, void* user_data );
+extern int full_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data);
+
+/* sparse double features */
+extern int sparse_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data );
+extern int sparse_compute_output( double *output, void* user_data );
+
+
+/* dense double features for multi-class solver */
+extern int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data);
+extern int msvm_full_compute_output( double *output, void* user_data );
+
+/* sparse double features for multi-class solver */
+extern int msvm_sparse_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data );
+extern int msvm_sparse_compute_output( double *output, void* user_data );
+
+
+#endif
diff --git a/features_int8.c b/features_int8.c
new file mode 100644
index 0000000..e6f8918
--- /dev/null
+++ b/features_int8.c
@@ -0,0 +1,89 @@
+/*-----------------------------------------------------------------------
+ * features_int8.c: Helper functions for the OCAS solver working with
+ * INT8 features.
+ *-------------------------------------------------------------------- */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "ocas_helper.h"
+#include "features_int8.h"
+
+
+/*----------------------------------------------------------------------------------
+ full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+ new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ full_A(:,nSel+1) = new_a;
+
+ ---------------------------------------------------------------------------------*/
+int full_int8_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data)
+{
+/* double *new_a, */
+ double sq_norm_a;
+ uint32_t i, j;
+ int8_t *ptr;
+
+ ptr = (int8_t*)mxGetPr(data_X);
+
+ memset(new_a, 0, sizeof(double)*nDim);
+
+
+ for(i=0; i < cut_length; i++) {
+ for(j=0; j < nDim; j++ ) {
+ new_a[j] += (double)ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+ }
+
+ A0[nSel] += X0*data_y[new_cut[i]];
+ }
+
+ /* compute new_a'*new_a and insert new_a to the last column of full_A */
+ sq_norm_a = A0[nSel]*A0[nSel];
+ for(j=0; j < nDim; j++ ) {
+ sq_norm_a += new_a[j]*new_a[j];
+ full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = A0[nSel]*A0[i];
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ new_col_H[i] = tmp;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+ full_int8_compute_output( output ) does the follwing:
+
+ output = data_X'*W;
+ ----------------------------------------------------------------------*/
+int full_int8_compute_output( double *output, void* user_data )
+{
+ uint32_t i, j;
+ double tmp;
+ int8_t* ptr;
+
+ ptr = (int8_t*)mxGetPr( data_X );
+
+ for(i=0; i < nData; i++) {
+ tmp = data_y[i]*X0*W0;
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += W[j]*(double)ptr[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ output[i] = tmp;
+ }
+
+ return 0;
+}
+
diff --git a/features_int8.h b/features_int8.h
new file mode 100644
index 0000000..b7a0222
--- /dev/null
+++ b/features_int8.h
@@ -0,0 +1,20 @@
+/*-----------------------------------------------------------------------
+ * features_int8.h: Helper functions for the OCAS solver working with
+ * INT8 features.
+ *
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_int8_h
+#define _features_int8_h
+
+#include <stdint.h>
+
+
+extern int full_int8_compute_output( double *output, void* user_data );
+extern int full_int8_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data);
+
+#endif
diff --git a/features_single.c b/features_single.c
new file mode 100644
index 0000000..0b8296e
--- /dev/null
+++ b/features_single.c
@@ -0,0 +1,91 @@
+/*-----------------------------------------------------------------------
+ * features_single.c: Helper functions for the OCAS solver working with
+ * features in single precision.
+ *-------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ocas_helper.h"
+#include "features_single.h"
+
+/*----------------------------------------------------------------------------------
+ full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
+
+ new_a = sum(data_X(:,find(new_cut ~=0 )),2);
+ new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
+ full_A(:,nSel+1) = new_a;
+
+ ---------------------------------------------------------------------------------*/
+int full_single_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data)
+{
+ double sq_norm_a;
+ float *ptr;
+ uint32_t i, j;
+
+ ptr = (float*)mxGetPr(data_X);
+
+ memset(new_a, 0, sizeof(double)*nDim);
+
+
+ for(i=0; i < cut_length; i++) {
+ for(j=0; j < nDim; j++ ) {
+ new_a[j] += (double)ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
+ }
+
+ A0[nSel] += X0*data_y[new_cut[i]];
+ }
+
+ /* compute new_a'*new_a and insert new_a to the last column of full_A */
+ sq_norm_a = A0[nSel]*A0[nSel];
+ for(j=0; j < nDim; j++ ) {
+ sq_norm_a += new_a[j]*new_a[j];
+ full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
+ }
+
+ new_col_H[nSel] = sq_norm_a;
+ for(i=0; i < nSel; i++) {
+ double tmp = A0[nSel]*A0[i];
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ new_col_H[i] = tmp;
+ }
+
+/* mxFree( new_a );*/
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------
+ full_compute_output( output ) does the follwing:
+
+ output = data_X'*W;
+ ----------------------------------------------------------------------*/
+int full_single_compute_output( double *output, void* user_data )
+{
+ uint32_t i, j;
+ float *ptr;
+ double tmp;
+
+ ptr = (float*)mxGetPr( data_X );
+
+ for(i=0; i < nData; i++) {
+ tmp = data_y[i]*X0*W0;
+
+ for(j=0; j < nDim; j++ ) {
+ tmp += W[j] * (double)ptr[LIBOCAS_INDEX(j,i,nDim)];
+ }
+ output[i] = tmp;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/features_single.h b/features_single.h
new file mode 100644
index 0000000..c7e06d2
--- /dev/null
+++ b/features_single.h
@@ -0,0 +1,20 @@
+/*-----------------------------------------------------------------------
+ * features_single.h: Helper functions for the OCAS solver working with
+ * features in double precision.
+ *-------------------------------------------------------------------- */
+
+#ifndef _features_single_h
+#define _features_single_h
+
+#include <stdint.h>
+
+/* dense double features */
+extern int full_single_compute_output( double *output, void* user_data );
+extern int full_single_add_new_cut( double *new_col_H,
+ uint32_t *new_cut,
+ uint32_t cut_length,
+ uint32_t nSel,
+ void* user_data);
+
+
+#endif
diff --git a/html/ChangeLog b/html/ChangeLog
index 5e762e3..cd5b4d2 100644
--- a/html/ChangeLog
+++ b/html/ChangeLog
@@ -1,3 +1,5 @@
+2011-12-22 Vojtech Fracn
+ * Added "svmocas_int8" supporting features represented as int8.
2010-06-11 Vojtech Franc
* Added functions which implement the COFFIN framework for training
* translation invariant image classifier from virtual example.
diff --git a/html/index.html b/html/index.html
index 13ee3c8..4d8814c 100644
--- a/html/index.html
+++ b/html/index.html
@@ -13,7 +13,7 @@ classifiers from large-scale data</H2>
<A href="http://ida.first.fraunhofer.de/homepages/sonne/first/">Soeren
Sonnenburg</a>
<p>
-Last Modified: 11-Jun-2010
+Last Modified: 06-Feb-2012
</div>
@@ -47,18 +47,15 @@ notebook with just 4GB of memory.
<h4>Features</h4>
<ul>
- <li>SVM solvers for training linear classifiers from large scale-data.</li>
- <li>Binary (two-class) and genuine multi-class SVM formulations.</li>
- <li>Optimized code written in C.</li>
- <li>A stand alone application and MEX interface for Matlab.</li>
- <li>Reads examples from SVM^light format.</li>
- <li>Optimized for both sparse and dense features.</li>
- <li>Parallelized version of the binary solver.</li>
- <li>Allows using different C for each training example (Matlab's interace to binary solver).</li>
- <li>Tools for classification.</li>
- <li><img align="top" border="0" src="new.gif"> Training translation invariant image classifiers from virtual examples.</li>
- <li><img align="top" border="0" src="new.gif"> Functions for computing image features based on Local Binary Patterns (LBP).</li>
-
+ <li>SVM solvers for training linear classifiers from large scale-data.</li>
+ <li>Two-class and genuine multi-class SVM formulations.</li>
+ <li>A stand alone application and MEX interface for Matlab.</li>
+ <li>Optimized for features represented by different data types: sparse/dense, double/single precision, int8.</li>
+ <li>Reads examples from SVM^light format.</li>
+ <li>Parallelized version of the two-class SVM solver.</li>
+ <li>Allows using different C for each training example (only for Matlab).</li>
+ <li>Training translation invariant image classifier from virtual examples using LBP features.</li>
+ <li>Functions for computing image features based on Local Binary Patterns (LBP).</li>
</ul>
<h4>Problem formulation</h4>
@@ -93,7 +90,11 @@ from <img align="top" border="0" src="set_y_sc.png">.
LIBOCAS can be downloaded from here:
<ul>
- <li><img align="top" border="0" src="new.gif"> Version 0.93, 2010-06-11, <a
+ <li><img align="top" border="0" src="new.gif"> Version 0.95, 2012-02-06, <a
+ href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v095.zip">libocas_v095.zip</a>: Support for features in single precision floats. Code polished. </li>
+ <li>Version 0.94, 2011-12-22, <a
+ href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v094.zip">libocas_v094.zip</a>: Support for features represented as int8. </li>
+ <li>Version 0.93, 2010-06-11, <a
href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v093.zip">libocas_v093.zip</a> </li>
<li>Version 0.92, 2008-08-03, <a
href="http://cmp.felk.cvut.cz/~xfrancv/ocas/libocas_v092.zip">libocas_v092.zip</a> </li>
diff --git a/lbpfilter_mex.c b/lbpfilter_mex.c
deleted file mode 100644
index 5681682..0000000
--- a/lbpfilter_mex.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*=================================================================
- * LBPFILTER computes LBP for each 3x3 subwindow in input image.
- *
- * Synopsis:
- * F = lbpfilter(I)
- * where
- * I [h x w (double)] is input image.
- * F [h x w (double)] is image of LBP responses;
- * the border colums and rows, for which LBP is not defined, are set 0.
- *
- *=================================================================*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <mex.h>
-#include <time.h>
-#include <errno.h>
-
-#define MIN(A,B) ((A) > (B) ? (B) : (A))
-#define MAX(A,B) ((A) < (B) ? (B) : (A))
-#define ABS(A) ((A) < 0 ? -(A) : (A))
-#define INDEX(ROW,COL,NUM_ROWS) ((COL)*(NUM_ROWS)+(ROW))
-
-
-/*======================================================================
- Main code plus interface to Matlab.
-========================================================================*/
-
-void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
-{
-
- double *I, *P;
- int w,h, x,y;
- double center;
- unsigned char pattern;
-
- if( nrhs != 1 )
- mexErrMsgTxt("One input argument required.\n\n"
- "LBPFILTER computes LBP for each 3x3 subwindow in input image.\n"
- "\n"
- "Synopsis:\n"
- " F = lbpfilter(I)\n"
- "where\n"
- " I [h x w (double)] is input image.\n"
- " F [h x w (double)] is image of LBP responses; \n"
- " the border colums and rows, for which LBP is not defined, are set 0.\n"
- );
-
- I = (double*)mxGetPr(prhs[0]);
- h = mxGetM(prhs[0]);
- w = mxGetN(prhs[0]);
-
- plhs[0] = mxCreateDoubleMatrix(h,w,mxREAL);
- P = (double*)mxGetPr(plhs[0]);
-
- for(x=1; x < w-1; x++)
- {
- for(y=1; y< h-1; y++)
- {
- pattern = 0;
- center = I[INDEX(y,x,h)];
- if(I[INDEX(y-1,x-1,h)] < center) pattern = pattern | 0x01;
- if(I[INDEX(y-1,x,h)] < center) pattern = pattern | 0x02;
- if(I[INDEX(y-1,x+1,h)] < center) pattern = pattern | 0x04;
- if(I[INDEX(y,x-1,h)] < center) pattern = pattern | 0x08;
- if(I[INDEX(y,x+1,h)] < center) pattern = pattern | 0x10;
- if(I[INDEX(y+1,x-1,h)] < center) pattern = pattern | 0x20;
- if(I[INDEX(y+1,x,h)] < center) pattern = pattern | 0x40;
- if(I[INDEX(y+1,x+1,h)] < center) pattern = pattern | 0x80;
-
- P[INDEX(y,x,h)] = (double)pattern;
- }
- }
-
- return;
-}
-
diff --git a/lbppyr.m b/lbppyr.m
deleted file mode 100644
index cfcba4b..0000000
--- a/lbppyr.m
+++ /dev/null
@@ -1,59 +0,0 @@
-function F = lbppyr(I, P)
-% LBPPYR computes LBP features on scale-pyramid of input image.
-%
-% Synopsis:
-% F = lbppyr(I, P)
-%
-% Description:
-% Local Binary Pattern (LBP) is 1 Byte number which encodes grey-scale
-% intensities of a given 3x3 window.
-%
-% For P = 1, LBPPYR computes LBP features for all 3x3 windows
-% in the input image I. The LBP features are stucked to a column
-% vector F.
-%
-% For P > 1, the input image I is down-scaled (P-1)-times to create
-% a scale-pyramid of height P. Each subsequent level of the pyramid is
-% obtained by downscaling the original image by 2. Having the pyramid,
-% the LBP features are computed on each leavel of the pyramid and
-% they are stucked to a column vector F.
-%
-% For more details on LBP see:
-% Ojala, et. al: Multiresolution gray-scale and rotation invariant
-% texture classification with local binary patterns. IEEE PAMI,
-% 24(7):971-987,2002.
-%
-% Input:
-% I [H x W (uint8)] Input image.
-% lbp_pyramid [1 x 1] Height of the LBP pyramids.
-%
-% Output:
-% F [nDim x 1] LBP features stucked to a column vector.
-%
-% Example:
-% I = imread('./data/lena.jpg');
-% F = lbppyr(I,4);
-%
-% Matlab code equivalent to LBPPYR_MEX.C:
-%
-% [h,w] = size(I);
-% I = uint32(I);
-% F = [];
-% k = 1;
-% while k <= P & min(w,h) >= 3
-% k = k + 1;
-% tmp = lbpfilter(double(I));
-% tmp = tmp(2:end-1,2:end-1);
-% F = [F; tmp(:)];
-% if mod(w,2) == 1
-% I = I(:,1:w-1);
-% w= w - 1;
-% end
-% if mod(h,2) == 1
-% I = I(1:h-1,:);
-% h = h - 1;
-% end
-% I = I(1:2:h,1:2:w)+I(1:2:h,2:2:w)+I(2:2:h,1:2:w)+I(2:2:h,2:2:w);
-% [h,w] = size(I);
-% end
-%
\ No newline at end of file
diff --git a/lbppyr_features.mexa64 b/lbppyr_features.mexa64
new file mode 100755
index 0000000..65c4668
Binary files /dev/null and b/lbppyr_features.mexa64 differ
diff --git a/lbppyr_features_mex.c b/lbppyr_features_mex.c
index e31ab8b..bc173f2 100644
--- a/lbppyr_features_mex.c
+++ b/lbppyr_features_mex.c
@@ -29,9 +29,10 @@
void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
- uint32_t i, j;
+/* uint32_t i, j;*/
+ mwSize i, j;
double *tmp;
- char *Features ;
+ char *Features;
uint8_t *CroppedWin;
int verb;
@@ -58,7 +59,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
verb = 1;
uint8_t * Images = (uint8_t*)mxGetPr(prhs[0]);
- uint32_t nImages = mxGetN(prhs[0]);
+/* uint32_t nImages = mxGetN(prhs[0]);*/
+ mwSize nImages = mxGetN(prhs[0]);
tmp = (double*)mxGetPr(prhs[1]);
uint32_t im_H = (uint32_t)tmp[0];
@@ -74,9 +76,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
uint16_t win_W = (uint16_t)tmp[1];
uint16_t nPyramids = (uint32_t)mxGetScalar(prhs[4]);
- uint32_t nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
+/* uint32_t nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);*/
+ mwSize nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
- uint32_t nData = mxGetN(prhs[2]);
+/* uint32_t nData = mxGetN(prhs[2]);*/
+ mwSize nData = mxGetN(prhs[2]);
if(verb)
{
@@ -105,7 +109,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
CroppedWin = (uint8_t*)mxGetPr(plhs[1]);
- uint32_t cnt, cnt0, mirror,x,x1,y,y1,idx;
+/* uint32_t cnt, cnt0, mirror,x,x1,y,y1,idx;*/
+ mwSize cnt, cnt0, mirror,x,x1,y,y1,idx;
uint32_t *win;
uint8_t *img_ptr;
diff --git a/lbppyr_mex.c b/lbppyr_mex.c
deleted file mode 100644
index a005149..0000000
--- a/lbppyr_mex.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*=================================================================
- * LBPPYR computes LBP features on scale-pyramid of input image.
- *
- * Synopsis:
- * F = lbppyr_mat(I, P)
- * where
- * I [H x W (uint8)] is input image.
- * P [1 x 1 (double)] is height of the scale-pyramid.
- * F [N x 1 (uint8)] LBP features stucked to a column vector.
- *
- *=================================================================*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <mex.h>
-#include <time.h>
-#include <errno.h>
-
-#define MIN(A,B) ((A) > (B) ? (B) : (A))
-#define MAX(A,B) ((A) < (B) ? (B) : (A))
-#define ABS(A) ((A) < 0 ? -(A) : (A))
-#define INDEX(ROW,COL,NUM_ROWS) ((COL)*(NUM_ROWS)+(ROW))
-
-
-/*======================================================================
- Main code plus interface to Matlab.
-========================================================================*/
-
-void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
-{
-
- uint8_t *I, K;
- uint32_t *P;
- uint32_t *J;
- int w,h,x,y,i,j,N;
- int ww,hh;
- uint32_t center;
- uint32_t offset;
- uint8_t pattern;
-
- if( nrhs != 2 )
- mexErrMsgTxt("Two input arguments required.\n\n"
- "LBPPYR computes LBP features on scale-pyramid of input image.\n"
- "Synopsis:\n"
- " F = lbppyr(I, P)\n"
- "where\n"
- " I [H x W (uint8)] is input image.\n"
- " P [1 x 1 (double)] is height of the scale-pyramid.\n"
- " F [N x 1 (uint8)] LBP features stucked to a column vector. \n");
-
- I = (uint8_t*)mxGetPr(prhs[0]);
- K = (uint8_t)mxGetScalar(prhs[1]);
-
- h = mxGetM(prhs[0]);
- w = mxGetN(prhs[0]);
-
- /* printf("h: %d\n", h);
- printf("w: %d\n", w);
- printf("K: %d\n", K);
- */
-
- /* count number of LBPs */
- for(ww=w, hh=h, N=0, i=0; i < K && MIN(ww,hh) >= 3; i++)
- {
- N += (ww-2)*(hh-2);
-
- if(ww % 2) ww--;
- if(hh % 2) hh--;
- ww = ww/2;
- hh = hh/2;
- }
- K = i;
- N = 256*N;
-
-/* printf("N: %d (=256*%d)\n", N,N/256);*/
-/* printf("K: %d\n",K);*/
- /* printf("%d/%d = %d*%d + %d \n", b,a, a, b/a, b % a);*/
-
- plhs[0] = mxCreateNumericMatrix(N, 1, mxUINT32_CLASS, mxREAL);
- P = (uint32_t*)mxGetPr(plhs[0]);
-
- J = mxCalloc(h*w, sizeof(uint32_t));
- if(J ==NULL)
- mexErrMsgTxt("Not enough memory.");
-
- for(x=0; x < w; x++)
- for(y=0; y < h; y++)
- J[INDEX(y,x,h)] = I[INDEX(y,x,h)];
-
- for(ww=w, hh=h, i=0, offset = 0; i < K; i++)
- {
- for(x=1; x < ww-1; x++)
- {
- for(y=1; y< hh-1; y++)
- {
- pattern = 0;
- center = J[INDEX(y,x,h)];
- if(J[INDEX(y-1,x-1,h)] < center) pattern = pattern | 0x01;
- if(J[INDEX(y-1,x,h)] < center) pattern = pattern | 0x02;
- if(J[INDEX(y-1,x+1,h)] < center) pattern = pattern | 0x04;
- if(J[INDEX(y,x-1,h)] < center) pattern = pattern | 0x08;
- if(J[INDEX(y,x+1,h)] < center) pattern = pattern | 0x10;
- if(J[INDEX(y+1,x-1,h)] < center) pattern = pattern | 0x20;
- if(J[INDEX(y+1,x,h)] < center) pattern = pattern | 0x40;
- if(J[INDEX(y+1,x+1,h)] < center) pattern = pattern | 0x80;
-
- /* P[cnt++] = pattern; */
- P[offset+pattern] = 1;
- offset += 256;
- }
- }
-
- if( i < K-1 )
- {
- if(ww % 2 == 1) ww--;
- if(hh % 2 == 1) hh--;
-
- ww = ww/2;
- for(x=0; x < ww; x++)
- for(j=0; j < hh; j++)
- J[INDEX(j,x,h)] = J[INDEX(j,2*x,h)] + J[INDEX(j,2*x+1,h)];
-
- hh = hh/2;
- for(y=0; y < hh; y++)
- for(j=0; j < ww; j++)
- J[INDEX(y,j,h)] = J[INDEX(2*y,j,h)] + J[INDEX(2*y+1,j,h)];
- }
-
- }
-
- return;
-}
-
diff --git a/libocas.so b/libocas.so
new file mode 100755
index 0000000..41a9953
Binary files /dev/null and b/libocas.so differ
diff --git a/libocas_test.m b/libocas_test.m
index 4e0847e..d2b1aef 100644
--- a/libocas_test.m
+++ b/libocas_test.m
@@ -1,171 +1,287 @@
-% This script tests functionality of SVMOCAS and MSVMOCAS solvers.
+% This script tests functionality of SVM solvers implemneted in the LIBOCAS.
%
-% It runs the solvers on example data and compares results to solutions
-% stored in reference files.
-%
+% The script runs SVM solvers on example data (in ./data/) and compares
+% the obtained results with the solutions stored in reference files.
+%
+% This script is useful to check potential bugs e.g. introduced when
+% changing the library code.
+%
+
+% jump to root dir of libocas
+cd(fileparts(which('svmocas')));
% two-class problem
-BinaryTrnFile = './data/riply_trn.light';
+TWO_CLASS_PROBLEM = './data/riply_trn.mat';
+
+% two-class problem in SVM^light format
+TWO_CLASS_PROBLEM_SVMLIGHT = './data/riply_trn.light';
% multi-class problem
-MulticlassTrnFile = './data/example4_train.light';
+MULTI_CLASS_PROBLEM = './data/example4_train.mat';
+
+% multi-class problem in SVM^light format
+MULTI_CLASS_PROBLEM_SVMLIGHT = './data/example4_train.light';
+
+% gender classification (male vs. female) from face images
+GENDER_IMAGE_DATABASE = './data/gender_images.mat';
% file to store/load reference solution
-ReferenceFile = './data/refernce_solution';
+ReferenceFile = './data/reference_solution';
% if 1 save results to reference files else compares the results to the
-% reference solutions
+% reference solutions;
CREATE_REFERNCE_FILES = 0;
-% Solver options
+%% Solver settings
opt.C = 1;
opt.Method = 1;
opt.TolRel = 0.01;
opt.TolAbs = 0;
opt.QPBound = 0;
-opt.BufSize = 2000;
+opt.BufSize = 500;
opt.MaxTime = inf;
opt.X0 = 1;
opt.verb = 0;
-fprintf('Training binary SVM classifier by SVMOCAS...');
-[bin.W,bin.W0,bin.stat] = svmocas(BinaryTrnFile,opt.X0,opt.C,opt.Method,opt.TolRel,...
- opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+%% run all solvers for different inputs
+
+% SVMOCAS for dense double features
+fprintf('SVMOCAS: training two-class SVM classifier from dense features in double precision ...');
+data = load( TWO_CLASS_PROBLEM );
+[svmocasResults.W,svmocasResults.W0,svmocasResults.stat] = ...
+ svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
fprintf('done.\n');
-fprintf('Training multi-class SVM classifier by MSVMOCAS...');
-[multi.W,multi.stat] = msvmocas(MulticlassTrnFile,opt.C,opt.Method,opt.TolRel,...
- opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+% SVMOCAS for dense single prec. features
+fprintf('SVMOCAS: training two-class SVM classifier from dense features in single precision ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = single(data.X);
+[svmocasSingleResults.W,svmocasSingleResults.W0,svmocasSingleResults.stat] = ...
+ svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
fprintf('done.\n');
+% SVMOCAS for sparse double features
+fprintf('SVMOCAS: training two-class SVM classifier from sparse features in double precision ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = sparse(data.X);
+[svmocasSparseResults.W,svmocasSparseResults.W0,svmocasSparseResults.stat] = ...
+ svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% SVMOCAS for INT8 features
+fprintf('SVMOCAS: training two-class SVM classifier from dense int8 features ...');
+data = load( TWO_CLASS_PROBLEM );
+data.X = int8(100*data.X);
+[svmocasInt8Results.W,svmocasInt8Results.W0,svmocasInt8Results.stat] = ...
+ svmocas(data.X,opt.X0,data.y, opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
-if CREATE_REFERNCE_FILES == 1,
+% SVMOCAS_LIGHT
+fprintf('SVMOCAS_LIGHT: training two-class SVM classifier from examples stored in SVM^light file ...');
+[svmocasLightResults.W,svmocasLightResults.W0,svmocasLightResults.stat] = ...
+ svmocas_light(TWO_CLASS_PROBLEM_SVMLIGHT,opt.X0, opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% SVMOCAS_LBP
+fprintf('SVMOCAS_LBP: training two-class SVM classifier from LBP features computed on images ...');
+data = load( GENDER_IMAGE_DATABASE );
+HEIGHT_OF_LBP_PYRAMID = 4;
+BASE_WINDOW_SIZE = [60 40];
+numMaleImages = size(data.trn_male_images,2);
+numFemaleImages = size(data.trn_male_images,2);
+wins = [ [1:numMaleImages numMaleImages+[1:numFemaleImages]]; ...
+ repmat([20;15;0],1,numFemaleImages+numMaleImages)];
+labels = [ones(1,numMaleImages) -ones(1,numFemaleImages)];
+[svmocasLBPResults.W,svmocasLBPResults.W0,svmocasLBPResults.stat] = ...
+ svmocas_lbp([data.trn_male_images data.trn_female_images], data.IMAGE_SIZE,...
+ uint32(wins), BASE_WINDOW_SIZE, HEIGHT_OF_LBP_PYRAMID, opt.X0, labels, 0.001*opt.C, ...
+ opt.Method, opt.TolRel,opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% MSVMOCAS
+fprintf('MSVMOCAS: training multi-class SVM classifier from dense features in double precision ...');
+data = load( MULTI_CLASS_PROBLEM );
+[msvmocasResults.W,msvmocasResults.stat] = ...
+ msvmocas(data.X,data.y,opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+% MSVMOCAS_LIGHT
+fprintf('MSVMOCAS_LIGHT: training multi-class SVM classifier from examples stored in SVM^light file ...');
+[msvmocasLightResults.W,msvmocasLightResults.stat] = ...
+ msvmocas_light(MULTI_CLASS_PROBLEM_SVMLIGHT,opt.C,opt.Method,opt.TolRel,...
+ opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime,opt.verb);
+fprintf('done.\n');
+
+if CREATE_REFERNCE_FILES == 1,
+ %% save reference solutions to file
fprintf('Saving reference solutions to %s\n', ReferenceFile);
- save(ReferenceFile,'bin','multi');
+ save(ReferenceFile,'svmocasResults','svmocasSparseResults','msvmocasResults',...
+ 'svmocasInt8Results','svmocasLBPResults','svmocasSingleResults', ...
+ 'svmocasLightResults','msvmocasLightResults');
+
else
+ %% compare obtained solutions to those stored in the reference file
ref = load(ReferenceFile);
-
- test(1).dif = sum(abs(bin.W - ref.bin.W)+abs(bin.W0-ref.bin.W0));
+
+ test = [];
+
+ % SVMOCAS for dense double features
+ test(1).dif = sum(abs(svmocasResults.W - ref.svmocasResults.W) + ...
+ abs(svmocasResults.W0-ref.svmocasResults.W0));
test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
- test(2).dif = abs(bin.stat.Q_P - ref.bin.stat.Q_P);
+ test(2).dif = abs(svmocasResults.stat.Q_P - ref.svmocasResults.stat.Q_P);
test(2).name = 'PrimalVal - ref.PrimalVal ';
- test(3).dif = abs(bin.stat.Q_D - ref.bin.stat.Q_D);
+ test(3).dif = abs(svmocasResults.stat.Q_D - ref.svmocasResults.stat.Q_D);
test(3).name = 'DualVal - ref.DualVal ';
- fprintf('\nSVMOCAS (solver for binary classifiation problems):\n');
+ fprintf('\nSVMOCAS for dense features in double precision:\n');
for i=1:length(test)
fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
if test(i).dif == 0
fprintf('SOLUTIONS EQUAL - OK\n');
else
- fprintf('SOLUTION DIFFERS\n');
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
+
+ % SVMOCAS for dense single precision features
+ test(1).dif = sum(abs(svmocasSingleResults.W - ref.svmocasSingleResults.W) + ...
+ abs(svmocasSingleResults.W0-ref.svmocasSingleResults.W0));
+ test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+ test(2).dif = abs(svmocasSingleResults.stat.Q_P - ref.svmocasSingleResults.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal ';
+ test(3).dif = abs(svmocasSingleResults.stat.Q_D - ref.svmocasSingleResults.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+
+ fprintf('\nSVMOCAS for dense features in single precision:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
+
+ % SVMOCAS for sparse double features
+ test(1).dif = sum(abs(svmocasSparseResults.W - ref.svmocasSparseResults.W) + ...
+ abs(svmocasSparseResults.W0-ref.svmocasSparseResults.W0));
+ test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+ test(2).dif = abs(svmocasSparseResults.stat.Q_P - ref.svmocasSparseResults.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal ';
+ test(3).dif = abs(svmocasSparseResults.stat.Q_D - ref.svmocasSparseResults.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+
+ fprintf('\nSVMOCAS for sparse features in double precision:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
+
+ % SVMOCAS for dense INT8 features
+ test(1).dif = sum(abs(svmocasInt8Results.W - ref.svmocasInt8Results.W) + ...
+ abs(svmocasInt8Results.W0-ref.svmocasInt8Results.W0));
+ test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+ test(2).dif = abs(svmocasInt8Results.stat.Q_P - ref.svmocasInt8Results.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal ';
+ test(3).dif = abs(svmocasInt8Results.stat.Q_D - ref.svmocasInt8Results.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+
+ fprintf('\nSVMOCAS for dense int8 features:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
+
+ % SVMOCAS_LIGHT
+ test(1).dif = sum(abs(svmocasLightResults.W - ref.svmocasLightResults.W) + ...
+ abs(svmocasLightResults.W0-ref.svmocasLightResults.W0));
+ test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+ test(2).dif = abs(svmocasLightResults.stat.Q_P - ref.svmocasLightResults.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal ';
+ test(3).dif = abs(svmocasLightResults.stat.Q_D - ref.svmocasLightResults.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+
+ fprintf('\nSVMOCAS_LIGHT:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
end
end
-
- test(1).dif = sum(sum(abs(multi.W - ref.multi.W)));
+
+ % SVMOCAS_LBP
+ test(1).dif = sum(abs(svmocasLBPResults.W - ref.svmocasLBPResults.W) + ...
+ abs(svmocasLBPResults.W0-ref.svmocasLBPResults.W0));
+ test(1).name = 'sum(|W-ref.W| + |W0-ref.W0])';
+ test(2).dif = abs(svmocasLBPResults.stat.Q_P - ref.svmocasLBPResults.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal ';
+ test(3).dif = abs(svmocasLBPResults.stat.Q_D - ref.svmocasLBPResults.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+
+ fprintf('\nSVMOCAS_LBP:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name,test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
+
+ % MSVMOCAS
+ test(1).dif = sum(sum(abs(msvmocasResults.W - ref.msvmocasResults.W)));
test(1).name = 'sum(|W-ref.W|) ';
- test(2).dif = abs(multi.stat.Q_P - ref.multi.stat.Q_P);
+ test(2).dif = abs(msvmocasResults.stat.Q_P - ref.msvmocasResults.stat.Q_P);
test(2).name = 'PrimalVal - ref.PrimalVal';
- test(3).dif = abs(multi.stat.Q_D - ref.multi.stat.Q_D);
+ test(3).dif = abs(msvmocasResults.stat.Q_D - ref.msvmocasResults.stat.Q_D);
test(3).name = 'DualVal - ref.DualVal ';
- fprintf('\nMSVMOCAS: (solver for multi-class problems\n');
+ fprintf('\nMSVMOCAS:\n');
for i=1:length(test)
fprintf(' %s = %.20f ... ',test(i).name, test(i).dif);
if test(i).dif == 0
fprintf('SOLUTIONS EQUAL - OK\n');
else
- fprintf('SOLUTION DIFFERS\n');
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
end
- end
+ end
+ % MSVMOCAS_LIGHT
+ test(1).dif = sum(sum(abs(msvmocasLightResults.W - ref.msvmocasLightResults.W)));
+ test(1).name = 'sum(|W-ref.W|) ';
+ test(2).dif = abs(msvmocasLightResults.stat.Q_P - ref.msvmocasLightResults.stat.Q_P);
+ test(2).name = 'PrimalVal - ref.PrimalVal';
+ test(3).dif = abs(msvmocasLightResults.stat.Q_D - ref.msvmocasLightResults.stat.Q_D);
+ test(3).name = 'DualVal - ref.DualVal ';
+ fprintf('\nMSVMOCAS_LIGHT:\n');
+ for i=1:length(test)
+ fprintf(' %s = %.20f ... ',test(i).name, test(i).dif);
+ if test(i).dif == 0
+ fprintf('SOLUTIONS EQUAL - OK\n');
+ else
+ fprintf('SOLUTION IS DIFFERENT!!!\n');
+ end
+ end
end
+% EOF
-break;
-for i=1:length(DataSets)
- fprintf('\nDataset: %s\n', DataSets{i});
-
- [exp{i}.W,exp{i}.W0,exp{i}.stat] = svmocas(DataSets{i},opt.X0,opt.C,opt.Method,...
- opt.TolRel,opt.TolAbs,opt.QPBound,opt.BufSize,inf,opt.MaxTime);
-end
-
-fprintf('\n\nRESULTS SUMMARY\n================================\n\n');
-for i=1:length(DataSets)
- fprintf('\nDataset: %s\n--------------------------------\n', DataSets{i});
-
- % remove suffix
- sol_fname = DataSets{i};
- idx = findstr(sol_fname,'.');
- sol_fname = sol_fname(1:idx(end)-1);
-
- sol_fname = [sol_fname '_ocas_C' num2str(opt.C) '_solution.mat'];
- if SAVE_AS_REFERENCE,
- if exist(sol_fname)
- fprintf('Solution file %s already exists.\n', sol_fname);
- error('Erase the file or set SAVE_AS_REFERENCE = 0 and run the test again.');
- else
- fprintf('Saving solution to %s ...', sol_fname);
- ref_sol = exp{i};
- ref_opt = opt;
- save(sol_fname,'ref_sol','ref_opt');
- fprintf('done.\n');
- ref_sol = [];
- end
- else
- if exist(sol_fname)
- load(sol_fname,'ref_sol','ref_opt');
-
- fprintf('\nReference solution\n');
- fprintf('file: %s\n', sol_fname);
- fprintf(['settings: C: %f, Method: %d, TolRel: %f, TolAbs: %f, ' ...
- 'QPBound: %f, BufSize: %d, MaxTime: %f, X0: %f \n'], ...
- ref_opt.C, ref_opt.Method, ref_opt.TolRel, ref_opt.TolAbs, ...
- ref_opt.QPBound, ref_opt.BufSize, ref_opt.MaxTime, ref_opt.X0);
- fprintf(['solution: QP: %.10f, QD: %.10f, nIter: %d, nCutPlanes: %d, '...
- 'exitflag: %d, ocas_time: %f, total_time: %f\n'],...
- ref_sol.stat.Q_P, ref_sol.stat.Q_D, ref_sol.stat.nIter, ref_sol.stat.nCutPlanes, ...
- ref_sol.stat.exitflag, ref_sol.stat.ocas_time, ref_sol.stat.total_time);
- end
- end
-
- fprintf('\nCurrent solution \n');
- fprintf(['settings: C: %f, Method: %d, TolRel: %f, TolAbs: %f, ' ...
- 'QPBound: %f, BufSize: %d, MaxTime: %f, X0: %f \n'], ...
- opt.C, opt.Method, opt.TolRel, opt.TolAbs, ...
- opt.QPBound, opt.BufSize, opt.MaxTime, opt.X0);
- fprintf(['solution: QP: %.10f, QD: %.10f, nIter: %d, nCutPlanes: %d, '...
- 'exitflag: %d, ocas_time: %f, total_time: %f\n'],...
- exp{i}.stat.Q_P, exp{i}.stat.Q_D, exp{i}.stat.nIter, exp{i}.stat.nCutPlanes, ...
- exp{i}.stat.exitflag, exp{i}.stat.ocas_time, exp{i}.stat.total_time);
-
- if ~isempty(ref_sol)
- opt_dif = any([opt.Method~=ref_opt.Method opt.C~=ref_opt.C opt.TolRel ~= ref_opt.TolRel ...
- opt.TolAbs~=ref_opt.TolAbs opt.QPBound~=ref_opt.QPBound ...
- opt.BufSize~=ref_opt.BufSize opt.MaxTime~=ref_opt.MaxTime opt.X0~=ref_opt.X0]);
- sol_dif = max(max(abs(exp{i}.W-ref_sol.W)),abs(exp{i}.W0-ref_sol.W0));
- fprintf('\nSolution difference: max(abs(ref.W-W)) = %f. Solutions are ', sol_dif);
- if ~sol_dif
- fprintf('EQUAL.\n');
- else
- fprintf('DIFFERENT.\n');
- end
- fprintf('Current and refrence settings are ');
- if ~opt_dif
- fprintf('EQUAL.\n');
- else
- fprintf('DIFFERENT.\n');
- end
- fprintf('Comparison result: ');
- if sol_dif && ~opt_dif ,
- fprintf('THIS IS NOT GOOD ... BUT DON''T PANIC.\n');
- elseif ~sol_dif && ~opt_dif
- fprintf('OK.\n');
- elseif opt_dif
- fprintf('UNDECIDED since options are different.\n');
- end
-
- end
-end
diff --git a/linclassif b/linclassif
new file mode 100755
index 0000000..b5c20eb
Binary files /dev/null and b/linclassif differ
diff --git a/linclass.c b/linclassif.c
similarity index 96%
rename from linclass.c
rename to linclassif.c
index 7cb99d5..b62211d 100644
--- a/linclass.c
+++ b/linclassif.c
@@ -1,9 +1,9 @@
/*-----------------------------------------------------------------------
- * linclass.c: Implementation of linear classification rule classifying
+ * linclassif.c: Implementation of linear classification rule classifying
* examples from the SVM^light format.
*
- * Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
- * Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+ * Copyright (C) 2008-2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
@@ -26,7 +26,7 @@
void print_usage(void)
{
- printf("LINCLASS: Predict labels by linear classication rule\n"
+ printf("LINCLASSIF: Predict labels by linear classication rule\n"
" " OCAS_VERSION "\n"
"\n"
" usage: linclass [options] example_file model_file\n"
@@ -48,11 +48,11 @@ void print_usage(void)
"Examples\n"
" Train SVM classifier from riply_trn.light with regularization constant C = 10,\n"
" bias switched on, verbosity switched off and model saved to svmocas.model\n"
- " ./svmocas -c 10 -b 1 -v 0 riply_trn.light svmocas.model \n"
+ " ./svmocas -c 10 -b 1 -v 0 ./data/riply_trn.light ./data/svmocas.model \n"
"\n"
" Compute testing error of the classifier stored in svmocas.model using testing\n"
" examples from riply_tst.light and save predicted labels to riply_tst.pred\n"
- " ./linclass -e -o riply_tst.pred riply_tst.light svmocas.model\n"
+ " ./linclassif -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
"\n"
);
}
diff --git a/svmlight_linclass.m b/linclassif_light.m
similarity index 53%
rename from svmlight_linclass.m
rename to linclassif_light.m
index 1b8f84c..ff7e601 100644
--- a/svmlight_linclass.m
+++ b/linclassif_light.m
@@ -1,17 +1,20 @@
% SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.
%
% Synopsis:
-% [score,true_lab] = svmlight_linclass(data_file,W,[])
-% [score,true_lab] = svmlight_linclass(data_file,W,W0)
-% [score,true_lab] = svmlight_linclass(data_file,W,W0,verb)
+% [score,trueLabels] = linclassif_light(dataFile,W,[])
+% [score,trueLabels] = linclassif_light(dataFile,W,W0)
+% [score,trueLabels] = linclassif_light(dataFile,W,W0,verb)
%
% Input:
-% data_file [string] Path to file with examples stored in SVM^light format.
+% dataFile [string] File with examples stored in the SVM^light format.
% W [nDims x nModels] Parameter vectors of nModels linear classifiers.
% W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used.
% verb [1x1] If ~= 0 then prints info (default 0).
%
% Output:
% score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)
-% true_labels [nExamples x 1] labels from the data_file
+% trueLabels [nExamples x 1] labels from the dataFile
+%
+% Example:
+% help svmocas_light
%
diff --git a/linclassif_light.mexa64 b/linclassif_light.mexa64
new file mode 100755
index 0000000..a13e38f
Binary files /dev/null and b/linclassif_light.mexa64 differ
diff --git a/svmlight_linclass_mex.c b/linclassif_light_mex.c
similarity index 74%
rename from svmlight_linclass_mex.c
rename to linclassif_light_mex.c
index cfedb55..1378f40 100644
--- a/svmlight_linclass_mex.c
+++ b/linclassif_light_mex.c
@@ -1,23 +1,22 @@
-/*=================================================================
- * SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.
- *
- * Synopsis:
- * [score,true_lab] = svmlight_linclass(data_file,W,[])
- * [score,true_lab] = svmlight_linclass(data_file,W,W0)
- * [score,true_lab] = svmlight_linclass(data_file,W,W0,verb)
- *
- *
- * Input:
- * data_file [string] Path to file with examples stored in SVM^light format.
- * W [nDims x nModels] Parameter vectors of nModels linear classifiers.
- * W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used.
- * verb [1x1] If ~= 0 then prints info (default 0).
- *
- * Output:
- * score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)
- * true_labels [nExamples x 1] labels from the data_file
- *
- *=================================================================*/
+/*==============================================================================
+* SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule. *
+* *
+* Synopsis: *
+* [score,trueLabels] = svmlight_linclass(dataFile,W,[]) *
+* [score,trueLabels] = svmlight_linclass(dataFile,W,W0) *
+* [score,trueLabels] = svmlight_linclass(dataFile,W,W0,verb) *
+* *
+* Input: *
+* dataFile [string] Path to file with examples stored in SVM^light format. *
+* W [nDims x nModels] Parameter vectors of nModels linear classifiers. *
+* W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used. *
+* verb [1x1] If ~= 0 then prints info (default 0). *
+* *
+* Output: *
+* score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i) *
+* trueLabels [nExamples x 1] labels from the dataFile *
+* *
+*===============================================================================*/
#define _FILE_OFFSET_BITS 64
@@ -131,11 +130,22 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
int verb = 0;
double *auc;
- if( nrhs < 3 )
- mexErrMsgTxt("At least three input arguments must be passed.");
-
- if( nrhs > 4)
- mexErrMsgTxt("At most four input arguments must be passed.");
+ if( nrhs <3 || nrhs > 4)
+ mexErrMsgTxt("SVMLIGHT_LINCLASS classifies examples in SVM^light file by linear rule.\n"
+ "\n"
+ " [score,trueLabels] = svmlight_linclass(dataFile,W,[])\n"
+ " [score,trueLabels] = svmlight_linclass(dataFile,W,W0)\n"
+ " [score,trueLabels] = svmlight_linclass(dataFile,W,W0,verb)\n"
+ "\n"
+ "Input:\n"
+ " dataFile [string] Path to file with examples stored in SVM^light format.\n"
+ " W [nDims x nModels] Parameter vectors of nModels linear classifiers.\n"
+ " W0 [nModels x 1] Bias of decision rule. If W0 is empty then W0 = 0 is used.\n"
+ " verb [1x1] If ~= 0 then prints info (default 0).\n"
+ "\n"
+ "Output:\n"
+ " score [nModels x nExamples] score(i,j) = W(:,i)'*X_j + W0(i)\n"
+ " trueLabels [nExamples x 1] labels from the dataFile\n");
if( nrhs == 4)
verb = (int)mxGetScalar(prhs[3]);
@@ -258,7 +268,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
mexErrMsgTxt("Not enought memory to allocate buffer for score.");
score = (double*)mxGetPr(plhs[0]);
- plhs[1] = (mxArray*)mxCreateDoubleMatrix(line_cnt,1,mxREAL);
+ plhs[1] = (mxArray*)mxCreateDoubleMatrix(1,line_cnt,mxREAL);
if(plhs[1] == NULL)
mexErrMsgTxt("Not enought memory to allocate buffer for true_labels.");
true_lab = (double*)mxGetPr(plhs[1]);
diff --git a/msvmocas b/msvmocas
new file mode 100755
index 0000000..0d7e283
Binary files /dev/null and b/msvmocas differ
diff --git a/msvmocas.c b/msvmocas.c
index 59c1d4a..f8067f5 100644
--- a/msvmocas.c
+++ b/msvmocas.c
@@ -21,6 +21,7 @@
#include "libocas.h"
#include "sparse_mat.h"
#include "ocas_helper.h"
+#include "features_double.h"
#include "version.h"
@@ -62,7 +63,7 @@ void print_usage(void)
"\n"
" Compute testing error of the classifier stored in ./data/msvmocas.model using testing\n"
" examples from ./data/example4_test.light and save predicted labels to ./data/example4_test.pred\n"
- " ./linclass -e -o ./data/exaple4_test.pred ./data/example4_test.light ./data/msvmocas.model\n"
+ " ./linclassif -e -o ./data/exaple4_test.pred ./data/example4_test.light ./data/msvmocas.model\n"
"\n"
);
}
@@ -412,13 +413,13 @@ int main(int argc, char *argv[])
printf("Starting optimization:\n");
ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
+ &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
&msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
}
else
{
ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
+ &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
&msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
}
}
@@ -437,13 +438,13 @@ int main(int argc, char *argv[])
printf("Starting optimization:\n");
ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
+ &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
&msvm_full_compute_output, &qsort_data, &ocas_print, 0);
}
else
{
ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
+ &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
&msvm_full_compute_output, &qsort_data, &ocas_print_null, 0);
}
diff --git a/msvmocas.m b/msvmocas.m
index 6a48dd0..a2a5b4f 100644
--- a/msvmocas.m
+++ b/msvmocas.m
@@ -1,8 +1,7 @@
-% MSVMOCAS Train multi-class linear SVM classifier using OCAS solver.
+% MSVMOCAS OCAS solver for training multi-class linear SVM classifiers.
%
% Synopsis:
% [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
-% [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
%
% Desription:
% This function trains multi-class linear SVM classifier by solving
@@ -10,16 +9,16 @@
% W^* = argmin 0.5*sum_y (W(:,y)'*W(:,y)) + C* sum max( (y~=y(i)) + (W(:,y) - W(:,y(i))'*X(:,i))
% W i=1:nData y
%
-% The function accepts examples either in Matlab matrix X (both sparse and dense) and
-% a dense vector y or as path to a file in SVM^light format.
+% The function accepts examples either in Matlab matrix X both sparse and
+% dense matrix.
%
% Reference:
-% V. Franc, S. Sonnenburg. To be published. 2009
+% V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+% Minimization. Journal of Machine Learning Research. 2009
+% http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
%
% Input:
-% data_file [string] Training examples stored in SVM^light format.
-%
-% X [nDim x nExamples] training inputs (sparse or dense matrix).
+% X [nDim x nExamples] training inputs (sparse or dense matrix of doubles).
% y [nExamples x 1] labels; intgers 1,2,...nY
% C [1x1] regularization constant
% Method [1x1] 0..cutting plane; 1..OCAS (default 1)
@@ -38,19 +37,16 @@
% stat [struct] Optimizer statistics (field names are self-explaining).
%
% Example:
-% C = 1;
-%
-% % case 1: loading data directly from file in SVM^light format
-% [W,stat] = msvmocas('example4_train.light',C);
-%
-% % case 2: using data loaded in Matlab
-% load('example4_train','X','y');
-% [W,stat] = msvmocas(X,y,C);
-%
-% % classification
-% load('example4_test.mat','X','y');
-% [dummy,ypred] = max(W'*X);
-% sum(ypred(:) ~= y(:))/length(y)
+% % training
+% libocasPath = fileparts(which('svmocas'));
+% trn = load([libocasPath '/data/example4_train.mat'],'X','y');
+% svmC = 1;
+% [W,stat] = msvmocas(trn.X,trn.y,svmC);
+%
+% % classifying test examples
+% tst = load([libocasPath '/data/example4_test.mat'],'X','y');
+% [dummy,ypred] = max(W'*tst.X);
+% sum(ypred(:) ~= tst.y(:))/length(tst.y)
%
%
diff --git a/msvmocas.mexa64 b/msvmocas.mexa64
new file mode 100755
index 0000000..f905495
Binary files /dev/null and b/msvmocas.mexa64 differ
diff --git a/msvmocas.m b/msvmocas_light.m
similarity index 62%
copy from msvmocas.m
copy to msvmocas_light.m
index 6a48dd0..f81219c 100644
--- a/msvmocas.m
+++ b/msvmocas_light.m
@@ -1,8 +1,8 @@
-% MSVMOCAS Train multi-class linear SVM classifier using OCAS solver.
+% MSVMOCAS_LIGHT OCAS solver for training multi-class linear SVM classifier from SVM^light file.
+%
%
% Synopsis:
-% [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
-% [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+% [W,stat] = msvmocas_light(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
%
% Desription:
% This function trains multi-class linear SVM classifier by solving
@@ -10,16 +10,15 @@
% W^* = argmin 0.5*sum_y (W(:,y)'*W(:,y)) + C* sum max( (y~=y(i)) + (W(:,y) - W(:,y(i))'*X(:,i))
% W i=1:nData y
%
-% The function accepts examples either in Matlab matrix X (both sparse and dense) and
-% a dense vector y or as path to a file in SVM^light format.
+% The function loads examples from dataFile in SVM^light format.
%
% Reference:
-% V. Franc, S. Sonnenburg. To be published. 2009
+% V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+% Minimization. Journal of Machine Learning Research. 2009
+% http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
%
% Input:
-% data_file [string] Training examples stored in SVM^light format.
-%
-% X [nDim x nExamples] training inputs (sparse or dense matrix).
+% dataFile [string] path to file with training examples in SVM^light format.
% y [nExamples x 1] labels; intgers 1,2,...nY
% C [1x1] regularization constant
% Method [1x1] 0..cutting plane; 1..OCAS (default 1)
@@ -38,19 +37,15 @@
% stat [struct] Optimizer statistics (field names are self-explaining).
%
% Example:
-% C = 1;
-%
-% % case 1: loading data directly from file in SVM^light format
-% [W,stat] = msvmocas('example4_train.light',C);
-%
-% % case 2: using data loaded in Matlab
-% load('example4_train','X','y');
-% [W,stat] = msvmocas(X,y,C);
-%
-% % classification
-% load('example4_test.mat','X','y');
-% [dummy,ypred] = max(W'*X);
-% sum(ypred(:) ~= y(:))/length(y)
+% % training
+% libocasPath = fileparts(which('svmocas'));
+% svmC = 1;
+% [W,stat] = msvmocas_light([libocasPath '/data/example4_train.light'],svmC);
+%
+% % classifying test examples
+% [score,trueLabels] = linclassif_light([libocasPath '/data/example4_test.light'],W,[]);
+% [dummy,ypred] = max(score);
+% sum(ypred~=trueLabels)/length(trueLabels)
%
%
diff --git a/msvmocas_light.mexa64 b/msvmocas_light.mexa64
new file mode 100755
index 0000000..f7a1d4b
Binary files /dev/null and b/msvmocas_light.mexa64 differ
diff --git a/msvmocas_test.m b/msvmocas_light_example.m
similarity index 72%
rename from msvmocas_test.m
rename to msvmocas_light_example.m
index 55d8e5c..4bda560 100644
--- a/msvmocas_test.m
+++ b/msvmocas_light_example.m
@@ -1,5 +1,5 @@
-trn_file = 'example4_train.light';
-tst_file = 'example4_test.light';
+trn_file = './data/example4_train.light';
+tst_file = './data/example4_test.light';
C = 1;
TolRel = 0.01;
@@ -10,13 +10,13 @@ nData = inf;
MaxTime = inf;
verb = 0;
-Method = 0; % Cutting Plane Algorithm
+Method = 0; % standard BMRM alias Cutting Plane Algorithm
fprintf('Training SVM by Cutting Plane Algorithm...');
-[cp_W,cp_stat] = msvmocas(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
+[cp_W,cp_stat] = msvmocas_light(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
fprintf('done\n');
fprintf('Evaluating classifier on testing data...');
-[score,true_labels] = svmlight_linclass(tst_file,cp_W,[]);
+[score,true_labels] = linclassif_light(tst_file,cp_W,[]);
[dummy,pred_labels] = max(score);
cp_tst_err = sum(pred_labels(:) ~= true_labels(:))/length(true_labels);
fprintf('done\n');
@@ -31,11 +31,11 @@ fprintf('Testing error: %f %%\n',cp_tst_err*100);
Method = 1; % OCAS
fprintf('\nTraining SVM by OCAS...');
-[ocas_W,ocas_stat] = msvmocas(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
+[ocas_W,ocas_stat] = msvmocas_light(trn_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb);
fprintf('done\n');
fprintf('Evaluating classifier on testing data...');
-[score,true_labels] = svmlight_linclass(tst_file,ocas_W,[]);
+[score,true_labels] = linclassif_light(tst_file,ocas_W,[]);
[dummy,pred_labels] = max(score);
ocas_tst_err = sum(pred_labels(:) ~= true_labels(:))/length(true_labels);
fprintf('done\n');
diff --git a/msvmocas_mex.c b/msvmocas_light_mex.c
similarity index 53%
copy from msvmocas_mex.c
copy to msvmocas_light_mex.c
index 330972e..43b4373 100644
--- a/msvmocas_mex.c
+++ b/msvmocas_light_mex.c
@@ -1,12 +1,30 @@
/*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+ * msvmocas_light_mex.c: OCAS solver for training multi-class linear SVM classifiers
+ * loading examples from SVM^light file.
*
* Synopsis:
- * [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- * [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ * [W,stat] = msvmocas_light(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+ *
+ * Input:
+ * dataFile [string] path to file with training examples in SVM^light format
+ * X [nDim x nExamples] training feature inputs (sparse or dense matrix of doubles).
+ * y [nExamples x 1] labels; intgers 1,2,...nY
+ * C [1x1] regularization constant
+ * Method [1x1] 0..cutting plane; 1..OCAS (default 1)
+ * TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel (default 0.01)
+ * TolAbs [1x1] halts if Q_P-Q_D <= TolAbs (default 0)
+ * QPValue [1x1] halts if Q_P <= QPBpound (default 0)
+ * BufSize [1x1] Initial size of active constrains buffer (default 2000)
+ * nExamples [1x1] Number of training examplesused for training; must be >0 and <= size(X,2).
+ * If nExamples = inf then nExamples is set to size(X,2).
+ * MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds
+ * MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.
+ * verb [1x1] if non-zero then prints some info; (default 1)
*
- * Synopsis:
- * [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)
+ * Output:
+ * W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)
+ * stat [struct] Optimizer statistics (field names are self-explaining).
+ *
* Copyright (C) 2008 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
*
* This program is free software; you can redistribute it and/or
@@ -23,6 +41,7 @@
#include "libocas.h"
#include "ocas_helper.h"
+#include "features_double.h"
#define DEFAULT_METHOD 1
#define DEFAULT_TOLREL 0.01
@@ -54,152 +73,101 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
total_time = get_time();
init_time = total_time;
- if(nrhs < 1)
- mexErrMsgTxt("Improper number of input arguments.");
-
- /* get input arguments */
- if(mxIsChar(prhs[0]) == false)
- {
-
- if(nrhs < 3 || nrhs > 11)
- mexErrMsgTxt("Improper number of input arguments.");
-
- /* [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-
- data_X = (mxArray*)prhs[0];
- if (!(mxIsDouble(data_X)))
- mexErrMsgTxt("Input argument X must be of type double.");
-
- if (mxGetNumberOfDimensions(data_X) != 2)
- mexErrMsgTxt("Input argument X must be two dimensional.");
-
- data_y = (double*)mxGetPr(prhs[1]);
-
- if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
- mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
-
- C = (double)mxGetScalar(prhs[2]);
-
- if(nrhs >= 4)
- Method = (uint32_t)mxGetScalar(prhs[3]);
- else
- Method = DEFAULT_METHOD;
-
- if(nrhs >= 5)
- TolRel = (double)mxGetScalar(prhs[4]);
- else
- TolRel = DEFAULT_TOLREL;
-
- if(nrhs >= 6)
- TolAbs = (double)mxGetScalar(prhs[5]);
- else
- TolAbs = DEFAULT_TOLABS;
-
- if(nrhs >= 7)
- QPBound = (double)mxGetScalar(prhs[6]);
- else
- QPBound = DEFAULT_QPVALUE;
-
- if(nrhs >= 8)
- BufSize = (uint32_t)mxGetScalar(prhs[7]);
- else
- BufSize = DEFAULT_BUFSIZE;
-
- if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
- nData = (uint32_t)mxGetScalar(prhs[8]);
- else
- nData = mxGetN(data_X);
-
- if(nData < 1 || nData > mxGetN(prhs[0]))
- mexErrMsgTxt("Improper value of argument nData.");
-
- if(nrhs >= 10)
- MaxTime = (double)mxGetScalar(prhs[9]);
- else
- MaxTime = DEFAULT_MAXTIME;
-
- if(nrhs >= 11)
- verb = (int)mxGetScalar(prhs[10]);
- else
- verb = DEFAULT_VERB;
-
-
- }
+ if(nrhs < 2 || nrhs > 10)
+ mexErrMsgTxt("Improper number of input arguments.\n"
+ "\n"
+ "OCAS solver for training multi-class linear SVM classifiers.\n"
+ "\n"
+ "Synopsis:\n"
+ " [W,stat] = msvmocas(dataFile,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)\n"
+ "\n"
+ "Input:\n"
+ " dataFile [string] path to file with training examples in SVM^light format\n"
+ " y [nExamples x 1] labels must be integers 1,2,...nY\n"
+ " C [1x1] regularization constant\n"
+ " Method [1x1] 0..cutting plane; 1..OCAS (default 1)\n"
+ " TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel (default 0.01)\n"
+ " TolAbs [1x1] halts if Q_P-Q_D <= TolAbs (default 0)\n"
+ " QPValue [1x1] halts if Q_P <= QPBpound (default 0)\n"
+ " BufSize [1x1] Initial size of active constrains buffer (default 2000)\n"
+ " nExamples [1x1] Number of training examples used for training; must be >0 and <= size(X,2).\n"
+ " If nExamples = inf then nExamples is set to size(X,2).\n"
+ " MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds\n"
+ " MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.\n"
+ " verb [1x1] if non-zero then prints some info; (default 1)\n"
+ "\n"
+ "Output:\n"
+ " W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)\n"
+ " stat [struct] Optimizer statistics (field names are self-explaining).\n");
+
+ char *fname;
+ int fname_len;
+
+ if(!mxIsChar(prhs[0]))
+ mexErrMsgTxt("First input argument must be of type string.");
+
+ fname_len = mxGetNumberOfElements(prhs[0]) + 1;
+ fname = mxCalloc(fname_len, sizeof(char));
+
+ if (mxGetString(prhs[0], fname, fname_len) != 0)
+ mexErrMsgTxt("Could not convert first input argument to string.");
+
+ if(nrhs >= 10)
+ verb = (int)mxGetScalar(prhs[9]);
else
- {
- /* [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
- char *fname;
- int fname_len;
-
- if(nrhs < 2 || nrhs > 10)
- mexErrMsgTxt("Improper number of input arguments.");
-
- if(!mxIsChar(prhs[0]))
- mexErrMsgTxt("First input argument must be of type string.");
-
- fname_len = mxGetNumberOfElements(prhs[0]) + 1;
- fname = mxCalloc(fname_len, sizeof(char));
-
- if (mxGetString(prhs[0], fname, fname_len) != 0)
- mexErrMsgTxt("Could not convert first input argument to string.");
-
- if(nrhs >= 10)
- verb = (int)mxGetScalar(prhs[9]);
- else
- verb = DEFAULT_VERB;
+ verb = DEFAULT_VERB;
- /* load data */
- if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
- mexErrMsgTxt("Cannot load input file.");
+ /* load data */
+ if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
+ mexErrMsgTxt("Cannot load input file.");
- C = (double)mxGetScalar(prhs[1]);
+ C = (double)mxGetScalar(prhs[1]);
- if(nrhs >= 3)
- Method = (uint32_t)mxGetScalar(prhs[2]);
- else
- Method = DEFAULT_METHOD;
+ if(nrhs >= 3)
+ Method = (uint32_t)mxGetScalar(prhs[2]);
+ else
+ Method = DEFAULT_METHOD;
- if(nrhs >= 4)
- TolRel = (double)mxGetScalar(prhs[3]);
- else
- TolRel = DEFAULT_TOLREL;
+ if(nrhs >= 4)
+ TolRel = (double)mxGetScalar(prhs[3]);
+ else
+ TolRel = DEFAULT_TOLREL;
- if(nrhs >= 5)
- TolAbs = (double)mxGetScalar(prhs[4]);
- else
- TolAbs = DEFAULT_TOLABS;
+ if(nrhs >= 5)
+ TolAbs = (double)mxGetScalar(prhs[4]);
+ else
+ TolAbs = DEFAULT_TOLABS;
- if(nrhs >= 6)
- QPBound = (double)mxGetScalar(prhs[5]);
- else
- QPBound = DEFAULT_QPVALUE;
+ if(nrhs >= 6)
+ QPBound = (double)mxGetScalar(prhs[5]);
+ else
+ QPBound = DEFAULT_QPVALUE;
- if(nrhs >= 7)
- BufSize = (uint32_t)mxGetScalar(prhs[6]);
- else
- BufSize = DEFAULT_BUFSIZE;
-
- if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
- nData = (uint32_t)mxGetScalar(prhs[7]);
- else
- nData = mxGetN(data_X);
+ if(nrhs >= 7)
+ BufSize = (uint32_t)mxGetScalar(prhs[6]);
+ else
+ BufSize = DEFAULT_BUFSIZE;
- if(nData < 1 || nData > mxGetN(data_X))
- mexErrMsgTxt("Improper value of argument nData.");
+ if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
+ nData = (uint32_t)mxGetScalar(prhs[7]);
+ else
+ nData = mxGetN(data_X);
- if(nrhs >= 9)
- MaxTime = (double)mxGetScalar(prhs[8]);
- else
- MaxTime = DEFAULT_MAXTIME;
+ if(nData < 1 || nData > mxGetN(data_X))
+ mexErrMsgTxt("Improper value of argument nData.");
+ if(nrhs >= 9)
+ MaxTime = (double)mxGetScalar(prhs[8]);
+ else
+ MaxTime = DEFAULT_MAXTIME;
- }
/* nDim = mxGetM(prhs[0]);*/
nDim = mxGetM(data_X);
- for(i=0, nY = 0; i < nData; i++)
- nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
-
+ for(i=0, nY = 0; i < nData; i++)
+ {
+ nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
+ }
/*----------------------------------------------------------------
Print setting
@@ -243,6 +211,17 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(new_a == NULL)
mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");
+ /* select function to print progress info */
+ void (*print_function)(ocas_return_value_T);
+ if(verb)
+ {
+ mexPrintf("Starting optimization:\n");
+ print_function = &ocas_print;
+ }
+ else
+ {
+ print_function = &ocas_print_null;
+ }
if( mxIsSparse(data_X)== true )
{
@@ -253,19 +232,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL)
mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");
- if(verb)
- mexPrintf("Starting optimization:\n");
-
init_time=get_time()-init_time;
- if(verb)
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
- &msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
- &msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
+ ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
+ &msvm_sparse_compute_output, &qsort_data, print_function, 0);
}
else
{
@@ -274,21 +245,15 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if( full_A == NULL )
mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");
- if(verb)
- mexPrintf("Starting optimization:\n");
-
init_time=get_time()-init_time;
- if(verb)
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
- &msvm_full_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
- &msvm_full_compute_output, &qsort_data, &ocas_print_null, 0);
+ ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
+ &msvm_full_compute_output, &qsort_data, print_function, 0);
}
+
+ total_time=get_time()-total_time;
if(verb)
{
@@ -302,11 +267,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
case -1: mexPrintf("Has not converged!\n" ); break;
case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
}
- }
-
- total_time=get_time()-total_time;
- if(verb)
- {
+
mexPrintf("Timing statistics:\n"
" init_time : %f[s]\n"
" qp_solver_time : %f[s]\n"
@@ -323,20 +284,6 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
}
-
- /* return ocas optimizer statistics */
- /* typedef struct {
- uint32_t nIter;
- uint32_t nCutPlanes;
- double trn_err;
- double Q_P;
- double Q_D;
- double output_time;
- double sort_time;
- double solver_time;
- int8_t exitflag;
- } ocas_return_value_T; */
-
const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
"init_time","output_time","sort_time","qp_solver_time","add_time",
"w_time","ocas_time","total_time"};
diff --git a/msvmocas_mex.c b/msvmocas_mex.c
index 330972e..99d01a2 100644
--- a/msvmocas_mex.c
+++ b/msvmocas_mex.c
@@ -1,13 +1,29 @@
/*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+ * msvmocas_mex.c: OCAS solver for training multi-class linear SVM classifiers.
*
* Synopsis:
- * [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- * [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ * [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)
+ *
+ * Input:
+ * X [nDim x nExamples] training feature inputs (sparse or dense matrix of doubles).
+ * y [nExamples x 1] labels; intgers 1,2,...nY
+ * C [1x1] regularization constant
+ * Method [1x1] 0..cutting plane; 1..OCAS (default 1)
+ * TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel (default 0.01)
+ * TolAbs [1x1] halts if Q_P-Q_D <= TolAbs (default 0)
+ * QPValue [1x1] halts if Q_P <= QPBpound (default 0)
+ * BufSize [1x1] Initial size of active constrains buffer (default 2000)
+ * nExamples [1x1] Number of training examplesused for training; must be >0 and <= size(X,2).
+ * If nExamples = inf then nExamples is set to size(X,2).
+ * MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds
+ * MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.
+ * verb [1x1] if non-zero then prints some info; (default 1)
*
- * Synopsis:
- * [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)
- * Copyright (C) 2008 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Output:
+ * W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)
+ * stat [struct] Optimizer statistics (field names are self-explaining).
+ *
+ * Copyright (C) 2008, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
@@ -19,10 +35,9 @@
#include <stdint.h>
#include <mex.h>
-/*#define LIBOCAS_MATLAB*/
-
#include "libocas.h"
#include "ocas_helper.h"
+#include "features_double.h"
#define DEFAULT_METHOD 1
#define DEFAULT_TOLREL 0.01
@@ -54,153 +69,97 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
total_time = get_time();
init_time = total_time;
- if(nrhs < 1)
- mexErrMsgTxt("Improper number of input arguments.");
-
- /* get input arguments */
- if(mxIsChar(prhs[0]) == false)
+ if(nrhs < 3 || nrhs > 11)
+ mexErrMsgTxt("Improper number of input arguments.\n"
+ "\n"
+ "OCAS solver for training multi-class linear SVM classifiers.\n"
+ "\n"
+ "Synopsis:\n"
+ " [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb)\n"
+ "\n"
+ "Input:\n"
+ " X [nDim x nExamples] training inputs (sparse or dense matrix of doubles).\n"
+ " y [nExamples x 1] labels must be integers 1,2,...nY\n"
+ " C [1x1] regularization constant\n"
+ " Method [1x1] 0..cutting plane; 1..OCAS (default 1)\n"
+ " TolRel [1x1] halts if Q_P-Q_D <= abs(Q_P)*TolRel (default 0.01)\n"
+ " TolAbs [1x1] halts if Q_P-Q_D <= TolAbs (default 0)\n"
+ " QPValue [1x1] halts if Q_P <= QPBpound (default 0)\n"
+ " BufSize [1x1] Initial size of active constrains buffer (default 2000)\n"
+ " nExamples [1x1] Number of training examples used for training; must be >0 and <= size(X,2).\n"
+ " If nExamples = inf then nExamples is set to size(X,2).\n"
+ " MaxTime [1x1] halts if time used by solver (data loading time is not counted) exceeds\n"
+ " MaxTime given in seconds. Use MaxTime=inf (default) to switch off this stopping condition.\n"
+ " verb [1x1] if non-zero then prints some info; (default 1)\n"
+ "\n"
+ "Output:\n"
+ " W [nDim x nY] Paramater vectors of decision rule; [dummy,ypred] = max(W'*x)\n"
+ " stat [struct] Optimizer statistics (field names are self-explaining).\n");
+
+ data_X = (mxArray*)prhs[0];
+ if( (mxGetNumberOfDimensions(data_X) != 2) ||
+ !( ( mxIsDouble(data_X) && mxIsSparse(data_X) ) ||
+ ( mxIsDouble(data_X) && !mxIsSparse(data_X) ) ))
{
-
- if(nrhs < 3 || nrhs > 11)
- mexErrMsgTxt("Improper number of input arguments.");
-
- /* [W,stat] = msvmocas(X,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
-
- data_X = (mxArray*)prhs[0];
- if (!(mxIsDouble(data_X)))
- mexErrMsgTxt("Input argument X must be of type double.");
-
- if (mxGetNumberOfDimensions(data_X) != 2)
- mexErrMsgTxt("Input argument X must be two dimensional.");
-
- data_y = (double*)mxGetPr(prhs[1]);
-
- if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
- mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
-
- C = (double)mxGetScalar(prhs[2]);
-
- if(nrhs >= 4)
- Method = (uint32_t)mxGetScalar(prhs[3]);
- else
- Method = DEFAULT_METHOD;
-
- if(nrhs >= 5)
- TolRel = (double)mxGetScalar(prhs[4]);
- else
- TolRel = DEFAULT_TOLREL;
-
- if(nrhs >= 6)
- TolAbs = (double)mxGetScalar(prhs[5]);
- else
- TolAbs = DEFAULT_TOLABS;
-
- if(nrhs >= 7)
- QPBound = (double)mxGetScalar(prhs[6]);
- else
- QPBound = DEFAULT_QPVALUE;
+ mexErrMsgTxt("The first input argument must be two dimensional matrix of the following type:\n"
+ "dense double matrix or sparse double matrix.\n");
+ }
- if(nrhs >= 8)
- BufSize = (uint32_t)mxGetScalar(prhs[7]);
- else
- BufSize = DEFAULT_BUFSIZE;
-
- if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
- nData = (uint32_t)mxGetScalar(prhs[8]);
- else
- nData = mxGetN(data_X);
-
- if(nData < 1 || nData > mxGetN(prhs[0]))
- mexErrMsgTxt("Improper value of argument nData.");
+ data_y = (double*)mxGetPr(prhs[1]);
- if(nrhs >= 10)
- MaxTime = (double)mxGetScalar(prhs[9]);
- else
- MaxTime = DEFAULT_MAXTIME;
+ if(LIBOCAS_MAX(mxGetM(prhs[1]),mxGetN(prhs[1])) != mxGetN(prhs[0]))
+ mexErrMsgTxt("Length of vector y must equal to the number of columns of matrix X.");
- if(nrhs >= 11)
- verb = (int)mxGetScalar(prhs[10]);
- else
- verb = DEFAULT_VERB;
+ C = (double)mxGetScalar(prhs[2]);
-
- }
+ if(nrhs >= 4)
+ Method = (uint32_t)mxGetScalar(prhs[3]);
else
- {
- /* [W,stat] = msvmocas(svmlight_data_file,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime)*/
- char *fname;
- int fname_len;
-
- if(nrhs < 2 || nrhs > 10)
- mexErrMsgTxt("Improper number of input arguments.");
-
- if(!mxIsChar(prhs[0]))
- mexErrMsgTxt("First input argument must be of type string.");
-
- fname_len = mxGetNumberOfElements(prhs[0]) + 1;
- fname = mxCalloc(fname_len, sizeof(char));
-
- if (mxGetString(prhs[0], fname, fname_len) != 0)
- mexErrMsgTxt("Could not convert first input argument to string.");
-
- if(nrhs >= 10)
- verb = (int)mxGetScalar(prhs[9]);
- else
- verb = DEFAULT_VERB;
-
- /* load data */
- if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
- mexErrMsgTxt("Cannot load input file.");
-
- C = (double)mxGetScalar(prhs[1]);
+ Method = DEFAULT_METHOD;
- if(nrhs >= 3)
- Method = (uint32_t)mxGetScalar(prhs[2]);
- else
- Method = DEFAULT_METHOD;
-
- if(nrhs >= 4)
- TolRel = (double)mxGetScalar(prhs[3]);
- else
- TolRel = DEFAULT_TOLREL;
+ if(nrhs >= 5)
+ TolRel = (double)mxGetScalar(prhs[4]);
+ else
+ TolRel = DEFAULT_TOLREL;
- if(nrhs >= 5)
- TolAbs = (double)mxGetScalar(prhs[4]);
- else
- TolAbs = DEFAULT_TOLABS;
+ if(nrhs >= 6)
+ TolAbs = (double)mxGetScalar(prhs[5]);
+ else
+ TolAbs = DEFAULT_TOLABS;
- if(nrhs >= 6)
- QPBound = (double)mxGetScalar(prhs[5]);
- else
- QPBound = DEFAULT_QPVALUE;
+ if(nrhs >= 7)
+ QPBound = (double)mxGetScalar(prhs[6]);
+ else
+ QPBound = DEFAULT_QPVALUE;
- if(nrhs >= 7)
- BufSize = (uint32_t)mxGetScalar(prhs[6]);
- else
- BufSize = DEFAULT_BUFSIZE;
-
- if(nrhs >= 8 && mxIsInf(mxGetScalar(prhs[7])) == false)
- nData = (uint32_t)mxGetScalar(prhs[7]);
- else
- nData = mxGetN(data_X);
+ if(nrhs >= 8)
+ BufSize = (uint32_t)mxGetScalar(prhs[7]);
+ else
+ BufSize = DEFAULT_BUFSIZE;
- if(nData < 1 || nData > mxGetN(data_X))
- mexErrMsgTxt("Improper value of argument nData.");
+ if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
+ nData = (uint32_t)mxGetScalar(prhs[8]);
+ else
+ nData = mxGetN(data_X);
+
+ if(nData < 1 || nData > mxGetN(prhs[0]))
+ mexErrMsgTxt("Improper value of argument nData.");
- if(nrhs >= 9)
- MaxTime = (double)mxGetScalar(prhs[8]);
- else
- MaxTime = DEFAULT_MAXTIME;
+ if(nrhs >= 10)
+ MaxTime = (double)mxGetScalar(prhs[9]);
+ else
+ MaxTime = DEFAULT_MAXTIME;
+ if(nrhs >= 11)
+ verb = (int)mxGetScalar(prhs[10]);
+ else
+ verb = DEFAULT_VERB;
- }
-/* nDim = mxGetM(prhs[0]);*/
nDim = mxGetM(data_X);
for(i=0, nY = 0; i < nData; i++)
nY = LIBOCAS_MAX(nY, (uint32_t)data_y[i]);
-
/*----------------------------------------------------------------
Print setting
-------------------------------------------------------------------*/
@@ -243,7 +202,19 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(new_a == NULL)
mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");
+ /* select function to print progress info */
+ void (*print_function)(ocas_return_value_T);
+ if(verb)
+ {
+ mexPrintf("Starting optimization:\n");
+ print_function = &ocas_print;
+ }
+ else
+ {
+ print_function = &ocas_print_null;
+ }
+
if( mxIsSparse(data_X)== true )
{
/* init cutting plane buffer */
@@ -253,19 +224,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL)
mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");
- if(verb)
- mexPrintf("Starting optimization:\n");
-
init_time=get_time()-init_time;
- if(verb)
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
- &msvm_sparse_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_sparse_compute_W, &msvm_full_update_W, &msvm_sparse_add_new_cut,
- &msvm_sparse_compute_output, &qsort_data, &ocas_print_null, 0);
+ ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &msvm_sparse_compute_W, &msvm_update_W, &msvm_sparse_add_new_cut,
+ &msvm_sparse_compute_output, &qsort_data, print_function, 0);
}
else
{
@@ -274,21 +237,14 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if( full_A == NULL )
mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");
- if(verb)
- mexPrintf("Starting optimization:\n");
-
init_time=get_time()-init_time;
- if(verb)
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
- &msvm_full_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &msvm_full_compute_W, &msvm_full_update_W, &msvm_full_add_new_cut,
- &msvm_full_compute_output, &qsort_data, &ocas_print_null, 0);
-
+ ocas = msvm_ocas_solver( C, data_y, nY, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &msvm_full_compute_W, &msvm_update_W, &msvm_full_add_new_cut,
+ &msvm_full_compute_output, &qsort_data, print_function, 0);
}
+
+ total_time=get_time()-total_time;
if(verb)
{
@@ -302,41 +258,23 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
case -1: mexPrintf("Has not converged!\n" ); break;
case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
}
- }
- total_time=get_time()-total_time;
- if(verb)
- {
mexPrintf("Timing statistics:\n"
- " init_time : %f[s]\n"
- " qp_solver_time : %f[s]\n"
- " sort_time : %f[s]\n"
- " output_time : %f[s]\n"
- " add_time : %f[s]\n"
- " w_time : %f[s]\n"
- " print_time : %f[s]\n"
- " ocas_time : %f[s]\n"
- " total_time : %f[s]\n",
- init_time, ocas.qp_solver_time, ocas.sort_time, ocas.output_time,
+ " init_time : %f[s]\n"
+ " qp_solver_time : %f[s]\n"
+ " sort_time : %f[s]\n"
+ " output_time : %f[s]\n"
+ " add_time : %f[s]\n"
+ " w_time : %f[s]\n"
+ " print_time : %f[s]\n"
+ " ocas_time : %f[s]\n"
+ " total_time : %f[s]\n",
+ init_time, ocas.qp_solver_time, ocas.sort_time, ocas.output_time,
ocas.add_time, ocas.w_time, ocas.print_time, ocas.ocas_time, total_time);
mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
}
-
- /* return ocas optimizer statistics */
- /* typedef struct {
- uint32_t nIter;
- uint32_t nCutPlanes;
- double trn_err;
- double Q_P;
- double Q_D;
- double output_time;
- double sort_time;
- double solver_time;
- int8_t exitflag;
- } ocas_return_value_T; */
-
const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
"init_time","output_time","sort_time","qp_solver_time","add_time",
"w_time","ocas_time","total_time"};
diff --git a/ocas_helper.c b/ocas_helper.c
index 7372086..bf38e65 100644
--- a/ocas_helper.c
+++ b/ocas_helper.c
@@ -1,8 +1,6 @@
/*-----------------------------------------------------------------------
* ocas_helper.c: Implementation of helper functions for the OCAS solver.
*
- * It supports both sparse and dense matrices and loading data from
- * the SVM^light format.
*-------------------------------------------------------------------- */
#define _FILE_OFFSET_BITS 64
@@ -78,9 +76,50 @@ static struct thread_params_add* params_add;
/* use multi-threads only if minimal number of examples to add is higher than the constant*/
static const uint32_t MinimalParallelCutLenght = 100;
-/***********************************************************************
- Multiclass SVM helper functions.
- **********************************************************************/
+
+/*----------------------------------------------------------------------
+ sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
+
+ oldW = W;
+ W = sparse_A(:,1:nSel)'*alpha;
+ sq_norm_W = W'*W;
+ dp_WoldW = W'*oldW';
+
+ ----------------------------------------------------------------------*/
+void sparse_compute_W( double *sq_norm_W,
+ double *dp_WoldW,
+ double *alpha,
+ uint32_t nSel,
+ void* user_data )
+{
+ uint32_t i,j, nz_dims;
+
+ memcpy(oldW, W, sizeof(double)*nDim );
+ memset(W, 0, sizeof(double)*nDim);
+
+ oldW0 = W0;
+ W0 = 0;
+
+ for(i=0; i < nSel; i++) {
+ nz_dims = sparse_A.nz_dims[i];
+ if(nz_dims > 0 && alpha[i] > 0) {
+ for(j=0; j < nz_dims; j++) {
+ W[sparse_A.index[i][j]] += alpha[i]*sparse_A.value[i][j];
+ }
+ }
+ W0 += A0[i]*alpha[i];
+ }
+
+ *sq_norm_W = W0*W0;
+ *dp_WoldW = W0*oldW0;
+ for(j=0; j < nDim; j++) {
+ *sq_norm_W += W[j]*W[j];
+ *dp_WoldW += W[j]*oldW[j];
+ }
+
+ return;
+}
+
/*----------------------------------------------------------------------
sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
@@ -130,7 +169,7 @@ void msvm_sparse_compute_W( double *sq_norm_W,
sq_norm_W = W'*W;
---------------------------------------------------------------------------------*/
-double msvm_full_update_W( double t, void* user_data )
+double msvm_update_W( double t, void* user_data )
{
uint32_t j;
double sq_norm_W;
@@ -146,202 +185,29 @@ double msvm_full_update_W( double t, void* user_data )
}
-/*----------------------------------------------------------------------------------
- sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
- new_a = zeros(nDim,nY);
- for i=1:nData
- if new_cut(i) ~= data_y(i)
- new_a(:,data_y(i)) = new_a(:,data_y(i)) + X(;,i);
- new_a(:,new_cut(i)) = new_a(:,new_cut(i)) - X(;,i);
- end
- end
-
- new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
- sparse_A(:,nSel+1) = new_a;
-
- Warning: data_y is 1-based while new_cut is 0-based
-
- ---------------------------------------------------------------------------------*/
-int msvm_sparse_add_new_cut( double *new_col_H,
- uint32_t *new_cut,
- uint32_t nSel,
- void* user_data )
-{
-/* double *new_a, */
- double sq_norm_a;
- uint32_t i, j, nz_dims, ptr, y;
-
- memset(new_a, 0, sizeof(double)*nY*nDim);
-
- for(i=0; i < nData; i++)
- {
- y = (uint32_t)(data_y[i]-1);
- if(new_cut[i] != y)
- {
- add_sparse_col(&new_a[nDim*y], data_X, i);
- subtract_sparse_col(&new_a[nDim*(uint32_t)new_cut[i]], data_X, i);
- }
- }
-
- /* compute new_a'*new_a and count number of non-zero dimensions */
- nz_dims = 0;
- sq_norm_a = 0;
- for(j=0; j < nY*nDim; j++ ) {
- if(new_a[j] != 0) {
- nz_dims++;
- sq_norm_a += new_a[j]*new_a[j];
- }
- }
-
- /* sparsify new_a and insert it to the last column of sparse_A */
- sparse_A.nz_dims[nSel] = nz_dims;
- if(nz_dims > 0) {
- sparse_A.index[nSel] = NULL;
- sparse_A.value[nSel] = NULL;
- sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
- sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
- if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
- {
-/* mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
- mxFree(sparse_A.index[nSel]);
- mxFree(sparse_A.value[nSel]);
- return(-1);
- }
-
- ptr = 0;
- for(j=0; j < nY*nDim; j++ ) {
- if(new_a[j] != 0) {
- sparse_A.index[nSel][ptr] = j;
- sparse_A.value[nSel][ptr++] = new_a[j];
- }
- }
- }
-
- new_col_H[nSel] = sq_norm_a;
- for(i=0; i < nSel; i++) {
- double tmp = 0;
-
- for(j=0; j < sparse_A.nz_dims[i]; j++) {
- tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
- }
-
- new_col_H[i] = tmp;
- }
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
- sparse_compute_output( output ) does the follwing:
-
- output = W'*data_X;
- ----------------------------------------------------------------------*/
-int msvm_sparse_compute_output( double *output, void* user_data )
-{
- uint32_t i,y;
-
- for(i=0; i < nData; i++)
- {
- for(y=0; y < nY; y++)
- {
- output[LIBOCAS_INDEX(y,i,nY)] = dp_sparse_col(&W[y*nDim], data_X, i);
- }
- }
-
- return 0;
-}
-
-
-/*-----------------------------------------------------------
- Functions working with full data.
- -------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------------------
- full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
- new_a = sum(data_X(:,find(new_cut ~=0 )),2);
- new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
- full_A(:,nSel+1) = new_a;
-
- ---------------------------------------------------------------------------------*/
-int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data)
-{
- double sq_norm_a, *ptr;
- uint32_t i, j, y, y2;
-
- ptr = mxGetPr(data_X);
-
- memset(new_a, 0, sizeof(double)*nDim*nY);
-
- for(i=0; i < nData; i++)
- {
- y = (uint32_t)(data_y[i]-1);
- y2 = (uint32_t)new_cut[i];
- if(y2 != y)
- {
- for(j=0; j < nDim; j++ )
- {
- new_a[LIBOCAS_INDEX(j,y,nDim)] += ptr[LIBOCAS_INDEX(j,i,nDim)];
- new_a[LIBOCAS_INDEX(j,y2,nDim)] -= ptr[LIBOCAS_INDEX(j,i,nDim)];
- }
- }
- }
-
- /* compute new_a'*new_a and insert new_a to the last column of full_A */
- sq_norm_a = 0;
- for(j=0; j < nDim*nY; j++ ) {
- sq_norm_a += new_a[j]*new_a[j];
- full_A[LIBOCAS_INDEX(j,nSel,nDim*nY)] = new_a[j];
- }
-
- new_col_H[nSel] = sq_norm_a;
- for(i=0; i < nSel; i++) {
- double tmp = 0;
-
- for(j=0; j < nDim*nY; j++ ) {
- tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim*nY)];
- }
- new_col_H[i] = tmp;
- }
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
- full_compute_output( output ) does the follwing:
+/*-------------------------------------------------------------------------
+ sq_norm_W = full_update_W( t ) does the following:
- output = data_X'*W;
- ----------------------------------------------------------------------*/
-int msvm_full_compute_output( double *output, void* user_data )
+ W = oldW*(1-t) + t*W;
+ sq_norm_W = W'*W;
+---------------------------------------------------------------------------*/
+double update_W( double t, void* user_data )
{
- uint32_t i, j, y;
- double *ptr, tmp;
+ uint32_t j;
+ double sq_norm_W;
- ptr = mxGetPr( data_X );
+ W0 = oldW0*(1-t) + t*W0;
+ sq_norm_W = W0*W0;
- for(i=0; i < nData; i++)
- {
- for(y=0; y < nY; y++)
- {
- tmp = 0;
+ for(j=0; j <nDim; j++) {
+ W[j] = oldW[j]*(1-t) + t*W[j];
+ sq_norm_W += W[j]*W[j];
+ }
- for(j=0; j < nDim; j++ )
- {
- tmp += W[LIBOCAS_INDEX(j,y,nDim)]*ptr[LIBOCAS_INDEX(j,i,nDim)];
- }
-
- output[LIBOCAS_INDEX(y,i,nY)] = tmp;
- }
- }
-
- return 0;
+ return( sq_norm_W );
}
-
/*----------------------------------------------------------------------
sq_norm_W = full_compute_W( alpha, nSel ) does the following:
@@ -378,12 +244,6 @@ void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, ui
}
-
-/***********************************************************************
- Generic functions.
- **********************************************************************/
-
-
/*-----------------------------------------------------------------------
Print statistics.
-----------------------------------------------------------------------*/
@@ -413,13 +273,6 @@ double get_time()
}
-/*=========================================================================
- *
- * Ocas helper functions implemented for input data represented as
- * Matlab sparse matrix.
- *
- *=========================================================================*/
-
/*----------------------------------------------------------------------
in-place computes sparse_mat(:,col)= alpha * sparse_mat(:,col)
where alpha is a scalar and sparse_mat is Matlab sparse matrix.
@@ -427,10 +280,9 @@ double get_time()
void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col)
{
uint32_t nItems, ptr, i;
- INDEX_TYPE_T *Ir, *Jc;
+ INDEX_TYPE_T *Jc;
double *Pr;
- Ir = mxGetIr(sparse_mat);
Jc = mxGetJc(sparse_mat);
Pr = mxGetPr(sparse_mat);
@@ -468,6 +320,7 @@ void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
}
}
+
/*----------------------------------------------------------------------
It computes full_vec = full_vec - sparse_mat(:,col)
where full_vec is a double array and sparse_mat is Matlab
@@ -494,6 +347,7 @@ void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
}
}
+
/*----------------------------------------------------------------------
It computes dp = full_vec'*sparse_mat(:,col)
where full_vec is a double array and sparse_mat is Matlab
@@ -524,269 +378,6 @@ double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col)
}
-/*----------------------------------------------------------------------------------
- sq_norm_W = sparse_update_W( t ) does the following:
-
- W = oldW*(1-t) + t*W;
- sq_norm_W = W'*W;
-
- ---------------------------------------------------------------------------------*/
-double sparse_update_W( double t, void* user_data )
-{
- uint32_t j;
- double sq_norm_W;
-
- W0 = oldW0*(1-t) + t*W0;
- sq_norm_W = W0*W0;
-
- for(j=0; j <nDim; j++) {
- W[j] = oldW[j]*(1-t) + t*W[j];
- sq_norm_W += W[j]*W[j];
- }
-
- return( sq_norm_W );
-}
-
-/*-------------------------------------------------------------------------
- sq_norm_W = full_update_W( t ) does the following:
-
- W = oldW*(1-t) + t*W;
- sq_norm_W = W'*W;
----------------------------------------------------------------------------*/
-double full_update_W( double t, void* user_data )
-{
- uint32_t j;
- double sq_norm_W;
-
- W0 = oldW0*(1-t) + t*W0;
- sq_norm_W = W0*W0;
-
- for(j=0; j <nDim; j++) {
- W[j] = oldW[j]*(1-t) + t*W[j];
- sq_norm_W += W[j]*W[j];
- }
-
- return( sq_norm_W );
-}
-
-
-/*----------------------------------------------------------------------------------
- sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
- new_a = sum(data_X(:,find(new_cut ~=0 )),2);
- new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
- sparse_A(:,nSel+1) = new_a;
-
- ---------------------------------------------------------------------------------*/
-int sparse_add_new_cut( double *new_col_H,
- uint32_t *new_cut,
- uint32_t cut_length,
- uint32_t nSel,
- void* user_data )
-{
-/* double *new_a, */
- double sq_norm_a;
- uint32_t i, j, nz_dims, ptr;
-
- memset(new_a, 0, sizeof(double)*nDim);
-
- for(i=0; i < cut_length; i++) {
- add_sparse_col(new_a, data_X, new_cut[i]);
-
- A0[nSel] += X0*data_y[new_cut[i]];
- }
-
- /* compute new_a'*new_a and count number of non-zero dimensions */
- nz_dims = 0;
- sq_norm_a = A0[nSel]*A0[nSel];
- for(j=0; j < nDim; j++ ) {
- if(new_a[j] != 0) {
- nz_dims++;
- sq_norm_a += new_a[j]*new_a[j];
- }
- }
-
- /* sparsify new_a and insert it to the last column of sparse_A */
- sparse_A.nz_dims[nSel] = nz_dims;
- if(nz_dims > 0) {
- sparse_A.index[nSel] = NULL;
- sparse_A.value[nSel] = NULL;
- sparse_A.index[nSel] = mxCalloc(nz_dims,sizeof(uint32_t));
- sparse_A.value[nSel] = mxCalloc(nz_dims,sizeof(double));
- if(sparse_A.index[nSel]==NULL || sparse_A.value[nSel]==NULL)
- {
-/* mexErrMsgTxt("Not enough memory for vector sparse_A.index[nSel], sparse_A.value[nSel].");*/
- mxFree(sparse_A.index[nSel]);
- mxFree(sparse_A.value[nSel]);
- return(-1);
- }
-
- ptr = 0;
- for(j=0; j < nDim; j++ ) {
- if(new_a[j] != 0) {
- sparse_A.index[nSel][ptr] = j;
- sparse_A.value[nSel][ptr++] = new_a[j];
- }
- }
- }
-
- new_col_H[nSel] = sq_norm_a;
- for(i=0; i < nSel; i++) {
- double tmp = A0[nSel]*A0[i];
-
- for(j=0; j < sparse_A.nz_dims[i]; j++) {
- tmp += new_a[sparse_A.index[i][j]]*sparse_A.value[i][j];
- }
-
- new_col_H[i] = tmp;
- }
-
-/* mxFree( new_a );*/
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------------------------
- full_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
-
- new_a = sum(data_X(:,find(new_cut ~=0 )),2);
- new_col_H = [full_A(:,1:nSel)'*new_a ; new_a'*new_a];
- full_A(:,nSel+1) = new_a;
-
- ---------------------------------------------------------------------------------*/
-int full_add_new_cut( double *new_col_H,
- uint32_t *new_cut,
- uint32_t cut_length,
- uint32_t nSel,
- void* user_data)
-{
-/* double *new_a, */
- double sq_norm_a, *ptr;
- uint32_t i, j;
-
- ptr = mxGetPr(data_X);
-
- memset(new_a, 0, sizeof(double)*nDim);
-
-
- for(i=0; i < cut_length; i++) {
- for(j=0; j < nDim; j++ ) {
- new_a[j] += ptr[LIBOCAS_INDEX(j,new_cut[i],nDim)];
- }
-
- A0[nSel] += X0*data_y[new_cut[i]];
- }
-
- /* compute new_a'*new_a and insert new_a to the last column of full_A */
- sq_norm_a = A0[nSel]*A0[nSel];
- for(j=0; j < nDim; j++ ) {
- sq_norm_a += new_a[j]*new_a[j];
- full_A[LIBOCAS_INDEX(j,nSel,nDim)] = new_a[j];
- }
-
- new_col_H[nSel] = sq_norm_a;
- for(i=0; i < nSel; i++) {
- double tmp = A0[nSel]*A0[i];
-
- for(j=0; j < nDim; j++ ) {
- tmp += new_a[j]*full_A[LIBOCAS_INDEX(j,i,nDim)];
- }
- new_col_H[i] = tmp;
- }
-
-/* mxFree( new_a );*/
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
- sparse_compute_output( output ) does the follwing:
-
- output = data_X'*W;
- ----------------------------------------------------------------------*/
-int sparse_compute_output( double *output, void* user_data )
-{
- uint32_t i;
-
- for(i=0; i < nData; i++) {
- output[i] = data_y[i]*X0*W0 + dp_sparse_col(W, data_X, i);
- }
-
- return 0;
-}
-
-/*----------------------------------------------------------------------
- full_compute_output( output ) does the follwing:
-
- output = data_X'*W;
- ----------------------------------------------------------------------*/
-int full_compute_output( double *output, void* user_data )
-{
- uint32_t i, j;
- double *ptr, tmp;
-
- ptr = mxGetPr( data_X );
-
- for(i=0; i < nData; i++) {
- tmp = data_y[i]*X0*W0;
-
- for(j=0; j < nDim; j++ ) {
- tmp += W[j]*ptr[LIBOCAS_INDEX(j,i,nDim)];
- }
- output[i] = tmp;
- }
-
- return 0;
-}
-
-
-
-/*----------------------------------------------------------------------
- sq_norm_W = sparse_compute_W( alpha, nSel ) does the following:
-
- oldW = W;
- W = sparse_A(:,1:nSel)'*alpha;
- sq_norm_W = W'*W;
- dp_WoldW = W'*oldW';
-
- ----------------------------------------------------------------------*/
-void sparse_compute_W( double *sq_norm_W,
- double *dp_WoldW,
- double *alpha,
- uint32_t nSel,
- void* user_data )
-{
- uint32_t i,j, nz_dims;
-
- memcpy(oldW, W, sizeof(double)*nDim );
- memset(W, 0, sizeof(double)*nDim);
-
- oldW0 = W0;
- W0 = 0;
-
- for(i=0; i < nSel; i++) {
- nz_dims = sparse_A.nz_dims[i];
- if(nz_dims > 0 && alpha[i] > 0) {
- for(j=0; j < nz_dims; j++) {
- W[sparse_A.index[i][j]] += alpha[i]*sparse_A.value[i][j];
- }
- }
- W0 += A0[i]*alpha[i];
- }
-
- *sq_norm_W = W0*W0;
- *dp_WoldW = W0*oldW0;
- for(j=0; j < nDim; j++) {
- *sq_norm_W += W[j]*W[j];
- *dp_WoldW += W[j]*oldW[j];
- }
-
- return;
-}
-
-
/*----------------------------------------------------------------------
sq_norm_W = full_compute_W( alpha, nSel ) does the following:
@@ -827,17 +418,6 @@ void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_
}
-/* ==========================================================================
- Multi-thread version of the OCAS helper functions.
-
- int parallel_sparse_compute_output( double *output, void* user_data )
-
- void destroy_parallel_ocas(void)
- int init_parallel_ocas(int number_of_threads)
-
-============================================================================*/
-
-
/*----------------------------------------------------------------------
parallel_sparse_compute_output( output, user_data ) does the following
@@ -1153,15 +733,6 @@ int parallel_sparse_add_new_cut( double *new_col_H,
}
-/*=========================================================================
- *
- * Ocas helper functions implemented for input data represented as
- * an array of doubles.
- *
- *=========================================================================*/
-
-
-
/*=======================================================================
OCAS helper functions for sorting numbers.
=======================================================================*/
@@ -1172,12 +743,6 @@ static void swapf(double* a, double* b)
*a=dummy;
}
-/*static void swapi(uint32_t* a, uint32_t* b)*/
-/*{*/
-/* int dummy=*b;*/
-/* *b=*a;*/
-/* *a=dummy;*/
-/*}*/
/* sort arrays value and data according to value in ascending order */
int qsort_data(double* value, double* data, uint32_t size)
@@ -1346,9 +911,8 @@ int parallel_qsort_data(double* value, double* data, uint32_t size)
return(0);
}
-/* =================================================================================
- Other auxiliary functions.
- =================================================================================*/
+
+
/* ---------------------------------------------------------------------------------
This function loads regularization constants from a text file. Each line contains
diff --git a/ocas_helper.h b/ocas_helper.h
index f6aece6..8eb14bb 100644
--- a/ocas_helper.h
+++ b/ocas_helper.h
@@ -1,14 +1,13 @@
/*-----------------------------------------------------------------------
* ocas_helper.h: Implementation of helper functions for the OCAS solver.
*
- * It supports both sparse and dense matrices and loading data from
- * the SVM^light format.
*-------------------------------------------------------------------- */
#ifndef _ocas_helper_h
#define _ocas_helper_h
#include <stdint.h>
+#include "libocas.h"
#ifdef LIBOCAS_MATLAB
@@ -52,53 +51,47 @@ extern double W0;
extern double oldW0;
extern double X0;
-double get_time(void);
-void ocas_print(ocas_return_value_T value);
-void ocas_print_null(ocas_return_value_T value);
-
-void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col);
-void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
-double sparse_update_W( double t, void* user_data );
-int sparse_add_new_cut( double *new_col_H,
- uint32_t *new_cut,
- uint32_t cut_length,
- uint32_t nSel,
- void* user_data );
-int sparse_compute_output( double *output, void* user_data );
-void sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-
-void msvm_sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-int msvm_sparse_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data );
-int msvm_sparse_compute_output( double *output, void* user_data );
-
-double msvm_full_update_W( double t, void* user_data );
-int msvm_full_add_new_cut( double *new_col_H, uint32_t *new_cut, uint32_t nSel, void* user_data);
-int msvm_full_compute_output( double *output, void* user_data );
-void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-
-
-double full_update_W( double t, void* user_data );
-int full_compute_output( double *output, void* user_data );
-void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
-int full_add_new_cut( double *new_col_H,
- uint32_t *new_cut,
- uint32_t cut_length,
- uint32_t nSel,
- void* user_data);
-
-int load_svmlight_file(char *fname, int verb);
-double compute_auc(double *score, int *label, uint32_t nData);
-int load_regconsts(char *fname, double **vec_C, uint32_t *len_vec_C, int verb);
-
-int qsort_data(double* value, double* data, uint32_t size);
-
-void destroy_parallel_ocas(void);
-int init_parallel_ocas(int number_of_threads);
-int parallel_sparse_compute_output( double *output, void* user_data );
-int parallel_qsort_data(double* value, double* data, uint32_t size);
-int parallel_sparse_add_new_cut( double *new_col_H,uint32_t *new_cut, uint32_t cut_length,uint32_t nSel,void* user_data );
+
+/** helper functions for OCAS solver **/
+extern void ocas_print(ocas_return_value_T value);
+extern void ocas_print_null(ocas_return_value_T value);
+extern int qsort_data(double* value, double* data, uint32_t size);
+
+/* helper functions for two-class SVM solver */
+extern double update_W( double t, void* user_data );
+/* dense cutting plane buffer*/
+extern void full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+/* sparse cutting plane bugger */
+extern void sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+
+/* helper functions for multi-class SVM solver */
+extern double msvm_update_W( double t, void* user_data );
+/* dense cutting plane buffer*/
+extern void msvm_full_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+/* sparse cutting plane bugger */
+extern void msvm_sparse_compute_W( double *sq_norm_W, double *dp_WoldW, double *alpha, uint32_t nSel, void* user_data );
+
+
+/** parallelized implementation of helper functions for two-class OCAS solver **/
+extern void destroy_parallel_ocas(void);
+extern int init_parallel_ocas(int number_of_threads);
+extern int parallel_sparse_compute_output( double *output, void* user_data );
+extern int parallel_qsort_data(double* value, double* data, uint32_t size);
+extern int parallel_sparse_add_new_cut( double *new_col_H,uint32_t *new_cut, uint32_t cut_length,uint32_t nSel,void* user_data );
+
+
+/** functions for working with sparse vectors **/
+extern void mul_sparse_col(double alpha, mxArray *sparse_mat, uint32_t col);
+extern void add_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+extern void subtract_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+extern double dp_sparse_col(double *full_vec, mxArray *sparse_mat, uint32_t col);
+
+
+/** auxcilirary functions **/
+extern int load_svmlight_file(char *fname, int verb);
+extern double compute_auc(double *score, int *label, uint32_t nData);
+extern int load_regconsts(char *fname, double **vec_C, uint32_t *len_vec_C, int verb);
+extern double get_time(void);
#endif
diff --git a/ocas_lbp_helper.c b/ocas_lbp_helper.c
index aa6da0a..463b2e1 100644
--- a/ocas_lbp_helper.c
+++ b/ocas_lbp_helper.c
@@ -150,7 +150,7 @@ int full_add_new_cut( double *new_col_H,
croped_window[cnt++] = img_ptr[LIBOCAS_INDEX(y,x,im_H)];
}
- if(data_y[new_cut[i]] == +1) {
+ if(data_y[new_cut[i]] > 0) {
/* lbppyr_addvec(new_a,croped_window);*/
liblbp_pyr_addvec(new_a,nDim,croped_window,win_H,win_W);
}
@@ -237,7 +237,10 @@ int full_compute_output( double *output, void* user_data )
}
/* output[i] = data_y[i]*(X0*W0 + lbppyr_dotprod(W,croped_window));*/
- output[i] = data_y[i]*(X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
+ if( data_y[i] > 0)
+ output[i] = (X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
+ else
+ output[i] = -(X0*W0 + liblbp_pyr_dotprod(W,nDim,croped_window,win_H,win_W));
/*
for(j=0; j < nDim; j++ ) {
diff --git a/svmocas b/svmocas
new file mode 100755
index 0000000..df8c752
Binary files /dev/null and b/svmocas differ
diff --git a/svmocas.c b/svmocas.c
index 3b74dfb..b0944ba 100644
--- a/svmocas.c
+++ b/svmocas.c
@@ -2,7 +2,7 @@
* svmocas.c: Standalone application implementing the OCAS solver for
* training linear SVM classifiers.
*
- * Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
* Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
*
* This program is free software; you can redistribute it and/or
@@ -22,6 +22,7 @@
#include "libocas.h"
#include "sparse_mat.h"
#include "ocas_helper.h"
+#include "features_double.h"
#include "version.h"
@@ -67,7 +68,7 @@ void print_usage(void)
"\n"
" Compute testing error of the classifier stored in ./data/svmocas.model using testing\n"
" examples from ./data/riply_tst.light and save predicted labels to ./data/riply_tst.pred\n"
- " ./linclass -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
+ " ./linclassif -e -o ./data/riply_tst.pred ./data/riply_tst.light ./data/svmocas.model\n"
"\n"
);
}
@@ -520,11 +521,11 @@ int main(int argc, char *argv[])
printf("Starting optimization:\n");
if( vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
+ &sparse_compute_W, &update_W, &sparse_add_new_cut,
&sparse_compute_output, &qsort_data, &ocas_print, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
+ &sparse_compute_W, &update_W, &sparse_add_new_cut,
&sparse_compute_output, &qsort_data, &ocas_print, 0);
}
@@ -532,11 +533,11 @@ int main(int argc, char *argv[])
{
if( vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
+ &sparse_compute_W, &update_W, &sparse_add_new_cut,
&sparse_compute_output, &qsort_data, &ocas_print_null, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
+ &sparse_compute_W, &update_W, &sparse_add_new_cut,
&sparse_compute_output, &qsort_data, &ocas_print_null, 0);
}
@@ -555,11 +556,11 @@ int main(int argc, char *argv[])
if( vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, ¶llel_sparse_add_new_cut,
+ &sparse_compute_W, &update_W, ¶llel_sparse_add_new_cut,
¶llel_sparse_compute_output, ¶llel_qsort_data, &ocas_print, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, ¶llel_sparse_add_new_cut,
+ &sparse_compute_W, &update_W, ¶llel_sparse_add_new_cut,
¶llel_sparse_compute_output, ¶llel_qsort_data, &ocas_print, 0);
}
@@ -567,11 +568,11 @@ int main(int argc, char *argv[])
{
if( vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, ¶llel_sparse_add_new_cut,
+ &sparse_compute_W, &update_W, ¶llel_sparse_add_new_cut,
¶llel_sparse_compute_output, ¶llel_qsort_data, &ocas_print_null, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, ¶llel_sparse_add_new_cut,
+ &sparse_compute_W, &update_W, ¶llel_sparse_add_new_cut,
¶llel_sparse_compute_output, ¶llel_qsort_data, &ocas_print_null, 0);
}
@@ -606,11 +607,11 @@ int main(int argc, char *argv[])
if(vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
+ &full_compute_W, &update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
+ &full_compute_W, &update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print, 0);
}
@@ -618,11 +619,11 @@ int main(int argc, char *argv[])
{
if(vec_C == NULL)
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
+ &full_compute_W, &update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print_null, 0);
else
ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
+ &full_compute_W, &update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print_null, 0);
}
diff --git a/svmocas.m b/svmocas.m
index 963c99d..ae86f2d 100644
--- a/svmocas.m
+++ b/svmocas.m
@@ -1,28 +1,31 @@
-% SVMOCAS Train linear SVM classifier using OCAS solver.
+% SVMOCAS solver for training linear two-class SVM classifiers
%
% Synopsis:
-% [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime);
+% [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime)
%
-% [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime);
-%
% Desription:
% This function trains linear SVM classifier by solving
%
% W,W0 = argmin 0.5*(w'*w+w0^2) + C*sum max( 0, 1-y(i)*(w'*X(:,i)+w0*X0) )
% w,w0 i=1:nExamples
%
-% The function accepts examples either in Matlab matrix X (both sparse and dense) and
-% a dense vector y or as path to a file in SVM^light format.
+% The training examples are passed in the matrix X where each column is a single
+% feature vector. The matrix X can be one of the following types
+% dense double (default in Matlab)
+% sparse double
+% dense single
+% dense int8
+% The labels of the training examples must be given as dense vector y whose length
+% equals to the number of columns of the matrix X.
%
% Reference:
-% V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vector
-% Machines. In Proceedings of ICML. Omnipress, 2008.
-% http://ida.first.fraunhofer.de/~franc/papers/Franc-OCAS-ICML08.pdf
+% V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+% Minimization. Journal of Machine Learning Research. 2009
+% http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
%
% Input:
-% data_file [string] Training examples stored in SVM^light format.
-%
-% X [nDim x nExamples] training inputs (sparse or dense matrix).
+% X [nDim x nExamples] training inputs (dense double, sparse double, dense single,
+% dense int8 matrix).
% X0 [1x1] constant coordinate (implicitly) added to all examples;
% this allows training biased decision rule.
% y [nExamples x 1] labels (+1/-1).
@@ -45,22 +48,24 @@
% stat [struct] Optimizer statistics (field names are self-explaining).
%
% Example:
-% % loading data directly from file in SVM^light format
-% [W,W0,stat] = svmocas('./data/riply_trn.light',1,1);
+% % train linear SVM classifier
+% libocasPath = fileparts(which('svmocas'));
+% trn = load([libocasPath '/data/riply_trn.mat'],'X','y');
+% svmC = 1;
+% [W,W0,stat] = svmocas(trn.X,1,trn.y,svmC);
%
-% % using data loaded to Matlab
-% load('./data/riply_trn','X','y');
-% [W,W0,stat] = svmocas(X,1,y,1);
+% % classify test examples
+% tst = load([libocasPath '/data/riply_tst.mat'],'X','y');
+% ypred = sign(W'*tst.X + W0);
%
-% % classification
-% load('riply_tst','X','y');
-% ypred = sign(W'*X + W0);
-% sum(ypred ~= y)/length(y)
+% % compute test classification error and area under ROC
+% sum(ypred ~= tst.y)/length(tst.y)
+% compute_auc(W'*tst.X + W0, tst.y)
%
%
-% Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
-% Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+% Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+% Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public
diff --git a/svmocas.mexa64 b/svmocas.mexa64
new file mode 100755
index 0000000..d854b06
Binary files /dev/null and b/svmocas.mexa64 differ
diff --git a/svmocas_lbp.mexa64 b/svmocas_lbp.mexa64
new file mode 100755
index 0000000..e39e4ae
Binary files /dev/null and b/svmocas_lbp.mexa64 differ
diff --git a/svmocas_lbp_mex.c b/svmocas_lbp_mex.c
index 0a6806a..68102a5 100644
--- a/svmocas_lbp_mex.c
+++ b/svmocas_lbp_mex.c
@@ -12,7 +12,7 @@
* height_of_pyramid [1 x 1 (double)]
* X0 [1 x 1 (double)]
* y [nExamples x 1 (double)] +1/-1
- * C [1 x 1 (double)] OR [nExamples x 1 (double)]
+ * C [1 x 1 (double)]
* Method [1x1 (double)] 0 (BMRM) or 1 (OCAS)
* TolRel [1x1 (double)]
* TolAbs [1x1 (double)]
@@ -72,26 +72,27 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
total_time = get_time();
init_time = total_time;
- if(nrhs < 8 || nrhs > 15)
+ if(nrhs < 8 || nrhs > 16)
mexErrMsgTxt("Improper number of input arguments.\n\n"
"SVMOCAS_LBP train linear SVM classifier for images prepresented by LBP features. \n\n"
"Synopsis:\n"
" [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,\n"
- " X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb) \n\n"
+ " X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb) \n\n"
"Input: \n"
" Images [(im_H*im_W) x nImages (uint8)]\n"
- " imSize [2 x 1 (uint32)] imSize = [im_H im_W]\n"
- " Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror]\n"
- " winSize [2 x 1 (uint32)] [win_H win_W]\n"
+ " imSize [2 x 1 (double)] imSize = [im_H im_W]\n"
+ " Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror] 1-based\n"
+ " winSize [2 x 1 (double)] [win_H win_W]\n"
" height_of_pyramid [1 x 1 (double)]\n"
" X0 [1 x 1 (double)]\n"
" y [nExamples x 1 (double)] +1 or -1\n"
- " C [1 x 1 (double)] OR [nExamples x 1 (double)]\n"
+ " C [1 x 1 (double)]\n"
" Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
" TolRel [1x1 (double)]\n"
" TolAbs [1x1 (double)]\n"
" QPBound [1x1 (double)]\n"
" BufSize [1x1 (double)]\n"
+ " nExamples [1x1 (double) number of examples to use; (inf mens use all available)\n"
" MaxTime [1x1 (double)]\n"
" verb [1x1 (bouble)]\n\n"
"Output:\n"
@@ -114,7 +115,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
im_H = (uint32_t)tmp[0];
im_W = (uint32_t)tmp[1];
- mexPrintf("im_h=%d im_W=%d \n", im_H, im_W);
+/* mexPrintf("im_h=%d im_W=%d \n", im_H, im_W);*/
if(mxGetM(prhs[0]) != im_H*im_W)
mexErrMsgTxt("Dimension of Images does not match to im_H*im_W.");
@@ -129,7 +130,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
croped_window = (uint32_t*)mxCalloc(win_H*win_W,sizeof(uint32_t));
- if(croped_window == NULL)
+ if(croped_window == NULL)
mexErrMsgTxt("Not enough memory for croped_window.");
X0 = mxGetScalar(prhs[5]);
@@ -157,13 +158,18 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
}
num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[7]),mxGetM(prhs[7]));
+
if(num_of_Cs == 1)
{
C = (double)mxGetScalar(prhs[7]);
}
else
{
- vec_C = (double*)mxGetPr(prhs[7]);
+/* if(nData != num_of_Cs) */
+/* mexErrMsgTxt("The number of examples does not much the length of the vector C.");*/
+
+ mexErrMsgTxt("The argument C must be a scalar of type double.");
+/* vec_C = (double*)mxGetPr(prhs[7]);*/
}
if(nrhs >= 9)
@@ -215,12 +221,13 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
mexPrintf("SVM setting:\n");
- if( num_of_Cs == 1)
- mexPrintf(" C : %f\n", C);
- else
- mexPrintf(" C : different for each example\n");
+/* if( num_of_Cs == 1)*/
+/* mexPrintf(" C : %f\n", C);*/
+/* else*/
+/* mexPrintf(" C : different for each example\n");*/
- mexPrintf(" bias : %.0f\n"
+ mexPrintf(" C : %f\n"
+ " bias : %.0f\n"
" # of examples : %d\n"
" solver : %d\n"
" cache size : %d\n"
@@ -229,7 +236,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
" QPValue : %f\n"
" MaxTime : %f [s]\n"
" verb : %d\n",
- X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
+ C, X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
}
/* learned weight vector */
@@ -252,11 +259,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(new_a == NULL)
mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");
- if(num_of_Cs > 1)
- {
- for(i=0; i < nData; i++)
- data_y[i] = data_y[i]*vec_C[i];
- }
+/* if(num_of_Cs > 1)*/
+/* {*/
+/* for(i=0; i < nData; i++) */
+/* data_y[i] = data_y[i]*vec_C[i];*/
+/* }*/
/* !!!!!!!!!!!!
ptr = mxGetPr(data_X);
@@ -291,25 +298,25 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
mexPrintf("Starting optimization:\n");
- if(num_of_Cs == 1)
+/* if(num_of_Cs == 1)*/
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
&full_compute_W, &full_update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print, 0);
+/* else*/
+/* ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, */
+/* &full_compute_W, &full_update_W, &full_add_new_cut, */
+/* &full_compute_output, &qsort_data, &ocas_print, 0);*/
}
else
{
- if(num_of_Cs == 1)
+/* if(num_of_Cs == 1)*/
ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
&full_compute_W, &full_update_W, &full_add_new_cut,
&full_compute_output, &qsort_data, &ocas_print_null, 0);
- else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print_null, 0);
+/* else*/
+/* ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method, */
+/* &full_compute_W, &full_update_W, &full_add_new_cut, */
+/* &full_compute_output, &qsort_data, &ocas_print_null, 0);*/
}
@@ -346,11 +353,11 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
}
- if(num_of_Cs > 1)
- {
- for(i=0; i < nData; i++)
- data_y[i] = data_y[i]/vec_C[i];
- }
+/* if(num_of_Cs > 1)*/
+/* {*/
+/* for(i=0; i < nData; i++) */
+/* data_y[i] = data_y[i]/vec_C[i];*/
+/* }*/
plhs[1] = mxCreateDoubleScalar( W0 );
diff --git a/svmocas.m b/svmocas_light.m
similarity index 57%
copy from svmocas.m
copy to svmocas_light.m
index 963c99d..6848525 100644
--- a/svmocas.m
+++ b/svmocas_light.m
@@ -1,9 +1,7 @@
-% SVMOCAS Train linear SVM classifier using OCAS solver.
+% SVMOCAS OCAS solver for training linear SVM classifier from SVM^light file.
%
% Synopsis:
-% [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime);
-%
-% [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime);
+% [W,W0,stat] = svmocas(dataFile,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime);
%
% Desription:
% This function trains linear SVM classifier by solving
@@ -11,18 +9,15 @@
% W,W0 = argmin 0.5*(w'*w+w0^2) + C*sum max( 0, 1-y(i)*(w'*X(:,i)+w0*X0) )
% w,w0 i=1:nExamples
%
-% The function accepts examples either in Matlab matrix X (both sparse and dense) and
-% a dense vector y or as path to a file in SVM^light format.
+% The function loads examples from dataFile in SVM^light format.
%
% Reference:
-% V. Franc, S. Sonnenburg. OCAS optimized cutting plane algorithm for Support Vector
-% Machines. In Proceedings of ICML. Omnipress, 2008.
-% http://ida.first.fraunhofer.de/~franc/papers/Franc-OCAS-ICML08.pdf
+% V. Franc, S. Sonnenburg. Optimized Cutting Plane Algorithm for Large-scale Risk
+% Minimization. Journal of Machine Learning Research. 2009
+% http://jmlr.csail.mit.edu/papers/volume10/franc09a/franc09a.pdf
%
% Input:
-% data_file [string] Training examples stored in SVM^light format.
-%
-% X [nDim x nExamples] training inputs (sparse or dense matrix).
+% dataFile [string] Training examples stored in SVM^light format.
% X0 [1x1] constant coordinate (implicitly) added to all examples;
% this allows training biased decision rule.
% y [nExamples x 1] labels (+1/-1).
@@ -45,22 +40,20 @@
% stat [struct] Optimizer statistics (field names are self-explaining).
%
% Example:
-% % loading data directly from file in SVM^light format
-% [W,W0,stat] = svmocas('./data/riply_trn.light',1,1);
-%
-% % using data loaded to Matlab
-% load('./data/riply_trn','X','y');
-% [W,W0,stat] = svmocas(X,1,y,1);
+% % training
+% libocasPath = fileparts(which('svmocas'));
+% svmC = 1;
+% [W,W0,stat] = svmocas_light([libocasPath '/data/riply_trn.light'],1,svmC);
%
-% % classification
-% load('riply_tst','X','y');
-% ypred = sign(W'*X + W0);
-% sum(ypred ~= y)/length(y)
+% % classification
+% [score,trueLabels] = linclassif_light([libocasPath '/data/riply_tst.light'],W,W0);
+% ypred = sign(score);
+% sum(ypred~=trueLabels)/length(trueLabels)
%
%
-% Copyright (C) 2008, 2009 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
-% Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+% Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+% Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public
diff --git a/svmocas_light.mexa64 b/svmocas_light.mexa64
new file mode 100755
index 0000000..f62cee8
Binary files /dev/null and b/svmocas_light.mexa64 differ
diff --git a/svmocas_lbp_mex.c b/svmocas_light_mex.c
similarity index 51%
copy from svmocas_lbp_mex.c
copy to svmocas_light_mex.c
index 0a6806a..f6760bb 100644
--- a/svmocas_lbp_mex.c
+++ b/svmocas_light_mex.c
@@ -1,37 +1,20 @@
/*=================================================================================
- * SVMOCAS_LBP Train linear SVM classifier for images represented by LBP features.
- *
+ * svmocas_light_mex.c: Matlab MEX interface to OCAS solver training two-class
+ * linear SVM classifier from examples in SVM^light file.
+ *
* Synopsis:
- * [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb)
+ * [W,W0,stat] = svmocas_light(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,
+ * nData,MaxTime,verb)
*
- * Input:
- * Images [(im_H*im_W) x nImages (uint8)]
- * imSize [2 x 1 (uint32)] imSize = [im_H im_W]
- * Wins [4 x nExamples (uint32)] [image_idx; top_left_col; top_left_row; mirror]
- * winSize [2 x 1 (uint32)] [win_H win_W]
- * height_of_pyramid [1 x 1 (double)]
- * X0 [1 x 1 (double)]
- * y [nExamples x 1 (double)] +1/-1
- * C [1 x 1 (double)] OR [nExamples x 1 (double)]
- * Method [1x1 (double)] 0 (BMRM) or 1 (OCAS)
- * TolRel [1x1 (double)]
- * TolAbs [1x1 (double)]
- * QPBound [1x1 (double)]
- * BufSize [1x1 (double)]
- * MaxTime [1x1 (double)]
- * verb [1x1 (bouble)]
- * Output:
- * W [nDim x 1] Parameter vector
- * W0 [1x1] Bias term
- * stat [struct]
+ * See svmocas_light.m for more help.
*
- * Copyright (C) 2008, 2009, 2010 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
- * Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
+ * Copyright (C) 2008, 2009, 2012 Vojtech Franc, xfrancv at cmp.felk.cvut.cz
+ * Soeren Sonnenburg, soeren.sonnenburg at first.fraunhofer.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
- *======================================================================================*/
+ *===================================================================================*/
#include <stdio.h>
#include <string.h>
@@ -39,14 +22,14 @@
#include <mex.h>
#include "libocas.h"
-#include "ocas_lbp_helper.h"
-#include "liblbp.h"
+#include "ocas_helper.h"
+#include "features_double.h"
#define DEFAULT_METHOD 1
#define DEFAULT_TOLREL 0.01
#define DEFAULT_TOLABS 0.0
#define DEFAULT_QPVALUE 0.0
-#define DEFAULT_BUFSIZE 500
+#define DEFAULT_BUFSIZE 2000
#define DEFAULT_MAXTIME mxGetInf()
#define DEFAULT_VERB 1
@@ -58,12 +41,12 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
double C, TolRel, TolAbs, QPBound, trn_err, MaxTime;
double *vec_C;
+ double *ptr;
uint32_t num_of_Cs;
uint32_t i, j, BufSize;
uint16_t Method;
int verb;
ocas_return_value_T ocas;
- double *tmp;
/* timing variables */
double init_time;
@@ -72,26 +55,21 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
total_time = get_time();
init_time = total_time;
- if(nrhs < 8 || nrhs > 15)
+ if(nrhs < 3 || nrhs > 11)
mexErrMsgTxt("Improper number of input arguments.\n\n"
- "SVMOCAS_LBP train linear SVM classifier for images prepresented by LBP features. \n\n"
+ "SVMOCAS_LIGHT train two-class linear SVM classifier from examples in SVM^light file\n\n"
"Synopsis:\n"
- " [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,height_of_pyramid,\n"
- " X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,MaxTime,verb) \n\n"
+ " [W,W0,stat] = svmocas_light(dataFile,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime) \n\n"
"Input: \n"
- " Images [(im_H*im_W) x nImages (uint8)]\n"
- " imSize [2 x 1 (uint32)] imSize = [im_H im_W]\n"
- " Wins [4 x nExamples (uint32)] [img_idx; topleft_col; topleft_row; mirror]\n"
- " winSize [2 x 1 (uint32)] [win_H win_W]\n"
- " height_of_pyramid [1 x 1 (double)]\n"
- " X0 [1 x 1 (double)]\n"
- " y [nExamples x 1 (double)] +1 or -1\n"
- " C [1 x 1 (double)] OR [nExamples x 1 (double)]\n"
+ " dataFile [string] path to file with training examples in SVM^light format\n"
+ " X0 [1 x 1 (double)] constant feature added to all examples\n"
+ " C [1x1] or [nExamples x 1] regularization constant(s) \n"
" Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
" TolRel [1x1 (double)]\n"
" TolAbs [1x1 (double)]\n"
" QPBound [1x1 (double)]\n"
" BufSize [1x1 (double)]\n"
+ " nExamples [1x1 (double) number of examples to use; (inf means use all examples)\n"
" MaxTime [1x1 (double)]\n"
" verb [1x1 (bouble)]\n\n"
"Output:\n"
@@ -99,112 +77,84 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
" W0 [1x1] Bias term\n"
" stat [struct] \n");
- /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
- /* [W,W0,stat]= svmocas_lbp(Images,imSize,Wins,winSize,nPyramids,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nExamples,MaxTime,verb) */
+ char *fname;
+ int fname_len;
- if(nrhs >= 16)
- verb = (int)mxGetScalar(prhs[15]);
+ if(nrhs >= 11)
+ verb = (int)mxGetScalar(prhs[10]);
else
verb = DEFAULT_VERB;
- Images = (uint8_t*)mxGetPr(prhs[0]);
- nImages = mxGetN(prhs[0]);
-
- tmp = (double*)mxGetPr(prhs[1]);
- im_H = (uint32_t)tmp[0];
- im_W = (uint32_t)tmp[1];
+ if(!mxIsChar(prhs[0]))
+ mexErrMsgTxt("First input argument must be of type string.");
- mexPrintf("im_h=%d im_W=%d \n", im_H, im_W);
- if(mxGetM(prhs[0]) != im_H*im_W)
- mexErrMsgTxt("Dimension of Images does not match to im_H*im_W.");
+ fname_len = mxGetNumberOfElements(prhs[0]) + 1;
+ fname = mxCalloc(fname_len, sizeof(char));
- Wins = (uint32_t*)mxGetPr(prhs[2]);
+ if (mxGetString(prhs[0], fname, fname_len) != 0)
+ mexErrMsgTxt("Could not convert first input argument to string.");
- tmp = (double*)mxGetPr(prhs[3]);
- win_H = (uint32_t)tmp[0];
- win_W = (uint32_t)tmp[1];
+ if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
+ mexErrMsgTxt("Cannot load input file.");
- nPyramids = (uint32_t)mxGetScalar(prhs[4]);
-/* nDim = lbppyr_get_dim(win_H,win_W,nPyramids);*/
- nDim = liblbp_pyr_get_dim(win_H,win_W,nPyramids);
-
- croped_window = (uint32_t*)mxCalloc(win_H*win_W,sizeof(uint32_t));
- if(croped_window == NULL)
- mexErrMsgTxt("Not enough memory for croped_window.");
-
- X0 = mxGetScalar(prhs[5]);
- data_y = (double*)mxGetPr(prhs[6]);
-
- nData = LIBOCAS_MAX(mxGetM(prhs[6]),mxGetN(prhs[6]));
- if(nData != mxGetN(prhs[2]))
- mexErrMsgTxt("Dimension missmatch betwenn Wins and y.");
-
- if(verb)
- {
- mexPrintf("Input data:\n"
- " # of images : %d\n"
- " image height : %d\n"
- " image width : %d\n",
- nImages, im_H, im_W);
-
- mexPrintf("Feature represenation:\n"
- " base window height : %d\n"
- " base window width : %d\n"
- " nPyramids : %d\n"
- " # of virtual examples : %d\n"
- " # of features per example : %d\n",
- win_H, win_W, nPyramids, nData, nDim);
- }
+ nDim = mxGetM(data_X);
+ X0 = mxGetScalar(prhs[1]);
- num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[7]),mxGetM(prhs[7]));
+ num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[2]),mxGetM(prhs[2]));
if(num_of_Cs == 1)
{
- C = (double)mxGetScalar(prhs[7]);
+ C = (double)mxGetScalar(prhs[2]);
}
else
{
- vec_C = (double*)mxGetPr(prhs[7]);
+ vec_C = (double*)mxGetPr(prhs[2]);
}
- if(nrhs >= 9)
- Method = (uint32_t)mxGetScalar(prhs[8]);
+ if(verb)
+ mexPrintf("Input data statistics:\n"
+ " # of examples : %d\n"
+ " dimensionality : %d\n"
+ " density : %.2f%%\n",
+ mxGetN(data_X), nDim, 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
+
+ if(nrhs >= 4)
+ Method = (uint32_t)mxGetScalar(prhs[3]);
else
Method = DEFAULT_METHOD;
- if(nrhs >= 10)
- TolRel = (double)mxGetScalar(prhs[9]);
+ if(nrhs >= 5)
+ TolRel = (double)mxGetScalar(prhs[4]);
else
TolRel = DEFAULT_TOLREL;
-
- if(nrhs >= 11)
- TolAbs = (double)mxGetScalar(prhs[10]);
+
+ if(nrhs >= 6)
+ TolAbs = (double)mxGetScalar(prhs[5]);
else
TolAbs = DEFAULT_TOLABS;
- if(nrhs >= 12)
- QPBound = (double)mxGetScalar(prhs[11]);
+ if(nrhs >= 7)
+ QPBound = (double)mxGetScalar(prhs[6]);
else
QPBound = DEFAULT_QPVALUE;
- if(nrhs >= 13)
- BufSize = (uint32_t)mxGetScalar(prhs[12]);
+ if(nrhs >= 8)
+ BufSize = (uint32_t)mxGetScalar(prhs[7]);
else
BufSize = DEFAULT_BUFSIZE;
- if(num_of_Cs > 1 && num_of_Cs < nData)
- mexErrMsgTxt("Length of the vector C less than the number of examples.");
+ if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
+ nData = (uint32_t)mxGetScalar(prhs[8]);
+ else
+ nData = mxGetN(data_X);
- if(nrhs >= 14 && !mxIsInf(mxGetScalar(prhs[13])))
- {
- if((uint32_t)mxGetScalar(prhs[13]) < 0 || (uint32_t)mxGetScalar(prhs[13]) > nData)
- mexErrMsgTxt("Improper number of examples; must be > 0 and < max number of virtual example.\n");
+ if(nData < 1 || nData > mxGetN(data_X))
+ mexErrMsgTxt("Improper value of argument nData.");
- nData = (uint32_t)mxGetScalar(prhs[13]);
- mexPrintf(" # of examples set to : %d\n",nData);
- }
+ if(num_of_Cs > 1 && num_of_Cs < nData)
+ mexErrMsgTxt("Length of the vector C less than the number of examples.");
- if(nrhs >= 15)
- MaxTime = (double)mxGetScalar(prhs[14]);
+ if(nrhs >= 10)
+ MaxTime = (double)mxGetScalar(prhs[9]);
else
MaxTime = DEFAULT_MAXTIME;
@@ -213,7 +163,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
-------------------------------------------------------------------*/
if(verb)
{
- mexPrintf("SVM setting:\n");
+ mexPrintf("Setting:\n");
if( num_of_Cs == 1)
mexPrintf(" C : %f\n", C);
@@ -232,6 +182,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
X0, nData, Method,BufSize,TolAbs,TolRel, QPBound, MaxTime, verb);
}
+
/* learned weight vector */
plhs[0] = (mxArray*)mxCreateDoubleMatrix(nDim,1,mxREAL);
W = (double*)mxGetPr(plhs[0]);
@@ -247,8 +198,7 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(A0 == NULL) mexErrMsgTxt("Not enough memory for vector A0.");
/* allocate buffer for computing cutting plane */
-/* new_a = (double*)mxCalloc(nDim,sizeof(double));*/
- new_a = mxCalloc(nDim,sizeof(new_a[0]));
+ new_a = (double*)mxCalloc(nDim,sizeof(double));
if(new_a == NULL)
mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");
@@ -258,61 +208,87 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
data_y[i] = data_y[i]*vec_C[i];
}
- /* !!!!!!!!!!!!
- ptr = mxGetPr(data_X);
- for(i=0; i < nData; i++) {
- for(j=0; j < nDim; j++ ) {
- ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
- }
+
+ /* select function to print progress info */
+ void (*print_function)(ocas_return_value_T);
+ if(verb)
+ {
+ mexPrintf("Starting optimization:\n");
+ print_function = &ocas_print;
+ }
+ else
+ {
+ print_function = &ocas_print_null;
}
- */
- /* init cutting plane buffer */
-/* full_A = mxCalloc(BufSize*nDim,sizeof(double));*/
- full_A = mxCalloc(BufSize*nDim,sizeof(full_A[0]));
- if( full_A == NULL )
- mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");
+ if( mxIsSparse(data_X)== true ) {
- if(verb)
- {
- mexPrintf("Memory occupancy:\n"
- " raw images : %.2f MB\n"
- " CP buffer : %.2f MB\n"
- " parameter vector W : %.2f MB\n",
- (double)nImages*im_H*im_W/(1024*1024),
- (double)sizeof(full_A[0])*BufSize*nDim/(1024*1024),
- (double)sizeof(W[0])*nDim/(1024*1024));
- }
+ /* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
+ for(i=0; i < nData; i++)
+ mul_sparse_col(data_y[i], data_X, i);
+
- init_time=get_time()-init_time;
+ /* init cutting plane buffer */
+ sparse_A.nz_dims = mxCalloc(BufSize,sizeof(uint32_t));
+ sparse_A.index = mxCalloc(BufSize,sizeof(sparse_A.index[0]));
+ sparse_A.value = mxCalloc(BufSize,sizeof(sparse_A.value[0]));
+ if(sparse_A.nz_dims == NULL || sparse_A.index == NULL || sparse_A.value == NULL)
+ mexErrMsgTxt("Not enough memory for cutting plane buffer sparse_A.");
- if(verb)
- {
- mexPrintf("Starting optimization:\n");
+ init_time=get_time()-init_time;
if(num_of_Cs == 1)
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print, 0);
+ {
+ ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize,
+ Method, &sparse_compute_W, &update_W,
+ &sparse_add_new_cut, &sparse_compute_output,
+ &qsort_data, print_function, 0);
+ }
else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print, 0);
+ {
+ ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+ BufSize, Method, &sparse_compute_W,
+ &update_W, &sparse_add_new_cut,
+ &sparse_compute_output, &qsort_data,
+ print_function, 0);
+ }
}
else
{
+
+ ptr = mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+ }
+ }
+
+ /* init cutting plane buffer */
+ full_A = mxCalloc(BufSize*nDim,sizeof(double));
+ if( full_A == NULL )
+ mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");
+
+ init_time=get_time()-init_time;
+
if(num_of_Cs == 1)
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print_null, 0);
+ {
+ ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,
+ BufSize, Method,
+ &full_compute_W, &update_W, &full_add_new_cut,
+ &full_compute_output, &qsort_data,
+ print_function, 0);
+ }
else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print_null, 0);
+ {
+ ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+ BufSize, Method,
+ &full_compute_W, &update_W, &full_add_new_cut,
+ &full_compute_output, &qsort_data,
+ print_function, 0);
+ }
}
-
if(verb)
{
mexPrintf("Stopping condition: ");
@@ -321,7 +297,8 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
case 1: mexPrintf("1-Q_D/Q_P <= TolRel(=%f) satisfied.\n", TolRel); break;
case 2: mexPrintf("Q_P-Q_D <= TolAbs(=%f) satisfied.\n", TolAbs); break;
case 3: mexPrintf("Q_P <= QPBound(=%f) satisfied.\n", QPBound); break;
- case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", ocas.ocas_time, MaxTime); break;
+ case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n",
+ ocas.ocas_time, MaxTime); break;
case -1: mexPrintf("Has not converged!\n" ); break;
case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
}
@@ -346,20 +323,18 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
}
- if(num_of_Cs > 1)
- {
- for(i=0; i < nData; i++)
- data_y[i] = data_y[i]/vec_C[i];
- }
+ mxDestroyArray( data_X );
plhs[1] = mxCreateDoubleScalar( W0 );
+ /* return ocas optimizer statistics */
const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
- "init_time","output_time","sort_time","qp_solver_time","add_time",
- "w_time","print_time","ocas_time","total_time"};
+ "init_time","output_time","sort_time","qp_solver_time",
+ "add_time","w_time","print_time","ocas_time","total_time"};
mwSize dims[2] = {1,1};
- plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), field_names);
+ plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)),
+ field_names);
mxSetField(plhs[2],0,"nIter",mxCreateDoubleScalar((double)ocas.nIter));
mxSetField(plhs[2],0,"nCutPlanes",mxCreateDoubleScalar((double)ocas.nCutPlanes));
diff --git a/svmocas_mex.c b/svmocas_mex.c
index 3e489b0..957d109 100644
--- a/svmocas_mex.c
+++ b/svmocas_mex.c
@@ -1,9 +1,10 @@
-/*=================================================================================
- * svmocas_mex.c: Matlab MEX interface for OCAS solver training the linear SVM classifiers.
+/*======================================================================================
+ * svmocas_mex.c: Matlab MEX interface to OCAS solver for training two-class
+ * linear SVM classifier
*
* Synopsis:
- * [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
- * [W,W0,stat] = svmocas(data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime,verb)
+ * [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,
+ * nData,MaxTime,verb)
*
* See svmocas.m for more help.
*
@@ -13,7 +14,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
- *======================================================================================*/
+ *=====================================================================================*/
#include <stdio.h>
#include <string.h>
@@ -22,6 +23,9 @@
#include "libocas.h"
#include "ocas_helper.h"
+#include "features_int8.h"
+#include "features_double.h"
+#include "features_single.h"
#define DEFAULT_METHOD 1
#define DEFAULT_TOLREL 0.01
@@ -39,11 +43,13 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
{
double C, TolRel, TolAbs, QPBound, trn_err, MaxTime;
double *vec_C;
- double *ptr;
uint32_t num_of_Cs;
uint32_t i, j, BufSize;
uint16_t Method;
int verb;
+ double *ptr_double;
+ float *ptr_single;
+ int8_t *ptr_int8;
ocas_return_value_T ocas;
/* timing variables */
@@ -53,193 +59,132 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
total_time = get_time();
init_time = total_time;
- if(nrhs < 1)
- mexErrMsgTxt("Improper number of input arguments.");
-
- /* get input arguments */
- if(mxIsChar(prhs[0]) == false)
+ if(nrhs < 4 || nrhs > 12)
+ mexErrMsgTxt("Improper number of input arguments.\n\n"
+ "SVMOCAS solver for training two-class linear SVM classifiers\n\n"
+ "Synopsis:\n"
+ " [W,W0,stat] = svmocas(X,X0,y,C,Method,TolRel,TolAbs,QPBound,"
+ "BufSize,nExamples,MaxTime) \n\n"
+ "Input: \n"
+ " X [nDim x nExamples] training inputs (dense double or sparse double or dense single or dense int8)\n"
+ " X0 [1 x 1 (double)] constant feature added to all examples\n"
+ " y [nExamples x 1 (double)] labels of the examples (+1/-1)\n"
+ " C [1x1] or [nExamples x 1] regularization constant(s) \n"
+ " Method [1x1 (double)] 0 for BMRM; 1 for OCAS \n"
+ " TolRel [1x1 (double)]\n"
+ " TolAbs [1x1 (double)]\n"
+ " QPBound [1x1 (double)]\n"
+ " BufSize [1x1 (double)]\n"
+ " nExamples [1x1 (double) number of examples to use; "
+ "(inf means use all examples)\n"
+ " MaxTime [1x1 (double)]\n"
+ " verb [1x1 (bouble)]\n\n"
+ "Output:\n"
+ " W [nDim x 1] Parameter vector\n"
+ " W0 [1x1] Bias term\n"
+ " stat [struct] \n");
+
+
+ if(nrhs >= 12)
+ verb = (int)mxGetScalar(prhs[11]);
+ else
+ verb = DEFAULT_VERB;
+
+ /* 1st input argument: training feature vectors */
+ data_X = (mxArray*)prhs[0];
+ if( (mxGetNumberOfDimensions(data_X) != 2) ||
+ !( ( mxIsDouble(data_X) && mxIsSparse(data_X) ) ||
+ ( mxIsDouble(data_X) && !mxIsSparse(data_X) ) ||
+ ( mxIsSingle(data_X) && !mxIsSparse(data_X) ) ||
+ ( mxIsInt8(data_X) && !mxIsSparse(data_X) ) ))
{
- /* [W,W0,stat] = svmocas_mex(X,X0,y,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime); */
-
- if(nrhs < 4 || nrhs > 12)
- mexErrMsgTxt("Improper number of input arguments.");
-
- if(nrhs >= 12)
- verb = (int)mxGetScalar(prhs[11]);
- else
- verb = DEFAULT_VERB;
-
-
- data_X = (mxArray*)prhs[0];
- if (!(mxIsDouble(data_X)))
- mexErrMsgTxt("Input argument X must be of type double.");
-
- if (mxGetNumberOfDimensions(data_X) != 2)
- mexErrMsgTxt("Input argument X must be two dimensional");
+ mexErrMsgTxt("The first input argument must be two dimensional matrix of the following type:\n"
+ "dense double or sparse double or dense single or dense int8 matrix.\n");
+ }
+
+ /* 2nd input argument: constant coordinate added to feature vectors */
+ X0 = (double)mxGetScalar(prhs[1]);
- X0 = mxGetScalar(prhs[1]);
- data_y = (double*)mxGetPr(prhs[2]);
+ /*3rd input argument: vector of labels */
+ if( !mxIsDouble(prhs[2]) || mxIsSparse(prhs[2]) )
+ mexErrMsgTxt("The third input argument must be dense vector of doubles.");
+ data_y = (double*)mxGetPr(prhs[2]);
- if(LIBOCAS_MAX(mxGetM(prhs[2]),mxGetN(prhs[2])) != mxGetN(prhs[0]))
- mexErrMsgTxt("Length of vector y must equl to the number of columns of matrix X.");
+ if(LIBOCAS_MAX(mxGetM(prhs[2]),mxGetN(prhs[2])) != mxGetN(prhs[0]))
+ mexErrMsgTxt("Length of vector y (3rd input argument) must equl to the number of columns of matrix X (1st input argument).");
- nDim = mxGetM(prhs[0]);
+ nDim = mxGetM(prhs[0]);
- if(verb)
- {
- mexPrintf("Input data statistics:\n"
- " # of examples : %d\n"
- " dimensionality : %d\n",
- mxGetN(data_X), nDim);
+ if(verb)
+ {
+ mexPrintf("Input data statistics:\n"
+ " # of examples : %d\n"
+ " dimensionality : %d\n",
+ mxGetN(data_X), nDim);
- if( mxIsSparse(data_X)== true )
- mexPrintf(" density : %.2f%%\n",
- 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
- else
- mexPrintf(" density : 100%% (full)\n");
- }
-
-
- num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[3]),mxGetM(prhs[3]));
- if(num_of_Cs == 1)
- {
- C = (double)mxGetScalar(prhs[3]);
- }
- else
- {
- vec_C = (double*)mxGetPr(prhs[3]);
- }
-
- if(nrhs >= 5)
- Method = (uint32_t)mxGetScalar(prhs[4]);
- else
- Method = DEFAULT_METHOD;
-
- if(nrhs >= 6)
- TolRel = (double)mxGetScalar(prhs[5]);
- else
- TolRel = DEFAULT_TOLREL;
-
- if(nrhs >= 7)
- TolAbs = (double)mxGetScalar(prhs[6]);
- else
- TolAbs = DEFAULT_TOLABS;
-
- if(nrhs >= 8)
- QPBound = (double)mxGetScalar(prhs[7]);
+ if( mxIsSparse(data_X)== true )
+ mexPrintf(" sparse features (density=%.2f%%) ",
+ 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
else
- QPBound = DEFAULT_QPVALUE;
-
- if(nrhs >= 9)
- BufSize = (uint32_t)mxGetScalar(prhs[8]);
- else
- BufSize = DEFAULT_BUFSIZE;
-
- if(nrhs >= 10 && mxIsInf(mxGetScalar(prhs[9])) == false)
- nData = (uint32_t)mxGetScalar(prhs[9]);
- else
- nData = mxGetN(data_X);
-
- if(nData < 1 || nData > mxGetN(prhs[0]))
- mexErrMsgTxt("Improper value of argument nData.");
-
- if(num_of_Cs > 1 && num_of_Cs < nData)
- mexErrMsgTxt("Length of the vector C less than the number of examples.");
+ mexPrintf(" dense features ");
+ if( mxIsDouble(data_X) )
+ mexPrintf("in double precision\n");
+ if( mxIsSingle(data_X) )
+ mexPrintf("in single precision\n");
+ if( mxIsInt8(data_X) )
+ mexPrintf("represented as int8\n");
+ }
- if(nrhs >= 11)
- MaxTime = (double)mxGetScalar(prhs[10]);
- else
- MaxTime = DEFAULT_MAXTIME;
- }
+ num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[3]),mxGetM(prhs[3]));
+ if(num_of_Cs == 1)
+ {
+ C = (double)mxGetScalar(prhs[3]);
+ }
else
{
- /* [W,W0,stat] = svmocas_mex(svmlight_data_file,X0,C,Method,TolRel,TolAbs,QPBound,BufSize,nData,MaxTime); */
- char *fname;
- int fname_len;
-
- if(nrhs < 3 || nrhs > 11)
- mexErrMsgTxt("Improper number of input arguments.");
-
- if(nrhs >= 11)
- verb = (int)mxGetScalar(prhs[10]);
- else
- verb = DEFAULT_VERB;
-
- if(!mxIsChar(prhs[0]))
- mexErrMsgTxt("First input argument must be of type string.");
-
- fname_len = mxGetNumberOfElements(prhs[0]) + 1;
- fname = mxCalloc(fname_len, sizeof(char));
-
- if (mxGetString(prhs[0], fname, fname_len) != 0)
- mexErrMsgTxt("Could not convert first input argument to string.");
-
- if( load_svmlight_file(fname,verb) == -1 || data_X == NULL || data_y == NULL)
- mexErrMsgTxt("Cannot load input file.");
-
- nDim = mxGetM(data_X);
- X0 = mxGetScalar(prhs[1]);
-
-/* C = (double)mxGetScalar(prhs[2]);*/
- num_of_Cs = LIBOCAS_MAX(mxGetN(prhs[2]),mxGetM(prhs[2]));
- if(num_of_Cs == 1)
- {
- C = (double)mxGetScalar(prhs[2]);
- }
- else
- {
- vec_C = (double*)mxGetPr(prhs[2]);
- }
-
- if(verb)
- mexPrintf("Input data statistics:\n"
- " # of examples : %d\n"
- " dimensionality : %d\n"
- " density : %.2f%%\n",
- mxGetN(data_X), nDim, 100.0*(double)mxGetNzmax(data_X)/((double)nDim*(double)(mxGetN(data_X))));
-
- if(nrhs >= 4)
- Method = (uint32_t)mxGetScalar(prhs[3]);
- else
- Method = DEFAULT_METHOD;
-
- if(nrhs >= 5)
- TolRel = (double)mxGetScalar(prhs[4]);
- else
- TolRel = DEFAULT_TOLREL;
+ vec_C = (double*)mxGetPr(prhs[3]);
+ }
- if(nrhs >= 6)
- TolAbs = (double)mxGetScalar(prhs[5]);
- else
- TolAbs = DEFAULT_TOLABS;
+ if(nrhs >= 5)
+ Method = (uint32_t)mxGetScalar(prhs[4]);
+ else
+ Method = DEFAULT_METHOD;
- if(nrhs >= 7)
- QPBound = (double)mxGetScalar(prhs[6]);
- else
- QPBound = DEFAULT_QPVALUE;
+ if(nrhs >= 6)
+ TolRel = (double)mxGetScalar(prhs[5]);
+ else
+ TolRel = DEFAULT_TOLREL;
- if(nrhs >= 8)
- BufSize = (uint32_t)mxGetScalar(prhs[7]);
- else
- BufSize = DEFAULT_BUFSIZE;
+ if(nrhs >= 7)
+ TolAbs = (double)mxGetScalar(prhs[6]);
+ else
+ TolAbs = DEFAULT_TOLABS;
- if(nrhs >= 9 && mxIsInf(mxGetScalar(prhs[8])) == false)
- nData = (uint32_t)mxGetScalar(prhs[8]);
- else
- nData = mxGetN(data_X);
+ if(nrhs >= 8)
+ QPBound = (double)mxGetScalar(prhs[7]);
+ else
+ QPBound = DEFAULT_QPVALUE;
- if(nData < 1 || nData > mxGetN(data_X))
- mexErrMsgTxt("Improper value of argument nData.");
+ if(nrhs >= 9)
+ BufSize = (uint32_t)mxGetScalar(prhs[8]);
+ else
+ BufSize = DEFAULT_BUFSIZE;
- if(num_of_Cs > 1 && num_of_Cs < nData)
- mexErrMsgTxt("Length of the vector C less than the number of examples.");
+ if(nrhs >= 10 && mxIsInf(mxGetScalar(prhs[9])) == false)
+ nData = (uint32_t)mxGetScalar(prhs[9]);
+ else
+ nData = mxGetN(data_X);
+
+ if(nData < 1 || nData > mxGetN(prhs[0]))
+ mexErrMsgTxt("Improper value of argument nData.");
- if(nrhs >= 10)
- MaxTime = (double)mxGetScalar(prhs[9]);
- else
- MaxTime = DEFAULT_MAXTIME;
+ if(num_of_Cs > 1 && num_of_Cs < nData)
+ mexErrMsgTxt("Length of the vector C less than the number of examples.");
- }
+ if(nrhs >= 11)
+ MaxTime = (double)mxGetScalar(prhs[10]);
+ else
+ MaxTime = DEFAULT_MAXTIME;
/*----------------------------------------------------------------
@@ -285,15 +230,26 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
if(new_a == NULL)
mexErrMsgTxt("Not enough memory for auxciliary cutting plane buffer new_a.");
-
if(num_of_Cs > 1)
{
for(i=0; i < nData; i++)
data_y[i] = data_y[i]*vec_C[i];
}
+ /* select function to print progress info */
+ void (*print_function)(ocas_return_value_T);
+ if(verb)
+ {
+ mexPrintf("Starting optimization:\n");
+ print_function = &ocas_print;
+ }
+ else
+ {
+ print_function = &ocas_print_null;
+ }
- if( mxIsSparse(data_X)== true ) {
+ if( mxIsSparse(data_X)== true )
+ {
/* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
for(i=0; i < nData; i++)
@@ -309,85 +265,96 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
init_time=get_time()-init_time;
- if(verb)
- {
- mexPrintf("Starting optimization:\n");
-
- if(num_of_Cs == 1)
- {
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
- &sparse_compute_output, &qsort_data, &ocas_print, 0);
- }
- else
- {
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
- &sparse_compute_output, &qsort_data, &ocas_print, 0);
- }
- }
+ if(num_of_Cs == 1)
+ {
+ ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &sparse_compute_W, &update_W, &sparse_add_new_cut,
+ &sparse_compute_output, &qsort_data,
+ print_function, 0);
+ }
else
{
- if(num_of_Cs == 1)
- {
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
- &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
- }
- else
- {
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &sparse_compute_W, &sparse_update_W, &sparse_add_new_cut,
- &sparse_compute_output, &qsort_data, &ocas_print_null, 0);
- }
- }
+ ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound,
+ MaxTime,BufSize, Method,
+ &sparse_compute_W, &update_W,
+ &sparse_add_new_cut, &sparse_compute_output,
+ &qsort_data, print_function, 0);
+ }
}
else
{
- ptr = mxGetPr(data_X);
- for(i=0; i < nData; i++) {
- for(j=0; j < nDim; j++ ) {
- ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+ int (*add_new_cut)(double*, uint32_t*, uint32_t, uint32_t, void*);
+ int (*compute_output)( double*, void* );
+
+ /* features in double precision */
+ if( mxIsDouble(data_X) )
+ {
+ ptr_double = mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_double[LIBOCAS_INDEX(j,i,nDim)] = ptr_double[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+ }
}
+
+ add_new_cut = &full_add_new_cut;
+ compute_output = &full_compute_output;
}
+ /* features in single precision */
+ if( mxIsSingle(data_X) )
+ {
+ ptr_single = (float*)mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_single[LIBOCAS_INDEX(j,i,nDim)] = ptr_single[LIBOCAS_INDEX(j,i,nDim)]*data_y[i];
+ }
+ }
+
+ add_new_cut = &full_single_add_new_cut;
+ compute_output = &full_single_compute_output;
+ }
+
+ /* features in int8 */
+ if( mxIsInt8(data_X) )
+ {
+ ptr_int8 = (int8_t*)mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_int8[LIBOCAS_INDEX(j,i,nDim)] = ptr_int8[LIBOCAS_INDEX(j,i,nDim)]/(int8_t)data_y[i];
+ }
+ }
+
+ add_new_cut = &full_int8_add_new_cut;
+ compute_output = &full_int8_compute_output;
+ }
+
/* init cutting plane buffer */
full_A = mxCalloc(BufSize*nDim,sizeof(double));
if( full_A == NULL )
mexErrMsgTxt("Not enough memory for cutting plane buffer full_A.");
init_time=get_time()-init_time;
-
- if(verb)
- {
- mexPrintf("Starting optimization:\n");
- if(num_of_Cs == 1)
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print, 0);
- else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print, 0);
-
+ if(num_of_Cs == 1)
+ {
+ ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
+ &full_compute_W, &update_W, add_new_cut,
+ compute_output, &qsort_data, print_function, 0);
}
else
{
- if(num_of_Cs == 1)
- ocas = svm_ocas_solver( C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print_null, 0);
- else
- ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,BufSize, Method,
- &full_compute_W, &full_update_W, &full_add_new_cut,
- &full_compute_output, &qsort_data, &ocas_print_null, 0);
+ ocas = svm_ocas_solver_difC( vec_C, nData, TolRel, TolAbs, QPBound, MaxTime,
+ BufSize, Method,
+ &full_compute_W, &update_W, add_new_cut,
+ compute_output, &qsort_data, print_function, 0);
}
}
+ total_time=get_time()-total_time;
+
if(verb)
{
mexPrintf("Stopping condition: ");
@@ -396,15 +363,12 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
case 1: mexPrintf("1-Q_D/Q_P <= TolRel(=%f) satisfied.\n", TolRel); break;
case 2: mexPrintf("Q_P-Q_D <= TolAbs(=%f) satisfied.\n", TolAbs); break;
case 3: mexPrintf("Q_P <= QPBound(=%f) satisfied.\n", QPBound); break;
- case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n", ocas.ocas_time, MaxTime); break;
+ case 4: mexPrintf("Optimization time (=%f) >= MaxTime(=%f).\n",
+ ocas.ocas_time, MaxTime); break;
case -1: mexPrintf("Has not converged!\n" ); break;
case -2: mexPrintf("Not enough memory for the solver.\n" ); break;
}
- }
- total_time=get_time()-total_time;
- if(verb)
- {
mexPrintf("Timing statistics:\n"
" init_time : %f[s]\n"
" qp_solver_time : %f[s]\n"
@@ -421,8 +385,9 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
mexPrintf("Training error: %.4f%%\n", 100*(double)ocas.trn_err/(double)nData);
}
- /* multiply data ba labels as it was at the begining */
- if( mxIsSparse(data_X)== true ) {
+ /* multiply data by labels as it was at the begining */
+ if( mxIsSparse(data_X)== true )
+ {
/* for i=1:nData, X(:,i) = X(:,i)*y(i); end*/
for(i=0; i < nData; i++)
{
@@ -431,42 +396,59 @@ void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] )
}
else
{
- ptr = mxGetPr(data_X);
- for(i=0; i < nData; i++) {
- for(j=0; j < nDim; j++ ) {
- ptr[LIBOCAS_INDEX(j,i,nDim)] = ptr[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+
+ /* features in double precision */
+ if( mxIsDouble(data_X) )
+ {
+ ptr_double = mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_double[LIBOCAS_INDEX(j,i,nDim)] = ptr_double[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+ }
}
}
+
+ /* features in single precision */
+ if( mxIsSingle(data_X) )
+ {
+ ptr_single = (float*)mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_single[LIBOCAS_INDEX(j,i,nDim)] = ptr_single[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+ }
+ }
+ }
+
+ /* features in int8 */
+ if( mxIsInt8(data_X) )
+ {
+ ptr_int8 = (int8_t*)mxGetPr(data_X);
+ for(i=0; i < nData; i++) {
+ for(j=0; j < nDim; j++ ) {
+ ptr_int8[LIBOCAS_INDEX(j,i,nDim)] = ptr_int8[LIBOCAS_INDEX(j,i,nDim)]/data_y[i];
+ }
+ }
+ }
}
+ /* divide labels by Cs as it was at the begining */
if(num_of_Cs > 1)
{
for(i=0; i < nData; i++)
data_y[i] = data_y[i]/vec_C[i];
}
-
+ /* create output variables */
plhs[1] = mxCreateDoubleScalar( W0 );
- /* return ocas optimizer statistics */
- /* typedef struct {
- uint32_t nIter;
- uint32_t nCutPlanes;
- double trn_err;
- double Q_P;
- double Q_D;
- double output_time;
- double sort_time;
- double solver_time;
- int8_t exitflag;
- } ocas_return_value_T; */
-
const char *field_names[] = {"nTrnErrors","Q_P","Q_D","nIter","nCutPlanes","exitflag",
- "init_time","output_time","sort_time","qp_solver_time","add_time",
- "w_time","print_time","ocas_time","total_time"};
+ "init_time","output_time","sort_time",
+ "qp_solver_time","add_time","w_time","print_time",
+ "ocas_time","total_time"};
mwSize dims[2] = {1,1};
- plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)), field_names);
+ plhs[2] = mxCreateStructArray(2, dims, (sizeof(field_names)/sizeof(*field_names)),
+ field_names);
mxSetField(plhs[2],0,"nIter",mxCreateDoubleScalar((double)ocas.nIter));
mxSetField(plhs[2],0,"nCutPlanes",mxCreateDoubleScalar((double)ocas.nCutPlanes));
diff --git a/version.h b/version.h
index ed306ef..c79cd4a 100644
--- a/version.h
+++ b/version.h
@@ -1,3 +1,3 @@
/* this text will be printed in all programs */
-#define OCAS_VERSION "v0.93, (C) 2008, 2009, 2010 Vojtech Franc, Soeren Sonnenburg"
+#define OCAS_VERSION "v0.95, (C) 2008-2012 Vojtech Franc, Soeren Sonnenburg"
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/libocas.git
More information about the debian-science-commits
mailing list