wapiti 0.0.5 → 0.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 +7 -0
- data/.simplecov +3 -0
- data/Gemfile +25 -2
- data/HISTORY.md +5 -1
- data/LICENSE +14 -13
- data/README.md +9 -16
- data/Rakefile +38 -8
- data/ext/wapiti/bcd.c +126 -124
- data/ext/wapiti/decoder.c +203 -124
- data/ext/wapiti/decoder.h +6 -4
- data/ext/wapiti/extconf.rb +2 -2
- data/ext/wapiti/gradient.c +491 -320
- data/ext/wapiti/gradient.h +52 -34
- data/ext/wapiti/lbfgs.c +74 -33
- data/ext/wapiti/model.c +47 -37
- data/ext/wapiti/model.h +22 -20
- data/ext/wapiti/native.c +850 -839
- data/ext/wapiti/native.h +1 -1
- data/ext/wapiti/options.c +52 -20
- data/ext/wapiti/options.h +37 -30
- data/ext/wapiti/pattern.c +35 -33
- data/ext/wapiti/pattern.h +12 -11
- data/ext/wapiti/progress.c +14 -13
- data/ext/wapiti/progress.h +3 -2
- data/ext/wapiti/quark.c +14 -16
- data/ext/wapiti/quark.h +6 -5
- data/ext/wapiti/reader.c +83 -69
- data/ext/wapiti/reader.h +11 -9
- data/ext/wapiti/rprop.c +84 -43
- data/ext/wapiti/sequence.h +18 -16
- data/ext/wapiti/sgdl1.c +45 -43
- data/ext/wapiti/thread.c +19 -17
- data/ext/wapiti/thread.h +5 -4
- data/ext/wapiti/tools.c +7 -7
- data/ext/wapiti/tools.h +3 -4
- data/ext/wapiti/trainers.h +1 -1
- data/ext/wapiti/vmath.c +40 -38
- data/ext/wapiti/vmath.h +12 -11
- data/ext/wapiti/wapiti.c +159 -37
- data/ext/wapiti/wapiti.h +18 -4
- data/lib/wapiti.rb +15 -15
- data/lib/wapiti/errors.rb +15 -15
- data/lib/wapiti/model.rb +92 -84
- data/lib/wapiti/options.rb +123 -124
- data/lib/wapiti/utility.rb +14 -14
- data/lib/wapiti/version.rb +2 -2
- data/spec/spec_helper.rb +29 -9
- data/spec/wapiti/model_spec.rb +230 -194
- data/spec/wapiti/native_spec.rb +7 -8
- data/spec/wapiti/options_spec.rb +184 -174
- data/wapiti.gemspec +22 -8
- metadata +38 -42
- data/.gitignore +0 -5
data/ext/wapiti/gradient.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* Wapiti - A linear-chain CRF tool
|
3
3
|
*
|
4
|
-
* Copyright (c) 2009-
|
4
|
+
* Copyright (c) 2009-2013 CNRS
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without
|
@@ -32,50 +32,68 @@
|
|
32
32
|
#include "model.h"
|
33
33
|
#include "sequence.h"
|
34
34
|
|
35
|
-
/*
|
35
|
+
/* grd_st_t:
|
36
36
|
* State tracker for the gradient computation. To compute the gradient we need
|
37
37
|
* to perform several steps and communicate between them a lot of intermediate
|
38
|
-
* values, all these temporary are
|
38
|
+
* values, all these temporary are stored in this object.
|
39
39
|
* A tracker can be used to compute sequence of length <len> at most, before
|
40
|
-
* using it you must call
|
40
|
+
* using it you must call grd_stcheck to ensure that the tracker is big enough
|
41
41
|
* for your sequence.
|
42
|
+
* This tracker is used to perform single sample gradient computations or
|
43
|
+
* partial gradient computation in online algorithms and for decoding with
|
44
|
+
* posteriors.
|
42
45
|
*/
|
43
|
-
typedef struct
|
44
|
-
struct
|
45
|
-
mdl_t
|
46
|
-
|
47
|
-
double
|
48
|
-
double
|
49
|
-
double
|
50
|
-
double
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
double
|
55
|
-
double
|
56
|
-
double
|
57
|
-
double
|
58
|
-
double
|
59
|
-
|
60
|
-
|
46
|
+
typedef struct grd_st_s grd_st_t;
|
47
|
+
struct grd_st_s {
|
48
|
+
mdl_t *mdl;
|
49
|
+
uint32_t len; // =T max length of sequence
|
50
|
+
double *g; // [F] vector where to put gradient updates
|
51
|
+
double lloss; // loss value for the sequence
|
52
|
+
double *psi; // [T][Y][Y] the transitions scores
|
53
|
+
double *psiuni; // [T][Y] | Same as psi in sparse format
|
54
|
+
uint32_t *psiyp; // [T][Y][Y] |
|
55
|
+
uint32_t *psiidx; // [T][Y] |
|
56
|
+
uint32_t *psioff; // [T]
|
57
|
+
double *alpha; // [T][Y] forward scores
|
58
|
+
double *beta; // [T][Y] backward scores
|
59
|
+
double *scale; // [T] scaling factors of forward scores
|
60
|
+
double *unorm; // [T] normalization factors for unigrams
|
61
|
+
double *bnorm; // [T] normalization factors for bigrams
|
62
|
+
uint32_t first; // first position where gradient is needed
|
63
|
+
uint32_t last; // last position where gradient is needed
|
61
64
|
};
|
62
65
|
|
63
|
-
|
64
|
-
void
|
65
|
-
void
|
66
|
+
grd_st_t *grd_stnew(mdl_t *mdl, double *g);
|
67
|
+
void grd_stfree(grd_st_t *grd_st);
|
68
|
+
void grd_stcheck(grd_st_t *grd_st, uint32_t len);
|
69
|
+
|
70
|
+
void grd_fldopsi(grd_st_t *grd_st, const seq_t *seq);
|
71
|
+
void grd_flfwdbwd(grd_st_t *grd_st, const seq_t *seq);
|
72
|
+
void grd_flupgrad(grd_st_t *grd_st, const seq_t *seq);
|
73
|
+
|
74
|
+
void grd_spdopsi(grd_st_t *grd_st, const seq_t *seq);
|
75
|
+
void grd_spfwdbwd(grd_st_t *grd_st, const seq_t *seq);
|
76
|
+
void grd_spupgrad(grd_st_t *grd_st, const seq_t *seq);
|
66
77
|
|
67
|
-
void
|
68
|
-
void grd_flfwdbwd(grd_t *grd, const seq_t *seq);
|
69
|
-
void grd_flupgrad(grd_t *grd, const seq_t *seq);
|
78
|
+
void grd_logloss(grd_st_t *grd_st, const seq_t *seq);
|
70
79
|
|
71
|
-
void
|
72
|
-
void grd_spfwdbwd(grd_t *grd, const seq_t *seq);
|
73
|
-
void grd_spupgrad(grd_t *grd, const seq_t *seq);
|
80
|
+
void grd_dospl(grd_st_t *grd_st, const seq_t *seq);
|
74
81
|
|
75
|
-
|
82
|
+
/* grd_t:
|
83
|
+
* Multi-threaded full dataset gradient computer. This is used to compute the
|
84
|
+
* gradient by algorithm working on the full dataset at each iterations. It
|
85
|
+
* efficiently compute it using the fact it is additive to use as many threads
|
86
|
+
* as allowed.
|
87
|
+
*/
|
88
|
+
typedef struct grd_s grd_t;
|
89
|
+
struct grd_s {
|
90
|
+
mdl_t *mdl;
|
91
|
+
grd_st_t **grd_st;
|
92
|
+
};
|
76
93
|
|
77
|
-
|
78
|
-
|
94
|
+
grd_t *grd_new(mdl_t *mdl, double *g);
|
95
|
+
void grd_free(grd_t *grd);
|
96
|
+
double grd_gradient(grd_t *grd);
|
79
97
|
|
80
98
|
#endif
|
81
99
|
|
data/ext/wapiti/lbfgs.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* Wapiti - A linear-chain CRF tool
|
3
3
|
*
|
4
|
-
* Copyright (c) 2009-
|
4
|
+
* Copyright (c) 2009-2013 CNRS
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without
|
@@ -24,9 +24,12 @@
|
|
24
24
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
25
25
|
* POSSIBILITY OF SUCH DAMAGE.
|
26
26
|
*/
|
27
|
+
#include <inttypes.h>
|
27
28
|
#include <math.h>
|
28
29
|
#include <stdbool.h>
|
29
30
|
#include <stddef.h>
|
31
|
+
#include <stdint.h>
|
32
|
+
#include <stdio.h>
|
30
33
|
#include <stdlib.h>
|
31
34
|
#include <string.h>
|
32
35
|
|
@@ -58,12 +61,11 @@
|
|
58
61
|
******************************************************************************/
|
59
62
|
|
60
63
|
void trn_lbfgs(mdl_t *mdl) {
|
61
|
-
const
|
62
|
-
const
|
63
|
-
const
|
64
|
-
const
|
65
|
-
const
|
66
|
-
const bool l1 = mdl->opt->rho1 != 0.0;
|
64
|
+
const uint64_t F = mdl->nftr;
|
65
|
+
const uint32_t K = mdl->opt->maxiter;
|
66
|
+
const uint32_t C = mdl->opt->objwin;
|
67
|
+
const uint32_t M = mdl->opt->lbfgs.histsz;
|
68
|
+
const bool l1 = mdl->opt->rho1 != 0.0;
|
67
69
|
double *x, *xp; // Current and previous value of the variables
|
68
70
|
double *g, *gp; // Current and previous value of the gradient
|
69
71
|
double *pg; // The pseudo-gradient (only for owl-qn)
|
@@ -72,7 +74,6 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
72
74
|
double *y[M]; // History value y_k = Δ(g,pg)
|
73
75
|
double p[M]; // ρ_k
|
74
76
|
double fh[C]; // f(x) history
|
75
|
-
grd_t *grds[W];
|
76
77
|
// Initialization: Here, we have to allocate memory on the heap as we
|
77
78
|
// cannot request so much memory on the stack as this will have a too
|
78
79
|
// big impact on performance and will be refused by the system on non-
|
@@ -80,22 +81,50 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
80
81
|
x = mdl->theta;
|
81
82
|
xp = xvm_new(F); g = xvm_new(F);
|
82
83
|
gp = xvm_new(F); d = xvm_new(F);
|
83
|
-
for (
|
84
|
+
for (uint32_t m = 0; m < M; m++) {
|
84
85
|
s[m] = xvm_new(F);
|
85
86
|
y[m] = xvm_new(F);
|
86
87
|
}
|
87
88
|
pg = l1 ? xvm_new(F) : NULL;
|
88
|
-
|
89
|
-
|
90
|
-
|
89
|
+
grd_t *grd = grd_new(mdl, g);
|
90
|
+
// Restore a saved state if user specified one.
|
91
|
+
if (mdl->opt->rstate != NULL) {
|
92
|
+
const char *err = "invalid state file";
|
93
|
+
FILE *file = fopen(mdl->opt->rstate, "r");
|
94
|
+
if (file == NULL)
|
95
|
+
fatal("failed to open input state file");
|
96
|
+
int type, histsz;
|
97
|
+
uint64_t nftr;
|
98
|
+
if (fscanf(file, "#state#%d#%d#%"SCNu64"\n", &type, &histsz,
|
99
|
+
&nftr) != 3)
|
100
|
+
fatal("0 %s", err);
|
101
|
+
if (type != 0 || histsz != (int)M)
|
102
|
+
fatal("state is not compatible");
|
103
|
+
for (uint64_t i = 0; i < nftr; i++) {
|
104
|
+
uint64_t f;
|
105
|
+
if (fscanf(file, "%"PRIu64, &f) != 1)
|
106
|
+
fatal("1 %s", err);
|
107
|
+
if (fscanf(file, "%la %la", &xp[f], &gp[f]) != 2)
|
108
|
+
fatal("2 %s", err);
|
109
|
+
for (uint32_t m = 0; m < M; m++) {
|
110
|
+
if (fscanf(file, "%la", &s[m][f]) != 1)
|
111
|
+
fatal("3 %s", err);
|
112
|
+
if (fscanf(file, "%la", &y[m][f]) != 1)
|
113
|
+
fatal("4 %s", err);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
for (uint32_t m = 0; m < M; m++)
|
117
|
+
p[m] = 1.0 / xvm_dot(y[m], s[m], F);
|
118
|
+
fclose(file);
|
119
|
+
}
|
91
120
|
// Minimization: This is the heart of the function. (a big heart...) We
|
92
121
|
// will perform iterations until one these conditions is reached
|
93
122
|
// - the maximum iteration count is reached
|
94
123
|
// - we have converged (upto numerical precision)
|
95
124
|
// - the report function return false
|
96
125
|
// - an error happen somewhere
|
97
|
-
double fx = grd_gradient(
|
98
|
-
for (
|
126
|
+
double fx = grd_gradient(grd);
|
127
|
+
for (uint32_t k = 0; !uit_stop && k < K; k++) {
|
99
128
|
// We first compute the pseudo-gradient of f for owl-qn. It is
|
100
129
|
// defined in [3, pp 335(4)]
|
101
130
|
// | ∂_i^- f(x) if ∂_i^- f(x) > 0
|
@@ -106,7 +135,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
106
135
|
// | ±C if x_i = 0
|
107
136
|
if (l1) {
|
108
137
|
const double rho1 = mdl->opt->rho1;
|
109
|
-
for (
|
138
|
+
for (uint64_t f = 0; f < F; f++) {
|
110
139
|
if (x[f] < 0.0)
|
111
140
|
pg[f] = g[f] - rho1;
|
112
141
|
else if (x[f] > 0.0)
|
@@ -130,13 +159,13 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
130
159
|
// gradient instead of the true one.
|
131
160
|
xvm_neg(d, l1 ? pg : g, F);
|
132
161
|
if (k != 0) {
|
133
|
-
const
|
134
|
-
const
|
162
|
+
const uint32_t km = k % M;
|
163
|
+
const uint32_t bnd = (k <= M) ? k : M;
|
135
164
|
double alpha[M], beta;
|
136
165
|
// α_i = ρ_j s_j^T q_{i+1}
|
137
166
|
// q_i = q_{i+1} - α_i y_i
|
138
|
-
for (
|
139
|
-
const
|
167
|
+
for (uint32_t i = bnd; i > 0; i--) {
|
168
|
+
const uint32_t j = (M + 1 + k - i) % M;
|
140
169
|
alpha[i - 1] = p[j] * xvm_dot(s[j], d, F);
|
141
170
|
xvm_axpy(d, -alpha[i - 1], y[j], d, F);
|
142
171
|
}
|
@@ -147,12 +176,12 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
147
176
|
// = I * 1 / ρ_k ||y_k||²
|
148
177
|
const double y2 = xvm_dot(y[km], y[km], F);
|
149
178
|
const double v = 1.0 / (p[km] * y2);
|
150
|
-
for (
|
179
|
+
for (uint64_t f = 0; f < F; f++)
|
151
180
|
d[f] *= v;
|
152
181
|
// β_j = ρ_j y_j^T r_i
|
153
182
|
// r_{i+1} = r_i + s_j (α_i - β_i)
|
154
|
-
for (
|
155
|
-
const
|
183
|
+
for (uint32_t i = 0; i < bnd; i++) {
|
184
|
+
const uint32_t j = (M + k - i) % M;
|
156
185
|
beta = p[j] * xvm_dot(y[j], d, F);
|
157
186
|
xvm_axpy(d, alpha[i] - beta, s[j], d, F);
|
158
187
|
}
|
@@ -163,7 +192,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
163
192
|
// d^k = π(d^k ; v^k)
|
164
193
|
// = π(d^k ; -◇f(x^k))
|
165
194
|
if (l1)
|
166
|
-
for (
|
195
|
+
for (uint64_t f = 0; f < F; f++)
|
167
196
|
if (d[f] * pg[f] >= 0.0)
|
168
197
|
d[f] = 0.0;
|
169
198
|
// 2nd step: we perform a linesearch in the computed direction,
|
@@ -184,7 +213,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
184
213
|
double gd = l1 ? 0.0 : xvm_dot(g, d, F); // gd = g_k^T d_k
|
185
214
|
double fi = fx;
|
186
215
|
bool err = false;
|
187
|
-
for (
|
216
|
+
for (uint32_t ls = 1; !uit_stop; ls++, stp *= sc) {
|
188
217
|
// We compute the new point using the current step and
|
189
218
|
// search direction
|
190
219
|
xvm_axpy(x, stp, d, xp, F);
|
@@ -192,7 +221,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
192
221
|
// current orthant [3, pp 35]
|
193
222
|
// x^{k+1} = π(x^k + αp^k ; ξ)
|
194
223
|
if (l1) {
|
195
|
-
for (
|
224
|
+
for (uint64_t f = 0; f < F; f++) {
|
196
225
|
double or = xp[f];
|
197
226
|
if (or == 0.0)
|
198
227
|
or = -pg[f];
|
@@ -202,7 +231,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
202
231
|
}
|
203
232
|
// And we ask for the value of the objective function
|
204
233
|
// and its gradient.
|
205
|
-
fx = grd_gradient(
|
234
|
+
fx = grd_gradient(grd);
|
206
235
|
// Now we check if the step satisfy the conditions. For
|
207
236
|
// l-bfgs, we check the classical decrease and curvature
|
208
237
|
// known as the Wolfe conditions [2, pp 506]
|
@@ -221,7 +250,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
221
250
|
break;
|
222
251
|
} else {
|
223
252
|
double vp = 0.0;
|
224
|
-
for (
|
253
|
+
for (uint64_t f = 0; f < F; f++)
|
225
254
|
vp += (x[f] - xp[f]) * d[f];
|
226
255
|
if (fx < fi + vp * 1e-4)
|
227
256
|
break;
|
@@ -249,7 +278,7 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
249
278
|
// s_k = x_{k+1} - x_k
|
250
279
|
// y_k = g_{k+1} - g_k
|
251
280
|
// ρ_k = 1 / y_k^T s_k
|
252
|
-
const
|
281
|
+
const uint32_t kn = (k + 1) % M;
|
253
282
|
xvm_sub(s[kn], x, xp, F);
|
254
283
|
xvm_sub(y[kn], g, gp, F);
|
255
284
|
p[kn] = 1.0 / xvm_dot(y[kn], s[kn], F);
|
@@ -277,18 +306,30 @@ void trn_lbfgs(mdl_t *mdl) {
|
|
277
306
|
break;
|
278
307
|
}
|
279
308
|
}
|
309
|
+
// Save the optimizer state if requested by the user
|
310
|
+
if (mdl->opt->sstate != NULL) {
|
311
|
+
FILE *file = fopen(mdl->opt->sstate, "w");
|
312
|
+
if (file == NULL)
|
313
|
+
fatal("failed to open output state file");
|
314
|
+
fprintf(file, "#state#0#%"PRIu32"#%"PRIu64"\n", M, F);
|
315
|
+
for (uint64_t f = 0; f < F; f++) {
|
316
|
+
fprintf(file, "%"PRIu64, f);
|
317
|
+
fprintf(file, " %la %la", xp[f], gp[f]);
|
318
|
+
for (uint32_t m = 0; m < M; m++)
|
319
|
+
fprintf(file, " %la %la", s[m][f], y[m][f]);
|
320
|
+
fprintf(file, "\n");
|
321
|
+
}
|
322
|
+
fclose(file);
|
323
|
+
}
|
280
324
|
// Cleanup: We free all the vectors we have allocated.
|
281
325
|
xvm_free(xp); xvm_free(g);
|
282
326
|
xvm_free(gp); xvm_free(d);
|
283
|
-
for (
|
327
|
+
for (uint32_t m = 0; m < M; m++) {
|
284
328
|
xvm_free(s[m]);
|
285
329
|
xvm_free(y[m]);
|
286
330
|
}
|
287
331
|
if (l1)
|
288
332
|
xvm_free(pg);
|
289
|
-
|
290
|
-
xvm_free(grds[w]->g);
|
291
|
-
for (size_t w = 0; w < W; w++)
|
292
|
-
grd_free(grds[w]);
|
333
|
+
grd_free(grd);
|
293
334
|
}
|
294
335
|
|
data/ext/wapiti/model.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* Wapiti - A linear-chain CRF tool
|
3
3
|
*
|
4
|
-
* Copyright (c) 2009-
|
4
|
+
* Copyright (c) 2009-2013 CNRS
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
7
|
* Redistribution and use in source and binary forms, with or without
|
@@ -24,8 +24,10 @@
|
|
24
24
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
25
25
|
* POSSIBILITY OF SUCH DAMAGE.
|
26
26
|
*/
|
27
|
+
#include <inttypes.h>
|
27
28
|
#include <stdbool.h>
|
28
29
|
#include <stddef.h>
|
30
|
+
#include <stdint.h>
|
29
31
|
#include <stdlib.h>
|
30
32
|
#include <stdio.h>
|
31
33
|
#include <string.h>
|
@@ -120,8 +122,8 @@ void mdl_free(mdl_t *mdl) {
|
|
120
122
|
* This reduce the risk of mistakes.
|
121
123
|
*/
|
122
124
|
void mdl_sync(mdl_t *mdl) {
|
123
|
-
const
|
124
|
-
const
|
125
|
+
const uint32_t Y = qrk_count(mdl->reader->lbl);
|
126
|
+
const uint64_t O = qrk_count(mdl->reader->obs);
|
125
127
|
// If model is already synchronized, do nothing and just return
|
126
128
|
if (mdl->nlbl == Y && mdl->nobs == O)
|
127
129
|
return;
|
@@ -131,8 +133,8 @@ void mdl_sync(mdl_t *mdl) {
|
|
131
133
|
// case we also display a warning as this is probably not expected by
|
132
134
|
// the user. If only new observations was added, we will try to expand
|
133
135
|
// the model.
|
134
|
-
|
135
|
-
|
136
|
+
uint64_t oldF = mdl->nftr;
|
137
|
+
uint64_t oldO = mdl->nobs;
|
136
138
|
if (mdl->nlbl != Y && mdl->nlbl != 0) {
|
137
139
|
warning("labels count changed, discarding the model");
|
138
140
|
free(mdl->kind); mdl->kind = NULL;
|
@@ -148,16 +150,16 @@ void mdl_sync(mdl_t *mdl) {
|
|
148
150
|
mdl->nobs = O;
|
149
151
|
// Allocate the observations datastructure. If the model is empty or
|
150
152
|
// discarded, a new one iscreated, else the old one is expanded.
|
151
|
-
char
|
152
|
-
|
153
|
-
|
153
|
+
char *kind = wapiti_xrealloc(mdl->kind, sizeof(char ) * O);
|
154
|
+
uint64_t *uoff = wapiti_xrealloc(mdl->uoff, sizeof(uint64_t) * O);
|
155
|
+
uint64_t *boff = wapiti_xrealloc(mdl->boff, sizeof(uint64_t) * O);
|
154
156
|
mdl->kind = kind;
|
155
157
|
mdl->uoff = uoff;
|
156
158
|
mdl->boff = boff;
|
157
159
|
// Now, we can setup the features. For each new observations we fill the
|
158
160
|
// kind and offsets arrays and count total number of features as well.
|
159
|
-
|
160
|
-
for (
|
161
|
+
uint64_t F = oldF;
|
162
|
+
for (uint64_t o = oldO; o < O; o++) {
|
161
163
|
const char *obs = qrk_id2str(mdl->reader->obs, o);
|
162
164
|
switch (obs[0]) {
|
163
165
|
case 'u': kind[o] = 1; break;
|
@@ -176,14 +178,14 @@ void mdl_sync(mdl_t *mdl) {
|
|
176
178
|
// have to allocate a new vector and copy old values ourself.
|
177
179
|
if (oldF != 0) {
|
178
180
|
double *new = xvm_new(F);
|
179
|
-
for (
|
181
|
+
for (uint64_t f = 0; f < oldF; f++)
|
180
182
|
new[f] = mdl->theta[f];
|
181
183
|
xvm_free(mdl->theta);
|
182
184
|
mdl->theta = new;
|
183
185
|
} else {
|
184
186
|
mdl->theta = xvm_new(F);
|
185
187
|
}
|
186
|
-
for (
|
188
|
+
for (uint64_t f = oldF; f < F; f++)
|
187
189
|
mdl->theta[f] = 0.0;
|
188
190
|
// And lock the databases
|
189
191
|
qrk_lock(mdl->reader->lbl, true);
|
@@ -197,7 +199,7 @@ void mdl_sync(mdl_t *mdl) {
|
|
197
199
|
* and labeling.
|
198
200
|
*/
|
199
201
|
void mdl_compact(mdl_t *mdl) {
|
200
|
-
const
|
202
|
+
const uint32_t Y = mdl->nlbl;
|
201
203
|
// We first build the new observation list with only observations which
|
202
204
|
// lead to at least one active feature. At the same time we build the
|
203
205
|
// translation table which map the new observations index to the old
|
@@ -205,29 +207,29 @@ void mdl_compact(mdl_t *mdl) {
|
|
205
207
|
info(" - Scan the model\n");
|
206
208
|
qrk_t *old_obs = mdl->reader->obs;
|
207
209
|
qrk_t *new_obs = qrk_new();
|
208
|
-
|
209
|
-
for (
|
210
|
+
uint64_t *trans = wapiti_xmalloc(sizeof(uint64_t) * mdl->nobs);
|
211
|
+
for (uint64_t oldo = 0; oldo < mdl->nobs; oldo++) {
|
210
212
|
bool active = false;
|
211
213
|
if (mdl->kind[oldo] & 1)
|
212
|
-
for (
|
214
|
+
for (uint32_t y = 0; y < Y; y++)
|
213
215
|
if (mdl->theta[mdl->uoff[oldo] + y] != 0.0)
|
214
216
|
active = true;
|
215
217
|
if (mdl->kind[oldo] & 2)
|
216
|
-
for (
|
218
|
+
for (uint32_t d = 0; d < Y * Y; d++)
|
217
219
|
if (mdl->theta[mdl->boff[oldo] + d] != 0.0)
|
218
220
|
active = true;
|
219
221
|
if (!active)
|
220
222
|
continue;
|
221
|
-
const char
|
222
|
-
const
|
223
|
+
const char *str = qrk_id2str(old_obs, oldo);
|
224
|
+
const uint64_t newo = qrk_str2id(new_obs, str);
|
223
225
|
trans[newo] = oldo;
|
224
226
|
}
|
225
227
|
mdl->reader->obs = new_obs;
|
226
228
|
// Now we save the old model features informations and build a new one
|
227
229
|
// corresponding to the compacted model.
|
228
|
-
|
229
|
-
|
230
|
-
double
|
230
|
+
uint64_t *old_uoff = mdl->uoff; mdl->uoff = NULL;
|
231
|
+
uint64_t *old_boff = mdl->boff; mdl->boff = NULL;
|
232
|
+
double *old_theta = mdl->theta; mdl->theta = NULL;
|
231
233
|
free(mdl->kind);
|
232
234
|
mdl->kind = NULL;
|
233
235
|
mdl->nlbl = mdl->nobs = mdl->nftr = 0;
|
@@ -235,18 +237,18 @@ void mdl_compact(mdl_t *mdl) {
|
|
235
237
|
// The model is now ready, so we copy in it the features weights from
|
236
238
|
// the old model for observations we have kept.
|
237
239
|
info(" - Compact it\n");
|
238
|
-
for (
|
239
|
-
const
|
240
|
+
for (uint64_t newo = 0; newo < mdl->nobs; newo++) {
|
241
|
+
const uint64_t oldo = trans[newo];
|
240
242
|
if (mdl->kind[newo] & 1) {
|
241
243
|
double *src = old_theta + old_uoff[oldo];
|
242
244
|
double *dst = mdl->theta + mdl->uoff[newo];
|
243
|
-
for (
|
245
|
+
for (uint32_t y = 0; y < Y; y++)
|
244
246
|
dst[y] = src[y];
|
245
247
|
}
|
246
248
|
if (mdl->kind[newo] & 2) {
|
247
249
|
double *src = old_theta + old_boff[oldo];
|
248
250
|
double *dst = mdl->theta + mdl->boff[newo];
|
249
|
-
for (
|
251
|
+
for (uint32_t d = 0; d < Y * Y; d++)
|
250
252
|
dst[d] = src[d];
|
251
253
|
}
|
252
254
|
}
|
@@ -262,15 +264,15 @@ void mdl_compact(mdl_t *mdl) {
|
|
262
264
|
* Save a model to be restored later in a platform independant way.
|
263
265
|
*/
|
264
266
|
void mdl_save(mdl_t *mdl, FILE *file) {
|
265
|
-
|
266
|
-
for (
|
267
|
+
uint64_t nact = 0;
|
268
|
+
for (uint64_t f = 0; f < mdl->nftr; f++)
|
267
269
|
if (mdl->theta[f] != 0.0)
|
268
270
|
nact++;
|
269
|
-
fprintf(file, "#mdl#%
|
271
|
+
fprintf(file, "#mdl#%d#%"PRIu64"\n", mdl->type, nact);
|
270
272
|
rdr_save(mdl->reader, file);
|
271
|
-
for (
|
273
|
+
for (uint64_t f = 0; f < mdl->nftr; f++)
|
272
274
|
if (mdl->theta[f] != 0.0)
|
273
|
-
fprintf(file, "%
|
275
|
+
fprintf(file, "%"PRIu64"=%la\n", f, mdl->theta[f]);
|
274
276
|
}
|
275
277
|
|
276
278
|
/* mdl_load:
|
@@ -280,15 +282,23 @@ void mdl_save(mdl_t *mdl, FILE *file) {
|
|
280
282
|
*/
|
281
283
|
void mdl_load(mdl_t *mdl, FILE *file) {
|
282
284
|
const char *err = "invalid model format";
|
283
|
-
|
284
|
-
|
285
|
-
|
285
|
+
uint64_t nact = 0;
|
286
|
+
int type;
|
287
|
+
if (fscanf(file, "#mdl#%d#%"SCNu64"\n", &type, &nact) == 2) {
|
288
|
+
mdl->type = type;
|
289
|
+
} else {
|
290
|
+
rewind(file);
|
291
|
+
if (fscanf(file, "#mdl#%"SCNu64"\n", &nact) == 1)
|
292
|
+
mdl->type = 0;
|
293
|
+
else
|
294
|
+
fatal(err);
|
295
|
+
}
|
286
296
|
rdr_load(mdl->reader, file);
|
287
297
|
mdl_sync(mdl);
|
288
|
-
for (
|
289
|
-
|
298
|
+
for (uint64_t i = 0; i < nact; i++) {
|
299
|
+
uint64_t f;
|
290
300
|
double v;
|
291
|
-
if (fscanf(file, "%
|
301
|
+
if (fscanf(file, "%"SCNu64"=%la\n", &f, &v) != 2)
|
292
302
|
fatal(err);
|
293
303
|
mdl->theta[f] = v;
|
294
304
|
}
|