liblinear-ruby 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/blasp.h +8 -0
- data/ext/daxpy.c +8 -0
- data/ext/ddot.c +8 -0
- data/ext/dnrm2.c +8 -0
- data/ext/dscal.c +8 -0
- data/ext/liblinear_wrap.cxx +128 -3
- data/ext/linear.cpp +344 -175
- data/ext/linear.h +2 -0
- data/ext/tron.cpp +14 -8
- data/ext/tron.h +2 -1
- data/lib/liblinear/version.rb +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/COPYRIGHT +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/Makefile +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/Makefile.win +3 -9
- data/{liblinear-1.95 → liblinear-2.1}/README +45 -7
- data/{liblinear-1.95 → liblinear-2.1}/blas/Makefile +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/blas.h +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/blasp.h +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/daxpy.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/ddot.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/dnrm2.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/blas/dscal.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/heart_scale +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/linear.cpp +344 -175
- data/{liblinear-1.95 → liblinear-2.1}/linear.def +1 -0
- data/{liblinear-1.95 → liblinear-2.1}/linear.h +2 -0
- data/{liblinear-1.95 → liblinear-2.1}/matlab/Makefile +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/matlab/README +12 -2
- data/{liblinear-1.95 → liblinear-2.1}/matlab/libsvmread.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/matlab/libsvmwrite.c +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/matlab/linear_model_matlab.c +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/matlab/linear_model_matlab.h +0 -0
- data/liblinear-2.1/matlab/make.m +22 -0
- data/{liblinear-1.95 → liblinear-2.1}/matlab/predict.c +1 -1
- data/{liblinear-1.95 → liblinear-2.1}/matlab/train.c +65 -10
- data/{liblinear-1.95 → liblinear-2.1}/predict.c +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/python/Makefile +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/python/README +7 -0
- data/{liblinear-1.95 → liblinear-2.1}/python/liblinear.py +27 -8
- data/{liblinear-1.95 → liblinear-2.1}/python/liblinearutil.py +16 -2
- data/{liblinear-1.95 → liblinear-2.1}/train.c +51 -1
- data/{liblinear-1.95 → liblinear-2.1}/tron.cpp +14 -8
- data/{liblinear-1.95 → liblinear-2.1}/tron.h +2 -1
- data/liblinear-2.1/windows/liblinear.dll +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/windows/libsvmread.mexw64 +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/windows/libsvmwrite.mexw64 +0 -0
- data/liblinear-2.1/windows/predict.exe +0 -0
- data/{liblinear-1.95 → liblinear-2.1}/windows/predict.mexw64 +0 -0
- data/liblinear-2.1/windows/train.exe +0 -0
- data/liblinear-2.1/windows/train.mexw64 +0 -0
- data/liblinear-ruby.gemspec +9 -10
- metadata +49 -50
- data/liblinear-1.95/matlab/make.m +0 -21
- data/liblinear-1.95/windows/liblinear.dll +0 -0
- data/liblinear-1.95/windows/predict.exe +0 -0
- data/liblinear-1.95/windows/train.exe +0 -0
- data/liblinear-1.95/windows/train.mexw64 +0 -0
data/ext/linear.h
CHANGED
@@ -32,6 +32,7 @@ struct parameter
|
|
32
32
|
int *weight_label;
|
33
33
|
double* weight;
|
34
34
|
double p;
|
35
|
+
double *init_sol;
|
35
36
|
};
|
36
37
|
|
37
38
|
struct model
|
@@ -46,6 +47,7 @@ struct model
|
|
46
47
|
|
47
48
|
struct model* train(const struct problem *prob, const struct parameter *param);
|
48
49
|
void cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, double *target);
|
50
|
+
void find_parameter_C(const struct problem *prob, const struct parameter *param, int nr_fold, double start_C, double max_C, double *best_C, double *best_rate);
|
49
51
|
|
50
52
|
double predict_values(const struct model *model_, const struct feature_node *x, double* dec_values);
|
51
53
|
double predict(const struct model *model_, const struct feature_node *x);
|
data/ext/tron.cpp
CHANGED
@@ -41,10 +41,11 @@ void TRON::info(const char *fmt,...)
|
|
41
41
|
(*tron_print_string)(buf);
|
42
42
|
}
|
43
43
|
|
44
|
-
TRON::TRON(const function *fun_obj, double eps, int max_iter)
|
44
|
+
TRON::TRON(const function *fun_obj, double eps, double eps_cg, int max_iter)
|
45
45
|
{
|
46
46
|
this->fun_obj=const_cast<function *>(fun_obj);
|
47
47
|
this->eps=eps;
|
48
|
+
this->eps_cg=eps_cg;
|
48
49
|
this->max_iter=max_iter;
|
49
50
|
tron_print_string = default_print;
|
50
51
|
}
|
@@ -68,23 +69,28 @@ void TRON::tron(double *w)
|
|
68
69
|
int search = 1, iter = 1, inc = 1;
|
69
70
|
double *s = new double[n];
|
70
71
|
double *r = new double[n];
|
71
|
-
double *w_new = new double[n];
|
72
72
|
double *g = new double[n];
|
73
73
|
|
74
|
+
// calculate gradient norm at w=0 for stopping condition.
|
75
|
+
double *w0 = new double[n];
|
74
76
|
for (i=0; i<n; i++)
|
75
|
-
|
77
|
+
w0[i] = 0;
|
78
|
+
fun_obj->fun(w0);
|
79
|
+
fun_obj->grad(w0, g);
|
80
|
+
double gnorm0 = dnrm2_(&n, g, &inc);
|
81
|
+
delete [] w0;
|
76
82
|
|
77
83
|
f = fun_obj->fun(w);
|
78
84
|
fun_obj->grad(w, g);
|
79
85
|
delta = dnrm2_(&n, g, &inc);
|
80
|
-
double
|
81
|
-
double gnorm = gnorm1;
|
86
|
+
double gnorm = delta;
|
82
87
|
|
83
|
-
if (gnorm <= eps*
|
88
|
+
if (gnorm <= eps*gnorm0)
|
84
89
|
search = 0;
|
85
90
|
|
86
91
|
iter = 1;
|
87
92
|
|
93
|
+
double *w_new = new double[n];
|
88
94
|
while (iter <= max_iter && search)
|
89
95
|
{
|
90
96
|
cg_iter = trcg(delta, g, s, r);
|
@@ -130,7 +136,7 @@ void TRON::tron(double *w)
|
|
130
136
|
fun_obj->grad(w, g);
|
131
137
|
|
132
138
|
gnorm = dnrm2_(&n, g, &inc);
|
133
|
-
if (gnorm <= eps*
|
139
|
+
if (gnorm <= eps*gnorm0)
|
134
140
|
break;
|
135
141
|
}
|
136
142
|
if (f < -1.0e+32)
|
@@ -172,7 +178,7 @@ int TRON::trcg(double delta, double *g, double *s, double *r)
|
|
172
178
|
r[i] = -g[i];
|
173
179
|
d[i] = r[i];
|
174
180
|
}
|
175
|
-
cgtol =
|
181
|
+
cgtol = eps_cg*dnrm2_(&n, g, &inc);
|
176
182
|
|
177
183
|
int cg_iter = 0;
|
178
184
|
rTr = ddot_(&n, r, &inc, r, &inc);
|
data/ext/tron.h
CHANGED
@@ -15,7 +15,7 @@ public:
|
|
15
15
|
class TRON
|
16
16
|
{
|
17
17
|
public:
|
18
|
-
TRON(const function *fun_obj, double eps = 0.1, int max_iter = 1000);
|
18
|
+
TRON(const function *fun_obj, double eps = 0.1, double eps_cg = 0.1, int max_iter = 1000);
|
19
19
|
~TRON();
|
20
20
|
|
21
21
|
void tron(double *w);
|
@@ -26,6 +26,7 @@ private:
|
|
26
26
|
double norm_inf(int n, double *x);
|
27
27
|
|
28
28
|
double eps;
|
29
|
+
double eps_cg;
|
29
30
|
int max_iter;
|
30
31
|
function *fun_obj;
|
31
32
|
void info(const char *fmt,...);
|
data/lib/liblinear/version.rb
CHANGED
@@ -1,14 +1,8 @@
|
|
1
|
-
#You must ensure nmake.exe, cl.exe, link.exe are in system path.
|
2
|
-
#VCVARS32.bat
|
3
|
-
#Under dosbox prompt
|
4
|
-
#nmake -f Makefile.win
|
5
|
-
|
6
|
-
##########################################
|
7
1
|
CXX = cl.exe
|
8
|
-
CFLAGS = /nologo /O2 /EHsc /I. /D
|
2
|
+
CFLAGS = /nologo /O2 /EHsc /I. /D _WIN64 /D _CRT_SECURE_NO_DEPRECATE
|
9
3
|
TARGET = windows
|
10
4
|
|
11
|
-
all: $(TARGET)\train.exe $(TARGET)\predict.exe
|
5
|
+
all: $(TARGET)\train.exe $(TARGET)\predict.exe lib
|
12
6
|
|
13
7
|
$(TARGET)\train.exe: tron.obj linear.obj train.c blas\*.c
|
14
8
|
$(CXX) $(CFLAGS) -Fe$(TARGET)\train.exe tron.obj linear.obj train.c blas\*.c
|
@@ -26,5 +20,5 @@ lib: linear.cpp linear.h linear.def tron.obj
|
|
26
20
|
$(CXX) $(CFLAGS) -LD linear.cpp tron.obj blas\*.c -Fe$(TARGET)\liblinear -link -DEF:linear.def
|
27
21
|
|
28
22
|
clean:
|
29
|
-
-erase /Q *.obj $(TARGET)
|
23
|
+
-erase /Q *.obj $(TARGET)\*.exe $(TARGET)\*.dll $(TARGET)\*.exp $(TARGET)\*.lib
|
30
24
|
|
@@ -131,11 +131,16 @@ options:
|
|
131
131
|
-B bias : if bias >= 0, instance x becomes [x; bias]; if < 0, no bias term added (default -1)
|
132
132
|
-wi weight: weights adjust the parameter C of different classes (see README for details)
|
133
133
|
-v n: n-fold cross validation mode
|
134
|
+
-C : find parameter C (only for -s 0 and 2)
|
134
135
|
-q : quiet mode (no outputs)
|
135
136
|
|
136
137
|
Option -v randomly splits the data into n parts and calculates cross
|
137
138
|
validation accuracy on them.
|
138
139
|
|
140
|
+
Option -C conducts cross validation under different C values and finds
|
141
|
+
the best one. This options is supported only by -s 0 and -s 2. If
|
142
|
+
the solver is not specified, -s 2 is used.
|
143
|
+
|
139
144
|
Formulations:
|
140
145
|
|
141
146
|
For L2-regularized logistic regression (-s 0), we solve
|
@@ -241,10 +246,27 @@ Train a logistic regression model.
|
|
241
246
|
|
242
247
|
> train -v 5 -e 0.001 data_file
|
243
248
|
|
244
|
-
Do five-fold cross-validation using L2-loss
|
249
|
+
Do five-fold cross-validation using L2-loss SVM.
|
245
250
|
Use a smaller stopping tolerance 0.001 than the default
|
246
251
|
0.1 if you want more accurate solutions.
|
247
252
|
|
253
|
+
> train -C data_file
|
254
|
+
|
255
|
+
Conduct cross validation many times by L2-loss SVM
|
256
|
+
and find the parameter C which achieves the best cross
|
257
|
+
validation accuracy.
|
258
|
+
|
259
|
+
> train -C -s 0 -v 3 -c 0.5 -e 0.0001 data_file
|
260
|
+
|
261
|
+
For parameter selection by -C, users can specify other
|
262
|
+
solvers (currently -s 0 and -s 2 are supported) and
|
263
|
+
different number of CV folds. Further, users can use
|
264
|
+
the -c option to specify the smallest C value of the
|
265
|
+
search range. This setting is useful when users want
|
266
|
+
to rerun the parameter selection procedure from a
|
267
|
+
specified C under a different setting, such as a stricter
|
268
|
+
stopping tolerance -e 0.0001 in the above example.
|
269
|
+
|
248
270
|
> train -c 10 -w1 2 -w2 5 -w3 2 four_class_data_file
|
249
271
|
|
250
272
|
Train four classifiers:
|
@@ -407,6 +429,22 @@ Library Usage
|
|
407
429
|
|
408
430
|
The format of prob is same as that for train().
|
409
431
|
|
432
|
+
- Function: void find_parameter_C(const struct problem *prob,
|
433
|
+
const struct parameter *param, int nr_fold, double start_C,
|
434
|
+
double max_C, double *best_C, double *best_rate);
|
435
|
+
|
436
|
+
This function is similar to cross_validation. However, instead of
|
437
|
+
conducting cross validation under a specified parameter C, it
|
438
|
+
conducts cross validation many times under parameters C = start_C,
|
439
|
+
2*start_C, 4*start_C, 8*start_C, ..., and finds the best one with
|
440
|
+
the highest cross validation accuracy.
|
441
|
+
|
442
|
+
If start_C <= 0, then this procedure calculates a small enough C
|
443
|
+
for prob as the start_C. The procedure stops when the models of
|
444
|
+
all folds become stable or C reaches max_C. The best C and the
|
445
|
+
corresponding accuracy are assigned to *best_C and *best_rate,
|
446
|
+
respectively.
|
447
|
+
|
410
448
|
- Function: double predict(const model *model_, const feature_node *x);
|
411
449
|
|
412
450
|
For a classification model, the predicted class for x is returned.
|
@@ -418,11 +456,11 @@ Library Usage
|
|
418
456
|
|
419
457
|
This function gives nr_w decision values in the array dec_values.
|
420
458
|
nr_w=1 if regression is applied or the number of classes is two. An exception is
|
421
|
-
multi-class
|
459
|
+
multi-class SVM by Crammer and Singer (-s 4), where nr_w = 2 if there are two classes. For all other situations, nr_w is the
|
422
460
|
number of classes.
|
423
461
|
|
424
462
|
We implement one-vs-the rest multi-class strategy (-s 0,1,2,3,5,6,7)
|
425
|
-
and multi-class
|
463
|
+
and multi-class SVM by Crammer and Singer (-s 4) for multi-class SVM.
|
426
464
|
The class with the highest decision value is returned.
|
427
465
|
|
428
466
|
- Function: double predict_probability(const struct model *model_,
|
@@ -523,7 +561,7 @@ Visual C++, use the following steps:
|
|
523
561
|
1. Open a dos command box and change to liblinear directory. If
|
524
562
|
environment variables of VC++ have not been set, type
|
525
563
|
|
526
|
-
"C:\Program Files\Microsoft Visual Studio
|
564
|
+
""C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64\vcvars64.bat""
|
527
565
|
|
528
566
|
You may have to modify the above command according which version of
|
529
567
|
VC++ or where it is installed.
|
@@ -532,9 +570,9 @@ VC++ or where it is installed.
|
|
532
570
|
|
533
571
|
nmake -f Makefile.win clean all
|
534
572
|
|
535
|
-
2. (Optional) To build
|
536
|
-
(1) Setup
|
537
|
-
(2) Change CFLAGS in Makefile.win: /D
|
573
|
+
2. (Optional) To build 32-bit windows binaries, you must
|
574
|
+
(1) Setup "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat" instead of vcvars64.bat
|
575
|
+
(2) Change CFLAGS in Makefile.win: /D _WIN64 to /D _WIN32
|
538
576
|
|
539
577
|
MATLAB/OCTAVE Interface
|
540
578
|
=======================
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -27,6 +27,7 @@ static void print_string_stdout(const char *s)
|
|
27
27
|
fputs(s,stdout);
|
28
28
|
fflush(stdout);
|
29
29
|
}
|
30
|
+
static void print_null(const char *s) {}
|
30
31
|
|
31
32
|
static void (*liblinear_print_string) (const char *) = &print_string_stdout;
|
32
33
|
|
@@ -43,6 +44,40 @@ static void info(const char *fmt,...)
|
|
43
44
|
#else
|
44
45
|
static void info(const char *fmt,...) {}
|
45
46
|
#endif
|
47
|
+
class sparse_operator
|
48
|
+
{
|
49
|
+
public:
|
50
|
+
static double nrm2_sq(const feature_node *x)
|
51
|
+
{
|
52
|
+
double ret = 0;
|
53
|
+
while(x->index != -1)
|
54
|
+
{
|
55
|
+
ret += x->value*x->value;
|
56
|
+
x++;
|
57
|
+
}
|
58
|
+
return (ret);
|
59
|
+
}
|
60
|
+
|
61
|
+
static double dot(const double *s, const feature_node *x)
|
62
|
+
{
|
63
|
+
double ret = 0;
|
64
|
+
while(x->index != -1)
|
65
|
+
{
|
66
|
+
ret += s[x->index-1]*x->value;
|
67
|
+
x++;
|
68
|
+
}
|
69
|
+
return (ret);
|
70
|
+
}
|
71
|
+
|
72
|
+
static void axpy(const double a, const feature_node *x, double *y)
|
73
|
+
{
|
74
|
+
while(x->index != -1)
|
75
|
+
{
|
76
|
+
y[x->index-1] += a*x->value;
|
77
|
+
x++;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
};
|
46
81
|
|
47
82
|
class l2r_lr_fun: public function
|
48
83
|
{
|
@@ -139,12 +174,19 @@ void l2r_lr_fun::Hv(double *s, double *Hs)
|
|
139
174
|
int l=prob->l;
|
140
175
|
int w_size=get_nr_variable();
|
141
176
|
double *wa = new double[l];
|
177
|
+
feature_node **x=prob->x;
|
142
178
|
|
143
|
-
|
179
|
+
for(i=0;i<w_size;i++)
|
180
|
+
Hs[i] = 0;
|
144
181
|
for(i=0;i<l;i++)
|
182
|
+
{
|
183
|
+
feature_node * const xi=x[i];
|
184
|
+
wa[i] = sparse_operator::dot(s, xi);
|
185
|
+
|
145
186
|
wa[i] = C[i]*D[i]*wa[i];
|
146
187
|
|
147
|
-
|
188
|
+
sparse_operator::axpy(wa[i], xi, Hs);
|
189
|
+
}
|
148
190
|
for(i=0;i<w_size;i++)
|
149
191
|
Hs[i] = s[i] + Hs[i];
|
150
192
|
delete[] wa;
|
@@ -157,15 +199,7 @@ void l2r_lr_fun::Xv(double *v, double *Xv)
|
|
157
199
|
feature_node **x=prob->x;
|
158
200
|
|
159
201
|
for(i=0;i<l;i++)
|
160
|
-
|
161
|
-
feature_node *s=x[i];
|
162
|
-
Xv[i]=0;
|
163
|
-
while(s->index!=-1)
|
164
|
-
{
|
165
|
-
Xv[i]+=v[s->index-1]*s->value;
|
166
|
-
s++;
|
167
|
-
}
|
168
|
-
}
|
202
|
+
Xv[i]=sparse_operator::dot(v, x[i]);
|
169
203
|
}
|
170
204
|
|
171
205
|
void l2r_lr_fun::XTv(double *v, double *XTv)
|
@@ -178,14 +212,7 @@ void l2r_lr_fun::XTv(double *v, double *XTv)
|
|
178
212
|
for(i=0;i<w_size;i++)
|
179
213
|
XTv[i]=0;
|
180
214
|
for(i=0;i<l;i++)
|
181
|
-
|
182
|
-
feature_node *s=x[i];
|
183
|
-
while(s->index!=-1)
|
184
|
-
{
|
185
|
-
XTv[s->index-1]+=v[i]*s->value;
|
186
|
-
s++;
|
187
|
-
}
|
188
|
-
}
|
215
|
+
sparse_operator::axpy(v[i], x[i], XTv);
|
189
216
|
}
|
190
217
|
|
191
218
|
class l2r_l2_svc_fun: public function
|
@@ -202,7 +229,6 @@ public:
|
|
202
229
|
|
203
230
|
protected:
|
204
231
|
void Xv(double *v, double *Xv);
|
205
|
-
void subXv(double *v, double *Xv);
|
206
232
|
void subXTv(double *v, double *XTv);
|
207
233
|
|
208
234
|
double *C;
|
@@ -287,12 +313,19 @@ void l2r_l2_svc_fun::Hv(double *s, double *Hs)
|
|
287
313
|
int i;
|
288
314
|
int w_size=get_nr_variable();
|
289
315
|
double *wa = new double[sizeI];
|
316
|
+
feature_node **x=prob->x;
|
290
317
|
|
291
|
-
|
318
|
+
for(i=0;i<w_size;i++)
|
319
|
+
Hs[i]=0;
|
292
320
|
for(i=0;i<sizeI;i++)
|
321
|
+
{
|
322
|
+
feature_node * const xi=x[I[i]];
|
323
|
+
wa[i] = sparse_operator::dot(s, xi);
|
324
|
+
|
293
325
|
wa[i] = C[I[i]]*wa[i];
|
294
326
|
|
295
|
-
|
327
|
+
sparse_operator::axpy(wa[i], xi, Hs);
|
328
|
+
}
|
296
329
|
for(i=0;i<w_size;i++)
|
297
330
|
Hs[i] = s[i] + 2*Hs[i];
|
298
331
|
delete[] wa;
|
@@ -305,32 +338,7 @@ void l2r_l2_svc_fun::Xv(double *v, double *Xv)
|
|
305
338
|
feature_node **x=prob->x;
|
306
339
|
|
307
340
|
for(i=0;i<l;i++)
|
308
|
-
|
309
|
-
feature_node *s=x[i];
|
310
|
-
Xv[i]=0;
|
311
|
-
while(s->index!=-1)
|
312
|
-
{
|
313
|
-
Xv[i]+=v[s->index-1]*s->value;
|
314
|
-
s++;
|
315
|
-
}
|
316
|
-
}
|
317
|
-
}
|
318
|
-
|
319
|
-
void l2r_l2_svc_fun::subXv(double *v, double *Xv)
|
320
|
-
{
|
321
|
-
int i;
|
322
|
-
feature_node **x=prob->x;
|
323
|
-
|
324
|
-
for(i=0;i<sizeI;i++)
|
325
|
-
{
|
326
|
-
feature_node *s=x[I[i]];
|
327
|
-
Xv[i]=0;
|
328
|
-
while(s->index!=-1)
|
329
|
-
{
|
330
|
-
Xv[i]+=v[s->index-1]*s->value;
|
331
|
-
s++;
|
332
|
-
}
|
333
|
-
}
|
341
|
+
Xv[i]=sparse_operator::dot(v, x[i]);
|
334
342
|
}
|
335
343
|
|
336
344
|
void l2r_l2_svc_fun::subXTv(double *v, double *XTv)
|
@@ -342,14 +350,7 @@ void l2r_l2_svc_fun::subXTv(double *v, double *XTv)
|
|
342
350
|
for(i=0;i<w_size;i++)
|
343
351
|
XTv[i]=0;
|
344
352
|
for(i=0;i<sizeI;i++)
|
345
|
-
|
346
|
-
feature_node *s=x[I[i]];
|
347
|
-
while(s->index!=-1)
|
348
|
-
{
|
349
|
-
XTv[s->index-1]+=v[i]*s->value;
|
350
|
-
s++;
|
351
|
-
}
|
352
|
-
}
|
353
|
+
sparse_operator::axpy(v[i], x[I[i]], XTv);
|
353
354
|
}
|
354
355
|
|
355
356
|
class l2r_l2_svr_fun: public l2r_l2_svc_fun
|
@@ -830,14 +831,10 @@ static void solve_l2r_l1l2_svc(
|
|
830
831
|
{
|
831
832
|
QD[i] = diag[GETI(i)];
|
832
833
|
|
833
|
-
feature_node *xi = prob->x[i];
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
QD[i] += val*val;
|
838
|
-
w[xi->index-1] += y[i]*alpha[i]*val;
|
839
|
-
xi++;
|
840
|
-
}
|
834
|
+
feature_node * const xi = prob->x[i];
|
835
|
+
QD[i] += sparse_operator::nrm2_sq(xi);
|
836
|
+
sparse_operator::axpy(y[i]*alpha[i], xi, w);
|
837
|
+
|
841
838
|
index[i] = i;
|
842
839
|
}
|
843
840
|
|
@@ -855,16 +852,10 @@ static void solve_l2r_l1l2_svc(
|
|
855
852
|
for (s=0; s<active_size; s++)
|
856
853
|
{
|
857
854
|
i = index[s];
|
858
|
-
|
859
|
-
|
855
|
+
const schar yi = y[i];
|
856
|
+
feature_node * const xi = prob->x[i];
|
860
857
|
|
861
|
-
|
862
|
-
while(xi->index!= -1)
|
863
|
-
{
|
864
|
-
G += w[xi->index-1]*(xi->value);
|
865
|
-
xi++;
|
866
|
-
}
|
867
|
-
G = G*yi-1;
|
858
|
+
G = yi*sparse_operator::dot(w, xi)-1;
|
868
859
|
|
869
860
|
C = upper_bound[GETI(i)];
|
870
861
|
G += alpha[i]*diag[GETI(i)];
|
@@ -905,12 +896,7 @@ static void solve_l2r_l1l2_svc(
|
|
905
896
|
double alpha_old = alpha[i];
|
906
897
|
alpha[i] = min(max(alpha[i] - G/QD[i], 0.0), C);
|
907
898
|
d = (alpha[i] - alpha_old)*yi;
|
908
|
-
xi
|
909
|
-
while (xi->index != -1)
|
910
|
-
{
|
911
|
-
w[xi->index-1] += d*xi->value;
|
912
|
-
xi++;
|
913
|
-
}
|
899
|
+
sparse_operator::axpy(d, xi, w);
|
914
900
|
}
|
915
901
|
}
|
916
902
|
|
@@ -1035,15 +1021,9 @@ static void solve_l2r_l1l2_svr(
|
|
1035
1021
|
w[i] = 0;
|
1036
1022
|
for(i=0; i<l; i++)
|
1037
1023
|
{
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
{
|
1042
|
-
double val = xi->value;
|
1043
|
-
QD[i] += val*val;
|
1044
|
-
w[xi->index-1] += beta[i]*val;
|
1045
|
-
xi++;
|
1046
|
-
}
|
1024
|
+
feature_node * const xi = prob->x[i];
|
1025
|
+
QD[i] = sparse_operator::nrm2_sq(xi);
|
1026
|
+
sparse_operator::axpy(beta[i], xi, w);
|
1047
1027
|
|
1048
1028
|
index[i] = i;
|
1049
1029
|
}
|
@@ -1066,14 +1046,8 @@ static void solve_l2r_l1l2_svr(
|
|
1066
1046
|
G = -y[i] + lambda[GETI(i)]*beta[i];
|
1067
1047
|
H = QD[i] + lambda[GETI(i)];
|
1068
1048
|
|
1069
|
-
feature_node *xi = prob->x[i];
|
1070
|
-
|
1071
|
-
{
|
1072
|
-
int ind = xi->index-1;
|
1073
|
-
double val = xi->value;
|
1074
|
-
G += val*w[ind];
|
1075
|
-
xi++;
|
1076
|
-
}
|
1049
|
+
feature_node * const xi = prob->x[i];
|
1050
|
+
G += sparse_operator::dot(w, xi);
|
1077
1051
|
|
1078
1052
|
double Gp = G+p;
|
1079
1053
|
double Gn = G-p;
|
@@ -1140,14 +1114,7 @@ static void solve_l2r_l1l2_svr(
|
|
1140
1114
|
d = beta[i]-beta_old;
|
1141
1115
|
|
1142
1116
|
if(d != 0)
|
1143
|
-
|
1144
|
-
xi = prob->x[i];
|
1145
|
-
while(xi->index != -1)
|
1146
|
-
{
|
1147
|
-
w[xi->index-1] += d*xi->value;
|
1148
|
-
xi++;
|
1149
|
-
}
|
1150
|
-
}
|
1117
|
+
sparse_operator::axpy(d, xi, w);
|
1151
1118
|
}
|
1152
1119
|
|
1153
1120
|
if(iter == 0)
|
@@ -1260,15 +1227,9 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1260
1227
|
w[i] = 0;
|
1261
1228
|
for(i=0; i<l; i++)
|
1262
1229
|
{
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
{
|
1267
|
-
double val = xi->value;
|
1268
|
-
xTx[i] += val*val;
|
1269
|
-
w[xi->index-1] += y[i]*alpha[2*i]*val;
|
1270
|
-
xi++;
|
1271
|
-
}
|
1230
|
+
feature_node * const xi = prob->x[i];
|
1231
|
+
xTx[i] = sparse_operator::nrm2_sq(xi);
|
1232
|
+
sparse_operator::axpy(y[i]*alpha[2*i], xi, w);
|
1272
1233
|
index[i] = i;
|
1273
1234
|
}
|
1274
1235
|
|
@@ -1284,16 +1245,11 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1284
1245
|
for (s=0; s<l; s++)
|
1285
1246
|
{
|
1286
1247
|
i = index[s];
|
1287
|
-
schar yi = y[i];
|
1248
|
+
const schar yi = y[i];
|
1288
1249
|
double C = upper_bound[GETI(i)];
|
1289
1250
|
double ywTx = 0, xisq = xTx[i];
|
1290
|
-
feature_node *xi = prob->x[i];
|
1291
|
-
|
1292
|
-
{
|
1293
|
-
ywTx += w[xi->index-1]*xi->value;
|
1294
|
-
xi++;
|
1295
|
-
}
|
1296
|
-
ywTx *= y[i];
|
1251
|
+
feature_node * const xi = prob->x[i];
|
1252
|
+
ywTx = yi*sparse_operator::dot(w, xi);
|
1297
1253
|
double a = xisq, b = ywTx;
|
1298
1254
|
|
1299
1255
|
// Decide to minimize g_1(z) or g_2(z)
|
@@ -1335,12 +1291,7 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1335
1291
|
{
|
1336
1292
|
alpha[ind1] = z;
|
1337
1293
|
alpha[ind2] = C-z;
|
1338
|
-
xi
|
1339
|
-
while (xi->index != -1)
|
1340
|
-
{
|
1341
|
-
w[xi->index-1] += sign*(z-alpha_old)*yi*xi->value;
|
1342
|
-
xi++;
|
1343
|
-
}
|
1294
|
+
sparse_operator::axpy(sign*(z-alpha_old)*yi, xi, w);
|
1344
1295
|
}
|
1345
1296
|
}
|
1346
1297
|
|
@@ -1534,11 +1485,7 @@ static void solve_l1r_l2_svc(
|
|
1534
1485
|
if(appxcond <= 0)
|
1535
1486
|
{
|
1536
1487
|
x = prob_col->x[j];
|
1537
|
-
|
1538
|
-
{
|
1539
|
-
b[x->index-1] += d_diff*x->value;
|
1540
|
-
x++;
|
1541
|
-
}
|
1488
|
+
sparse_operator::axpy(d_diff, x, b);
|
1542
1489
|
break;
|
1543
1490
|
}
|
1544
1491
|
|
@@ -1598,11 +1545,7 @@ static void solve_l1r_l2_svc(
|
|
1598
1545
|
{
|
1599
1546
|
if(w[i]==0) continue;
|
1600
1547
|
x = prob_col->x[i];
|
1601
|
-
|
1602
|
-
{
|
1603
|
-
b[x->index-1] -= w[i]*x->value;
|
1604
|
-
x++;
|
1605
|
-
}
|
1548
|
+
sparse_operator::axpy(-w[i], x, b);
|
1606
1549
|
}
|
1607
1550
|
}
|
1608
1551
|
}
|
@@ -1891,12 +1834,7 @@ static void solve_l1r_lr(
|
|
1891
1834
|
wpd[j] += z;
|
1892
1835
|
|
1893
1836
|
x = prob_col->x[j];
|
1894
|
-
|
1895
|
-
{
|
1896
|
-
int ind = x->index-1;
|
1897
|
-
xTd[ind] += x->value*z;
|
1898
|
-
x++;
|
1899
|
-
}
|
1837
|
+
sparse_operator::axpy(z, x, xTd);
|
1900
1838
|
}
|
1901
1839
|
|
1902
1840
|
iter++;
|
@@ -1988,11 +1926,7 @@ static void solve_l1r_lr(
|
|
1988
1926
|
{
|
1989
1927
|
if(w[i]==0) continue;
|
1990
1928
|
x = prob_col->x[i];
|
1991
|
-
|
1992
|
-
{
|
1993
|
-
exp_wTx[x->index-1] += w[i]*x->value;
|
1994
|
-
x++;
|
1995
|
-
}
|
1929
|
+
sparse_operator::axpy(w[i], x, exp_wTx);
|
1996
1930
|
}
|
1997
1931
|
|
1998
1932
|
for(int i=0; i<l; i++)
|
@@ -2180,14 +2114,18 @@ static void group_classes(const problem *prob, int *nr_class_ret, int **label_re
|
|
2180
2114
|
|
2181
2115
|
static void train_one(const problem *prob, const parameter *param, double *w, double Cp, double Cn)
|
2182
2116
|
{
|
2183
|
-
|
2117
|
+
//inner and outer tolerances for TRON
|
2118
|
+
double eps = param->eps;
|
2119
|
+
double eps_cg = 0.1;
|
2120
|
+
if(param->init_sol != NULL)
|
2121
|
+
eps_cg = 0.5;
|
2122
|
+
|
2184
2123
|
int pos = 0;
|
2185
2124
|
int neg = 0;
|
2186
2125
|
for(int i=0;i<prob->l;i++)
|
2187
2126
|
if(prob->y[i] > 0)
|
2188
2127
|
pos++;
|
2189
2128
|
neg = prob->l - pos;
|
2190
|
-
|
2191
2129
|
double primal_solver_tol = eps*max(min(pos,neg), 1)/prob->l;
|
2192
2130
|
|
2193
2131
|
function *fun_obj=NULL;
|
@@ -2204,7 +2142,7 @@ static void train_one(const problem *prob, const parameter *param, double *w, do
|
|
2204
2142
|
C[i] = Cn;
|
2205
2143
|
}
|
2206
2144
|
fun_obj=new l2r_lr_fun(prob, C);
|
2207
|
-
TRON tron_obj(fun_obj, primal_solver_tol);
|
2145
|
+
TRON tron_obj(fun_obj, primal_solver_tol, eps_cg);
|
2208
2146
|
tron_obj.set_print_string(liblinear_print_string);
|
2209
2147
|
tron_obj.tron(w);
|
2210
2148
|
delete fun_obj;
|
@@ -2222,7 +2160,7 @@ static void train_one(const problem *prob, const parameter *param, double *w, do
|
|
2222
2160
|
C[i] = Cn;
|
2223
2161
|
}
|
2224
2162
|
fun_obj=new l2r_l2_svc_fun(prob, C);
|
2225
|
-
TRON tron_obj(fun_obj, primal_solver_tol);
|
2163
|
+
TRON tron_obj(fun_obj, primal_solver_tol, eps_cg);
|
2226
2164
|
tron_obj.set_print_string(liblinear_print_string);
|
2227
2165
|
tron_obj.tron(w);
|
2228
2166
|
delete fun_obj;
|
@@ -2287,6 +2225,36 @@ static void train_one(const problem *prob, const parameter *param, double *w, do
|
|
2287
2225
|
}
|
2288
2226
|
}
|
2289
2227
|
|
2228
|
+
// Calculate the initial C for parameter selection
|
2229
|
+
static double calc_start_C(const problem *prob, const parameter *param)
|
2230
|
+
{
|
2231
|
+
int i;
|
2232
|
+
double xTx,max_xTx;
|
2233
|
+
max_xTx = 0;
|
2234
|
+
for(i=0; i<prob->l; i++)
|
2235
|
+
{
|
2236
|
+
xTx = 0;
|
2237
|
+
feature_node *xi=prob->x[i];
|
2238
|
+
while(xi->index != -1)
|
2239
|
+
{
|
2240
|
+
double val = xi->value;
|
2241
|
+
xTx += val*val;
|
2242
|
+
xi++;
|
2243
|
+
}
|
2244
|
+
if(xTx > max_xTx)
|
2245
|
+
max_xTx = xTx;
|
2246
|
+
}
|
2247
|
+
|
2248
|
+
double min_C = 1.0;
|
2249
|
+
if(param->solver_type == L2R_LR)
|
2250
|
+
min_C = 1.0 / (prob->l * max_xTx);
|
2251
|
+
else if(param->solver_type == L2R_L2LOSS_SVC)
|
2252
|
+
min_C = 1.0 / (2 * prob->l * max_xTx);
|
2253
|
+
|
2254
|
+
return pow( 2, floor(log(min_C) / log(2.0)) );
|
2255
|
+
}
|
2256
|
+
|
2257
|
+
|
2290
2258
|
//
|
2291
2259
|
// Interface functions
|
2292
2260
|
//
|
@@ -2308,9 +2276,11 @@ model* train(const problem *prob, const parameter *param)
|
|
2308
2276
|
if(check_regression_model(model_))
|
2309
2277
|
{
|
2310
2278
|
model_->w = Malloc(double, w_size);
|
2279
|
+
for(i=0; i<w_size; i++)
|
2280
|
+
model_->w[i] = 0;
|
2311
2281
|
model_->nr_class = 2;
|
2312
2282
|
model_->label = NULL;
|
2313
|
-
train_one(prob, param,
|
2283
|
+
train_one(prob, param, model_->w, 0, 0);
|
2314
2284
|
}
|
2315
2285
|
else
|
2316
2286
|
{
|
@@ -2380,8 +2350,15 @@ model* train(const problem *prob, const parameter *param)
|
|
2380
2350
|
sub_prob.y[k] = +1;
|
2381
2351
|
for(; k<sub_prob.l; k++)
|
2382
2352
|
sub_prob.y[k] = -1;
|
2353
|
+
|
2354
|
+
if(param->init_sol != NULL)
|
2355
|
+
for(i=0;i<w_size;i++)
|
2356
|
+
model_->w[i] = param->init_sol[i];
|
2357
|
+
else
|
2358
|
+
for(i=0;i<w_size;i++)
|
2359
|
+
model_->w[i] = 0;
|
2383
2360
|
|
2384
|
-
train_one(&sub_prob, param,
|
2361
|
+
train_one(&sub_prob, param, model_->w, weighted_C[0], weighted_C[1]);
|
2385
2362
|
}
|
2386
2363
|
else
|
2387
2364
|
{
|
@@ -2400,6 +2377,13 @@ model* train(const problem *prob, const parameter *param)
|
|
2400
2377
|
for(; k<sub_prob.l; k++)
|
2401
2378
|
sub_prob.y[k] = -1;
|
2402
2379
|
|
2380
|
+
if(param->init_sol != NULL)
|
2381
|
+
for(j=0;j<w_size;j++)
|
2382
|
+
w[j] = param->init_sol[j*nr_class+i];
|
2383
|
+
else
|
2384
|
+
for(j=0;j<w_size;j++)
|
2385
|
+
w[j] = 0;
|
2386
|
+
|
2403
2387
|
train_one(&sub_prob, param, w, weighted_C[i], param->C);
|
2404
2388
|
|
2405
2389
|
for(int j=0;j<w_size;j++)
|
@@ -2480,6 +2464,158 @@ void cross_validation(const problem *prob, const parameter *param, int nr_fold,
|
|
2480
2464
|
free(perm);
|
2481
2465
|
}
|
2482
2466
|
|
2467
|
+
void find_parameter_C(const problem *prob, const parameter *param, int nr_fold, double start_C, double max_C, double *best_C, double *best_rate)
|
2468
|
+
{
|
2469
|
+
// variables for CV
|
2470
|
+
int i;
|
2471
|
+
int *fold_start;
|
2472
|
+
int l = prob->l;
|
2473
|
+
int *perm = Malloc(int, l);
|
2474
|
+
double *target = Malloc(double, prob->l);
|
2475
|
+
struct problem *subprob = Malloc(problem,nr_fold);
|
2476
|
+
|
2477
|
+
// variables for warm start
|
2478
|
+
double ratio = 2;
|
2479
|
+
double **prev_w = Malloc(double*, nr_fold);
|
2480
|
+
for(i = 0; i < nr_fold; i++)
|
2481
|
+
prev_w[i] = NULL;
|
2482
|
+
int num_unchanged_w = 0;
|
2483
|
+
struct parameter param1 = *param;
|
2484
|
+
void (*default_print_string) (const char *) = liblinear_print_string;
|
2485
|
+
|
2486
|
+
if (nr_fold > l)
|
2487
|
+
{
|
2488
|
+
nr_fold = l;
|
2489
|
+
fprintf(stderr,"WARNING: # folds > # data. Will use # folds = # data instead (i.e., leave-one-out cross validation)\n");
|
2490
|
+
}
|
2491
|
+
fold_start = Malloc(int,nr_fold+1);
|
2492
|
+
for(i=0;i<l;i++) perm[i]=i;
|
2493
|
+
for(i=0;i<l;i++)
|
2494
|
+
{
|
2495
|
+
int j = i+rand()%(l-i);
|
2496
|
+
swap(perm[i],perm[j]);
|
2497
|
+
}
|
2498
|
+
for(i=0;i<=nr_fold;i++)
|
2499
|
+
fold_start[i]=i*l/nr_fold;
|
2500
|
+
|
2501
|
+
for(i=0;i<nr_fold;i++)
|
2502
|
+
{
|
2503
|
+
int begin = fold_start[i];
|
2504
|
+
int end = fold_start[i+1];
|
2505
|
+
int j,k;
|
2506
|
+
|
2507
|
+
subprob[i].bias = prob->bias;
|
2508
|
+
subprob[i].n = prob->n;
|
2509
|
+
subprob[i].l = l-(end-begin);
|
2510
|
+
subprob[i].x = Malloc(struct feature_node*,subprob[i].l);
|
2511
|
+
subprob[i].y = Malloc(double,subprob[i].l);
|
2512
|
+
|
2513
|
+
k=0;
|
2514
|
+
for(j=0;j<begin;j++)
|
2515
|
+
{
|
2516
|
+
subprob[i].x[k] = prob->x[perm[j]];
|
2517
|
+
subprob[i].y[k] = prob->y[perm[j]];
|
2518
|
+
++k;
|
2519
|
+
}
|
2520
|
+
for(j=end;j<l;j++)
|
2521
|
+
{
|
2522
|
+
subprob[i].x[k] = prob->x[perm[j]];
|
2523
|
+
subprob[i].y[k] = prob->y[perm[j]];
|
2524
|
+
++k;
|
2525
|
+
}
|
2526
|
+
|
2527
|
+
}
|
2528
|
+
|
2529
|
+
*best_rate = 0;
|
2530
|
+
if(start_C <= 0)
|
2531
|
+
start_C = calc_start_C(prob,param);
|
2532
|
+
param1.C = start_C;
|
2533
|
+
|
2534
|
+
while(param1.C <= max_C)
|
2535
|
+
{
|
2536
|
+
//Output disabled for running CV at a particular C
|
2537
|
+
set_print_string_function(&print_null);
|
2538
|
+
|
2539
|
+
for(i=0; i<nr_fold; i++)
|
2540
|
+
{
|
2541
|
+
int j;
|
2542
|
+
int begin = fold_start[i];
|
2543
|
+
int end = fold_start[i+1];
|
2544
|
+
|
2545
|
+
param1.init_sol = prev_w[i];
|
2546
|
+
struct model *submodel = train(&subprob[i],¶m1);
|
2547
|
+
|
2548
|
+
int total_w_size;
|
2549
|
+
if(submodel->nr_class == 2)
|
2550
|
+
total_w_size = subprob[i].n;
|
2551
|
+
else
|
2552
|
+
total_w_size = subprob[i].n * submodel->nr_class;
|
2553
|
+
|
2554
|
+
if(prev_w[i] == NULL)
|
2555
|
+
{
|
2556
|
+
prev_w[i] = Malloc(double, total_w_size);
|
2557
|
+
for(j=0; j<total_w_size; j++)
|
2558
|
+
prev_w[i][j] = submodel->w[j];
|
2559
|
+
}
|
2560
|
+
else if(num_unchanged_w >= 0)
|
2561
|
+
{
|
2562
|
+
double norm_w_diff = 0;
|
2563
|
+
for(j=0; j<total_w_size; j++)
|
2564
|
+
{
|
2565
|
+
norm_w_diff += (submodel->w[j] - prev_w[i][j])*(submodel->w[j] - prev_w[i][j]);
|
2566
|
+
prev_w[i][j] = submodel->w[j];
|
2567
|
+
}
|
2568
|
+
norm_w_diff = sqrt(norm_w_diff);
|
2569
|
+
|
2570
|
+
if(norm_w_diff > 1e-15)
|
2571
|
+
num_unchanged_w = -1;
|
2572
|
+
}
|
2573
|
+
else
|
2574
|
+
{
|
2575
|
+
for(j=0; j<total_w_size; j++)
|
2576
|
+
prev_w[i][j] = submodel->w[j];
|
2577
|
+
}
|
2578
|
+
|
2579
|
+
for(j=begin; j<end; j++)
|
2580
|
+
target[perm[j]] = predict(submodel,prob->x[perm[j]]);
|
2581
|
+
|
2582
|
+
free_and_destroy_model(&submodel);
|
2583
|
+
}
|
2584
|
+
set_print_string_function(default_print_string);
|
2585
|
+
|
2586
|
+
int total_correct = 0;
|
2587
|
+
for(i=0; i<prob->l; i++)
|
2588
|
+
if(target[i] == prob->y[i])
|
2589
|
+
++total_correct;
|
2590
|
+
double current_rate = (double)total_correct/prob->l;
|
2591
|
+
if(current_rate > *best_rate)
|
2592
|
+
{
|
2593
|
+
*best_C = param1.C;
|
2594
|
+
*best_rate = current_rate;
|
2595
|
+
}
|
2596
|
+
|
2597
|
+
info("log2c=%7.2f\trate=%g\n",log(param1.C)/log(2.0),100.0*current_rate);
|
2598
|
+
num_unchanged_w++;
|
2599
|
+
if(num_unchanged_w == 3)
|
2600
|
+
break;
|
2601
|
+
param1.C = param1.C*ratio;
|
2602
|
+
}
|
2603
|
+
|
2604
|
+
if(param1.C > max_C && max_C > start_C)
|
2605
|
+
info("warning: maximum C reached.\n");
|
2606
|
+
free(fold_start);
|
2607
|
+
free(perm);
|
2608
|
+
free(target);
|
2609
|
+
for(i=0; i<nr_fold; i++)
|
2610
|
+
{
|
2611
|
+
free(subprob[i].x);
|
2612
|
+
free(subprob[i].y);
|
2613
|
+
free(prev_w[i]);
|
2614
|
+
}
|
2615
|
+
free(prev_w);
|
2616
|
+
free(subprob);
|
2617
|
+
}
|
2618
|
+
|
2483
2619
|
double predict_values(const struct model *model_, const struct feature_node *x, double *dec_values)
|
2484
2620
|
{
|
2485
2621
|
int idx;
|
@@ -2592,7 +2728,11 @@ int save_model(const char *model_file_name, const struct model *model_)
|
|
2592
2728
|
FILE *fp = fopen(model_file_name,"w");
|
2593
2729
|
if(fp==NULL) return -1;
|
2594
2730
|
|
2595
|
-
char *old_locale =
|
2731
|
+
char *old_locale = setlocale(LC_ALL, NULL);
|
2732
|
+
if (old_locale)
|
2733
|
+
{
|
2734
|
+
old_locale = strdup(old_locale);
|
2735
|
+
}
|
2596
2736
|
setlocale(LC_ALL, "C");
|
2597
2737
|
|
2598
2738
|
int nr_w;
|
@@ -2632,6 +2772,30 @@ int save_model(const char *model_file_name, const struct model *model_)
|
|
2632
2772
|
else return 0;
|
2633
2773
|
}
|
2634
2774
|
|
2775
|
+
//
|
2776
|
+
// FSCANF helps to handle fscanf failures.
|
2777
|
+
// Its do-while block avoids the ambiguity when
|
2778
|
+
// if (...)
|
2779
|
+
// FSCANF();
|
2780
|
+
// is used
|
2781
|
+
//
|
2782
|
+
#define FSCANF(_stream, _format, _var)do\
|
2783
|
+
{\
|
2784
|
+
if (fscanf(_stream, _format, _var) != 1)\
|
2785
|
+
{\
|
2786
|
+
fprintf(stderr, "ERROR: fscanf failed to read the model\n");\
|
2787
|
+
EXIT_LOAD_MODEL()\
|
2788
|
+
}\
|
2789
|
+
}while(0)
|
2790
|
+
// EXIT_LOAD_MODEL should NOT end with a semicolon.
|
2791
|
+
#define EXIT_LOAD_MODEL()\
|
2792
|
+
{\
|
2793
|
+
setlocale(LC_ALL, old_locale);\
|
2794
|
+
free(model_->label);\
|
2795
|
+
free(model_);\
|
2796
|
+
free(old_locale);\
|
2797
|
+
return NULL;\
|
2798
|
+
}
|
2635
2799
|
struct model *load_model(const char *model_file_name)
|
2636
2800
|
{
|
2637
2801
|
FILE *fp = fopen(model_file_name,"r");
|
@@ -2647,16 +2811,20 @@ struct model *load_model(const char *model_file_name)
|
|
2647
2811
|
|
2648
2812
|
model_->label = NULL;
|
2649
2813
|
|
2650
|
-
char *old_locale =
|
2814
|
+
char *old_locale = setlocale(LC_ALL, NULL);
|
2815
|
+
if (old_locale)
|
2816
|
+
{
|
2817
|
+
old_locale = strdup(old_locale);
|
2818
|
+
}
|
2651
2819
|
setlocale(LC_ALL, "C");
|
2652
2820
|
|
2653
2821
|
char cmd[81];
|
2654
2822
|
while(1)
|
2655
2823
|
{
|
2656
|
-
|
2824
|
+
FSCANF(fp,"%80s",cmd);
|
2657
2825
|
if(strcmp(cmd,"solver_type")==0)
|
2658
2826
|
{
|
2659
|
-
|
2827
|
+
FSCANF(fp,"%80s",cmd);
|
2660
2828
|
int i;
|
2661
2829
|
for(i=0;solver_type_table[i];i++)
|
2662
2830
|
{
|
@@ -2669,27 +2837,22 @@ struct model *load_model(const char *model_file_name)
|
|
2669
2837
|
if(solver_type_table[i] == NULL)
|
2670
2838
|
{
|
2671
2839
|
fprintf(stderr,"unknown solver type.\n");
|
2672
|
-
|
2673
|
-
setlocale(LC_ALL, old_locale);
|
2674
|
-
free(model_->label);
|
2675
|
-
free(model_);
|
2676
|
-
free(old_locale);
|
2677
|
-
return NULL;
|
2840
|
+
EXIT_LOAD_MODEL()
|
2678
2841
|
}
|
2679
2842
|
}
|
2680
2843
|
else if(strcmp(cmd,"nr_class")==0)
|
2681
2844
|
{
|
2682
|
-
|
2845
|
+
FSCANF(fp,"%d",&nr_class);
|
2683
2846
|
model_->nr_class=nr_class;
|
2684
2847
|
}
|
2685
2848
|
else if(strcmp(cmd,"nr_feature")==0)
|
2686
2849
|
{
|
2687
|
-
|
2850
|
+
FSCANF(fp,"%d",&nr_feature);
|
2688
2851
|
model_->nr_feature=nr_feature;
|
2689
2852
|
}
|
2690
2853
|
else if(strcmp(cmd,"bias")==0)
|
2691
2854
|
{
|
2692
|
-
|
2855
|
+
FSCANF(fp,"%lf",&bias);
|
2693
2856
|
model_->bias=bias;
|
2694
2857
|
}
|
2695
2858
|
else if(strcmp(cmd,"w")==0)
|
@@ -2701,16 +2864,12 @@ struct model *load_model(const char *model_file_name)
|
|
2701
2864
|
int nr_class = model_->nr_class;
|
2702
2865
|
model_->label = Malloc(int,nr_class);
|
2703
2866
|
for(int i=0;i<nr_class;i++)
|
2704
|
-
|
2867
|
+
FSCANF(fp,"%d",&model_->label[i]);
|
2705
2868
|
}
|
2706
2869
|
else
|
2707
2870
|
{
|
2708
2871
|
fprintf(stderr,"unknown text in model file: [%s]\n",cmd);
|
2709
|
-
|
2710
|
-
free(model_->label);
|
2711
|
-
free(model_);
|
2712
|
-
free(old_locale);
|
2713
|
-
return NULL;
|
2872
|
+
EXIT_LOAD_MODEL()
|
2714
2873
|
}
|
2715
2874
|
}
|
2716
2875
|
|
@@ -2731,8 +2890,12 @@ struct model *load_model(const char *model_file_name)
|
|
2731
2890
|
{
|
2732
2891
|
int j;
|
2733
2892
|
for(j=0; j<nr_w; j++)
|
2734
|
-
|
2735
|
-
fscanf(fp, "\n")
|
2893
|
+
FSCANF(fp, "%lf ", &model_->w[i*nr_w+j]);
|
2894
|
+
if (fscanf(fp, "\n") !=0)
|
2895
|
+
{
|
2896
|
+
fprintf(stderr, "ERROR: fscanf failed to read the model\n");
|
2897
|
+
EXIT_LOAD_MODEL()
|
2898
|
+
}
|
2736
2899
|
}
|
2737
2900
|
|
2738
2901
|
setlocale(LC_ALL, old_locale);
|
@@ -2831,6 +2994,8 @@ void destroy_param(parameter* param)
|
|
2831
2994
|
free(param->weight_label);
|
2832
2995
|
if(param->weight != NULL)
|
2833
2996
|
free(param->weight);
|
2997
|
+
if(param->init_sol != NULL)
|
2998
|
+
free(param->init_sol);
|
2834
2999
|
}
|
2835
3000
|
|
2836
3001
|
const char *check_parameter(const problem *prob, const parameter *param)
|
@@ -2857,6 +3022,10 @@ const char *check_parameter(const problem *prob, const parameter *param)
|
|
2857
3022
|
&& param->solver_type != L2R_L1LOSS_SVR_DUAL)
|
2858
3023
|
return "unknown solver type";
|
2859
3024
|
|
3025
|
+
if(param->init_sol != NULL
|
3026
|
+
&& param->solver_type != L2R_LR && param->solver_type != L2R_L2LOSS_SVC)
|
3027
|
+
return "Initial-solution specification supported only for solver L2R_LR and L2R_L2LOSS_SVC";
|
3028
|
+
|
2860
3029
|
return NULL;
|
2861
3030
|
}
|
2862
3031
|
|