wapiti 0.0.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|