blob: 9ad13d7b274dbd12c3c85f3e3b690feef2750fc7 [file] [log] [blame]
/* Writes the memory mappable form of a model next to the model file:
*
* <model>.vecs words * size floats, every word vector normalized to length 1
* <model>.words words * MMAP_MAX_W bytes, the word, NUL terminated and padded
*
* derekovecs memory maps these two files. When they are missing it builds them
* itself on its first start, which takes a while and needs write access to the
* directory the models live in - which a server does not necessarily have.
*
* The conversion deliberately mirrors init_net() of derekovecs, including the
* order of the floating point operations, so that both produce the same files.
*/
#ifndef MMAP_VECS_H
#define MMAP_VECS_H
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* has to match max_w in derekovecs */
#define MMAP_MAX_W 50
/* Reads the model written by SaveVectors() and writes its memory mappable
* form. Returns 0 on success. */
static int convert_vecs_to_mmap(const char *file_name) {
FILE *f, *binvecs, *binwords;
char binvecs_fname[4096], binwords_fname[4096];
long long words, size, a, b;
float len, *M;
char *vocab;
double val;
int is_text = (strstr(file_name, ".txt") != NULL);
snprintf(binvecs_fname, sizeof(binvecs_fname), "%s.vecs", file_name);
snprintf(binwords_fname, sizeof(binwords_fname), "%s.words", file_name);
if ((f = fopen(file_name, "rb")) == NULL) {
fprintf(stderr, "Cannot open %s for the memory mappable conversion\n", file_name);
return -1;
}
if (fscanf(f, "%lld", &words) != 1 || fscanf(f, "%lld", &size) != 1) {
fprintf(stderr, "Cannot read the header of %s\n", file_name);
fclose(f);
return -1;
}
vocab = (char *)calloc((size_t)words * MMAP_MAX_W, sizeof(char));
M = (float *)malloc((size_t)words * (size_t)size * sizeof(float));
if (vocab == NULL || M == NULL) {
fprintf(stderr, "Cannot allocate %lld MB for the memory mappable conversion\n",
(long long)((size_t)words * size * sizeof(float) / 1048576));
free(vocab);
free(M);
fclose(f);
return -1;
}
for (b = 0; b < words; b++) {
a = 0;
while (1) {
vocab[b * MMAP_MAX_W + a] = fgetc(f);
if (feof(f) || (vocab[b * MMAP_MAX_W + a] == ' ')) break;
if ((a < MMAP_MAX_W - 1) && (vocab[b * MMAP_MAX_W + a] != '\n')) a++;
}
vocab[b * MMAP_MAX_W + a] = 0;
len = 0;
if (is_text) {
for (a = 0; a < size; a++) {
if (fscanf(f, "%lf", &val) != 1) val = 0;
M[a + b * size] = val;
len += M[a + b * size] * M[a + b * size];
}
} else {
if (fread(&M[b * size], sizeof(float), size, f) != (size_t)size) {
fprintf(stderr, "Unexpected end of %s at word %lld\n", file_name, b);
free(vocab);
free(M);
fclose(f);
return -1;
}
for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
}
len = sqrt(len);
if (len > 0)
for (a = 0; a < size; a++) M[a + b * size] /= len;
}
fclose(f);
if ((binvecs = fopen(binvecs_fname, "wb")) == NULL ||
(binwords = fopen(binwords_fname, "wb")) == NULL) {
fprintf(stderr, "Cannot write %s or %s\n", binvecs_fname, binwords_fname);
free(vocab);
free(M);
return -1;
}
fwrite(M, sizeof(float), (size_t)words * (size_t)size, binvecs);
fclose(binvecs);
fwrite(vocab, sizeof(char), (size_t)words * MMAP_MAX_W, binwords);
fclose(binwords);
free(vocab);
free(M);
return 0;
}
#endif /* MMAP_VECS_H */