blob: 9ad13d7b274dbd12c3c85f3e3b690feef2750fc7 [file] [log] [blame]
Marc Kupietz50de14a2026-07-31 14:48:02 +09001/* Writes the memory mappable form of a model next to the model file:
2 *
3 * <model>.vecs words * size floats, every word vector normalized to length 1
4 * <model>.words words * MMAP_MAX_W bytes, the word, NUL terminated and padded
5 *
6 * derekovecs memory maps these two files. When they are missing it builds them
7 * itself on its first start, which takes a while and needs write access to the
8 * directory the models live in - which a server does not necessarily have.
9 *
10 * The conversion deliberately mirrors init_net() of derekovecs, including the
11 * order of the floating point operations, so that both produce the same files.
12 */
13
14#ifndef MMAP_VECS_H
15#define MMAP_VECS_H
16
17#include <math.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/* has to match max_w in derekovecs */
23#define MMAP_MAX_W 50
24
25/* Reads the model written by SaveVectors() and writes its memory mappable
26 * form. Returns 0 on success. */
27static int convert_vecs_to_mmap(const char *file_name) {
28 FILE *f, *binvecs, *binwords;
29 char binvecs_fname[4096], binwords_fname[4096];
30 long long words, size, a, b;
31 float len, *M;
32 char *vocab;
33 double val;
34 int is_text = (strstr(file_name, ".txt") != NULL);
35
36 snprintf(binvecs_fname, sizeof(binvecs_fname), "%s.vecs", file_name);
37 snprintf(binwords_fname, sizeof(binwords_fname), "%s.words", file_name);
38
39 if ((f = fopen(file_name, "rb")) == NULL) {
40 fprintf(stderr, "Cannot open %s for the memory mappable conversion\n", file_name);
41 return -1;
42 }
43 if (fscanf(f, "%lld", &words) != 1 || fscanf(f, "%lld", &size) != 1) {
44 fprintf(stderr, "Cannot read the header of %s\n", file_name);
45 fclose(f);
46 return -1;
47 }
48
49 vocab = (char *)calloc((size_t)words * MMAP_MAX_W, sizeof(char));
50 M = (float *)malloc((size_t)words * (size_t)size * sizeof(float));
51 if (vocab == NULL || M == NULL) {
52 fprintf(stderr, "Cannot allocate %lld MB for the memory mappable conversion\n",
53 (long long)((size_t)words * size * sizeof(float) / 1048576));
54 free(vocab);
55 free(M);
56 fclose(f);
57 return -1;
58 }
59
60 for (b = 0; b < words; b++) {
61 a = 0;
62 while (1) {
63 vocab[b * MMAP_MAX_W + a] = fgetc(f);
64 if (feof(f) || (vocab[b * MMAP_MAX_W + a] == ' ')) break;
65 if ((a < MMAP_MAX_W - 1) && (vocab[b * MMAP_MAX_W + a] != '\n')) a++;
66 }
67 vocab[b * MMAP_MAX_W + a] = 0;
68 len = 0;
69 if (is_text) {
70 for (a = 0; a < size; a++) {
71 if (fscanf(f, "%lf", &val) != 1) val = 0;
72 M[a + b * size] = val;
73 len += M[a + b * size] * M[a + b * size];
74 }
75 } else {
76 if (fread(&M[b * size], sizeof(float), size, f) != (size_t)size) {
77 fprintf(stderr, "Unexpected end of %s at word %lld\n", file_name, b);
78 free(vocab);
79 free(M);
80 fclose(f);
81 return -1;
82 }
83 for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
84 }
85 len = sqrt(len);
86 if (len > 0)
87 for (a = 0; a < size; a++) M[a + b * size] /= len;
88 }
89 fclose(f);
90
91 if ((binvecs = fopen(binvecs_fname, "wb")) == NULL ||
92 (binwords = fopen(binwords_fname, "wb")) == NULL) {
93 fprintf(stderr, "Cannot write %s or %s\n", binvecs_fname, binwords_fname);
94 free(vocab);
95 free(M);
96 return -1;
97 }
98 fwrite(M, sizeof(float), (size_t)words * (size_t)size, binvecs);
99 fclose(binvecs);
100 fwrite(vocab, sizeof(char), (size_t)words * MMAP_MAX_W, binwords);
101 fclose(binwords);
102
103 free(vocab);
104 free(M);
105 return 0;
106}
107
108#endif /* MMAP_VECS_H */