numo-liblinear 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +4 -0
- data/ext/numo/liblinear/src/COPYRIGHT +1 -1
- data/ext/numo/liblinear/src/linear.cpp +152 -95
- data/ext/numo/liblinear/src/linear.h +5 -5
- data/ext/numo/liblinear/src/newton.cpp +20 -14
- data/lib/numo/liblinear/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ea54dc3ead49a3edb3d55b2bf46c673fca3a11b8b29001658fc453d8bfd8831
|
4
|
+
data.tar.gz: 3c4751dce386d1127ab4c1570807671a7b8ab73f632899e63655096cead86ffe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f016fa4a2a372fb7948eea6418973ecf9228f3e8a8b58b23b7da9360f0dc3f0facd85a45d029b259bfd5d52ffb4a9b42565ebd1d163c9ac881f37c978a3f22b
|
7
|
+
data.tar.gz: 7119f78866b27df545177c6b6d24b2df261caade7a8437721df5b99c616af16ef2a039919ffc9ed35b5ee98760cc77520e9d708edeb9a851d822232b68c43806
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -172,3 +172,7 @@ param = {
|
|
172
172
|
|
173
173
|
Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/numo-liblinear.
|
174
174
|
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
175
|
+
|
176
|
+
## License
|
177
|
+
|
178
|
+
The gem is available as open source under the terms of the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
|
@@ -56,7 +56,7 @@ public:
|
|
56
56
|
ret += x->value*x->value;
|
57
57
|
x++;
|
58
58
|
}
|
59
|
-
return
|
59
|
+
return ret;
|
60
60
|
}
|
61
61
|
|
62
62
|
static double dot(const double *s, const feature_node *x)
|
@@ -67,7 +67,7 @@ public:
|
|
67
67
|
ret += s[x->index-1]*x->value;
|
68
68
|
x++;
|
69
69
|
}
|
70
|
-
return
|
70
|
+
return ret;
|
71
71
|
}
|
72
72
|
|
73
73
|
static double sparse_dot(const feature_node *x1, const feature_node *x2)
|
@@ -89,7 +89,7 @@ public:
|
|
89
89
|
++x1;
|
90
90
|
}
|
91
91
|
}
|
92
|
-
return
|
92
|
+
return ret;
|
93
93
|
}
|
94
94
|
|
95
95
|
static void axpy(const double a, const feature_node *x, double *y)
|
@@ -164,7 +164,7 @@ double l2r_erm_fun::fun(double *w)
|
|
164
164
|
f += C_times_loss(i, wx[i]);
|
165
165
|
f = f + 0.5 * wTw;
|
166
166
|
|
167
|
-
return
|
167
|
+
return f;
|
168
168
|
}
|
169
169
|
|
170
170
|
int l2r_erm_fun::get_nr_variable(void)
|
@@ -876,13 +876,13 @@ void Solver_MCSVM_CS::Solve(double *w)
|
|
876
876
|
// D is a diagonal matrix
|
877
877
|
//
|
878
878
|
// In L1-SVM case:
|
879
|
-
//
|
880
|
-
//
|
881
|
-
//
|
879
|
+
// upper_bound_i = Cp if y_i = 1
|
880
|
+
// upper_bound_i = Cn if y_i = -1
|
881
|
+
// D_ii = 0
|
882
882
|
// In L2-SVM case:
|
883
|
-
//
|
884
|
-
//
|
885
|
-
//
|
883
|
+
// upper_bound_i = INF
|
884
|
+
// D_ii = 1/(2*Cp) if y_i = 1
|
885
|
+
// D_ii = 1/(2*Cn) if y_i = -1
|
886
886
|
//
|
887
887
|
// Given:
|
888
888
|
// x, y, Cp, Cn
|
@@ -890,22 +890,23 @@ void Solver_MCSVM_CS::Solve(double *w)
|
|
890
890
|
//
|
891
891
|
// solution will be put in w
|
892
892
|
//
|
893
|
+
// this function returns the number of iterations
|
894
|
+
//
|
893
895
|
// See Algorithm 3 of Hsieh et al., ICML 2008
|
894
896
|
|
895
897
|
#undef GETI
|
896
898
|
#define GETI(i) (y[i]+1)
|
897
899
|
// To support weights for instances, use GETI(i) (i)
|
898
900
|
|
899
|
-
static
|
900
|
-
const problem *prob, double *w, double eps,
|
901
|
-
double Cp, double Cn, int solver_type)
|
901
|
+
static int solve_l2r_l1l2_svc(const problem *prob, const parameter *param, double *w, double Cp, double Cn, int max_iter=300)
|
902
902
|
{
|
903
903
|
int l = prob->l;
|
904
904
|
int w_size = prob->n;
|
905
|
+
double eps = param->eps;
|
906
|
+
int solver_type = param->solver_type;
|
905
907
|
int i, s, iter = 0;
|
906
908
|
double C, d, G;
|
907
909
|
double *QD = new double[l];
|
908
|
-
int max_iter = 1000;
|
909
910
|
int *index = new int[l];
|
910
911
|
double *alpha = new double[l];
|
911
912
|
schar *y = new schar[l];
|
@@ -1024,7 +1025,8 @@ static void solve_l2r_l1l2_svc(
|
|
1024
1025
|
if(iter % 10 == 0)
|
1025
1026
|
info(".");
|
1026
1027
|
|
1027
|
-
if(PGmax_new - PGmin_new <= eps
|
1028
|
+
if(PGmax_new - PGmin_new <= eps &&
|
1029
|
+
fabs(PGmax_new) <= eps && fabs(PGmin_new) <= eps)
|
1028
1030
|
{
|
1029
1031
|
if(active_size == l)
|
1030
1032
|
break;
|
@@ -1046,8 +1048,6 @@ static void solve_l2r_l1l2_svc(
|
|
1046
1048
|
}
|
1047
1049
|
|
1048
1050
|
info("\noptimization finished, #iter = %d\n",iter);
|
1049
|
-
if (iter >= max_iter)
|
1050
|
-
info("\nWARNING: reaching max number of iterations\nUsing -s 2 may be faster (also see FAQ)\n\n");
|
1051
1051
|
|
1052
1052
|
// calculate objective value
|
1053
1053
|
|
@@ -1068,6 +1068,8 @@ static void solve_l2r_l1l2_svc(
|
|
1068
1068
|
delete [] alpha;
|
1069
1069
|
delete [] y;
|
1070
1070
|
delete [] index;
|
1071
|
+
|
1072
|
+
return iter;
|
1071
1073
|
}
|
1072
1074
|
|
1073
1075
|
|
@@ -1081,11 +1083,11 @@ static void solve_l2r_l1l2_svc(
|
|
1081
1083
|
// D is a diagonal matrix
|
1082
1084
|
//
|
1083
1085
|
// In L1-SVM case:
|
1084
|
-
//
|
1085
|
-
//
|
1086
|
+
// upper_bound_i = C
|
1087
|
+
// lambda_i = 0
|
1086
1088
|
// In L2-SVM case:
|
1087
|
-
//
|
1088
|
-
//
|
1089
|
+
// upper_bound_i = INF
|
1090
|
+
// lambda_i = 1/(2*C)
|
1089
1091
|
//
|
1090
1092
|
// Given:
|
1091
1093
|
// x, y, p, C
|
@@ -1093,23 +1095,23 @@ static void solve_l2r_l1l2_svc(
|
|
1093
1095
|
//
|
1094
1096
|
// solution will be put in w
|
1095
1097
|
//
|
1098
|
+
// this function returns the number of iterations
|
1099
|
+
//
|
1096
1100
|
// See Algorithm 4 of Ho and Lin, 2012
|
1097
1101
|
|
1098
1102
|
#undef GETI
|
1099
1103
|
#define GETI(i) (0)
|
1100
1104
|
// To support weights for instances, use GETI(i) (i)
|
1101
1105
|
|
1102
|
-
static
|
1103
|
-
const problem *prob, double *w, const parameter *param,
|
1104
|
-
int solver_type)
|
1106
|
+
static int solve_l2r_l1l2_svr(const problem *prob, const parameter *param, double *w, int max_iter=300)
|
1105
1107
|
{
|
1108
|
+
const int solver_type = param->solver_type;
|
1106
1109
|
int l = prob->l;
|
1107
1110
|
double C = param->C;
|
1108
1111
|
double p = param->p;
|
1109
1112
|
int w_size = prob->n;
|
1110
1113
|
double eps = param->eps;
|
1111
1114
|
int i, s, iter = 0;
|
1112
|
-
int max_iter = 1000;
|
1113
1115
|
int active_size = l;
|
1114
1116
|
int *index = new int[l];
|
1115
1117
|
|
@@ -1260,8 +1262,6 @@ static void solve_l2r_l1l2_svr(
|
|
1260
1262
|
}
|
1261
1263
|
|
1262
1264
|
info("\noptimization finished, #iter = %d\n", iter);
|
1263
|
-
if(iter >= max_iter)
|
1264
|
-
info("\nWARNING: reaching max number of iterations\nUsing -s 11 may be faster\n\n");
|
1265
1265
|
|
1266
1266
|
// calculate objective value
|
1267
1267
|
double v = 0;
|
@@ -1282,6 +1282,8 @@ static void solve_l2r_l1l2_svr(
|
|
1282
1282
|
delete [] beta;
|
1283
1283
|
delete [] QD;
|
1284
1284
|
delete [] index;
|
1285
|
+
|
1286
|
+
return iter;
|
1285
1287
|
}
|
1286
1288
|
|
1287
1289
|
|
@@ -1301,19 +1303,21 @@ static void solve_l2r_l1l2_svr(
|
|
1301
1303
|
//
|
1302
1304
|
// solution will be put in w
|
1303
1305
|
//
|
1306
|
+
// this function returns the number of iterations
|
1307
|
+
//
|
1304
1308
|
// See Algorithm 5 of Yu et al., MLJ 2010
|
1305
1309
|
|
1306
1310
|
#undef GETI
|
1307
1311
|
#define GETI(i) (y[i]+1)
|
1308
1312
|
// To support weights for instances, use GETI(i) (i)
|
1309
1313
|
|
1310
|
-
|
1314
|
+
static int solve_l2r_lr_dual(const problem *prob, const parameter *param, double *w, double Cp, double Cn, int max_iter=300)
|
1311
1315
|
{
|
1312
1316
|
int l = prob->l;
|
1313
1317
|
int w_size = prob->n;
|
1318
|
+
double eps = param->eps;
|
1314
1319
|
int i, s, iter = 0;
|
1315
1320
|
double *xTx = new double[l];
|
1316
|
-
int max_iter = 1000;
|
1317
1321
|
int *index = new int[l];
|
1318
1322
|
double *alpha = new double[2*l]; // store alpha and C - alpha
|
1319
1323
|
schar *y = new schar[l];
|
@@ -1428,8 +1432,6 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1428
1432
|
}
|
1429
1433
|
|
1430
1434
|
info("\noptimization finished, #iter = %d\n",iter);
|
1431
|
-
if (iter >= max_iter)
|
1432
|
-
info("\nWARNING: reaching max number of iterations\nUsing -s 0 may be faster (also see FAQ)\n\n");
|
1433
1435
|
|
1434
1436
|
// calculate objective value
|
1435
1437
|
|
@@ -1446,6 +1448,8 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1446
1448
|
delete [] alpha;
|
1447
1449
|
delete [] y;
|
1448
1450
|
delete [] index;
|
1451
|
+
|
1452
|
+
return iter;
|
1449
1453
|
}
|
1450
1454
|
|
1451
1455
|
// A coordinate descent algorithm for
|
@@ -1459,6 +1463,8 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1459
1463
|
//
|
1460
1464
|
// solution will be put in w
|
1461
1465
|
//
|
1466
|
+
// this function returns the number of iterations
|
1467
|
+
//
|
1462
1468
|
// See Yuan et al. (2010) and appendix of LIBLINEAR paper, Fan et al. (2008)
|
1463
1469
|
//
|
1464
1470
|
// To not regularize the bias (i.e., regularize_bias = 0), a constant feature = 1
|
@@ -1468,12 +1474,11 @@ void solve_l2r_lr_dual(const problem *prob, double *w, double eps, double Cp, do
|
|
1468
1474
|
#define GETI(i) (y[i]+1)
|
1469
1475
|
// To support weights for instances, use GETI(i) (i)
|
1470
1476
|
|
1471
|
-
static
|
1472
|
-
problem *prob_col, double *w, double eps,
|
1473
|
-
double Cp, double Cn, int regularize_bias)
|
1477
|
+
static int solve_l1r_l2_svc(const problem *prob_col, const parameter* param, double *w, double Cp, double Cn, double eps)
|
1474
1478
|
{
|
1475
1479
|
int l = prob_col->l;
|
1476
1480
|
int w_size = prob_col->n;
|
1481
|
+
int regularize_bias = param->regularize_bias;
|
1477
1482
|
int j, s, iter = 0;
|
1478
1483
|
int max_iter = 1000;
|
1479
1484
|
int active_size = w_size;
|
@@ -1747,6 +1752,8 @@ static void solve_l1r_l2_svc(
|
|
1747
1752
|
delete [] y;
|
1748
1753
|
delete [] b;
|
1749
1754
|
delete [] xj_sq;
|
1755
|
+
|
1756
|
+
return iter;
|
1750
1757
|
}
|
1751
1758
|
|
1752
1759
|
// A coordinate descent algorithm for
|
@@ -1760,6 +1767,8 @@ static void solve_l1r_l2_svc(
|
|
1760
1767
|
//
|
1761
1768
|
// solution will be put in w
|
1762
1769
|
//
|
1770
|
+
// this function returns the number of iterations
|
1771
|
+
//
|
1763
1772
|
// See Yuan et al. (2011) and appendix of LIBLINEAR paper, Fan et al. (2008)
|
1764
1773
|
//
|
1765
1774
|
// To not regularize the bias (i.e., regularize_bias = 0), a constant feature = 1
|
@@ -1769,12 +1778,11 @@ static void solve_l1r_l2_svc(
|
|
1769
1778
|
#define GETI(i) (y[i]+1)
|
1770
1779
|
// To support weights for instances, use GETI(i) (i)
|
1771
1780
|
|
1772
|
-
static
|
1773
|
-
const problem *prob_col, double *w, double eps,
|
1774
|
-
double Cp, double Cn, int regularize_bias)
|
1781
|
+
static int solve_l1r_lr(const problem *prob_col, const parameter *param, double *w, double Cp, double Cn, double eps)
|
1775
1782
|
{
|
1776
1783
|
int l = prob_col->l;
|
1777
1784
|
int w_size = prob_col->n;
|
1785
|
+
int regularize_bias = param->regularize_bias;
|
1778
1786
|
int j, s, newton_iter=0, iter=0;
|
1779
1787
|
int max_newton_iter = 100;
|
1780
1788
|
int max_iter = 1000;
|
@@ -2143,6 +2151,8 @@ static void solve_l1r_lr(
|
|
2143
2151
|
delete [] exp_wTx_new;
|
2144
2152
|
delete [] tau;
|
2145
2153
|
delete [] D;
|
2154
|
+
|
2155
|
+
return newton_iter;
|
2146
2156
|
}
|
2147
2157
|
|
2148
2158
|
struct heap {
|
@@ -2230,12 +2240,16 @@ struct heap {
|
|
2230
2240
|
//
|
2231
2241
|
// solution will be put in w and rho
|
2232
2242
|
//
|
2243
|
+
// this function returns the number of iterations
|
2244
|
+
//
|
2233
2245
|
// See Algorithm 7 in supplementary materials of Chou et al., SDM 2020.
|
2234
2246
|
|
2235
|
-
static
|
2247
|
+
static int solve_oneclass_svm(const problem *prob, const parameter *param, double *w, double *rho)
|
2236
2248
|
{
|
2237
2249
|
int l = prob->l;
|
2238
2250
|
int w_size = prob->n;
|
2251
|
+
double eps = param->eps;
|
2252
|
+
double nu = param->nu;
|
2239
2253
|
int i, j, s, iter = 0;
|
2240
2254
|
double Gi, Gj;
|
2241
2255
|
double Qij, quad_coef, delta, sum;
|
@@ -2248,13 +2262,13 @@ static void solve_oneclass_svm(const problem *prob, double *w, double *rho, doub
|
|
2248
2262
|
int max_iter = 1000;
|
2249
2263
|
int active_size = l;
|
2250
2264
|
|
2251
|
-
double negGmax;
|
2252
|
-
double negGmin;
|
2265
|
+
double negGmax; // max { -grad(f)_i | alpha_i < 1 }
|
2266
|
+
double negGmin; // min { -grad(f)_i | alpha_i > 0 }
|
2253
2267
|
|
2254
2268
|
int *most_violating_i = new int[l];
|
2255
2269
|
int *most_violating_j = new int[l];
|
2256
2270
|
|
2257
|
-
int n = (int)(nu*l);
|
2271
|
+
int n = (int)(nu*l); // # of alpha's at upper bound
|
2258
2272
|
for(i=0; i<n; i++)
|
2259
2273
|
alpha[i] = 1;
|
2260
2274
|
if (n<l)
|
@@ -2479,6 +2493,8 @@ static void solve_oneclass_svm(const problem *prob, double *w, double *rho, doub
|
|
2479
2493
|
delete [] alpha;
|
2480
2494
|
delete [] most_violating_i;
|
2481
2495
|
delete [] most_violating_j;
|
2496
|
+
|
2497
|
+
return iter;
|
2482
2498
|
}
|
2483
2499
|
|
2484
2500
|
// transpose matrix X from row format to column format
|
@@ -2616,67 +2632,85 @@ static void group_classes(const problem *prob, int *nr_class_ret, int **label_re
|
|
2616
2632
|
|
2617
2633
|
static void train_one(const problem *prob, const parameter *param, double *w, double Cp, double Cn)
|
2618
2634
|
{
|
2619
|
-
|
2635
|
+
int solver_type = param->solver_type;
|
2636
|
+
int dual_solver_max_iter = 300;
|
2637
|
+
int iter;
|
2620
2638
|
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
if(prob->y[i] > 0)
|
2625
|
-
pos++;
|
2626
|
-
neg = prob->l - pos;
|
2627
|
-
double primal_solver_tol = eps*max(min(pos,neg), 1)/prob->l;
|
2639
|
+
bool is_regression = (solver_type==L2R_L2LOSS_SVR ||
|
2640
|
+
solver_type==L2R_L1LOSS_SVR_DUAL ||
|
2641
|
+
solver_type==L2R_L2LOSS_SVR_DUAL);
|
2628
2642
|
|
2629
|
-
|
2630
|
-
|
2643
|
+
// Some solvers use Cp,Cn but not C array; extensions possible but no plan for now
|
2644
|
+
double *C = new double[prob->l];
|
2645
|
+
double primal_solver_tol = param->eps;
|
2646
|
+
if(is_regression)
|
2631
2647
|
{
|
2632
|
-
|
2648
|
+
for(int i=0;i<prob->l;i++)
|
2649
|
+
C[i] = param->C;
|
2650
|
+
}
|
2651
|
+
else
|
2652
|
+
{
|
2653
|
+
int pos = 0;
|
2654
|
+
for(int i=0;i<prob->l;i++)
|
2633
2655
|
{
|
2634
|
-
|
2635
|
-
for(int i = 0; i < prob->l; i++)
|
2656
|
+
if(prob->y[i] > 0)
|
2636
2657
|
{
|
2637
|
-
|
2638
|
-
|
2639
|
-
else
|
2640
|
-
C[i] = Cn;
|
2658
|
+
pos++;
|
2659
|
+
C[i] = Cp;
|
2641
2660
|
}
|
2642
|
-
|
2643
|
-
|
2661
|
+
else
|
2662
|
+
C[i] = Cn;
|
2663
|
+
}
|
2664
|
+
int neg = prob->l - pos;
|
2665
|
+
primal_solver_tol = param->eps*max(min(pos,neg), 1)/prob->l;
|
2666
|
+
}
|
2667
|
+
|
2668
|
+
switch(solver_type)
|
2669
|
+
{
|
2670
|
+
case L2R_LR:
|
2671
|
+
{
|
2672
|
+
l2r_lr_fun fun_obj(prob, param, C);
|
2673
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2644
2674
|
newton_obj.set_print_string(liblinear_print_string);
|
2645
2675
|
newton_obj.newton(w);
|
2646
|
-
delete fun_obj;
|
2647
|
-
delete[] C;
|
2648
2676
|
break;
|
2649
2677
|
}
|
2650
2678
|
case L2R_L2LOSS_SVC:
|
2651
2679
|
{
|
2652
|
-
|
2653
|
-
|
2654
|
-
{
|
2655
|
-
if(prob->y[i] > 0)
|
2656
|
-
C[i] = Cp;
|
2657
|
-
else
|
2658
|
-
C[i] = Cn;
|
2659
|
-
}
|
2660
|
-
fun_obj=new l2r_l2_svc_fun(prob, param, C);
|
2661
|
-
NEWTON newton_obj(fun_obj, primal_solver_tol);
|
2680
|
+
l2r_l2_svc_fun fun_obj(prob, param, C);
|
2681
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2662
2682
|
newton_obj.set_print_string(liblinear_print_string);
|
2663
2683
|
newton_obj.newton(w);
|
2664
|
-
delete fun_obj;
|
2665
|
-
delete[] C;
|
2666
2684
|
break;
|
2667
2685
|
}
|
2668
2686
|
case L2R_L2LOSS_SVC_DUAL:
|
2669
|
-
|
2687
|
+
{
|
2688
|
+
iter = solve_l2r_l1l2_svc(prob, param, w, Cp, Cn, dual_solver_max_iter);
|
2689
|
+
if(iter >= dual_solver_max_iter)
|
2690
|
+
{
|
2691
|
+
info("\nWARNING: reaching max number of iterations\nSwitching to use -s 2\n\n");
|
2692
|
+
// primal_solver_tol obtained from eps for dual may be too loose
|
2693
|
+
primal_solver_tol *= 0.1;
|
2694
|
+
l2r_l2_svc_fun fun_obj(prob, param, C);
|
2695
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2696
|
+
newton_obj.set_print_string(liblinear_print_string);
|
2697
|
+
newton_obj.newton(w);
|
2698
|
+
}
|
2670
2699
|
break;
|
2700
|
+
}
|
2671
2701
|
case L2R_L1LOSS_SVC_DUAL:
|
2672
|
-
|
2702
|
+
{
|
2703
|
+
iter = solve_l2r_l1l2_svc(prob, param, w, Cp, Cn, dual_solver_max_iter);
|
2704
|
+
if(iter >= dual_solver_max_iter)
|
2705
|
+
info("\nWARNING: reaching max number of iterations\nUsing -s 2 may be faster (also see FAQ)\n\n");
|
2673
2706
|
break;
|
2707
|
+
}
|
2674
2708
|
case L1R_L2LOSS_SVC:
|
2675
2709
|
{
|
2676
2710
|
problem prob_col;
|
2677
2711
|
feature_node *x_space = NULL;
|
2678
2712
|
transpose(prob, &x_space ,&prob_col);
|
2679
|
-
solve_l1r_l2_svc(&prob_col,
|
2713
|
+
solve_l1r_l2_svc(&prob_col, param, w, Cp, Cn, primal_solver_tol);
|
2680
2714
|
delete [] prob_col.y;
|
2681
2715
|
delete [] prob_col.x;
|
2682
2716
|
delete [] x_space;
|
@@ -2687,40 +2721,64 @@ static void train_one(const problem *prob, const parameter *param, double *w, do
|
|
2687
2721
|
problem prob_col;
|
2688
2722
|
feature_node *x_space = NULL;
|
2689
2723
|
transpose(prob, &x_space ,&prob_col);
|
2690
|
-
solve_l1r_lr(&prob_col,
|
2724
|
+
solve_l1r_lr(&prob_col, param, w, Cp, Cn, primal_solver_tol);
|
2691
2725
|
delete [] prob_col.y;
|
2692
2726
|
delete [] prob_col.x;
|
2693
2727
|
delete [] x_space;
|
2694
2728
|
break;
|
2695
2729
|
}
|
2696
2730
|
case L2R_LR_DUAL:
|
2697
|
-
|
2731
|
+
{
|
2732
|
+
iter = solve_l2r_lr_dual(prob, param, w, Cp, Cn, dual_solver_max_iter);
|
2733
|
+
if(iter >= dual_solver_max_iter)
|
2734
|
+
{
|
2735
|
+
info("\nWARNING: reaching max number of iterations\nSwitching to use -s 0\n\n");
|
2736
|
+
// primal_solver_tol obtained from eps for dual may be too loose
|
2737
|
+
primal_solver_tol *= 0.1;
|
2738
|
+
l2r_lr_fun fun_obj(prob, param, C);
|
2739
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2740
|
+
newton_obj.set_print_string(liblinear_print_string);
|
2741
|
+
newton_obj.newton(w);
|
2742
|
+
}
|
2698
2743
|
break;
|
2744
|
+
}
|
2699
2745
|
case L2R_L2LOSS_SVR:
|
2700
2746
|
{
|
2701
|
-
|
2702
|
-
|
2703
|
-
C[i] = param->C;
|
2704
|
-
|
2705
|
-
fun_obj=new l2r_l2_svr_fun(prob, param, C);
|
2706
|
-
NEWTON newton_obj(fun_obj, param->eps);
|
2747
|
+
l2r_l2_svr_fun fun_obj(prob, param, C);
|
2748
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2707
2749
|
newton_obj.set_print_string(liblinear_print_string);
|
2708
2750
|
newton_obj.newton(w);
|
2709
|
-
delete fun_obj;
|
2710
|
-
delete[] C;
|
2711
2751
|
break;
|
2712
|
-
|
2713
2752
|
}
|
2714
2753
|
case L2R_L1LOSS_SVR_DUAL:
|
2715
|
-
|
2754
|
+
{
|
2755
|
+
iter = solve_l2r_l1l2_svr(prob, param, w, dual_solver_max_iter);
|
2756
|
+
if(iter >= dual_solver_max_iter)
|
2757
|
+
info("\nWARNING: reaching max number of iterations\nUsing -s 11 may be faster (also see FAQ)\n\n");
|
2758
|
+
|
2716
2759
|
break;
|
2760
|
+
}
|
2717
2761
|
case L2R_L2LOSS_SVR_DUAL:
|
2718
|
-
|
2762
|
+
{
|
2763
|
+
iter = solve_l2r_l1l2_svr(prob, param, w, dual_solver_max_iter);
|
2764
|
+
if(iter >= dual_solver_max_iter)
|
2765
|
+
{
|
2766
|
+
info("\nWARNING: reaching max number of iterations\nSwitching to use -s 11\n\n");
|
2767
|
+
// primal_solver_tol obtained from eps for dual may be too loose
|
2768
|
+
primal_solver_tol *= 0.001;
|
2769
|
+
l2r_l2_svr_fun fun_obj(prob, param, C);
|
2770
|
+
NEWTON newton_obj(&fun_obj, primal_solver_tol);
|
2771
|
+
newton_obj.set_print_string(liblinear_print_string);
|
2772
|
+
newton_obj.newton(w);
|
2773
|
+
}
|
2719
2774
|
break;
|
2775
|
+
}
|
2720
2776
|
default:
|
2721
2777
|
fprintf(stderr, "ERROR: unknown solver_type\n");
|
2722
2778
|
break;
|
2723
2779
|
}
|
2780
|
+
|
2781
|
+
delete[] C;
|
2724
2782
|
}
|
2725
2783
|
|
2726
2784
|
// Calculate the initial C for parameter selection
|
@@ -2768,7 +2826,7 @@ static double calc_start_C(const problem *prob, const parameter *param)
|
|
2768
2826
|
return pow( 2, floor(log(min_C) / log(2.0)) );
|
2769
2827
|
}
|
2770
2828
|
|
2771
|
-
static double calc_max_p(const problem *prob
|
2829
|
+
static double calc_max_p(const problem *prob)
|
2772
2830
|
{
|
2773
2831
|
int i;
|
2774
2832
|
double max_p = 0.0;
|
@@ -2938,7 +2996,7 @@ model* train(const problem *prob, const parameter *param)
|
|
2938
2996
|
model_->w = Malloc(double, w_size);
|
2939
2997
|
model_->nr_class = 2;
|
2940
2998
|
model_->label = NULL;
|
2941
|
-
solve_oneclass_svm(prob, model_->w, &(model_->rho)
|
2999
|
+
solve_oneclass_svm(prob, param, model_->w, &(model_->rho));
|
2942
3000
|
}
|
2943
3001
|
else
|
2944
3002
|
{
|
@@ -3173,7 +3231,6 @@ void find_parameters(const problem *prob, const parameter *param, int nr_fold, d
|
|
3173
3231
|
subprob[i].y[k] = prob->y[perm[j]];
|
3174
3232
|
++k;
|
3175
3233
|
}
|
3176
|
-
|
3177
3234
|
}
|
3178
3235
|
|
3179
3236
|
struct parameter param_tmp = *param;
|
@@ -3193,7 +3250,7 @@ void find_parameters(const problem *prob, const parameter *param, int nr_fold, d
|
|
3193
3250
|
}
|
3194
3251
|
else if(param->solver_type == L2R_L2LOSS_SVR)
|
3195
3252
|
{
|
3196
|
-
double max_p = calc_max_p(prob
|
3253
|
+
double max_p = calc_max_p(prob);
|
3197
3254
|
int num_p_steps = 20;
|
3198
3255
|
double max_C = 1048576;
|
3199
3256
|
*best_score = INF;
|
@@ -3655,7 +3712,7 @@ const char *check_parameter(const problem *prob, const parameter *param)
|
|
3655
3712
|
if(param->C <= 0)
|
3656
3713
|
return "C <= 0";
|
3657
3714
|
|
3658
|
-
if(param->p < 0)
|
3715
|
+
if(param->p < 0 && param->solver_type == L2R_L2LOSS_SVR)
|
3659
3716
|
return "p < 0";
|
3660
3717
|
|
3661
3718
|
if(prob->bias >= 0 && param->solver_type == ONECLASS_SVM)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef _LIBLINEAR_H
|
2
2
|
#define _LIBLINEAR_H
|
3
3
|
|
4
|
-
#define LIBLINEAR_VERSION
|
4
|
+
#define LIBLINEAR_VERSION 244
|
5
5
|
|
6
6
|
#ifdef __cplusplus
|
7
7
|
extern "C" {
|
@@ -30,7 +30,7 @@ struct parameter
|
|
30
30
|
int solver_type;
|
31
31
|
|
32
32
|
/* these are for training only */
|
33
|
-
double eps;
|
33
|
+
double eps; /* stopping tolerance */
|
34
34
|
double C;
|
35
35
|
int nr_weight;
|
36
36
|
int *weight_label;
|
@@ -44,12 +44,12 @@ struct parameter
|
|
44
44
|
struct model
|
45
45
|
{
|
46
46
|
struct parameter param;
|
47
|
-
int nr_class;
|
47
|
+
int nr_class; /* number of classes */
|
48
48
|
int nr_feature;
|
49
49
|
double *w;
|
50
|
-
int *label;
|
50
|
+
int *label; /* label of each class */
|
51
51
|
double bias;
|
52
|
-
double rho;
|
52
|
+
double rho; /* one-class SVM only */
|
53
53
|
};
|
54
54
|
|
55
55
|
struct model* train(const struct problem *prob, const struct parameter *param);
|
@@ -117,14 +117,13 @@ void NEWTON::newton(double *w)
|
|
117
117
|
delete [] w0;
|
118
118
|
|
119
119
|
f = fun_obj->fun(w);
|
120
|
-
info("init f %5.3e\n", f);
|
121
120
|
fun_obj->grad(w, g);
|
122
121
|
double gnorm = dnrm2_(&n, g, &inc);
|
122
|
+
info("init f %5.3e |g| %5.3e\n", f, gnorm);
|
123
123
|
|
124
124
|
if (gnorm <= eps*gnorm0)
|
125
125
|
search = 0;
|
126
126
|
|
127
|
-
double *w_new = new double[n];
|
128
127
|
while (iter <= max_iter && search)
|
129
128
|
{
|
130
129
|
fun_obj->get_diag_preconditioner(M);
|
@@ -133,7 +132,7 @@ void NEWTON::newton(double *w)
|
|
133
132
|
cg_iter = pcg(g, M, s, r);
|
134
133
|
|
135
134
|
fold = f;
|
136
|
-
step_size = fun_obj->linesearch_and_update(w, s, &
|
135
|
+
step_size = fun_obj->linesearch_and_update(w, s, &f, g, init_step_size);
|
137
136
|
|
138
137
|
if (step_size == 0)
|
139
138
|
{
|
@@ -141,14 +140,11 @@ void NEWTON::newton(double *w)
|
|
141
140
|
break;
|
142
141
|
}
|
143
142
|
|
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
143
|
fun_obj->grad(w, g);
|
150
|
-
|
151
144
|
gnorm = dnrm2_(&n, g, &inc);
|
145
|
+
|
146
|
+
info("iter %2d f %5.3e |g| %5.3e CG %3d step_size %4.2e \n", iter, f, gnorm, cg_iter, step_size);
|
147
|
+
|
152
148
|
if (gnorm <= eps*gnorm0)
|
153
149
|
break;
|
154
150
|
if (f < -1.0e+32)
|
@@ -156,16 +152,21 @@ void NEWTON::newton(double *w)
|
|
156
152
|
info("WARNING: f < -1.0e+32\n");
|
157
153
|
break;
|
158
154
|
}
|
155
|
+
actred = fold - f;
|
159
156
|
if (fabs(actred) <= 1.0e-12*fabs(f))
|
160
157
|
{
|
161
158
|
info("WARNING: actred too small\n");
|
162
159
|
break;
|
163
160
|
}
|
161
|
+
|
162
|
+
iter++;
|
164
163
|
}
|
165
164
|
|
165
|
+
if(iter >= max_iter)
|
166
|
+
info("\nWARNING: reaching max number of Newton iterations\n");
|
167
|
+
|
166
168
|
delete[] g;
|
167
169
|
delete[] r;
|
168
|
-
delete[] w_new;
|
169
170
|
delete[] s;
|
170
171
|
delete[] M;
|
171
172
|
}
|
@@ -177,7 +178,7 @@ int NEWTON::pcg(double *g, double *M, double *s, double *r)
|
|
177
178
|
double one = 1;
|
178
179
|
double *d = new double[n];
|
179
180
|
double *Hd = new double[n];
|
180
|
-
double zTr, znewTrnew, alpha, beta, cgtol;
|
181
|
+
double zTr, znewTrnew, alpha, beta, cgtol, dHd;
|
181
182
|
double *z = new double[n];
|
182
183
|
double Q = 0, newQ, Qdiff;
|
183
184
|
|
@@ -198,9 +199,14 @@ int NEWTON::pcg(double *g, double *M, double *s, double *r)
|
|
198
199
|
while (cg_iter < max_cg_iter)
|
199
200
|
{
|
200
201
|
cg_iter++;
|
201
|
-
fun_obj->Hv(d, Hd);
|
202
202
|
|
203
|
-
|
203
|
+
fun_obj->Hv(d, Hd);
|
204
|
+
dHd = ddot_(&n, d, &inc, Hd, &inc);
|
205
|
+
// avoid 0/0 in getting alpha
|
206
|
+
if (dHd <= 1.0e-16)
|
207
|
+
break;
|
208
|
+
|
209
|
+
alpha = zTr/dHd;
|
204
210
|
daxpy_(&n, &alpha, d, &inc, s, &inc);
|
205
211
|
alpha = -alpha;
|
206
212
|
daxpy_(&n, &alpha, Hd, &inc, r, &inc);
|
@@ -236,7 +242,7 @@ int NEWTON::pcg(double *g, double *M, double *s, double *r)
|
|
236
242
|
delete[] Hd;
|
237
243
|
delete[] z;
|
238
244
|
|
239
|
-
return
|
245
|
+
return cg_iter;
|
240
246
|
}
|
241
247
|
|
242
248
|
void NEWTON::set_print_string(void (*print_string) (const char *buf))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: numo-liblinear
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yoshoku
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
|
-
rubygems_version: 3.3.
|
80
|
+
rubygems_version: 3.3.7
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
83
|
summary: Numo::Liblinear is a Ruby gem binding to the LIBLINEAR library. Numo::Liblinear
|