Skip to content

Commit

Permalink
[ossvm] OSSVM implementation for binary classification
Browse files Browse the repository at this point in the history
This commit provides the OSSVM implementation as proposed by [1].  For
usage through LibSVM’s executable, it provides the additional `-l`
option for the lambda regularization parameters described in
Equation (11) of the paper [1].  The `-l` option is only accepted when
the kernel type is RBF, i.e., when `-t 2` is provided.

Note: Although in the paper [1] it is presented that the lambda
regularization parameter can be up to `C * mp`, in which `C` is the
SVM cost parameter and `mp` is the number of positive training
instances on the training set, to facilitate usage, `-l` option
accepts a value in the interval `[0, 1)` which is linearly mapped to
the interval `[0, C*mp)`.  Value of the lambda parameters equals to 1
is not accepted, as explained in the second paragraph after
Proposition 1 in the paper [1].

This commit also adjusts the Python wrap for usage.

[1] Mendes Júnior, Pedro Ribeiro; Boult, Terrance E.; Wainer, Jacques;
and Rocha, Anderson de Rezende (2021), “Open-Set Support Vector
Machines”, to appear in IEEE Transactions on Systems, Man, and
Cybernetics: Systems. URL: https://pedrormjunior.github.io/OSSVM.html
  • Loading branch information
pedrormjunior committed Apr 11, 2021
1 parent 5f4a812 commit 50d51dc
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ options:
-g gamma : set gamma in kernel function (default 1/num_features)
-r coef0 : set coef0 in kernel function (default 0)
-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
-l lamb : set the parameter lambda of SSVM (C-SVC) for open-set recognition (default -1)
-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)
-m cachesize : set cache memory size in MB (default 100)
Expand Down Expand Up @@ -385,6 +386,7 @@ to classify new data.
double cache_size; /* in MB */
double eps; /* stopping criteria */
double C; /* for C_SVC, EPSILON_SVR, and NU_SVR */
double lamb; /* for SSVM (open-set recognition) */
int nr_weight; /* for C_SVC */
int *weight_label; /* for C_SVC */
double* weight; /* for C_SVC */
Expand Down
8 changes: 6 additions & 2 deletions python/svm.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,10 @@ def __init__(self, y, x, isKernel=False):

class svm_parameter(Structure):
_names = ["svm_type", "kernel_type", "degree", "gamma", "coef0",
"cache_size", "eps", "C", "nr_weight", "weight_label", "weight",
"cache_size", "eps", "C", "lamb", "nr_weight", "weight_label", "weight",
"nu", "p", "shrinking", "probability"]
_types = [c_int, c_int, c_int, c_double, c_double,
c_double, c_double, c_double, c_int, POINTER(c_int), POINTER(c_double),
c_double, c_double, c_double, c_double, c_int, POINTER(c_int), POINTER(c_double),
c_double, c_double, c_int, c_int]
_fields_ = genFields(_names, _types)

Expand Down Expand Up @@ -255,6 +255,7 @@ def set_to_default_values(self):
self.nu = 0.5
self.cache_size = 100
self.C = 1
self.lamb = -1
self.eps = 0.001
self.p = 0.1
self.shrinking = 1
Expand Down Expand Up @@ -304,6 +305,9 @@ def parse_options(self, options):
elif argv[i] == "-c":
i = i + 1
self.C = float(argv[i])
elif argv[i] == "-l":
i = i + 1
self.lamb = float(argv[i])
elif argv[i] == "-e":
i = i + 1
self.eps = float(argv[i])
Expand Down
1 change: 1 addition & 0 deletions python/svmutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def svm_train(arg1, arg2=None, arg3=None):
-g gamma : set gamma in kernel function (default 1/num_features)
-r coef0 : set coef0 in kernel function (default 0)
-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
-l lamb : set the parameter lamb of SSVM (C-SVC) for open-set recognition (default -1)
-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)
-m cachesize : set cache memory size in MB (default 100)
Expand Down
5 changes: 5 additions & 0 deletions svm-train.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void exit_with_help()
"-g gamma : set gamma in kernel function (default 1/num_features)\n"
"-r coef0 : set coef0 in kernel function (default 0)\n"
"-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)\n"
"-l lamb : set the parameter lambda of SSVM (C-SVC) for open-set recognition (default -1)\n"
"-n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)\n"
"-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)\n"
"-m cachesize : set cache memory size in MB (default 100)\n"
Expand Down Expand Up @@ -172,6 +173,7 @@ void parse_command_line(int argc, char **argv, char *input_file_name, char *mode
param.nu = 0.5;
param.cache_size = 100;
param.C = 1;
param.lamb = -1;
param.eps = 1e-3;
param.p = 0.1;
param.shrinking = 1;
Expand Down Expand Up @@ -213,6 +215,9 @@ void parse_command_line(int argc, char **argv, char *input_file_name, char *mode
case 'c':
param.C = atof(argv[i]);
break;
case 'l':
param.lamb = atof(argv[i]);
break;
case 'e':
param.eps = atof(argv[i]);
break;
Expand Down
16 changes: 15 additions & 1 deletion svm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1447,9 +1447,10 @@ static void solve_c_svc(

int i;

double alpha_epsilon = param->lamb >= 0 ? param->lamb * param->C : 0;
for(i=0;i<l;i++)
{
alpha[i] = 0;
alpha[i] = prob->y[i] > 0 ? alpha_epsilon : 0;
minus_ones[i] = -1;
if(prob->y[i] > 0) y[i] = +1; else y[i] = -1;
}
Expand Down Expand Up @@ -2669,6 +2670,8 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
if(param.kernel_type == POLY || param.kernel_type == SIGMOID)
fprintf(fp,"coef0 %.17g\n", param.coef0);

fprintf(fp,"lamb %g\n", param.lamb);

int nr_class = model->nr_class;
int l = model->l;
fprintf(fp, "nr_class %d\n", nr_class);
Expand Down Expand Up @@ -2825,6 +2828,8 @@ bool read_model_header(FILE *fp, svm_model* model)
FSCANF(fp,"%lf",&param.gamma);
else if(strcmp(cmd,"coef0")==0)
FSCANF(fp,"%lf",&param.coef0);
else if(strcmp(cmd,"lamb")==0)
FSCANF(fp,"%lf",&param.lamb);
else if(strcmp(cmd,"nr_class")==0)
FSCANF(fp,"%d",&model->nr_class);
else if(strcmp(cmd,"total_sv")==0)
Expand Down Expand Up @@ -3086,6 +3091,15 @@ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *pa
if(param->C <= 0)
return "C <= 0";

if(param->lamb < 0 && param->lamb != -1)
return "lamb < 0 and lamb != -1";
if(param->lamb >= 1)
return "lamb >= 1";
if(param->lamb >= 0 && svm_type != C_SVC)
return "lamb >= 0 and svm_type != C_SVC";
if(param->lamb >= 0 && kernel_type != RBF)
return "lamb > 0 and kernel_type != RBF";

if(svm_type == NU_SVC ||
svm_type == ONE_CLASS ||
svm_type == NU_SVR)
Expand Down
1 change: 1 addition & 0 deletions svm.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct svm_parameter
double cache_size; /* in MB */
double eps; /* stopping criteria */
double C; /* for C_SVC, EPSILON_SVR and NU_SVR */
double lamb; /* for SSVM (open-set recognition) */
int nr_weight; /* for C_SVC */
int *weight_label; /* for C_SVC */
double* weight; /* for C_SVC */
Expand Down

0 comments on commit 50d51dc

Please sign in to comment.