static_embeddings 0.1.3 → 0.1.5
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 +153 -0
- data/README.md +56 -28
- data/Rakefile +1 -1
- data/docs/ARCHITECTURE.md +50 -31
- data/docs/LIMITATIONS.md +16 -8
- data/docs/MODEL_AUDIT.md +84 -43
- data/docs/PERFORMANCE.md +28 -19
- data/ext/static_embeddings/se_embed.c +48 -8
- data/ext/static_embeddings/se_f16.c +43 -7
- data/ext/static_embeddings/se_format.c +121 -9
- data/ext/static_embeddings/se_internal.h +26 -5
- data/ext/static_embeddings/se_tokenizer.c +451 -47
- data/ext/static_embeddings/se_unicode.c +1 -1
- data/ext/static_embeddings/static_embeddings.c +136 -48
- data/lib/static_embeddings/cli.rb +1 -0
- data/lib/static_embeddings/converter.rb +51 -7
- data/lib/static_embeddings/format.rb +60 -22
- data/lib/static_embeddings/paths.rb +18 -1
- data/lib/static_embeddings/reference.rb +54 -7
- data/lib/static_embeddings/safetensors.rb +178 -34
- data/lib/static_embeddings/version.rb +1 -1
- data/lib/static_embeddings.rb +3 -5
- data/tools/check_model2vec_parity.rb +85 -54
- metadata +1 -1
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
#include <stdlib.h>
|
|
5
5
|
#include <string.h>
|
|
6
6
|
|
|
7
|
+
#ifndef _WIN32
|
|
8
|
+
#include <pthread.h>
|
|
9
|
+
#else
|
|
10
|
+
#ifndef WIN32_LEAN_AND_MEAN
|
|
11
|
+
#define WIN32_LEAN_AND_MEAN
|
|
12
|
+
#endif
|
|
13
|
+
#ifndef _WIN32_WINNT
|
|
14
|
+
#define _WIN32_WINNT 0x0600
|
|
15
|
+
#endif
|
|
16
|
+
#include <windows.h>
|
|
17
|
+
#endif
|
|
18
|
+
|
|
7
19
|
#define SE_CANCEL_CHECK_MASK 0x3ffu
|
|
8
20
|
|
|
9
21
|
void se_scratch_init(se_scratch_t *s) {
|
|
@@ -75,14 +87,19 @@ static int push_id(se_scratch_t *sc, size_t *n_ids, uint32_t id) {
|
|
|
75
87
|
return 1;
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
#define SE_SCRATCH_CPS_KEEP 256
|
|
91
|
+
#define SE_SCRATCH_IDS_RESERVE 512
|
|
92
|
+
#define SE_SCRATCH_IDS_RETAIN_MAX 8192
|
|
93
|
+
#define SE_SCRATCH_BYTES_KEEP 1024
|
|
94
|
+
|
|
78
95
|
int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
|
|
79
|
-
if (!grow_u32(&s->cps, &s->cps_cap,
|
|
96
|
+
if (!grow_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP))
|
|
80
97
|
return 0;
|
|
81
|
-
if (!grow_u32(&s->cps2, &s->cps2_cap,
|
|
98
|
+
if (!grow_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP))
|
|
82
99
|
return 0;
|
|
83
|
-
if (!grow_u32(&s->ids, &s->ids_cap,
|
|
100
|
+
if (!grow_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_RESERVE))
|
|
84
101
|
return 0;
|
|
85
|
-
if (!grow_bytes(&s->bytes, &s->bytes_cap,
|
|
102
|
+
if (!grow_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP))
|
|
86
103
|
return 0;
|
|
87
104
|
if (!grow_float(&s->acc, &s->acc_cap, dim))
|
|
88
105
|
return 0;
|
|
@@ -90,21 +107,224 @@ int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
|
|
|
90
107
|
return 1;
|
|
91
108
|
}
|
|
92
109
|
|
|
110
|
+
static int shrink_u32(uint32_t **buf, size_t *cap, size_t keep) {
|
|
111
|
+
size_t bytes = 0;
|
|
112
|
+
void *p;
|
|
113
|
+
|
|
114
|
+
if (*cap <= keep)
|
|
115
|
+
return 1;
|
|
116
|
+
if (!*buf) {
|
|
117
|
+
*cap = 0;
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
if (!se_array_bytes(keep, sizeof(uint32_t), &bytes))
|
|
121
|
+
return 0;
|
|
122
|
+
p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
|
|
123
|
+
if (!p)
|
|
124
|
+
return 0;
|
|
125
|
+
*buf = (uint32_t *)p;
|
|
126
|
+
*cap = keep;
|
|
127
|
+
return 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static int shrink_bytes(uint8_t **buf, size_t *cap, size_t keep) {
|
|
131
|
+
size_t bytes = 0;
|
|
132
|
+
void *p;
|
|
133
|
+
|
|
134
|
+
if (*cap <= keep)
|
|
135
|
+
return 1;
|
|
136
|
+
if (!*buf) {
|
|
137
|
+
*cap = 0;
|
|
138
|
+
return 1;
|
|
139
|
+
}
|
|
140
|
+
if (!se_array_bytes(keep, sizeof(uint8_t), &bytes))
|
|
141
|
+
return 0;
|
|
142
|
+
p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
|
|
143
|
+
if (!p)
|
|
144
|
+
return 0;
|
|
145
|
+
*buf = (uint8_t *)p;
|
|
146
|
+
*cap = keep;
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static void se_scratch_trim(se_scratch_t *s) {
|
|
151
|
+
(void)shrink_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP);
|
|
152
|
+
(void)shrink_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP);
|
|
153
|
+
if (s->ids_cap > SE_SCRATCH_IDS_RETAIN_MAX)
|
|
154
|
+
(void)shrink_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_RETAIN_MAX);
|
|
155
|
+
(void)shrink_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
typedef struct {
|
|
159
|
+
se_scratch_t scratch;
|
|
160
|
+
int in_use;
|
|
161
|
+
} se_tls_scratch_t;
|
|
162
|
+
|
|
163
|
+
static void se_scratch_tls_dtor(void *p) {
|
|
164
|
+
se_tls_scratch_t *tls = (se_tls_scratch_t *)p;
|
|
165
|
+
if (!tls)
|
|
166
|
+
return;
|
|
167
|
+
se_scratch_free(&tls->scratch);
|
|
168
|
+
se_free(tls);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#ifndef _WIN32
|
|
172
|
+
static pthread_key_t se_scratch_key;
|
|
173
|
+
static pthread_once_t se_scratch_once = PTHREAD_ONCE_INIT;
|
|
174
|
+
|
|
175
|
+
static void se_scratch_key_init(void) {
|
|
176
|
+
(void)pthread_key_create(&se_scratch_key, se_scratch_tls_dtor);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static se_tls_scratch_t *se_scratch_tls_get(void) {
|
|
180
|
+
(void)pthread_once(&se_scratch_once, se_scratch_key_init);
|
|
181
|
+
return (se_tls_scratch_t *)pthread_getspecific(se_scratch_key);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static se_tls_scratch_t *se_scratch_tls_slot(void) {
|
|
185
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
186
|
+
if (tls)
|
|
187
|
+
return tls;
|
|
188
|
+
|
|
189
|
+
tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
|
|
190
|
+
if (!tls)
|
|
191
|
+
return NULL;
|
|
192
|
+
memset(tls, 0, sizeof(*tls));
|
|
193
|
+
se_scratch_init(&tls->scratch);
|
|
194
|
+
if (pthread_setspecific(se_scratch_key, tls) != 0) {
|
|
195
|
+
se_free(tls);
|
|
196
|
+
return NULL;
|
|
197
|
+
}
|
|
198
|
+
return tls;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
static void se_scratch_tls_clear(void) {
|
|
202
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
203
|
+
if (!tls)
|
|
204
|
+
return;
|
|
205
|
+
(void)pthread_setspecific(se_scratch_key, NULL);
|
|
206
|
+
se_scratch_tls_dtor(tls);
|
|
207
|
+
}
|
|
208
|
+
#else
|
|
209
|
+
static DWORD se_fls_index = FLS_OUT_OF_INDEXES;
|
|
210
|
+
static INIT_ONCE se_fls_once = INIT_ONCE_STATIC_INIT;
|
|
211
|
+
|
|
212
|
+
static VOID WINAPI se_scratch_fls_dtor(PVOID p) {
|
|
213
|
+
se_scratch_tls_dtor(p);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static BOOL CALLBACK se_scratch_fls_init(PINIT_ONCE once, PVOID param, PVOID *ctx) {
|
|
217
|
+
(void)once;
|
|
218
|
+
(void)param;
|
|
219
|
+
(void)ctx;
|
|
220
|
+
se_fls_index = FlsAlloc(se_scratch_fls_dtor);
|
|
221
|
+
return se_fls_index != FLS_OUT_OF_INDEXES;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static se_tls_scratch_t *se_scratch_tls_get(void) {
|
|
225
|
+
if (se_fls_index == FLS_OUT_OF_INDEXES)
|
|
226
|
+
return NULL;
|
|
227
|
+
return (se_tls_scratch_t *)FlsGetValue(se_fls_index);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static se_tls_scratch_t *se_scratch_tls_slot(void) {
|
|
231
|
+
if (!InitOnceExecuteOnce(&se_fls_once, se_scratch_fls_init, NULL, NULL) ||
|
|
232
|
+
se_fls_index == FLS_OUT_OF_INDEXES)
|
|
233
|
+
return NULL;
|
|
234
|
+
|
|
235
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
236
|
+
if (tls)
|
|
237
|
+
return tls;
|
|
238
|
+
|
|
239
|
+
tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
|
|
240
|
+
if (!tls)
|
|
241
|
+
return NULL;
|
|
242
|
+
memset(tls, 0, sizeof(*tls));
|
|
243
|
+
se_scratch_init(&tls->scratch);
|
|
244
|
+
if (!FlsSetValue(se_fls_index, tls)) {
|
|
245
|
+
se_free(tls);
|
|
246
|
+
return NULL;
|
|
247
|
+
}
|
|
248
|
+
return tls;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
static void se_scratch_tls_clear(void) {
|
|
252
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
253
|
+
if (!tls)
|
|
254
|
+
return;
|
|
255
|
+
(void)FlsSetValue(se_fls_index, NULL);
|
|
256
|
+
se_scratch_tls_dtor(tls);
|
|
257
|
+
}
|
|
258
|
+
#endif
|
|
259
|
+
|
|
260
|
+
se_scratch_t *se_scratch_acquire(uint32_t dim) {
|
|
261
|
+
se_tls_scratch_t *tls = se_scratch_tls_slot();
|
|
262
|
+
if (!tls)
|
|
263
|
+
return NULL;
|
|
264
|
+
|
|
265
|
+
if (!tls->in_use) {
|
|
266
|
+
if (!se_scratch_reserve(&tls->scratch, dim))
|
|
267
|
+
return NULL;
|
|
268
|
+
tls->in_use = 1;
|
|
269
|
+
return &tls->scratch;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
se_scratch_t *heap = (se_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*heap));
|
|
273
|
+
if (!heap)
|
|
274
|
+
return NULL;
|
|
275
|
+
se_scratch_init(heap);
|
|
276
|
+
if (!se_scratch_reserve(heap, dim)) {
|
|
277
|
+
se_scratch_free(heap);
|
|
278
|
+
se_free(heap);
|
|
279
|
+
return NULL;
|
|
280
|
+
}
|
|
281
|
+
return heap;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void se_scratch_release(se_scratch_t *s) {
|
|
285
|
+
se_tls_scratch_t *tls;
|
|
286
|
+
|
|
287
|
+
if (!s)
|
|
288
|
+
return;
|
|
289
|
+
|
|
290
|
+
tls = se_scratch_tls_get();
|
|
291
|
+
if (tls && s == &tls->scratch) {
|
|
292
|
+
tls->in_use = 0;
|
|
293
|
+
se_scratch_trim(&tls->scratch);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
se_scratch_free(s);
|
|
297
|
+
se_free(s);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
void se_scratch_drop_thread(void) {
|
|
301
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
302
|
+
if (tls && tls->in_use)
|
|
303
|
+
tls->in_use = 0;
|
|
304
|
+
se_scratch_tls_clear();
|
|
305
|
+
}
|
|
306
|
+
|
|
93
307
|
static int is_whitespace(const se_model_t *m, uint32_t cp) {
|
|
94
308
|
if (cp < 0x80)
|
|
95
309
|
return se_is_ascii_whitespace(cp);
|
|
310
|
+
if (cp < 256)
|
|
311
|
+
return m->norm.whitespace256[cp];
|
|
96
312
|
return se_range_contains(m->norm.whitespace, m->norm.whitespace_count, cp);
|
|
97
313
|
}
|
|
98
314
|
|
|
99
315
|
static int is_control(const se_model_t *m, uint32_t cp) {
|
|
100
316
|
if (cp < 0x80)
|
|
101
317
|
return (cp < 0x20 || cp == 0x7f) && cp != '\t' && cp != '\n' && cp != '\r';
|
|
318
|
+
if (cp < 256)
|
|
319
|
+
return m->norm.control256[cp];
|
|
102
320
|
return se_range_contains(m->norm.control, m->norm.control_count, cp);
|
|
103
321
|
}
|
|
104
322
|
|
|
105
323
|
static int is_punct(const se_model_t *m, uint32_t cp) {
|
|
106
324
|
if (cp < 0x80)
|
|
107
325
|
return se_is_ascii_punct(cp);
|
|
326
|
+
if (cp < 256)
|
|
327
|
+
return m->norm.punct256[cp];
|
|
108
328
|
return se_range_contains(m->norm.punct, m->norm.punct_count, cp);
|
|
109
329
|
}
|
|
110
330
|
|
|
@@ -154,12 +374,18 @@ static int decode_one(const uint8_t *src, size_t len, size_t *i, uint32_t *cp_ou
|
|
|
154
374
|
static int normalization_stable(const se_model_t *m, uint32_t cp) {
|
|
155
375
|
if (cp < 0x80)
|
|
156
376
|
return 1;
|
|
157
|
-
if (m->meta.do_lower_case
|
|
158
|
-
|
|
377
|
+
if (m->meta.do_lower_case) {
|
|
378
|
+
const se_map_entry_t *lower =
|
|
379
|
+
cp < 256 ? m->norm.lower256[cp] : se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
|
|
380
|
+
if (lower)
|
|
381
|
+
return 0;
|
|
382
|
+
}
|
|
159
383
|
if (m->meta.strip_accents) {
|
|
160
|
-
|
|
384
|
+
const se_map_entry_t *nfd =
|
|
385
|
+
cp < 256 ? m->norm.nfd256[cp] : se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
|
|
386
|
+
if (nfd)
|
|
161
387
|
return 0;
|
|
162
|
-
if (se_range_contains(m->norm.mn, m->norm.mn_count, cp))
|
|
388
|
+
if (cp < 256 ? m->norm.mn256[cp] : se_range_contains(m->norm.mn, m->norm.mn_count, cp))
|
|
163
389
|
return 0;
|
|
164
390
|
}
|
|
165
391
|
return 1;
|
|
@@ -169,6 +395,37 @@ static int cp_is_cjk_segment(const se_model_t *m, uint32_t cp) {
|
|
|
169
395
|
return m->meta.handle_chinese_chars && cp >= 0x3400 && se_is_cjk(cp);
|
|
170
396
|
}
|
|
171
397
|
|
|
398
|
+
typedef struct {
|
|
399
|
+
const char *text;
|
|
400
|
+
uint32_t len;
|
|
401
|
+
uint32_t bit;
|
|
402
|
+
} se_added_token_spec_t;
|
|
403
|
+
|
|
404
|
+
static const se_added_token_spec_t SE_ADDED_TOKENS[] = {
|
|
405
|
+
{"[MASK]", 6u, SE_ADDED_MASK}, {"[PAD]", 5u, SE_ADDED_PAD}, {"[UNK]", 5u, SE_ADDED_UNK},
|
|
406
|
+
{"[CLS]", 5u, SE_ADDED_CLS}, {"[SEP]", 5u, SE_ADDED_SEP},
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
static int boundary_splits_added_token(const se_model_t *model, const uint8_t *input,
|
|
410
|
+
size_t input_len, size_t boundary) {
|
|
411
|
+
if (model->meta.added_token_mask == 0 || boundary == 0 || boundary >= input_len)
|
|
412
|
+
return 0;
|
|
413
|
+
|
|
414
|
+
for (size_t k = 0; k < SE_ARRAY_LEN(SE_ADDED_TOKENS); k++) {
|
|
415
|
+
const se_added_token_spec_t *token = &SE_ADDED_TOKENS[k];
|
|
416
|
+
if ((model->meta.added_token_mask & token->bit) == 0)
|
|
417
|
+
continue;
|
|
418
|
+
for (size_t back = 1; back < token->len && back <= boundary; back++) {
|
|
419
|
+
size_t start = boundary - back;
|
|
420
|
+
if (start + token->len > input_len || input[start] != '[')
|
|
421
|
+
continue;
|
|
422
|
+
if (memcmp(input + start, token->text, token->len) == 0)
|
|
423
|
+
return 1;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
172
429
|
size_t se_prefix_boundary_len(const se_model_t *model, const uint8_t *input, size_t input_len,
|
|
173
430
|
size_t target, size_t backscan) {
|
|
174
431
|
if (target >= input_len)
|
|
@@ -196,14 +453,15 @@ size_t se_prefix_boundary_len(const se_model_t *model, const uint8_t *input, siz
|
|
|
196
453
|
continue;
|
|
197
454
|
|
|
198
455
|
if (cp_is_cjk_segment(model, cp)) {
|
|
199
|
-
if (after <= target)
|
|
456
|
+
if (after <= target && !boundary_splits_added_token(model, input, input_len, after))
|
|
200
457
|
return after;
|
|
201
|
-
if (pos > 0)
|
|
458
|
+
if (pos > 0 && !boundary_splits_added_token(model, input, input_len, pos))
|
|
202
459
|
return pos;
|
|
203
|
-
|
|
460
|
+
continue;
|
|
204
461
|
}
|
|
205
462
|
|
|
206
|
-
if ((is_whitespace(model, cp) || is_punct(model, cp)) && after <= target
|
|
463
|
+
if ((is_whitespace(model, cp) || is_punct(model, cp)) && after <= target &&
|
|
464
|
+
!boundary_splits_added_token(model, input, input_len, after))
|
|
207
465
|
return after;
|
|
208
466
|
}
|
|
209
467
|
|
|
@@ -230,9 +488,11 @@ typedef struct {
|
|
|
230
488
|
const se_model_t *model;
|
|
231
489
|
se_scratch_t *scratch;
|
|
232
490
|
uint32_t max_tokens;
|
|
491
|
+
se_token_limit_t limit_mode;
|
|
233
492
|
size_t n_ids;
|
|
234
493
|
size_t n_unk;
|
|
235
494
|
size_t segment_len;
|
|
495
|
+
int segment_ascii;
|
|
236
496
|
se_token_stats_t *stats;
|
|
237
497
|
se_error_t *err;
|
|
238
498
|
volatile sig_atomic_t *cancelled;
|
|
@@ -248,23 +508,52 @@ static se_status_t oom(token_state_t *st, const char *where) {
|
|
|
248
508
|
}
|
|
249
509
|
|
|
250
510
|
static int append_segment_cp(token_state_t *st, uint32_t cp) {
|
|
511
|
+
if (cp >= 0x80)
|
|
512
|
+
st->segment_ascii = 0;
|
|
251
513
|
if (!grow_u32(&st->scratch->cps, &st->scratch->cps_cap, st->segment_len + 1))
|
|
252
514
|
return 0;
|
|
253
515
|
st->scratch->cps[st->segment_len++] = cp;
|
|
254
516
|
return 1;
|
|
255
517
|
}
|
|
256
518
|
|
|
519
|
+
static size_t limited_token_count(const token_state_t *st) {
|
|
520
|
+
if (st->limit_mode == SE_TOKEN_LIMIT_USABLE && st->model->meta.unk_policy == SE_UNK_DROP)
|
|
521
|
+
return st->n_ids - st->n_unk;
|
|
522
|
+
return st->n_ids;
|
|
523
|
+
}
|
|
524
|
+
|
|
257
525
|
static int cap_after_append(token_state_t *st) {
|
|
258
|
-
if (st->max_tokens == 0 || st
|
|
526
|
+
if (st->max_tokens == 0 || limited_token_count(st) <= (size_t)st->max_tokens)
|
|
259
527
|
return 0;
|
|
260
528
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
529
|
+
if (st->limit_mode == SE_TOKEN_LIMIT_RAW || st->model->meta.unk_policy != SE_UNK_DROP) {
|
|
530
|
+
size_t dropped_unk = 0;
|
|
531
|
+
for (size_t k = st->max_tokens; k < st->n_ids; k++) {
|
|
532
|
+
if (st->scratch->ids[k] == st->model->meta.unk_id)
|
|
533
|
+
dropped_unk++;
|
|
534
|
+
}
|
|
535
|
+
st->n_unk -= dropped_unk;
|
|
536
|
+
st->n_ids = st->max_tokens;
|
|
537
|
+
} else {
|
|
538
|
+
size_t usable = 0;
|
|
539
|
+
size_t kept_unk = 0;
|
|
540
|
+
size_t keep = 0;
|
|
541
|
+
for (size_t k = 0; k < st->n_ids; k++) {
|
|
542
|
+
uint32_t id = st->scratch->ids[k];
|
|
543
|
+
if (id == st->model->meta.unk_id) {
|
|
544
|
+
kept_unk++;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
usable++;
|
|
548
|
+
if (usable == (size_t)st->max_tokens) {
|
|
549
|
+
keep = k + 1;
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
st->n_ids = keep;
|
|
554
|
+
st->n_unk = kept_unk;
|
|
265
555
|
}
|
|
266
|
-
|
|
267
|
-
st->n_ids = st->max_tokens;
|
|
556
|
+
|
|
268
557
|
st->stats->truncated = 1;
|
|
269
558
|
return 1;
|
|
270
559
|
}
|
|
@@ -272,7 +561,8 @@ static int cap_after_append(token_state_t *st) {
|
|
|
272
561
|
typedef enum { WORDPIECE_OK = 1, WORDPIECE_OOM = 0, WORDPIECE_INVALID = -1 } wordpiece_status_t;
|
|
273
562
|
|
|
274
563
|
static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const uint32_t *word,
|
|
275
|
-
size_t word_len, size_t *n_ids, size_t *n_unk
|
|
564
|
+
size_t word_len, size_t *n_ids, size_t *n_unk,
|
|
565
|
+
int known_ascii) {
|
|
276
566
|
const se_meta_t *meta = &m->meta;
|
|
277
567
|
|
|
278
568
|
if (word_len == 0)
|
|
@@ -285,30 +575,49 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
|
|
|
285
575
|
return 1;
|
|
286
576
|
}
|
|
287
577
|
|
|
288
|
-
|
|
289
|
-
if (!
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
578
|
+
int ascii_identity = known_ascii;
|
|
579
|
+
if (!ascii_identity) {
|
|
580
|
+
ascii_identity = 1;
|
|
581
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
582
|
+
if (word[k] >= 0x80) {
|
|
583
|
+
ascii_identity = 0;
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
296
588
|
|
|
297
589
|
size_t blen = 0;
|
|
298
|
-
|
|
299
|
-
if (
|
|
590
|
+
if (ascii_identity) {
|
|
591
|
+
if (!grow_bytes(&sc->bytes, &sc->bytes_cap, word_len))
|
|
592
|
+
return 0;
|
|
593
|
+
if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
|
|
300
594
|
return 0;
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
595
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
596
|
+
sc->bytes[k] = (uint8_t)word[k];
|
|
597
|
+
sc->cps2[k] = (uint32_t)k;
|
|
598
|
+
}
|
|
599
|
+
blen = word_len;
|
|
600
|
+
sc->cps2[word_len] = (uint32_t)word_len;
|
|
601
|
+
} else {
|
|
602
|
+
size_t bytes_need = 0;
|
|
603
|
+
if (!se_checked_mul_size(word_len, 4, &bytes_need) ||
|
|
604
|
+
!se_checked_add_size(bytes_need, 4, &bytes_need))
|
|
605
|
+
return 0;
|
|
606
|
+
if (!grow_bytes(&sc->bytes, &sc->bytes_cap, bytes_need))
|
|
607
|
+
return 0;
|
|
608
|
+
if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
|
|
609
|
+
return 0;
|
|
610
|
+
|
|
611
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
612
|
+
if (blen > UINT32_MAX)
|
|
613
|
+
return 0;
|
|
614
|
+
sc->cps2[k] = (uint32_t)blen;
|
|
615
|
+
blen += se_utf8_encode(word[k], sc->bytes + blen);
|
|
307
616
|
}
|
|
617
|
+
if (blen > UINT32_MAX)
|
|
618
|
+
return 0;
|
|
619
|
+
sc->cps2[word_len] = (uint32_t)blen;
|
|
308
620
|
}
|
|
309
|
-
if (blen > UINT32_MAX)
|
|
310
|
-
return 0;
|
|
311
|
-
sc->cps2[word_len] = (uint32_t)blen;
|
|
312
621
|
|
|
313
622
|
if (word_len <= meta->max_token_chars) {
|
|
314
623
|
uint32_t exact_id = 0;
|
|
@@ -355,10 +664,59 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
|
|
|
355
664
|
return 1;
|
|
356
665
|
}
|
|
357
666
|
|
|
667
|
+
static uint32_t added_token_id(const se_model_t *model, uint32_t bit) {
|
|
668
|
+
switch (bit) {
|
|
669
|
+
case SE_ADDED_PAD:
|
|
670
|
+
return model->meta.pad_id;
|
|
671
|
+
case SE_ADDED_UNK:
|
|
672
|
+
return model->meta.unk_id;
|
|
673
|
+
case SE_ADDED_CLS:
|
|
674
|
+
return model->meta.cls_id;
|
|
675
|
+
case SE_ADDED_SEP:
|
|
676
|
+
return model->meta.sep_id;
|
|
677
|
+
case SE_ADDED_MASK:
|
|
678
|
+
return model->meta.mask_id;
|
|
679
|
+
default:
|
|
680
|
+
return SE_SLOT_EMPTY;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
static int match_added_token(const se_model_t *model, const uint8_t *input, size_t input_len,
|
|
685
|
+
size_t pos, uint32_t *id_out, size_t *len_out) {
|
|
686
|
+
if (model->meta.added_token_mask == 0 || pos >= input_len || input[pos] != '[')
|
|
687
|
+
return 0;
|
|
688
|
+
|
|
689
|
+
for (size_t k = 0; k < SE_ARRAY_LEN(SE_ADDED_TOKENS); k++) {
|
|
690
|
+
const se_added_token_spec_t *token = &SE_ADDED_TOKENS[k];
|
|
691
|
+
if ((model->meta.added_token_mask & token->bit) == 0)
|
|
692
|
+
continue;
|
|
693
|
+
if (token->len > input_len - pos)
|
|
694
|
+
continue;
|
|
695
|
+
if (memcmp(input + pos, token->text, token->len) != 0)
|
|
696
|
+
continue;
|
|
697
|
+
|
|
698
|
+
*id_out = added_token_id(model, token->bit);
|
|
699
|
+
*len_out = token->len;
|
|
700
|
+
return 1;
|
|
701
|
+
}
|
|
702
|
+
return 0;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
static se_status_t append_direct_id(token_state_t *st, uint32_t id, int *stop) {
|
|
706
|
+
if (!push_id(st->scratch, &st->n_ids, id))
|
|
707
|
+
return oom(st, "adding a special token");
|
|
708
|
+
if (id == st->model->meta.unk_id)
|
|
709
|
+
st->n_unk++;
|
|
710
|
+
if (cap_after_append(st))
|
|
711
|
+
*stop = 1;
|
|
712
|
+
return SE_OK;
|
|
713
|
+
}
|
|
714
|
+
|
|
358
715
|
static se_status_t append_wordpiece(token_state_t *st, const uint32_t *word, size_t word_len,
|
|
359
716
|
int *stop) {
|
|
360
717
|
wordpiece_status_t wp =
|
|
361
|
-
wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk
|
|
718
|
+
wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk,
|
|
719
|
+
word_len == 1 ? (word[0] < 0x80) : st->segment_ascii);
|
|
362
720
|
if (wp == WORDPIECE_OOM)
|
|
363
721
|
return oom(st, "tokenizing");
|
|
364
722
|
if (wp == WORDPIECE_INVALID) {
|
|
@@ -375,6 +733,7 @@ static se_status_t flush_segment(token_state_t *st, int *stop) {
|
|
|
375
733
|
return SE_OK;
|
|
376
734
|
se_status_t rc = append_wordpiece(st, st->scratch->cps, st->segment_len, stop);
|
|
377
735
|
st->segment_len = 0;
|
|
736
|
+
st->segment_ascii = 1;
|
|
378
737
|
return rc;
|
|
379
738
|
}
|
|
380
739
|
|
|
@@ -394,13 +753,30 @@ static se_status_t feed_token_cp(token_state_t *st, uint32_t cp, int *stop) {
|
|
|
394
753
|
return SE_OK;
|
|
395
754
|
}
|
|
396
755
|
|
|
756
|
+
static const se_map_entry_t *lower_entry(const se_model_t *m, uint32_t cp) {
|
|
757
|
+
if (cp < 256)
|
|
758
|
+
return m->norm.lower256[cp];
|
|
759
|
+
return se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
static const se_map_entry_t *nfd_entry(const se_model_t *m, uint32_t cp) {
|
|
763
|
+
if (cp < 256)
|
|
764
|
+
return m->norm.nfd256[cp];
|
|
765
|
+
return se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
static int is_mn(const se_model_t *m, uint32_t cp) {
|
|
769
|
+
if (cp < 256)
|
|
770
|
+
return m->norm.mn256[cp];
|
|
771
|
+
return se_range_contains(m->norm.mn, m->norm.mn_count, cp);
|
|
772
|
+
}
|
|
773
|
+
|
|
397
774
|
static se_status_t emit_lowered(token_state_t *st, uint32_t cp, int *stop) {
|
|
398
775
|
if (st->model->meta.do_lower_case) {
|
|
399
776
|
if (cp >= 'A' && cp <= 'Z')
|
|
400
777
|
cp += 32;
|
|
401
778
|
else if (cp >= 0x80) {
|
|
402
|
-
const se_map_entry_t *e =
|
|
403
|
-
se_map_lookup(st->model->norm.lower, st->model->norm.lower_count, cp);
|
|
779
|
+
const se_map_entry_t *e = lower_entry(st->model, cp);
|
|
404
780
|
if (e) {
|
|
405
781
|
for (uint32_t k = 0; k < e->len; k++) {
|
|
406
782
|
se_status_t rc = feed_token_cp(st, e->out[k], stop);
|
|
@@ -418,16 +794,16 @@ static se_status_t emit_stripped(token_state_t *st, uint32_t cp, int *stop) {
|
|
|
418
794
|
if (!st->model->meta.strip_accents || cp < 0x80)
|
|
419
795
|
return emit_lowered(st, cp, stop);
|
|
420
796
|
|
|
421
|
-
const se_map_entry_t *e =
|
|
797
|
+
const se_map_entry_t *e = nfd_entry(st->model, cp);
|
|
422
798
|
if (!e) {
|
|
423
|
-
if (
|
|
799
|
+
if (is_mn(st->model, cp))
|
|
424
800
|
return SE_OK;
|
|
425
801
|
return emit_lowered(st, cp, stop);
|
|
426
802
|
}
|
|
427
803
|
|
|
428
804
|
for (uint32_t k = 0; k < e->len; k++) {
|
|
429
805
|
uint32_t d = e->out[k];
|
|
430
|
-
if (
|
|
806
|
+
if (is_mn(st->model, d))
|
|
431
807
|
continue;
|
|
432
808
|
se_status_t rc = emit_lowered(st, d, stop);
|
|
433
809
|
if (rc != SE_OK || *stop)
|
|
@@ -486,6 +862,31 @@ static se_status_t tokenize_ascii_run(token_state_t *st, const uint8_t *input, s
|
|
|
486
862
|
if (b >= 0x80)
|
|
487
863
|
break;
|
|
488
864
|
|
|
865
|
+
if (b == '[' && st->model->meta.added_token_mask != 0) {
|
|
866
|
+
uint32_t added_id = 0;
|
|
867
|
+
size_t added_len = 0;
|
|
868
|
+
if (match_added_token(st->model, input, input_len, i, &added_id, &added_len)) {
|
|
869
|
+
se_status_t rc = flush_segment(st, stop);
|
|
870
|
+
if (rc != SE_OK) {
|
|
871
|
+
*ip = i;
|
|
872
|
+
return rc;
|
|
873
|
+
}
|
|
874
|
+
if (*stop) {
|
|
875
|
+
*ip = i;
|
|
876
|
+
return SE_OK;
|
|
877
|
+
}
|
|
878
|
+
rc = append_direct_id(st, added_id, stop);
|
|
879
|
+
if (rc != SE_OK) {
|
|
880
|
+
*ip = i;
|
|
881
|
+
return rc;
|
|
882
|
+
}
|
|
883
|
+
i += added_len;
|
|
884
|
+
if (*stop)
|
|
885
|
+
break;
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
489
890
|
if (i >= next_cancel_check) {
|
|
490
891
|
if (token_cancelled(st)) {
|
|
491
892
|
*ip = i;
|
|
@@ -545,8 +946,9 @@ static se_status_t tokenize_ascii_run(token_state_t *st, const uint8_t *input, s
|
|
|
545
946
|
}
|
|
546
947
|
|
|
547
948
|
se_status_t se_tokenize(const se_model_t *model, se_scratch_t *sc, const uint8_t *input,
|
|
548
|
-
size_t input_len, uint32_t max_tokens,
|
|
549
|
-
|
|
949
|
+
size_t input_len, uint32_t max_tokens, se_token_limit_t limit_mode,
|
|
950
|
+
se_token_stats_t *stats, se_error_t *err,
|
|
951
|
+
volatile sig_atomic_t *cancelled) {
|
|
550
952
|
memset(stats, 0, sizeof(*stats));
|
|
551
953
|
|
|
552
954
|
token_state_t st;
|
|
@@ -554,9 +956,11 @@ se_status_t se_tokenize(const se_model_t *model, se_scratch_t *sc, const uint8_t
|
|
|
554
956
|
st.model = model;
|
|
555
957
|
st.scratch = sc;
|
|
556
958
|
st.max_tokens = max_tokens;
|
|
959
|
+
st.limit_mode = limit_mode;
|
|
557
960
|
st.stats = stats;
|
|
558
961
|
st.err = err;
|
|
559
962
|
st.cancelled = cancelled;
|
|
963
|
+
st.segment_ascii = 1;
|
|
560
964
|
|
|
561
965
|
size_t i = 0;
|
|
562
966
|
size_t iterations = 0;
|
|
@@ -115,6 +115,6 @@ const se_map_entry_t *se_map_lookup(const se_map_entry_t *entries, uint32_t coun
|
|
|
115
115
|
int se_is_cjk(uint32_t cp) {
|
|
116
116
|
return (cp >= 0x4E00 && cp <= 0x9FFF) || (cp >= 0x3400 && cp <= 0x4DBF) ||
|
|
117
117
|
(cp >= 0x20000 && cp <= 0x2A6DF) || (cp >= 0x2A700 && cp <= 0x2B73F) ||
|
|
118
|
-
(cp >= 0x2B740 && cp <= 0x2B81F) || (cp >=
|
|
118
|
+
(cp >= 0x2B740 && cp <= 0x2B81F) || (cp >= 0x2B920 && cp <= 0x2CEAF) ||
|
|
119
119
|
(cp >= 0xF900 && cp <= 0xFAFF) || (cp >= 0x2F800 && cp <= 0x2FA1F);
|
|
120
120
|
}
|