numo-liblinear 0.3.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/build.yml +27 -0
- data/.gitmodules +3 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE.txt +1 -1
- data/README.md +13 -25
- data/ext/numo/liblinear/converter.c +31 -0
- data/ext/numo/liblinear/converter.h +2 -0
- data/ext/numo/liblinear/extconf.rb +7 -8
- data/ext/numo/liblinear/liblinear/blas/blas.h +25 -0
- data/ext/numo/liblinear/liblinear/blas/blasp.h +438 -0
- data/ext/numo/liblinear/liblinear/blas/daxpy.c +57 -0
- data/ext/numo/liblinear/liblinear/blas/ddot.c +58 -0
- data/ext/numo/liblinear/liblinear/blas/dnrm2.c +70 -0
- data/ext/numo/liblinear/liblinear/blas/dscal.c +52 -0
- data/ext/numo/liblinear/liblinear/linear.cpp +3725 -0
- data/ext/numo/liblinear/liblinear/linear.h +88 -0
- data/ext/numo/liblinear/liblinear/newton.cpp +245 -0
- data/ext/numo/liblinear/liblinear/newton.h +37 -0
- data/ext/numo/liblinear/liblinearext.c +57 -34
- data/ext/numo/liblinear/model.c +3 -0
- data/ext/numo/liblinear/parameter.c +34 -27
- data/ext/numo/liblinear/problem.c +37 -6
- data/ext/numo/liblinear/solver_type.c +8 -6
- data/lib/numo/liblinear/version.rb +1 -1
- data/numo-liblinear.gemspec +15 -1
- metadata +24 -11
- data/.travis.yml +0 -14
@@ -0,0 +1,88 @@
|
|
1
|
+
#ifndef _LIBLINEAR_H
|
2
|
+
#define _LIBLINEAR_H
|
3
|
+
|
4
|
+
#define LIBLINEAR_VERSION 241
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
extern int liblinear_version;
|
11
|
+
|
12
|
+
struct feature_node
|
13
|
+
{
|
14
|
+
int index;
|
15
|
+
double value;
|
16
|
+
};
|
17
|
+
|
18
|
+
struct problem
|
19
|
+
{
|
20
|
+
int l, n;
|
21
|
+
double *y;
|
22
|
+
struct feature_node **x;
|
23
|
+
double bias; /* < 0 if no bias term */
|
24
|
+
};
|
25
|
+
|
26
|
+
enum { L2R_LR, L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS, L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL, L2R_L2LOSS_SVR = 11, L2R_L2LOSS_SVR_DUAL, L2R_L1LOSS_SVR_DUAL, ONECLASS_SVM = 21 }; /* solver_type */
|
27
|
+
|
28
|
+
struct parameter
|
29
|
+
{
|
30
|
+
int solver_type;
|
31
|
+
|
32
|
+
/* these are for training only */
|
33
|
+
double eps; /* stopping criteria */
|
34
|
+
double C;
|
35
|
+
int nr_weight;
|
36
|
+
int *weight_label;
|
37
|
+
double* weight;
|
38
|
+
double p;
|
39
|
+
double nu;
|
40
|
+
double *init_sol;
|
41
|
+
int regularize_bias;
|
42
|
+
};
|
43
|
+
|
44
|
+
struct model
|
45
|
+
{
|
46
|
+
struct parameter param;
|
47
|
+
int nr_class; /* number of classes */
|
48
|
+
int nr_feature;
|
49
|
+
double *w;
|
50
|
+
int *label; /* label of each class */
|
51
|
+
double bias;
|
52
|
+
double rho; /* one-class SVM only */
|
53
|
+
};
|
54
|
+
|
55
|
+
struct model* train(const struct problem *prob, const struct parameter *param);
|
56
|
+
void cross_validation(const struct problem *prob, const struct parameter *param, int nr_fold, double *target);
|
57
|
+
void find_parameters(const struct problem *prob, const struct parameter *param, int nr_fold, double start_C, double start_p, double *best_C, double *best_p, double *best_score);
|
58
|
+
|
59
|
+
double predict_values(const struct model *model_, const struct feature_node *x, double* dec_values);
|
60
|
+
double predict(const struct model *model_, const struct feature_node *x);
|
61
|
+
double predict_probability(const struct model *model_, const struct feature_node *x, double* prob_estimates);
|
62
|
+
|
63
|
+
int save_model(const char *model_file_name, const struct model *model_);
|
64
|
+
struct model *load_model(const char *model_file_name);
|
65
|
+
|
66
|
+
int get_nr_feature(const struct model *model_);
|
67
|
+
int get_nr_class(const struct model *model_);
|
68
|
+
void get_labels(const struct model *model_, int* label);
|
69
|
+
double get_decfun_coef(const struct model *model_, int feat_idx, int label_idx);
|
70
|
+
double get_decfun_bias(const struct model *model_, int label_idx);
|
71
|
+
double get_decfun_rho(const struct model *model_);
|
72
|
+
|
73
|
+
void free_model_content(struct model *model_ptr);
|
74
|
+
void free_and_destroy_model(struct model **model_ptr_ptr);
|
75
|
+
void destroy_param(struct parameter *param);
|
76
|
+
|
77
|
+
const char *check_parameter(const struct problem *prob, const struct parameter *param);
|
78
|
+
int check_probability_model(const struct model *model);
|
79
|
+
int check_regression_model(const struct model *model);
|
80
|
+
int check_oneclass_model(const struct model *model);
|
81
|
+
void set_print_string_function(void (*print_func) (const char*));
|
82
|
+
|
83
|
+
#ifdef __cplusplus
|
84
|
+
}
|
85
|
+
#endif
|
86
|
+
|
87
|
+
#endif /* _LIBLINEAR_H */
|
88
|
+
|
@@ -0,0 +1,245 @@
|
|
1
|
+
#include <math.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <stdarg.h>
|
5
|
+
#include "newton.h"
|
6
|
+
|
7
|
+
#ifndef min
|
8
|
+
template <class T> static inline T min(T x,T y) { return (x<y)?x:y; }
|
9
|
+
#endif
|
10
|
+
|
11
|
+
#ifndef max
|
12
|
+
template <class T> static inline T max(T x,T y) { return (x>y)?x:y; }
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifdef __cplusplus
|
16
|
+
extern "C" {
|
17
|
+
#endif
|
18
|
+
|
19
|
+
extern double dnrm2_(int *, double *, int *);
|
20
|
+
extern double ddot_(int *, double *, int *, double *, int *);
|
21
|
+
extern int daxpy_(int *, double *, double *, int *, double *, int *);
|
22
|
+
extern int dscal_(int *, double *, double *, int *);
|
23
|
+
|
24
|
+
#ifdef __cplusplus
|
25
|
+
}
|
26
|
+
#endif
|
27
|
+
|
28
|
+
static void default_print(const char *buf)
|
29
|
+
{
|
30
|
+
fputs(buf,stdout);
|
31
|
+
fflush(stdout);
|
32
|
+
}
|
33
|
+
|
34
|
+
// On entry *f must be the function value of w
|
35
|
+
// On exit w is updated and *f is the new function value
|
36
|
+
double function::linesearch_and_update(double *w, double *s, double *f, double *g, double alpha)
|
37
|
+
{
|
38
|
+
double gTs = 0;
|
39
|
+
double eta = 0.01;
|
40
|
+
int n = get_nr_variable();
|
41
|
+
int max_num_linesearch = 20;
|
42
|
+
double *w_new = new double[n];
|
43
|
+
double fold = *f;
|
44
|
+
|
45
|
+
for (int i=0;i<n;i++)
|
46
|
+
gTs += s[i] * g[i];
|
47
|
+
|
48
|
+
int num_linesearch = 0;
|
49
|
+
for(num_linesearch=0; num_linesearch < max_num_linesearch; num_linesearch++)
|
50
|
+
{
|
51
|
+
for (int i=0;i<n;i++)
|
52
|
+
w_new[i] = w[i] + alpha*s[i];
|
53
|
+
*f = fun(w_new);
|
54
|
+
if (*f - fold <= eta * alpha * gTs)
|
55
|
+
break;
|
56
|
+
else
|
57
|
+
alpha *= 0.5;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (num_linesearch >= max_num_linesearch)
|
61
|
+
{
|
62
|
+
*f = fold;
|
63
|
+
return 0;
|
64
|
+
}
|
65
|
+
else
|
66
|
+
memcpy(w, w_new, sizeof(double)*n);
|
67
|
+
|
68
|
+
delete [] w_new;
|
69
|
+
return alpha;
|
70
|
+
}
|
71
|
+
|
72
|
+
void NEWTON::info(const char *fmt,...)
|
73
|
+
{
|
74
|
+
char buf[BUFSIZ];
|
75
|
+
va_list ap;
|
76
|
+
va_start(ap,fmt);
|
77
|
+
vsprintf(buf,fmt,ap);
|
78
|
+
va_end(ap);
|
79
|
+
(*newton_print_string)(buf);
|
80
|
+
}
|
81
|
+
|
82
|
+
NEWTON::NEWTON(const function *fun_obj, double eps, double eps_cg, int max_iter)
|
83
|
+
{
|
84
|
+
this->fun_obj=const_cast<function *>(fun_obj);
|
85
|
+
this->eps=eps;
|
86
|
+
this->eps_cg=eps_cg;
|
87
|
+
this->max_iter=max_iter;
|
88
|
+
newton_print_string = default_print;
|
89
|
+
}
|
90
|
+
|
91
|
+
NEWTON::~NEWTON()
|
92
|
+
{
|
93
|
+
}
|
94
|
+
|
95
|
+
void NEWTON::newton(double *w)
|
96
|
+
{
|
97
|
+
int n = fun_obj->get_nr_variable();
|
98
|
+
int i, cg_iter;
|
99
|
+
double step_size;
|
100
|
+
double f, fold, actred;
|
101
|
+
double init_step_size = 1;
|
102
|
+
int search = 1, iter = 1, inc = 1;
|
103
|
+
double *s = new double[n];
|
104
|
+
double *r = new double[n];
|
105
|
+
double *g = new double[n];
|
106
|
+
|
107
|
+
const double alpha_pcg = 0.01;
|
108
|
+
double *M = new double[n];
|
109
|
+
|
110
|
+
// calculate gradient norm at w=0 for stopping condition.
|
111
|
+
double *w0 = new double[n];
|
112
|
+
for (i=0; i<n; i++)
|
113
|
+
w0[i] = 0;
|
114
|
+
fun_obj->fun(w0);
|
115
|
+
fun_obj->grad(w0, g);
|
116
|
+
double gnorm0 = dnrm2_(&n, g, &inc);
|
117
|
+
delete [] w0;
|
118
|
+
|
119
|
+
f = fun_obj->fun(w);
|
120
|
+
info("init f %5.3e\n", f);
|
121
|
+
fun_obj->grad(w, g);
|
122
|
+
double gnorm = dnrm2_(&n, g, &inc);
|
123
|
+
|
124
|
+
if (gnorm <= eps*gnorm0)
|
125
|
+
search = 0;
|
126
|
+
|
127
|
+
double *w_new = new double[n];
|
128
|
+
while (iter <= max_iter && search)
|
129
|
+
{
|
130
|
+
fun_obj->get_diag_preconditioner(M);
|
131
|
+
for(i=0; i<n; i++)
|
132
|
+
M[i] = (1-alpha_pcg) + alpha_pcg*M[i];
|
133
|
+
cg_iter = pcg(g, M, s, r);
|
134
|
+
|
135
|
+
fold = f;
|
136
|
+
step_size = fun_obj->linesearch_and_update(w, s, & f, g, init_step_size);
|
137
|
+
|
138
|
+
if (step_size == 0)
|
139
|
+
{
|
140
|
+
info("WARNING: line search fails\n");
|
141
|
+
break;
|
142
|
+
}
|
143
|
+
|
144
|
+
info("iter %2d f %5.3e |g| %5.3e CG %3d step_size %4.2e \n", iter, f, gnorm, cg_iter, step_size);
|
145
|
+
|
146
|
+
actred = fold - f;
|
147
|
+
iter++;
|
148
|
+
|
149
|
+
fun_obj->grad(w, g);
|
150
|
+
|
151
|
+
gnorm = dnrm2_(&n, g, &inc);
|
152
|
+
if (gnorm <= eps*gnorm0)
|
153
|
+
break;
|
154
|
+
if (f < -1.0e+32)
|
155
|
+
{
|
156
|
+
info("WARNING: f < -1.0e+32\n");
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
if (fabs(actred) <= 1.0e-12*fabs(f))
|
160
|
+
{
|
161
|
+
info("WARNING: actred too small\n");
|
162
|
+
break;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
delete[] g;
|
167
|
+
delete[] r;
|
168
|
+
delete[] w_new;
|
169
|
+
delete[] s;
|
170
|
+
delete[] M;
|
171
|
+
}
|
172
|
+
|
173
|
+
int NEWTON::pcg(double *g, double *M, double *s, double *r)
|
174
|
+
{
|
175
|
+
int i, inc = 1;
|
176
|
+
int n = fun_obj->get_nr_variable();
|
177
|
+
double one = 1;
|
178
|
+
double *d = new double[n];
|
179
|
+
double *Hd = new double[n];
|
180
|
+
double zTr, znewTrnew, alpha, beta, cgtol;
|
181
|
+
double *z = new double[n];
|
182
|
+
double Q = 0, newQ, Qdiff;
|
183
|
+
|
184
|
+
for (i=0; i<n; i++)
|
185
|
+
{
|
186
|
+
s[i] = 0;
|
187
|
+
r[i] = -g[i];
|
188
|
+
z[i] = r[i] / M[i];
|
189
|
+
d[i] = z[i];
|
190
|
+
}
|
191
|
+
|
192
|
+
zTr = ddot_(&n, z, &inc, r, &inc);
|
193
|
+
double gMinv_norm = sqrt(zTr);
|
194
|
+
cgtol = min(eps_cg, sqrt(gMinv_norm));
|
195
|
+
int cg_iter = 0;
|
196
|
+
int max_cg_iter = max(n, 5);
|
197
|
+
|
198
|
+
while (cg_iter < max_cg_iter)
|
199
|
+
{
|
200
|
+
cg_iter++;
|
201
|
+
fun_obj->Hv(d, Hd);
|
202
|
+
|
203
|
+
alpha = zTr/ddot_(&n, d, &inc, Hd, &inc);
|
204
|
+
daxpy_(&n, &alpha, d, &inc, s, &inc);
|
205
|
+
alpha = -alpha;
|
206
|
+
daxpy_(&n, &alpha, Hd, &inc, r, &inc);
|
207
|
+
|
208
|
+
// Using quadratic approximation as CG stopping criterion
|
209
|
+
newQ = -0.5*(ddot_(&n, s, &inc, r, &inc) - ddot_(&n, s, &inc, g, &inc));
|
210
|
+
Qdiff = newQ - Q;
|
211
|
+
if (newQ <= 0 && Qdiff <= 0)
|
212
|
+
{
|
213
|
+
if (cg_iter * Qdiff >= cgtol * newQ)
|
214
|
+
break;
|
215
|
+
}
|
216
|
+
else
|
217
|
+
{
|
218
|
+
info("WARNING: quadratic approximation > 0 or increasing in CG\n");
|
219
|
+
break;
|
220
|
+
}
|
221
|
+
Q = newQ;
|
222
|
+
|
223
|
+
for (i=0; i<n; i++)
|
224
|
+
z[i] = r[i] / M[i];
|
225
|
+
znewTrnew = ddot_(&n, z, &inc, r, &inc);
|
226
|
+
beta = znewTrnew/zTr;
|
227
|
+
dscal_(&n, &beta, d, &inc);
|
228
|
+
daxpy_(&n, &one, z, &inc, d, &inc);
|
229
|
+
zTr = znewTrnew;
|
230
|
+
}
|
231
|
+
|
232
|
+
if (cg_iter == max_cg_iter)
|
233
|
+
info("WARNING: reaching maximal number of CG steps\n");
|
234
|
+
|
235
|
+
delete[] d;
|
236
|
+
delete[] Hd;
|
237
|
+
delete[] z;
|
238
|
+
|
239
|
+
return(cg_iter);
|
240
|
+
}
|
241
|
+
|
242
|
+
void NEWTON::set_print_string(void (*print_string) (const char *buf))
|
243
|
+
{
|
244
|
+
newton_print_string = print_string;
|
245
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#ifndef _NEWTON_H
|
2
|
+
#define _NEWTON_H
|
3
|
+
|
4
|
+
class function
|
5
|
+
{
|
6
|
+
public:
|
7
|
+
virtual double fun(double *w) = 0 ;
|
8
|
+
virtual void grad(double *w, double *g) = 0 ;
|
9
|
+
virtual void Hv(double *s, double *Hs) = 0 ;
|
10
|
+
virtual int get_nr_variable(void) = 0 ;
|
11
|
+
virtual void get_diag_preconditioner(double *M) = 0 ;
|
12
|
+
virtual ~function(void){}
|
13
|
+
|
14
|
+
// base implementation in newton.cpp
|
15
|
+
virtual double linesearch_and_update(double *w, double *s, double *f, double *g, double alpha);
|
16
|
+
};
|
17
|
+
|
18
|
+
class NEWTON
|
19
|
+
{
|
20
|
+
public:
|
21
|
+
NEWTON(const function *fun_obj, double eps = 0.1, double eps_cg = 0.5, int max_iter = 1000);
|
22
|
+
~NEWTON();
|
23
|
+
|
24
|
+
void newton(double *w);
|
25
|
+
void set_print_string(void (*i_print) (const char *buf));
|
26
|
+
|
27
|
+
private:
|
28
|
+
int pcg(double *g, double *M, double *s, double *r);
|
29
|
+
|
30
|
+
double eps;
|
31
|
+
double eps_cg;
|
32
|
+
int max_iter;
|
33
|
+
function *fun_obj;
|
34
|
+
void info(const char *fmt,...);
|
35
|
+
void (*newton_print_string)(const char *buf);
|
36
|
+
};
|
37
|
+
#endif
|
@@ -53,6 +53,7 @@ VALUE numo_liblinear_train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_has
|
|
53
53
|
narray_t* y_nary;
|
54
54
|
char* err_msg;
|
55
55
|
VALUE random_seed;
|
56
|
+
VALUE verbose;
|
56
57
|
VALUE model_hash;
|
57
58
|
|
58
59
|
if (CLASS_OF(x_val) != numo_cDFloat) {
|
@@ -99,7 +100,11 @@ VALUE numo_liblinear_train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_has
|
|
99
100
|
return Qnil;
|
100
101
|
}
|
101
102
|
|
102
|
-
|
103
|
+
verbose = rb_hash_aref(param_hash, ID2SYM(rb_intern("verbose")));
|
104
|
+
if (verbose != Qtrue) {
|
105
|
+
set_print_string_function(print_null);
|
106
|
+
}
|
107
|
+
|
103
108
|
model = train(problem, param);
|
104
109
|
model_hash = model_to_rb_hash(model);
|
105
110
|
free_and_destroy_model(&model);
|
@@ -107,6 +112,9 @@ VALUE numo_liblinear_train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_has
|
|
107
112
|
xfree_problem(problem);
|
108
113
|
xfree_parameter(param);
|
109
114
|
|
115
|
+
RB_GC_GUARD(x_val);
|
116
|
+
RB_GC_GUARD(y_val);
|
117
|
+
|
110
118
|
return model_hash;
|
111
119
|
}
|
112
120
|
|
@@ -120,6 +128,28 @@ VALUE numo_liblinear_train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_has
|
|
120
128
|
* @param param [Hash] The parameters of a model.
|
121
129
|
* @param n_folds [Integer] The number of folds.
|
122
130
|
*
|
131
|
+
* @example
|
132
|
+
* require 'numo/liblinear'
|
133
|
+
*
|
134
|
+
* # x: samples
|
135
|
+
* # y: labels
|
136
|
+
*
|
137
|
+
* # Define parameters of L2-regularized L2-loss support vector classification.
|
138
|
+
* param = {
|
139
|
+
* solver_type: Numo::Liblinear::SolverType::L2R_L2LOSS_SVC_DUAL,
|
140
|
+
* C: 1,
|
141
|
+
* random_seed: 1,
|
142
|
+
* verbose: true
|
143
|
+
* }
|
144
|
+
*
|
145
|
+
* # Perform 5-cross validation.
|
146
|
+
* n_folds = 5
|
147
|
+
* res = Numo::Liblinear::cv(x, y, param, n_folds)
|
148
|
+
*
|
149
|
+
* # Print mean accuracy.
|
150
|
+
* mean_accuracy = y.eq(res).count.fdiv(y.size)
|
151
|
+
* puts "Accuracy: %.1f %%" % (100 * mean_accuracy)
|
152
|
+
*
|
123
153
|
* @raise [ArgumentError] If the sample array is not 2-dimensional, the label array is not 1-dimensional,
|
124
154
|
* the sample array and label array do not have the same number of samples, or
|
125
155
|
* the hyperparameter has an invalid value, this error is raised.
|
@@ -136,6 +166,7 @@ VALUE numo_liblinear_cross_validation(VALUE self, VALUE x_val, VALUE y_val, VALU
|
|
136
166
|
narray_t* y_nary;
|
137
167
|
char* err_msg;
|
138
168
|
VALUE random_seed;
|
169
|
+
VALUE verbose;
|
139
170
|
struct problem* problem;
|
140
171
|
struct parameter* param;
|
141
172
|
|
@@ -187,12 +218,19 @@ VALUE numo_liblinear_cross_validation(VALUE self, VALUE x_val, VALUE y_val, VALU
|
|
187
218
|
t_val = rb_narray_new(numo_cDFloat, 1, t_shape);
|
188
219
|
t_pt = (double*)na_get_pointer_for_write(t_val);
|
189
220
|
|
190
|
-
|
221
|
+
verbose = rb_hash_aref(param_hash, ID2SYM(rb_intern("verbose")));
|
222
|
+
if (verbose != Qtrue) {
|
223
|
+
set_print_string_function(print_null);
|
224
|
+
}
|
225
|
+
|
191
226
|
cross_validation(problem, param, n_folds, t_pt);
|
192
227
|
|
193
228
|
xfree_problem(problem);
|
194
229
|
xfree_parameter(param);
|
195
230
|
|
231
|
+
RB_GC_GUARD(x_val);
|
232
|
+
RB_GC_GUARD(y_val);
|
233
|
+
|
196
234
|
return t_val;
|
197
235
|
}
|
198
236
|
|
@@ -250,21 +288,17 @@ VALUE numo_liblinear_predict(VALUE self, VALUE x_val, VALUE param_hash, VALUE mo
|
|
250
288
|
x_pt = (double*)na_get_pointer_for_read(x_val);
|
251
289
|
|
252
290
|
/* Predict values. */
|
253
|
-
x_nodes = ALLOC_N(struct feature_node, n_features + 1);
|
254
|
-
x_nodes[n_features].index = -1;
|
255
|
-
x_nodes[n_features].value = 0.0;
|
256
291
|
for (i = 0; i < n_samples; i++) {
|
257
|
-
|
258
|
-
x_nodes[j].index = j + 1;
|
259
|
-
x_nodes[j].value = (double)x_pt[i * n_features + j];
|
260
|
-
}
|
292
|
+
x_nodes = dbl_vec_to_node(&x_pt[i * n_features], n_features);
|
261
293
|
y_pt[i] = predict(model, x_nodes);
|
294
|
+
xfree(x_nodes);
|
262
295
|
}
|
263
296
|
|
264
|
-
xfree(x_nodes);
|
265
297
|
xfree_model(model);
|
266
298
|
xfree_parameter(param);
|
267
299
|
|
300
|
+
RB_GC_GUARD(x_val);
|
301
|
+
|
268
302
|
return y_val;
|
269
303
|
}
|
270
304
|
|
@@ -333,40 +367,30 @@ VALUE numo_liblinear_decision_function(VALUE self, VALUE x_val, VALUE param_hash
|
|
333
367
|
|
334
368
|
/* Predict values. */
|
335
369
|
if (model->nr_class == 2 && model->param.solver_type != MCSVM_CS) {
|
336
|
-
x_nodes = ALLOC_N(struct feature_node, n_features + 1);
|
337
|
-
x_nodes[n_features].index = -1;
|
338
|
-
x_nodes[n_features].value = 0.0;
|
339
370
|
for (i = 0; i < n_samples; i++) {
|
340
|
-
|
341
|
-
x_nodes[j].index = j + 1;
|
342
|
-
x_nodes[j].value = (double)x_pt[i * n_features + j];
|
343
|
-
}
|
371
|
+
x_nodes = dbl_vec_to_node(&x_pt[i * n_features], n_features);
|
344
372
|
predict_values(model, x_nodes, &y_pt[i]);
|
373
|
+
xfree(x_nodes);
|
345
374
|
}
|
346
|
-
xfree(x_nodes);
|
347
375
|
} else {
|
348
376
|
y_cols = (int)y_shape[1];
|
349
377
|
dec_values = ALLOC_N(double, y_cols);
|
350
|
-
x_nodes = ALLOC_N(struct feature_node, n_features + 1);
|
351
|
-
x_nodes[n_features].index = -1;
|
352
|
-
x_nodes[n_features].value = 0.0;
|
353
378
|
for (i = 0; i < n_samples; i++) {
|
354
|
-
|
355
|
-
x_nodes[j].index = j + 1;
|
356
|
-
x_nodes[j].value = (double)x_pt[i * n_features + j];
|
357
|
-
}
|
379
|
+
x_nodes = dbl_vec_to_node(&x_pt[i * n_features], n_features);
|
358
380
|
predict_values(model, x_nodes, dec_values);
|
381
|
+
xfree(x_nodes);
|
359
382
|
for (j = 0; j < y_cols; j++) {
|
360
383
|
y_pt[i * y_cols + j] = dec_values[j];
|
361
384
|
}
|
362
385
|
}
|
363
|
-
xfree(x_nodes);
|
364
386
|
xfree(dec_values);
|
365
387
|
}
|
366
388
|
|
367
389
|
xfree_model(model);
|
368
390
|
xfree_parameter(param);
|
369
391
|
|
392
|
+
RB_GC_GUARD(x_val);
|
393
|
+
|
370
394
|
return y_val;
|
371
395
|
}
|
372
396
|
|
@@ -429,26 +453,22 @@ VALUE numo_liblinear_predict_proba(VALUE self, VALUE x_val, VALUE param_hash, VA
|
|
429
453
|
|
430
454
|
/* Predict values. */
|
431
455
|
probs = ALLOC_N(double, model->nr_class);
|
432
|
-
x_nodes = ALLOC_N(struct feature_node, n_features + 1);
|
433
|
-
x_nodes[n_features].index = -1;
|
434
|
-
x_nodes[n_features].value = 0.0;
|
435
456
|
for (i = 0; i < n_samples; i++) {
|
436
|
-
|
437
|
-
x_nodes[j].index = j + 1;
|
438
|
-
x_nodes[j].value = (double)x_pt[i * n_features + j];
|
439
|
-
}
|
457
|
+
x_nodes = dbl_vec_to_node(&x_pt[i * n_features], n_features);
|
440
458
|
predict_probability(model, x_nodes, probs);
|
459
|
+
xfree(x_nodes);
|
441
460
|
for (j = 0; j < model->nr_class; j++) {
|
442
461
|
y_pt[i * model->nr_class + j] = probs[j];
|
443
462
|
}
|
444
463
|
}
|
445
|
-
xfree(x_nodes);
|
446
464
|
xfree(probs);
|
447
465
|
}
|
448
466
|
|
449
467
|
xfree_model(model);
|
450
468
|
xfree_parameter(param);
|
451
469
|
|
470
|
+
RB_GC_GUARD(x_val);
|
471
|
+
|
452
472
|
return y_val;
|
453
473
|
}
|
454
474
|
|
@@ -537,6 +557,9 @@ void Init_liblinearext()
|
|
537
557
|
*/
|
538
558
|
mLiblinear = rb_define_module_under(mNumo, "Liblinear");
|
539
559
|
|
560
|
+
/* The version of LIBLINEAR used in backgroud library. */
|
561
|
+
rb_define_const(mLiblinear, "LIBLINEAR_VERSION", INT2NUM(LIBLINEAR_VERSION));
|
562
|
+
|
540
563
|
rb_define_module_function(mLiblinear, "train", numo_liblinear_train, 3);
|
541
564
|
rb_define_module_function(mLiblinear, "cv", numo_liblinear_cross_validation, 4);
|
542
565
|
rb_define_module_function(mLiblinear, "predict", numo_liblinear_predict, 3);
|