blob: 7c8bb5ff8c00270360b465c5f7c599d54f5afc6b [file] [log] [blame]
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001// Copyright 2013 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Marc Kupietze23c5402016-07-14 11:10:09 +020015#include <locale.h>
Marc Kupietzd6f9c712016-03-16 11:50:56 +010016#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
Marc Kupietz202723e2016-07-14 09:12:00 +020019#include <unistd.h>
Marc Kupietzd6f9c712016-03-16 11:50:56 +010020#include <math.h>
21#include <pthread.h>
Marc Kupietz613edbf2018-01-11 21:38:03 +010022#include <collocatordb.h>
Marc Kupietzd6f9c712016-03-16 11:50:56 +010023
Marc Kupietz50de14a2026-07-31 14:48:02 +090024#include "mmap_vecs.h"
25
Marc Kupietzd6f9c712016-03-16 11:50:56 +010026#define MAX_STRING 100
27#define EXP_TABLE_SIZE 1000
28#define MAX_EXP 6
29#define MAX_SENTENCE_LENGTH 1000
Marc Kupietz71996e72016-03-18 13:40:24 +010030#define MAX_CC 100
Marc Kupietzd6f9c712016-03-16 11:50:56 +010031#define MAX_CODE_LENGTH 40
32
33const int vocab_hash_size = 30000000; // Maximum 30 * 0.7 = 21M words in the vocabulary
34
35typedef float real; // Precision of float numbers
36
37struct vocab_word {
38 long long cn;
39 int *point;
40 char *word, *code, codelen;
41};
42
43char train_file[MAX_STRING], output_file[MAX_STRING];
44char save_vocab_file[MAX_STRING], read_vocab_file[MAX_STRING];
45char save_net_file[MAX_STRING], read_net_file[MAX_STRING];
Marc Kupietze423f732017-12-22 17:57:03 +010046char magic_stop_file[MAX_STRING];
47
Marc Kupietzd6f9c712016-03-16 11:50:56 +010048struct vocab_word *vocab;
49int binary = 0, type = 1, debug_mode = 2, window = 5, min_count = 5,
Marc Kupietzc2731b22016-07-14 08:56:14 +020050 num_threads = 12, min_reduce = 1;
Marc Kupietzd6f9c712016-03-16 11:50:56 +010051int *vocab_hash;
Marc Kupietzc2731b22016-07-14 08:56:14 +020052long long *threadPos;
53int *threadIters;
Marc Kupietzd6f9c712016-03-16 11:50:56 +010054long long vocab_max_size = 1000, vocab_size = 0, layer1_size = 100;
55long long train_words = 0, word_count_actual = 0, iter = 5, file_size = 0,
56 classes = 0;
57real alpha = 0.025, starting_alpha, sample = 1e-3;
58real *syn0, *syn1, *syn1neg, *syn1nce, *expTable;
Marc Kupietzc2731b22016-07-14 08:56:14 +020059real avgWordLength=0;
Marc Kupietzb366bcd2018-01-11 21:29:41 +010060clock_t start, start_clock;
Marc Kupietzd6f9c712016-03-16 11:50:56 +010061
62real *syn1_window, *syn1neg_window, *syn1nce_window;
63int w_offset, window_layer_size;
64
65int window_hidden_size = 500;
66real *syn_window_hidden, *syn_hidden_word, *syn_hidden_word_neg,
67 *syn_hidden_word_nce;
68
69int hs = 0, negative = 5;
70const int table_size = 1e8;
71int *table;
72
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +010073long cc = 0;
74
Marc Kupietzd6f9c712016-03-16 11:50:56 +010075//constrastive negative sampling
76char negative_classes_file[MAX_STRING];
77int *word_to_group;
78int *group_to_table; //group_size*table_size
79int class_number;
80
81//nce
82real* noise_distribution;
83int nce = 0;
84
85//param caps
86real CAP_VALUE = 50;
87int cap = 0;
88
Marc Kupietz613edbf2018-01-11 21:38:03 +010089COLLOCATORDB *cdb = NULL;
90
Marc Kupietzd6f9c712016-03-16 11:50:56 +010091void capParam(real* array, int index) {
92 if (array[index] > CAP_VALUE)
93 array[index] = CAP_VALUE;
94 else if (array[index] < -CAP_VALUE)
95 array[index] = -CAP_VALUE;
96}
97
98real hardTanh(real x) {
99 if (x >= 1) {
100 return 1;
101 } else if (x <= -1) {
102 return -1;
103 } else {
104 return x;
105 }
106}
107
108real dHardTanh(real x, real g) {
109 if (x > 1 && g > 0) {
110 return 0;
111 }
112 if (x < -1 && g < 0) {
113 return 0;
114 }
115 return 1;
116}
117
118void InitUnigramTable() {
119 int a, i;
120 long long train_words_pow = 0;
121 real d1, power = 0.75;
122 table = (int *) malloc(table_size * sizeof(int));
123 for (a = 0; a < vocab_size; a++)
124 train_words_pow += pow(vocab[a].cn, power);
125 i = 0;
126 d1 = pow(vocab[i].cn, power) / (real) train_words_pow;
127 for (a = 0; a < table_size; a++) {
128 table[a] = i;
129 if (a / (real) table_size > d1) {
130 i++;
131 d1 += pow(vocab[i].cn, power) / (real) train_words_pow;
132 }
133 if (i >= vocab_size)
134 i = vocab_size - 1;
135 }
136
137 noise_distribution = (real *) calloc(vocab_size, sizeof(real));
138 for (a = 0; a < vocab_size; a++)
139 noise_distribution[a] = pow(vocab[a].cn, power)
140 / (real) train_words_pow;
141}
142
143// Reads a single word from a file, assuming space + tab + EOL to be word boundaries
144void ReadWord(char *word, FILE *fin) {
145 int a = 0, ch;
146 while (!feof(fin)) {
147 ch = fgetc(fin);
148 if (ch == 13)
149 continue;
150 if ((ch == ' ') || (ch == '\t') || (ch == '\n')) {
151 if (a > 0) {
152 if (ch == '\n')
153 ungetc(ch, fin);
154 break;
155 }
156 if (ch == '\n') {
157 strcpy(word, (char *) "</s>");
158 return;
159 } else
160 continue;
161 }
162 word[a] = ch;
163 a++;
164 if (a >= MAX_STRING - 1)
165 a--; // Truncate too long words
166 }
167 word[a] = 0;
168}
169
170// Returns hash value of a word
171int GetWordHash(char *word) {
172 unsigned long long a, hash = 0;
173 for (a = 0; a < strlen(word); a++)
174 hash = hash * 257 + word[a];
175 hash = hash % vocab_hash_size;
176 return hash;
177}
178
179// Returns position of a word in the vocabulary; if the word is not found, returns -1
180int SearchVocab(char *word) {
181 unsigned int hash = GetWordHash(word);
182 while (1) {
183 if (vocab_hash[hash] == -1)
184 return -1;
185 if (!strcmp(word, vocab[vocab_hash[hash]].word))
186 return vocab_hash[hash];
187 hash = (hash + 1) % vocab_hash_size;
188 }
189 return -1;
190}
191
192// Reads a word and returns its index in the vocabulary
193int ReadWordIndex(FILE *fin) {
194 char word[MAX_STRING];
195 ReadWord(word, fin);
196 if (feof(fin))
197 return -1;
198 return SearchVocab(word);
199}
200
201// Adds a word to the vocabulary
202int AddWordToVocab(char *word) {
203 unsigned int hash, length = strlen(word) + 1;
204 if (length > MAX_STRING)
205 length = MAX_STRING;
206 vocab[vocab_size].word = (char *) calloc(length, sizeof(char));
207 strcpy(vocab[vocab_size].word, word);
208 vocab[vocab_size].cn = 0;
209 vocab_size++;
210 // Reallocate memory if needed
211 if (vocab_size + 2 >= vocab_max_size) {
212 vocab_max_size += 1000;
213 vocab = (struct vocab_word *) realloc(vocab,
214 vocab_max_size * sizeof(struct vocab_word));
215 }
216 hash = GetWordHash(word);
217 while (vocab_hash[hash] != -1)
218 hash = (hash + 1) % vocab_hash_size;
219 vocab_hash[hash] = vocab_size - 1;
220 return vocab_size - 1;
221}
222
223// Used later for sorting by word counts
224int VocabCompare(const void *a, const void *b) {
„feldmueller“7f1fc332024-10-21 18:05:57 +0200225 long long freq1 = ((struct vocab_word *) a)->cn;
226 long long freq2 = ((struct vocab_word *) b)->cn;
227 if (freq1 < freq2) return 1;
228 else if (freq1 > freq2) return -1;
229 else return 0;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100230}
231
232// Sorts the vocabulary by frequency using word counts
233void SortVocab() {
234 int a, size;
235 unsigned int hash;
236 // Sort the vocabulary and keep </s> at the first position
237 qsort(&vocab[1], vocab_size - 1, sizeof(struct vocab_word), VocabCompare);
238 for (a = 0; a < vocab_hash_size; a++)
239 vocab_hash[a] = -1;
240 size = vocab_size;
241 train_words = 0;
242 for (a = 0; a < size; a++) {
Marc Kupietzc2731b22016-07-14 08:56:14 +0200243 avgWordLength += vocab[a].cn * (strlen(vocab[a].word) + 1);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100244 // Words occuring less than min_count times will be discarded from the vocab
245 if ((vocab[a].cn < min_count) && (a != 0)) {
246 vocab_size--;
247 free(vocab[a].word);
248 } else {
249 // Hash will be re-computed, as after the sorting it is not actual
250 hash = GetWordHash(vocab[a].word);
251 while (vocab_hash[hash] != -1)
252 hash = (hash + 1) % vocab_hash_size;
253 vocab_hash[hash] = a;
254 train_words += vocab[a].cn;
255 }
256 }
Marc Kupietzc2731b22016-07-14 08:56:14 +0200257 avgWordLength /= train_words;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100258 vocab = (struct vocab_word *) realloc(vocab,
259 (vocab_size + 1) * sizeof(struct vocab_word));
260 // Allocate memory for the binary tree construction
261 for (a = 0; a < vocab_size; a++) {
262 vocab[a].code = (char *) calloc(MAX_CODE_LENGTH, sizeof(char));
263 vocab[a].point = (int *) calloc(MAX_CODE_LENGTH, sizeof(int));
264 }
265}
266
267// Reduces the vocabulary by removing infrequent tokens
268void ReduceVocab() {
269 int a, b = 0;
270 unsigned int hash;
271 for (a = 0; a < vocab_size; a++)
272 if (vocab[a].cn > min_reduce) {
273 vocab[b].cn = vocab[a].cn;
274 vocab[b].word = vocab[a].word;
275 b++;
276 } else
277 free(vocab[a].word);
278 vocab_size = b;
279 for (a = 0; a < vocab_hash_size; a++)
280 vocab_hash[a] = -1;
281 for (a = 0; a < vocab_size; a++) {
282 // Hash will be re-computed, as it is not actual
283 hash = GetWordHash(vocab[a].word);
284 while (vocab_hash[hash] != -1)
285 hash = (hash + 1) % vocab_hash_size;
286 vocab_hash[hash] = a;
287 }
288 fflush(stdout);
289 min_reduce++;
290}
291
292// Create binary Huffman tree using the word counts
293// Frequent words will have short uniqe binary codes
294void CreateBinaryTree() {
295 long long a, b, i, min1i, min2i, pos1, pos2, point[MAX_CODE_LENGTH];
296 char code[MAX_CODE_LENGTH];
297 long long *count = (long long *) calloc(vocab_size * 2 + 1,
298 sizeof(long long));
299 long long *binary = (long long *) calloc(vocab_size * 2 + 1,
300 sizeof(long long));
301 long long *parent_node = (long long *) calloc(vocab_size * 2 + 1,
302 sizeof(long long));
303 for (a = 0; a < vocab_size; a++)
304 count[a] = vocab[a].cn;
305 for (a = vocab_size; a < vocab_size * 2; a++)
306 count[a] = 1e15;
307 pos1 = vocab_size - 1;
308 pos2 = vocab_size;
309 // Following algorithm constructs the Huffman tree by adding one node at a time
310 for (a = 0; a < vocab_size - 1; a++) {
311 // First, find two smallest nodes 'min1, min2'
312 if (pos1 >= 0) {
313 if (count[pos1] < count[pos2]) {
314 min1i = pos1;
315 pos1--;
316 } else {
317 min1i = pos2;
318 pos2++;
319 }
320 } else {
321 min1i = pos2;
322 pos2++;
323 }
324 if (pos1 >= 0) {
325 if (count[pos1] < count[pos2]) {
326 min2i = pos1;
327 pos1--;
328 } else {
329 min2i = pos2;
330 pos2++;
331 }
332 } else {
333 min2i = pos2;
334 pos2++;
335 }
336 count[vocab_size + a] = count[min1i] + count[min2i];
337 parent_node[min1i] = vocab_size + a;
338 parent_node[min2i] = vocab_size + a;
339 binary[min2i] = 1;
340 }
341 // Now assign binary code to each vocabulary word
342 for (a = 0; a < vocab_size; a++) {
343 b = a;
344 i = 0;
345 while (1) {
346 code[i] = binary[b];
347 point[i] = b;
348 i++;
349 b = parent_node[b];
350 if (b == vocab_size * 2 - 2)
351 break;
352 }
353 vocab[a].codelen = i;
354 vocab[a].point[0] = vocab_size - 2;
355 for (b = 0; b < i; b++) {
356 vocab[a].code[i - b - 1] = code[b];
357 vocab[a].point[i - b] = point[b] - vocab_size;
358 }
359 }
360 free(count);
361 free(binary);
362 free(parent_node);
363}
364
365void LearnVocabFromTrainFile() {
366 char word[MAX_STRING];
367 FILE *fin;
368 long long a, i;
369 for (a = 0; a < vocab_hash_size; a++)
370 vocab_hash[a] = -1;
371 fin = fopen(train_file, "rb");
372 if (fin == NULL) {
373 printf("ERROR: training data file not found!\n");
374 exit(1);
375 }
376 vocab_size = 0;
377 AddWordToVocab((char *) "</s>");
378 while (1) {
379 ReadWord(word, fin);
380 if (feof(fin))
381 break;
382 train_words++;
383 if ((debug_mode > 1) && (train_words % 100000 == 0)) {
384 printf("%lldK%c", train_words / 1000, 13);
385 fflush(stdout);
386 }
387 i = SearchVocab(word);
388 if (i == -1) {
389 a = AddWordToVocab(word);
390 vocab[a].cn = 1;
391 } else
392 vocab[i].cn++;
393 if (vocab_size > vocab_hash_size * 0.7)
394 ReduceVocab();
395 }
396 SortVocab();
397 if (debug_mode > 0) {
Marc Kupietze23c5402016-07-14 11:10:09 +0200398 printf("Vocab size: %'lld\n", vocab_size);
399 printf("Words in train file: %'lld\n", train_words);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100400 }
401 file_size = ftell(fin);
402 fclose(fin);
403}
404
405void SaveVocab() {
406 long long i;
407 FILE *fo = fopen(save_vocab_file, "wb");
408 for (i = 0; i < vocab_size; i++)
409 fprintf(fo, "%s %lld\n", vocab[i].word, vocab[i].cn);
410 fclose(fo);
411}
412
413void ReadVocab() {
414 long long a, i = 0;
415 char c;
416 char word[MAX_STRING];
417 FILE *fin = fopen(read_vocab_file, "rb");
418 if (fin == NULL) {
419 printf("Vocabulary file not found\n");
420 exit(1);
421 }
422 for (a = 0; a < vocab_hash_size; a++)
423 vocab_hash[a] = -1;
424 vocab_size = 0;
425 while (1) {
426 ReadWord(word, fin);
427 if (feof(fin))
428 break;
429 a = AddWordToVocab(word);
430 fscanf(fin, "%lld%c", &vocab[a].cn, &c);
431 i++;
432 }
Marc Kupietzc2731b22016-07-14 08:56:14 +0200433 fclose(fin);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100434 fin = fopen(train_file, "rb");
435 if (fin == NULL) {
436 printf("ERROR: training data file not found!\n");
437 exit(1);
438 }
439 fseek(fin, 0, SEEK_END);
440 file_size = ftell(fin);
441 fclose(fin);
Marc Kupietzc2731b22016-07-14 08:56:14 +0200442 SortVocab();
443 if (debug_mode > 0) {
Marc Kupietze23c5402016-07-14 11:10:09 +0200444 printf("Vocab size: %'lld\n", vocab_size);
445 printf("Words in vocab's train file: %'lld\n", train_words);
446 printf("Avg. word length in vocab's train file: %.2f\n", avgWordLength);
Marc Kupietzc2731b22016-07-14 08:56:14 +0200447 }
Marc Kupietze23c5402016-07-14 11:10:09 +0200448 train_words = file_size / avgWordLength;
449 if(debug_mode > 0)
450 printf("Estimated words in train file: %'lld\n", train_words);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100451}
452
453void InitClassUnigramTable() {
454 long long a, c;
455 printf("loading class unigrams \n");
456 FILE *fin = fopen(negative_classes_file, "rb");
457 if (fin == NULL) {
458 printf("ERROR: class file not found!\n");
459 exit(1);
460 }
461 word_to_group = (int *) malloc(vocab_size * sizeof(int));
462 for (a = 0; a < vocab_size; a++)
463 word_to_group[a] = -1;
464 char class[MAX_STRING];
465 char prev_class[MAX_STRING];
466 prev_class[0] = 0;
467 char word[MAX_STRING];
468 class_number = -1;
469 while (1) {
470 if (feof(fin))
471 break;
472 ReadWord(class, fin);
473 ReadWord(word, fin);
474 int word_index = SearchVocab(word);
475 if (word_index != -1) {
476 if (strcmp(class, prev_class) != 0) {
477 class_number++;
478 strcpy(prev_class, class);
479 }
480 word_to_group[word_index] = class_number;
481 }
482 ReadWord(word, fin);
483 }
484 class_number++;
485 fclose(fin);
486
487 group_to_table = (int *) malloc(table_size * class_number * sizeof(int));
488 long long train_words_pow = 0;
489 real d1, power = 0.75;
490
491 for (c = 0; c < class_number; c++) {
492 long long offset = c * table_size;
493 train_words_pow = 0;
494 for (a = 0; a < vocab_size; a++)
495 if (word_to_group[a] == c)
496 train_words_pow += pow(vocab[a].cn, power);
497 int i = 0;
498 while (word_to_group[i] != c && i < vocab_size)
499 i++;
500 d1 = pow(vocab[i].cn, power) / (real) train_words_pow;
501 for (a = 0; a < table_size; a++) {
502 //printf("index %lld , word %d\n", a, i);
503 group_to_table[offset + a] = i;
504 if (a / (real) table_size > d1) {
505 i++;
506 while (word_to_group[i] != c && i < vocab_size)
507 i++;
508 d1 += pow(vocab[i].cn, power) / (real) train_words_pow;
509 }
510 if (i >= vocab_size)
511 while (word_to_group[i] != c && i >= 0)
512 i--;
513 }
514 }
515}
516
Marc Kupietz61485ad2023-12-22 16:16:59 +0100517void SaveArgs(unsigned int argc, char **argv) {
Marc Kupietz210b9d52016-04-02 21:48:13 +0200518 unsigned int i;
Marc Kupietz44136742017-12-22 17:52:56 +0100519 char args_file[MAX_STRING];
520 strcpy(args_file, output_file);
Marc Kupietz210b9d52016-04-02 21:48:13 +0200521 strcat(args_file, ".args");
522 FILE *fargs = fopen(args_file, "w");
523 if (fargs == NULL) {
524 printf("Cannot save args to %s.\n", args_file);
525 return;
526 }
527
Marc Kupietz44136742017-12-22 17:52:56 +0100528 for(i=1; i<argc; i++)
529 fprintf(fargs, "%s ", argv[i]);
530
531 fprintf(fargs, "\n");
Marc Kupietz210b9d52016-04-02 21:48:13 +0200532 fclose(fargs);
Marc Kupietz44136742017-12-22 17:52:56 +0100533
Marc Kupietz210b9d52016-04-02 21:48:13 +0200534 return;
535}
536
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100537void SaveNet() {
Marc Kupietz313fcc52016-03-16 16:43:37 +0100538 if(type != 3 || negative <= 0) {
539 fprintf(stderr, "save-net only supported for type 3 with negative sampling\n");
540 return;
541 }
542
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100543 FILE *fnet = fopen(save_net_file, "wb");
544 if (fnet == NULL) {
545 printf("Net parameter file not found\n");
546 exit(1);
547 }
Marc Kupietzc6979332016-03-16 15:29:07 +0100548 fwrite(syn0, sizeof(real), vocab_size * layer1_size, fnet);
Marc Kupietz313fcc52016-03-16 16:43:37 +0100549 fwrite(syn1neg_window, sizeof(real), vocab_size * window_layer_size, fnet);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100550 fclose(fnet);
551}
552
553void InitNet() {
554 long long a, b;
555 unsigned long long next_random = 1;
Marc Kupietz57c0df12016-03-18 12:48:00 +0100556 long long read;
557
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100558 window_layer_size = layer1_size * window * 2;
559 a = posix_memalign((void **) &syn0, 128,
560 (long long) vocab_size * layer1_size * sizeof(real));
561 if (syn0 == NULL) {
562 printf("Memory allocation failed\n");
563 exit(1);
564 }
565
566 if (hs) {
567 a = posix_memalign((void **) &syn1, 128,
568 (long long) vocab_size * layer1_size * sizeof(real));
569 if (syn1 == NULL) {
570 printf("Memory allocation failed\n");
571 exit(1);
572 }
573 a = posix_memalign((void **) &syn1_window, 128,
574 (long long) vocab_size * window_layer_size * sizeof(real));
575 if (syn1_window == NULL) {
576 printf("Memory allocation failed\n");
577 exit(1);
578 }
579 a = posix_memalign((void **) &syn_hidden_word, 128,
580 (long long) vocab_size * window_hidden_size * sizeof(real));
581 if (syn_hidden_word == NULL) {
582 printf("Memory allocation failed\n");
583 exit(1);
584 }
585
586 for (a = 0; a < vocab_size; a++)
587 for (b = 0; b < layer1_size; b++)
588 syn1[a * layer1_size + b] = 0;
589 for (a = 0; a < vocab_size; a++)
590 for (b = 0; b < window_layer_size; b++)
591 syn1_window[a * window_layer_size + b] = 0;
592 for (a = 0; a < vocab_size; a++)
593 for (b = 0; b < window_hidden_size; b++)
594 syn_hidden_word[a * window_hidden_size + b] = 0;
595 }
596 if (negative > 0) {
Marc Kupietz1006a272016-03-16 15:50:20 +0100597 if(type == 0) {
598 a = posix_memalign((void **) &syn1neg, 128,
599 (long long) vocab_size * layer1_size * sizeof(real));
600 if (syn1neg == NULL) {
601 printf("Memory allocation failed\n");
602 exit(1);
603 }
604 for (a = 0; a < vocab_size; a++)
605 for (b = 0; b < layer1_size; b++)
606 syn1neg[a * layer1_size + b] = 0;
607 } else if (type == 3) {
608 a = posix_memalign((void **) &syn1neg_window, 128,
609 (long long) vocab_size * window_layer_size * sizeof(real));
610 if (syn1neg_window == NULL) {
611 printf("Memory allocation failed\n");
612 exit(1);
613 }
614 for (a = 0; a < vocab_size; a++)
615 for (b = 0; b < window_layer_size; b++)
616 syn1neg_window[a * window_layer_size + b] = 0;
617 } else if (type == 4) {
618 a = posix_memalign((void **) &syn_hidden_word_neg, 128,
619 (long long) vocab_size * window_hidden_size * sizeof(real));
620 if (syn_hidden_word_neg == NULL) {
621 printf("Memory allocation failed\n");
622 exit(1);
623 }
624 for (a = 0; a < vocab_size; a++)
625 for (b = 0; b < window_hidden_size; b++)
626 syn_hidden_word_neg[a * window_hidden_size + b] = 0;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100627 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100628 }
629 if (nce > 0) {
630 a = posix_memalign((void **) &syn1nce, 128,
631 (long long) vocab_size * layer1_size * sizeof(real));
632 if (syn1nce == NULL) {
633 printf("Memory allocation failed\n");
634 exit(1);
635 }
636 a = posix_memalign((void **) &syn1nce_window, 128,
637 (long long) vocab_size * window_layer_size * sizeof(real));
638 if (syn1nce_window == NULL) {
639 printf("Memory allocation failed\n");
640 exit(1);
641 }
642 a = posix_memalign((void **) &syn_hidden_word_nce, 128,
643 (long long) vocab_size * window_hidden_size * sizeof(real));
644 if (syn_hidden_word_nce == NULL) {
645 printf("Memory allocation failed\n");
646 exit(1);
647 }
648
649 for (a = 0; a < vocab_size; a++)
650 for (b = 0; b < layer1_size; b++)
651 syn1nce[a * layer1_size + b] = 0;
652 for (a = 0; a < vocab_size; a++)
653 for (b = 0; b < window_layer_size; b++)
654 syn1nce_window[a * window_layer_size + b] = 0;
655 for (a = 0; a < vocab_size; a++)
656 for (b = 0; b < window_hidden_size; b++)
657 syn_hidden_word_nce[a * window_hidden_size + b] = 0;
658 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100659
Marc Kupietz1006a272016-03-16 15:50:20 +0100660 if(type == 4) {
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100661 a = posix_memalign((void **) &syn_window_hidden, 128,
662 window_hidden_size * window_layer_size * sizeof(real));
663 if (syn_window_hidden == NULL) {
664 printf("Memory allocation failed\n");
665 exit(1);
666 }
667 for (a = 0; a < window_hidden_size * window_layer_size; a++) {
668 next_random = next_random * (unsigned long long) 25214903917 + 11;
669 syn_window_hidden[a] = (((next_random & 0xFFFF) / (real) 65536)
670 - 0.5) / (window_hidden_size * window_layer_size);
671 }
672 }
Marc Kupietz1006a272016-03-16 15:50:20 +0100673
674 if (read_net_file[0] == 0) {
675 for (a = 0; a < vocab_size; a++)
676 for (b = 0; b < layer1_size; b++) {
677 next_random = next_random * (unsigned long long) 25214903917
678 + 11;
679 syn0[a * layer1_size + b] = (((next_random & 0xFFFF)
680 / (real) 65536) - 0.5) / layer1_size;
681 }
Marc Kupietz313fcc52016-03-16 16:43:37 +0100682 } else if(type == 3 && negative > 0) {
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100683 FILE *fnet = fopen(read_net_file, "rb");
684 if (fnet == NULL) {
685 printf("Net parameter file not found\n");
686 exit(1);
687 }
Marc Kupietz57c0df12016-03-18 12:48:00 +0100688 printf("vocab-size: %lld, layer1_size: %lld, window_layer_size %d\n", vocab_size, layer1_size, window_layer_size);
689 read = fread(syn0, sizeof(real), vocab_size * layer1_size, fnet);
690 if(read != vocab_size * layer1_size) {
691 fprintf(stderr, "read-net failed %lld\n", read);
692 exit(-1);
693 }
694 read = fread(syn1neg_window, sizeof(real), vocab_size * window_layer_size, fnet);
695 if(read != (long long) vocab_size * window_layer_size) {
696 fprintf(stderr, "read-net failed, read %lld, expected: %lld\n", read ,
697 (long long) sizeof(real) * vocab_size * window_layer_size);
698 exit(-1);
699 }
700 fgetc(fnet);
701 if(!feof(fnet)) {
702 fprintf(stderr, "Remaining bytes in net-file after read-net. File position: %ld\n", ftell(fnet));
703 exit(-1);
704 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100705 fclose(fnet);
Marc Kupietz313fcc52016-03-16 16:43:37 +0100706 } else {
707 fprintf(stderr, "read-net only supported for type 3 with negative sampling\n");
708 exit(-1);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100709 }
710
711 CreateBinaryTree();
712}
713
Marc Kupietz202723e2016-07-14 09:12:00 +0200714char *currentDateTime(char *buf, real offset) {
715 time_t t;
716 time(&t);
717 t += (long) offset;
718 struct tm tstruct;
719 tstruct = *localtime(&t);
720 strftime(buf, 80, "%c", &tstruct);
721 return buf;
722}
723
724void *MonitorThread(void *id) {
725 char *timebuf = malloc(80);;
726 int i, n=num_threads;
727 long long sum;
728 sleep(1);
729 while(n > 0) {
730 sleep(1);
731 sum = n = 0;
732 for(i=0; i < num_threads; i++) {
733 if(threadPos[i] >= 0) {
734 sum += (iter - threadIters[i]) * file_size / num_threads + threadPos[i] - (file_size / num_threads) * i;
735 n++;
736 } else {
737 sum += iter * file_size / num_threads;
738 }
739 }
740 if(n == 0)
741 break;
742 real finished_portion = (real) sum / (float) (file_size * iter);
Marc Kupietzb366bcd2018-01-11 21:29:41 +0100743 long long now = time(NULL);
744 long long elapsed = (now - start);
745 long long ttg = ((1.0 / finished_portion) * (real) elapsed - elapsed);
Marc Kupietz202723e2016-07-14 09:12:00 +0200746
Marc Kupietzb366bcd2018-01-11 21:29:41 +0100747 printf("\rAlpha: %.3f Done: %.2f%% with %.2fKB/s TE: %llds TTG: %llds ETA: %s\033[K",
Marc Kupietz202723e2016-07-14 09:12:00 +0200748 alpha,
749 finished_portion * 100,
Marc Kupietzb366bcd2018-01-11 21:29:41 +0100750 (float) sum / elapsed / 1000,
Marc Kupietz202723e2016-07-14 09:12:00 +0200751 elapsed,
752 ttg,
753 currentDateTime(timebuf, ttg)
754 );
755 fflush(stdout);
756 }
757 pthread_exit(NULL);
758}
759
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100760void *TrainModelThread(void *id) {
761 long long a, b, d, cw, word, last_word, sentence_length = 0,
762 sentence_position = 0;
763 long long word_count = 0, last_word_count = 0, sen[MAX_SENTENCE_LENGTH + 1];
764 long long l1, l2, c, target, label, local_iter = iter;
765 unsigned long long next_random = (long long) id;
766 real f, g;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100767 int input_len_1 = layer1_size;
768 int window_offset = -1;
769 if (type == 2 || type == 4) {
770 input_len_1 = window_layer_size;
771 }
772 real *neu1 = (real *) calloc(input_len_1, sizeof(real));
773 real *neu1e = (real *) calloc(input_len_1, sizeof(real));
Marc Kupietz202723e2016-07-14 09:12:00 +0200774 threadIters[(long) id] = iter;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100775
776 int input_len_2 = 0;
777 if (type == 4) {
778 input_len_2 = window_hidden_size;
779 }
780 real *neu2 = (real *) calloc(input_len_2, sizeof(real));
781 real *neu2e = (real *) calloc(input_len_2, sizeof(real));
782
783 FILE *fi = fopen(train_file, "rb");
Marc Kupietz202723e2016-07-14 09:12:00 +0200784 long long start_pos = file_size / (long long) num_threads * (long long) id;
785 long long end_pos = file_size / (long long) num_threads * (long long) (id + 1) -1;
786 long long current_pos = start_pos;
787 long long last_pos = start_pos;;
788 fseek(fi, start_pos, SEEK_SET);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100789 while (1) {
Marc Kupietz202723e2016-07-14 09:12:00 +0200790 if ((current_pos - last_pos > 100000)) {
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100791 word_count_actual += word_count - last_word_count;
Marc Kupietz202723e2016-07-14 09:12:00 +0200792 last_pos = current_pos;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100793 last_word_count = word_count;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100794 alpha = starting_alpha
795 * (1 - word_count_actual / (real) (iter * train_words + 1));
796 if (alpha < starting_alpha * 0.0001)
797 alpha = starting_alpha * 0.0001;
798 }
799 if (sentence_length == 0) {
800 while (1) {
801 word = ReadWordIndex(fi);
802 if (feof(fi))
803 break;
804 if (word == -1)
805 continue;
806 word_count++;
807 if (word == 0)
808 break;
809 // The subsampling randomly discards frequent words while keeping the ranking same
810 if (sample > 0) {
811 real ran = (sqrt(vocab[word].cn / (sample * train_words))
812 + 1) * (sample * train_words) / vocab[word].cn;
813 next_random = next_random * (unsigned long long) 25214903917
814 + 11;
Marc Kupietzab4e5af2016-03-22 14:24:03 +0100815 if (ran < (next_random & 0xFFFF) / (real) 65536) {
816 if(type == 3) // in structured skipgrams
817 word = -2; // keep the window position correct
818 else
819 continue;
820 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100821 }
822 sen[sentence_length] = word;
823 sentence_length++;
824 if (sentence_length >= MAX_SENTENCE_LENGTH)
825 break;
826 }
827 sentence_position = 0;
828 }
Marc Kupietz202723e2016-07-14 09:12:00 +0200829 current_pos = threadPos[(long) id] = ftell(fi);
830 if (feof(fi) || current_pos >= end_pos ) {
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100831 word_count_actual += word_count - last_word_count;
Marc Kupietz202723e2016-07-14 09:12:00 +0200832 threadIters[(long) id]--;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100833 local_iter--;
834 if (local_iter == 0)
835 break;
Marc Kupietze423f732017-12-22 17:57:03 +0100836 if (magic_stop_file[0] && access(magic_stop_file, F_OK ) != -1) {
837 printf("Magic stop file %s found. Stopping traing ...\n", magic_stop_file);
838 break;
839 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100840 word_count = 0;
Marc Kupietz202723e2016-07-14 09:12:00 +0200841 current_pos = last_pos = start_pos;
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100842 last_word_count = 0;
843 sentence_length = 0;
Marc Kupietz202723e2016-07-14 09:12:00 +0200844 fseek(fi, start_pos, SEEK_SET);
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100845 continue;
846 }
847 word = sen[sentence_position];
Peter Fankhauser66035a42016-04-20 13:29:33 +0200848 while (word == -2 && sentence_position<sentence_length)
849 word = sen[++sentence_position];
850 if (sentence_position>=sentence_length) {
851 sentence_length=0;
852 continue;
853 }
854 if (word < 0)
Marc Kupietzd6f9c712016-03-16 11:50:56 +0100855 continue;
856 for (c = 0; c < input_len_1; c++)
857 neu1[c] = 0;
858 for (c = 0; c < input_len_1; c++)
859 neu1e[c] = 0;
860 for (c = 0; c < input_len_2; c++)
861 neu2[c] = 0;
862 for (c = 0; c < input_len_2; c++)
863 neu2e[c] = 0;
864 next_random = next_random * (unsigned long long) 25214903917 + 11;
865 b = next_random % window;
866 if (type == 0) { //train the cbow architecture
867 // in -> hidden
868 cw = 0;
869 for (a = b; a < window * 2 + 1 - b; a++)
870 if (a != window) {
871 c = sentence_position - window + a;
872 if (c < 0)
873 continue;
874 if (c >= sentence_length)
875 continue;
876 last_word = sen[c];
877 if (last_word == -1)
878 continue;
879 for (c = 0; c < layer1_size; c++)
880 neu1[c] += syn0[c + last_word * layer1_size];
881 cw++;
882 }
883 if (cw) {
884 for (c = 0; c < layer1_size; c++)
885 neu1[c] /= cw;
886 if (hs)
887 for (d = 0; d < vocab[word].codelen; d++) {
888 f = 0;
889 l2 = vocab[word].point[d] * layer1_size;
890 // Propagate hidden -> output
891 for (c = 0; c < layer1_size; c++)
892 f += neu1[c] * syn1[c + l2];
893 if (f <= -MAX_EXP)
894 continue;
895 else if (f >= MAX_EXP)
896 continue;
897 else
898 f = expTable[(int) ((f + MAX_EXP)
899 * (EXP_TABLE_SIZE / MAX_EXP / 2))];
900 // 'g' is the gradient multiplied by the learning rate
901 g = (1 - vocab[word].code[d] - f) * alpha;
902 // Propagate errors output -> hidden
903 for (c = 0; c < layer1_size; c++)
904 neu1e[c] += g * syn1[c + l2];
905 // Learn weights hidden -> output
906 for (c = 0; c < layer1_size; c++)
907 syn1[c + l2] += g * neu1[c];
908 if (cap == 1)
909 for (c = 0; c < layer1_size; c++)
910 capParam(syn1, c + l2);
911 }
912 // NEGATIVE SAMPLING
913 if (negative > 0)
914 for (d = 0; d < negative + 1; d++) {
915 if (d == 0) {
916 target = word;
917 label = 1;
918 } else {
919 next_random = next_random
920 * (unsigned long long) 25214903917 + 11;
921 if (word_to_group != NULL
922 && word_to_group[word] != -1) {
923 target = word;
924 while (target == word) {
925 target = group_to_table[word_to_group[word]
926 * table_size
927 + (next_random >> 16) % table_size];
928 next_random = next_random
929 * (unsigned long long) 25214903917
930 + 11;
931 }
932 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
933 } else {
934 target =
935 table[(next_random >> 16) % table_size];
936 }
937 if (target == 0)
938 target = next_random % (vocab_size - 1) + 1;
939 if (target == word)
940 continue;
941 label = 0;
942 }
943 l2 = target * layer1_size;
944 f = 0;
945 for (c = 0; c < layer1_size; c++)
946 f += neu1[c] * syn1neg[c + l2];
947 if (f > MAX_EXP)
948 g = (label - 1) * alpha;
949 else if (f < -MAX_EXP)
950 g = (label - 0) * alpha;
951 else
952 g = (label
953 - expTable[(int) ((f + MAX_EXP)
954 * (EXP_TABLE_SIZE / MAX_EXP / 2))])
955 * alpha;
956 for (c = 0; c < layer1_size; c++)
957 neu1e[c] += g * syn1neg[c + l2];
958 for (c = 0; c < layer1_size; c++)
959 syn1neg[c + l2] += g * neu1[c];
960 if (cap == 1)
961 for (c = 0; c < layer1_size; c++)
962 capParam(syn1neg, c + l2);
963 }
964 // Noise Contrastive Estimation
965 if (nce > 0)
966 for (d = 0; d < nce + 1; d++) {
967 if (d == 0) {
968 target = word;
969 label = 1;
970 } else {
971 next_random = next_random
972 * (unsigned long long) 25214903917 + 11;
973 if (word_to_group != NULL
974 && word_to_group[word] != -1) {
975 target = word;
976 while (target == word) {
977 target = group_to_table[word_to_group[word]
978 * table_size
979 + (next_random >> 16) % table_size];
980 next_random = next_random
981 * (unsigned long long) 25214903917
982 + 11;
983 }
984 } else {
985 target =
986 table[(next_random >> 16) % table_size];
987 }
988 if (target == 0)
989 target = next_random % (vocab_size - 1) + 1;
990 if (target == word)
991 continue;
992 label = 0;
993 }
994 l2 = target * layer1_size;
995 f = 0;
996
997 for (c = 0; c < layer1_size; c++)
998 f += neu1[c] * syn1nce[c + l2];
999 if (f > MAX_EXP)
1000 g = (label - 1) * alpha;
1001 else if (f < -MAX_EXP)
1002 g = (label - 0) * alpha;
1003 else {
1004 f = exp(f);
1005 g =
1006 (label
1007 - f
1008 / (noise_distribution[target]
1009 * nce + f)) * alpha;
1010 }
1011 for (c = 0; c < layer1_size; c++)
1012 neu1e[c] += g * syn1nce[c + l2];
1013 for (c = 0; c < layer1_size; c++)
1014 syn1nce[c + l2] += g * neu1[c];
1015 if (cap == 1)
1016 for (c = 0; c < layer1_size; c++)
1017 capParam(syn1nce, c + l2);
1018 }
1019 // hidden -> in
1020 for (a = b; a < window * 2 + 1 - b; a++)
1021 if (a != window) {
1022 c = sentence_position - window + a;
1023 if (c < 0)
1024 continue;
1025 if (c >= sentence_length)
1026 continue;
1027 last_word = sen[c];
1028 if (last_word == -1)
1029 continue;
1030 for (c = 0; c < layer1_size; c++)
1031 syn0[c + last_word * layer1_size] += neu1e[c];
1032 }
1033 }
1034 } else if (type == 1) { //train skip-gram
1035 for (a = b; a < window * 2 + 1 - b; a++)
1036 if (a != window) {
1037 c = sentence_position - window + a;
1038 if (c < 0)
1039 continue;
1040 if (c >= sentence_length)
1041 continue;
1042 last_word = sen[c];
1043 if (last_word == -1)
1044 continue;
1045 l1 = last_word * layer1_size;
1046 for (c = 0; c < layer1_size; c++)
1047 neu1e[c] = 0;
1048 // HIERARCHICAL SOFTMAX
1049 if (hs)
1050 for (d = 0; d < vocab[word].codelen; d++) {
1051 f = 0;
1052 l2 = vocab[word].point[d] * layer1_size;
1053 // Propagate hidden -> output
1054 for (c = 0; c < layer1_size; c++)
1055 f += syn0[c + l1] * syn1[c + l2];
1056 if (f <= -MAX_EXP)
1057 continue;
1058 else if (f >= MAX_EXP)
1059 continue;
1060 else
1061 f = expTable[(int) ((f + MAX_EXP)
1062 * (EXP_TABLE_SIZE / MAX_EXP / 2))];
1063 // 'g' is the gradient multiplied by the learning rate
1064 g = (1 - vocab[word].code[d] - f) * alpha;
1065 // Propagate errors output -> hidden
1066 for (c = 0; c < layer1_size; c++)
1067 neu1e[c] += g * syn1[c + l2];
1068 // Learn weights hidden -> output
1069 for (c = 0; c < layer1_size; c++)
1070 syn1[c + l2] += g * syn0[c + l1];
1071 if (cap == 1)
1072 for (c = 0; c < layer1_size; c++)
1073 capParam(syn1, c + l2);
1074 }
1075 // NEGATIVE SAMPLING
1076 if (negative > 0)
1077 for (d = 0; d < negative + 1; d++) {
1078 if (d == 0) {
1079 target = word;
1080 label = 1;
1081 } else {
1082 next_random = next_random
1083 * (unsigned long long) 25214903917 + 11;
1084 if (word_to_group != NULL
1085 && word_to_group[word] != -1) {
1086 target = word;
1087 while (target == word) {
1088 target =
1089 group_to_table[word_to_group[word]
1090 * table_size
1091 + (next_random >> 16)
1092 % table_size];
1093 next_random =
1094 next_random
1095 * (unsigned long long) 25214903917
1096 + 11;
1097 }
1098 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1099 } else {
1100 target = table[(next_random >> 16)
1101 % table_size];
1102 }
1103 if (target == 0)
1104 target = next_random % (vocab_size - 1) + 1;
1105 if (target == word)
1106 continue;
1107 label = 0;
1108 }
1109 l2 = target * layer1_size;
1110 f = 0;
1111 for (c = 0; c < layer1_size; c++)
1112 f += syn0[c + l1] * syn1neg[c + l2];
1113 if (f > MAX_EXP)
1114 g = (label - 1) * alpha;
1115 else if (f < -MAX_EXP)
1116 g = (label - 0) * alpha;
1117 else
1118 g =
1119 (label
1120 - expTable[(int) ((f + MAX_EXP)
1121 * (EXP_TABLE_SIZE
1122 / MAX_EXP / 2))])
1123 * alpha;
1124 for (c = 0; c < layer1_size; c++)
1125 neu1e[c] += g * syn1neg[c + l2];
1126 for (c = 0; c < layer1_size; c++)
1127 syn1neg[c + l2] += g * syn0[c + l1];
1128 if (cap == 1)
1129 for (c = 0; c < layer1_size; c++)
1130 capParam(syn1neg, c + l2);
1131 }
1132 //Noise Contrastive Estimation
1133 if (nce > 0)
1134 for (d = 0; d < nce + 1; d++) {
1135 if (d == 0) {
1136 target = word;
1137 label = 1;
1138 } else {
1139 next_random = next_random
1140 * (unsigned long long) 25214903917 + 11;
1141 if (word_to_group != NULL
1142 && word_to_group[word] != -1) {
1143 target = word;
1144 while (target == word) {
1145 target =
1146 group_to_table[word_to_group[word]
1147 * table_size
1148 + (next_random >> 16)
1149 % table_size];
1150 next_random =
1151 next_random
1152 * (unsigned long long) 25214903917
1153 + 11;
1154 }
1155 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1156 } else {
1157 target = table[(next_random >> 16)
1158 % table_size];
1159 }
1160 if (target == 0)
1161 target = next_random % (vocab_size - 1) + 1;
1162 if (target == word)
1163 continue;
1164 label = 0;
1165 }
1166 l2 = target * layer1_size;
1167 f = 0;
1168 for (c = 0; c < layer1_size; c++)
1169 f += syn0[c + l1] * syn1nce[c + l2];
1170 if (f > MAX_EXP)
1171 g = (label - 1) * alpha;
1172 else if (f < -MAX_EXP)
1173 g = (label - 0) * alpha;
1174 else {
1175 f = exp(f);
1176 g = (label
1177 - f
1178 / (noise_distribution[target]
1179 * nce + f)) * alpha;
1180 }
1181 for (c = 0; c < layer1_size; c++)
1182 neu1e[c] += g * syn1nce[c + l2];
1183 for (c = 0; c < layer1_size; c++)
1184 syn1nce[c + l2] += g * syn0[c + l1];
1185 if (cap == 1)
1186 for (c = 0; c < layer1_size; c++)
1187 capParam(syn1nce, c + l2);
1188 }
1189 // Learn weights input -> hidden
1190 for (c = 0; c < layer1_size; c++)
1191 syn0[c + l1] += neu1e[c];
1192 }
1193 } else if (type == 2) { //train the cwindow architecture
1194 // in -> hidden
1195 cw = 0;
1196 for (a = 0; a < window * 2 + 1; a++)
1197 if (a != window) {
1198 c = sentence_position - window + a;
1199 if (c < 0)
1200 continue;
1201 if (c >= sentence_length)
1202 continue;
1203 last_word = sen[c];
1204 if (last_word == -1)
1205 continue;
1206 window_offset = a * layer1_size;
1207 if (a > window)
1208 window_offset -= layer1_size;
1209 for (c = 0; c < layer1_size; c++)
1210 neu1[c + window_offset] += syn0[c
1211 + last_word * layer1_size];
1212 cw++;
1213 }
1214 if (cw) {
1215 if (hs)
1216 for (d = 0; d < vocab[word].codelen; d++) {
1217 f = 0;
1218 l2 = vocab[word].point[d] * window_layer_size;
1219 // Propagate hidden -> output
1220 for (c = 0; c < window_layer_size; c++)
1221 f += neu1[c] * syn1_window[c + l2];
1222 if (f <= -MAX_EXP)
1223 continue;
1224 else if (f >= MAX_EXP)
1225 continue;
1226 else
1227 f = expTable[(int) ((f + MAX_EXP)
1228 * (EXP_TABLE_SIZE / MAX_EXP / 2))];
1229 // 'g' is the gradient multiplied by the learning rate
1230 g = (1 - vocab[word].code[d] - f) * alpha;
1231 // Propagate errors output -> hidden
1232 for (c = 0; c < window_layer_size; c++)
1233 neu1e[c] += g * syn1_window[c + l2];
1234 // Learn weights hidden -> output
1235 for (c = 0; c < window_layer_size; c++)
1236 syn1_window[c + l2] += g * neu1[c];
1237 if (cap == 1)
1238 for (c = 0; c < window_layer_size; c++)
1239 capParam(syn1_window, c + l2);
1240 }
1241 // NEGATIVE SAMPLING
1242 if (negative > 0)
1243 for (d = 0; d < negative + 1; d++) {
1244 if (d == 0) {
1245 target = word;
1246 label = 1;
1247 } else {
1248 next_random = next_random
1249 * (unsigned long long) 25214903917 + 11;
1250 if (word_to_group != NULL
1251 && word_to_group[word] != -1) {
1252 target = word;
1253 while (target == word) {
1254 target = group_to_table[word_to_group[word]
1255 * table_size
1256 + (next_random >> 16) % table_size];
1257 next_random = next_random
1258 * (unsigned long long) 25214903917
1259 + 11;
1260 }
1261 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1262 } else {
1263 target =
1264 table[(next_random >> 16) % table_size];
1265 }
1266 if (target == 0)
1267 target = next_random % (vocab_size - 1) + 1;
1268 if (target == word)
1269 continue;
1270 label = 0;
1271 }
1272 l2 = target * window_layer_size;
1273 f = 0;
1274 for (c = 0; c < window_layer_size; c++)
1275 f += neu1[c] * syn1neg_window[c + l2];
1276 if (f > MAX_EXP)
1277 g = (label - 1) * alpha;
1278 else if (f < -MAX_EXP)
1279 g = (label - 0) * alpha;
1280 else
1281 g = (label
1282 - expTable[(int) ((f + MAX_EXP)
1283 * (EXP_TABLE_SIZE / MAX_EXP / 2))])
1284 * alpha;
1285 for (c = 0; c < window_layer_size; c++)
1286 neu1e[c] += g * syn1neg_window[c + l2];
1287 for (c = 0; c < window_layer_size; c++)
1288 syn1neg_window[c + l2] += g * neu1[c];
1289 if (cap == 1)
1290 for (c = 0; c < window_layer_size; c++)
1291 capParam(syn1neg_window, c + l2);
1292 }
1293 // Noise Contrastive Estimation
1294 if (nce > 0)
1295 for (d = 0; d < nce + 1; d++) {
1296 if (d == 0) {
1297 target = word;
1298 label = 1;
1299 } else {
1300 next_random = next_random
1301 * (unsigned long long) 25214903917 + 11;
1302 if (word_to_group != NULL
1303 && word_to_group[word] != -1) {
1304 target = word;
1305 while (target == word) {
1306 target = group_to_table[word_to_group[word]
1307 * table_size
1308 + (next_random >> 16) % table_size];
1309 next_random = next_random
1310 * (unsigned long long) 25214903917
1311 + 11;
1312 }
1313 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1314 } else {
1315 target =
1316 table[(next_random >> 16) % table_size];
1317 }
1318 if (target == 0)
1319 target = next_random % (vocab_size - 1) + 1;
1320 if (target == word)
1321 continue;
1322 label = 0;
1323 }
1324 l2 = target * window_layer_size;
1325 f = 0;
1326 for (c = 0; c < window_layer_size; c++)
1327 f += neu1[c] * syn1nce_window[c + l2];
1328 if (f > MAX_EXP)
1329 g = (label - 1) * alpha;
1330 else if (f < -MAX_EXP)
1331 g = (label - 0) * alpha;
1332 else {
1333 f = exp(f);
1334 g =
1335 (label
1336 - f
1337 / (noise_distribution[target]
1338 * nce + f)) * alpha;
1339 }
1340 for (c = 0; c < window_layer_size; c++)
1341 neu1e[c] += g * syn1nce_window[c + l2];
1342 for (c = 0; c < window_layer_size; c++)
1343 syn1nce_window[c + l2] += g * neu1[c];
1344 if (cap == 1)
1345 for (c = 0; c < window_layer_size; c++)
1346 capParam(syn1nce_window, c + l2);
1347 }
1348 // hidden -> in
1349 for (a = 0; a < window * 2 + 1; a++)
1350 if (a != window) {
1351 c = sentence_position - window + a;
1352 if (c < 0)
1353 continue;
1354 if (c >= sentence_length)
1355 continue;
1356 last_word = sen[c];
1357 if (last_word == -1)
1358 continue;
1359 window_offset = a * layer1_size;
1360 if (a > window)
1361 window_offset -= layer1_size;
1362 for (c = 0; c < layer1_size; c++)
1363 syn0[c + last_word * layer1_size] += neu1e[c
1364 + window_offset];
1365 }
1366 }
1367 } else if (type == 3) { //train structured skip-gram
1368 for (a = 0; a < window * 2 + 1; a++)
1369 if (a != window) {
1370 c = sentence_position - window + a;
1371 if (c < 0)
1372 continue;
1373 if (c >= sentence_length)
1374 continue;
1375 last_word = sen[c];
Peter Fankhauser66035a42016-04-20 13:29:33 +02001376 if (last_word < 0)
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001377 continue;
1378 l1 = last_word * layer1_size;
1379 window_offset = a * layer1_size;
1380 if (a > window)
1381 window_offset -= layer1_size;
1382 for (c = 0; c < layer1_size; c++)
1383 neu1e[c] = 0;
1384 // HIERARCHICAL SOFTMAX
1385 if (hs)
1386 for (d = 0; d < vocab[word].codelen; d++) {
1387 f = 0;
1388 l2 = vocab[word].point[d] * window_layer_size;
1389 // Propagate hidden -> output
1390 for (c = 0; c < layer1_size; c++)
1391 f += syn0[c + l1]
1392 * syn1_window[c + l2 + window_offset];
1393 if (f <= -MAX_EXP)
1394 continue;
1395 else if (f >= MAX_EXP)
1396 continue;
1397 else
1398 f = expTable[(int) ((f + MAX_EXP)
1399 * (EXP_TABLE_SIZE / MAX_EXP / 2))];
1400 // 'g' is the gradient multiplied by the learning rate
1401 g = (1 - vocab[word].code[d] - f) * alpha;
1402 // Propagate errors output -> hidden
1403 for (c = 0; c < layer1_size; c++)
1404 neu1e[c] += g
1405 * syn1_window[c + l2 + window_offset];
1406 // Learn weights hidden -> output
1407 for (c = 0; c < layer1_size; c++)
1408 syn1[c + l2 + window_offset] += g
1409 * syn0[c + l1];
1410 if (cap == 1)
1411 for (c = 0; c < layer1_size; c++)
1412 capParam(syn1, c + l2 + window_offset);
1413 }
1414 // NEGATIVE SAMPLING
1415 if (negative > 0)
1416 for (d = 0; d < negative + 1; d++) {
1417 if (d == 0) {
1418 target = word;
1419 label = 1;
1420 } else {
1421 next_random = next_random
1422 * (unsigned long long) 25214903917 + 11;
1423 if (word_to_group != NULL
1424 && word_to_group[word] != -1) {
1425 target = word;
1426 while (target == word) {
1427 target =
1428 group_to_table[word_to_group[word]
1429 * table_size
1430 + (next_random >> 16)
1431 % table_size];
1432 next_random =
1433 next_random
1434 * (unsigned long long) 25214903917
1435 + 11;
1436 }
1437 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1438 } else {
1439 target = table[(next_random >> 16)
1440 % table_size];
1441 }
1442 if (target == 0)
1443 target = next_random % (vocab_size - 1) + 1;
1444 if (target == word)
1445 continue;
1446 label = 0;
1447 }
1448 l2 = target * window_layer_size;
1449 f = 0;
1450 for (c = 0; c < layer1_size; c++)
1451 f +=
1452 syn0[c + l1]
1453 * syn1neg_window[c + l2
1454 + window_offset];
1455 if (f > MAX_EXP)
1456 g = (label - 1) * alpha;
1457 else if (f < -MAX_EXP)
1458 g = (label - 0) * alpha;
1459 else
1460 g =
1461 (label
1462 - expTable[(int) ((f + MAX_EXP)
1463 * (EXP_TABLE_SIZE
1464 / MAX_EXP / 2))])
1465 * alpha;
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001466 if(debug_mode > 2 && ((long long) id) == 0) {
1467 printf("negative sampling %lld for input (word) %s (#%lld), target (last word) %s returned %s (#%lld), ", d, vocab[word].word, word, vocab[last_word].word, vocab[target].word, target);
1468 printf("label %lld, a %lld, gain %.4f\n", label, a-window, g);
1469 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001470 for (c = 0; c < layer1_size; c++)
1471 neu1e[c] +=
1472 g
1473 * syn1neg_window[c + l2
1474 + window_offset];
1475 for (c = 0; c < layer1_size; c++)
1476 syn1neg_window[c + l2 + window_offset] += g
1477 * syn0[c + l1];
1478 if (cap == 1)
1479 for (c = 0; c < layer1_size; c++)
1480 capParam(syn1neg_window,
1481 c + l2 + window_offset);
1482 }
1483 // Noise Constrastive Estimation
1484 if (nce > 0)
1485 for (d = 0; d < nce + 1; d++) {
1486 if (d == 0) {
1487 target = word;
1488 label = 1;
1489 } else {
1490 next_random = next_random
1491 * (unsigned long long) 25214903917 + 11;
1492 if (word_to_group != NULL
1493 && word_to_group[word] != -1) {
1494 target = word;
1495 while (target == word) {
1496 target =
1497 group_to_table[word_to_group[word]
1498 * table_size
1499 + (next_random >> 16)
1500 % table_size];
1501 next_random =
1502 next_random
1503 * (unsigned long long) 25214903917
1504 + 11;
1505 }
1506 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1507 } else {
1508 target = table[(next_random >> 16)
1509 % table_size];
1510 }
1511 if (target == 0)
1512 target = next_random % (vocab_size - 1) + 1;
1513 if (target == word)
1514 continue;
1515 label = 0;
1516 }
1517 l2 = target * window_layer_size;
1518 f = 0;
1519 for (c = 0; c < layer1_size; c++)
1520 f +=
1521 syn0[c + l1]
1522 * syn1nce_window[c + l2
1523 + window_offset];
1524 if (f > MAX_EXP)
1525 g = (label - 1) * alpha;
1526 else if (f < -MAX_EXP)
1527 g = (label - 0) * alpha;
1528 else {
1529 f = exp(f);
1530 g = (label
1531 - f
1532 / (noise_distribution[target]
1533 * nce + f)) * alpha;
1534 }
1535 for (c = 0; c < layer1_size; c++)
1536 neu1e[c] +=
1537 g
1538 * syn1nce_window[c + l2
1539 + window_offset];
1540 for (c = 0; c < layer1_size; c++)
1541 syn1nce_window[c + l2 + window_offset] += g
1542 * syn0[c + l1];
1543 if (cap == 1)
1544 for (c = 0; c < layer1_size; c++)
1545 capParam(syn1nce_window,
1546 c + l2 + window_offset);
1547 }
1548 // Learn weights input -> hidden
1549 for (c = 0; c < layer1_size; c++) {
1550 syn0[c + l1] += neu1e[c];
1551 if (syn0[c + l1] > 50)
1552 syn0[c + l1] = 50;
1553 if (syn0[c + l1] < -50)
1554 syn0[c + l1] = -50;
1555 }
1556 }
1557 } else if (type == 4) { //training senna
1558 // in -> hidden
1559 cw = 0;
1560 for (a = 0; a < window * 2 + 1; a++)
1561 if (a != window) {
1562 c = sentence_position - window + a;
1563 if (c < 0)
1564 continue;
1565 if (c >= sentence_length)
1566 continue;
1567 last_word = sen[c];
1568 if (last_word == -1)
1569 continue;
1570 window_offset = a * layer1_size;
1571 if (a > window)
1572 window_offset -= layer1_size;
1573 for (c = 0; c < layer1_size; c++)
1574 neu1[c + window_offset] += syn0[c
1575 + last_word * layer1_size];
1576 cw++;
1577 }
1578 if (cw) {
1579 for (a = 0; a < window_hidden_size; a++) {
1580 c = a * window_layer_size;
1581 for (b = 0; b < window_layer_size; b++) {
1582 neu2[a] += syn_window_hidden[c + b] * neu1[b];
1583 }
1584 }
1585 if (hs)
1586 for (d = 0; d < vocab[word].codelen; d++) {
1587 f = 0;
1588 l2 = vocab[word].point[d] * window_hidden_size;
1589 // Propagate hidden -> output
1590 for (c = 0; c < window_hidden_size; c++)
1591 f += hardTanh(neu2[c]) * syn_hidden_word[c + l2];
1592 if (f <= -MAX_EXP)
1593 continue;
1594 else if (f >= MAX_EXP)
1595 continue;
1596 else
1597 f = expTable[(int) ((f + MAX_EXP)
1598 * (EXP_TABLE_SIZE / MAX_EXP / 2))];
1599 // 'g' is the gradient multiplied by the learning rate
1600 g = (1 - vocab[word].code[d] - f) * alpha;
1601 // Propagate errors output -> hidden
1602 for (c = 0; c < window_hidden_size; c++)
1603 neu2e[c] += dHardTanh(neu2[c], g) * g
1604 * syn_hidden_word[c + l2];
1605 // Learn weights hidden -> output
1606 for (c = 0; c < window_hidden_size; c++)
1607 syn_hidden_word[c + l2] += dHardTanh(neu2[c], g) * g
1608 * neu2[c];
1609 }
1610 // NEGATIVE SAMPLING
1611 if (negative > 0)
1612 for (d = 0; d < negative + 1; d++) {
1613 if (d == 0) {
1614 target = word;
1615 label = 1;
1616 } else {
1617 next_random = next_random
1618 * (unsigned long long) 25214903917 + 11;
1619 if (word_to_group != NULL
1620 && word_to_group[word] != -1) {
1621 target = word;
1622 while (target == word) {
1623 target = group_to_table[word_to_group[word]
1624 * table_size
1625 + (next_random >> 16) % table_size];
1626 next_random = next_random
1627 * (unsigned long long) 25214903917
1628 + 11;
1629 }
1630 //printf("negative sampling %lld for word %s returned %s\n", d, vocab[word].word, vocab[target].word);
1631 } else {
1632 target =
1633 table[(next_random >> 16) % table_size];
1634 }
1635 if (target == 0)
1636 target = next_random % (vocab_size - 1) + 1;
1637 if (target == word)
1638 continue;
1639 label = 0;
1640 }
1641 l2 = target * window_hidden_size;
1642 f = 0;
1643 for (c = 0; c < window_hidden_size; c++)
1644 f += hardTanh(neu2[c])
1645 * syn_hidden_word_neg[c + l2];
1646 if (f > MAX_EXP)
1647 g = (label - 1) * alpha / negative;
1648 else if (f < -MAX_EXP)
1649 g = (label - 0) * alpha / negative;
1650 else
1651 g = (label
1652 - expTable[(int) ((f + MAX_EXP)
1653 * (EXP_TABLE_SIZE / MAX_EXP / 2))])
1654 * alpha / negative;
1655 for (c = 0; c < window_hidden_size; c++)
1656 neu2e[c] += dHardTanh(neu2[c], g) * g
1657 * syn_hidden_word_neg[c + l2];
1658 for (c = 0; c < window_hidden_size; c++)
1659 syn_hidden_word_neg[c + l2] += dHardTanh(neu2[c], g)
1660 * g * neu2[c];
1661 }
1662 for (a = 0; a < window_hidden_size; a++)
1663 for (b = 0; b < window_layer_size; b++)
1664 neu1e[b] += neu2e[a]
1665 * syn_window_hidden[a * window_layer_size + b];
1666 for (a = 0; a < window_hidden_size; a++)
1667 for (b = 0; b < window_layer_size; b++)
1668 syn_window_hidden[a * window_layer_size + b] += neu2e[a]
1669 * neu1[b];
1670 // hidden -> in
1671 for (a = 0; a < window * 2 + 1; a++)
1672 if (a != window) {
1673 c = sentence_position - window + a;
1674 if (c < 0)
1675 continue;
1676 if (c >= sentence_length)
1677 continue;
1678 last_word = sen[c];
1679 if (last_word == -1)
1680 continue;
1681 window_offset = a * layer1_size;
1682 if (a > window)
1683 window_offset -= layer1_size;
1684 for (c = 0; c < layer1_size; c++)
1685 syn0[c + last_word * layer1_size] += neu1e[c
1686 + window_offset];
1687 }
1688 }
Marc Kupietz613edbf2018-01-11 21:38:03 +01001689 } else if(type == 5) {
Marc Kupietzac23b982025-08-05 19:56:00 +02001690 for (a = 0; a < window * 2 + 1; a++) if (a != window) {
Marc Kupietz613edbf2018-01-11 21:38:03 +01001691 c = sentence_position - window + a;
1692 if (c < 0) continue;
1693 if (c >= sentence_length) continue;
1694 last_word = sen[c];
1695 if (last_word == -1) continue;
1696 inc_collocator(cdb, word, last_word, a - window);
1697 // printf("%2d: storing %s %s - %d\n", id, vocab[word].word, vocab[last_word].word, (int) a - window);
1698 // cw++;
1699 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001700 } else {
1701 printf("unknown type %i", type);
1702 exit(0);
1703 }
1704 sentence_position++;
1705 if (sentence_position >= sentence_length) {
1706 sentence_length = 0;
1707 continue;
1708 }
1709 }
1710 fclose(fi);
1711 free(neu1);
1712 free(neu1e);
Marc Kupietz202723e2016-07-14 09:12:00 +02001713 threadPos[(long) id] = -1;
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001714 pthread_exit(NULL);
1715}
1716
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001717void ShowCollocations() {
Marc Kupietz71996e72016-03-18 13:40:24 +01001718 long a, b, c, d, e, window_offset, target, max_target=0, maxmax_target;
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001719 real f, max_f, maxmax_f;
Marc Kupietzf00e7b02023-12-22 11:11:56 +01001720 real *target_sums=0L, bestf[MAX_CC], worstbest;
Marc Kupietz71996e72016-03-18 13:40:24 +01001721 long besti[MAX_CC];
Marc Kupietz79fd83d2016-03-18 14:09:07 +01001722 int N = 10, bestp[MAX_CC];
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001723 a = posix_memalign((void **) &target_sums, 128, vocab_size * sizeof(real));
1724
1725 for (d = cc; d < vocab_size; d++) {
1726 for (b = 0; b < vocab_size; b++)
1727 target_sums[b]=0;
Marc Kupietz71996e72016-03-18 13:40:24 +01001728 for (b = 0; b < N; b++)
1729 bestf[b]=-1;
1730 worstbest = -1;
1731
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001732 maxmax_f = -1;
1733 maxmax_target = 0;
Marc Kupietz0a664c12016-03-18 13:18:22 +01001734 for (a = window * 2 + 1; a >=0; a--) {
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001735 if (a != window) {
1736 max_f = -1;
1737 window_offset = a * layer1_size;
1738 if (a > window)
1739 window_offset -= layer1_size;
1740 for(target = 0; target < vocab_size; target ++) {
1741 if(target == d)
1742 continue;
1743 f = 0;
1744 for (c = 0; c < layer1_size; c++)
1745 f += syn0[d* layer1_size + c] * syn1neg_window[target * window_layer_size + window_offset + c];
1746 if (f < -MAX_EXP)
1747 continue;
1748 else if (f > MAX_EXP)
1749 continue;
1750 else
1751 f = expTable[(int) ((f + MAX_EXP) * (EXP_TABLE_SIZE / MAX_EXP / 2))];
1752 if(f > max_f) {
1753 max_f = f;
1754 max_target = target;
1755 }
Marc Kupietz0fb5d612016-03-18 11:01:21 +01001756 target_sums[target] += (1-target_sums[target]) * f;
Marc Kupietz71996e72016-03-18 13:40:24 +01001757 if(f > worstbest) {
1758 for (b = 0; b < N; b++) {
1759 if (f > bestf[b]) {
1760 for (e = N - 1; e > b; e--) {
1761 bestf[e] = bestf[e - 1];
1762 besti[e] = besti[e - 1];
Marc Kupietz79fd83d2016-03-18 14:09:07 +01001763 bestp[e] = bestp[e - 1];
Marc Kupietz71996e72016-03-18 13:40:24 +01001764 }
1765 bestf[b] = f;
1766 besti[b] = target;
Marc Kupietz79fd83d2016-03-18 14:09:07 +01001767 bestp[b] = window-a;
Marc Kupietz71996e72016-03-18 13:40:24 +01001768 break;
1769 }
1770 }
1771 worstbest = bestf[N-1];
1772 }
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001773 }
1774 printf("%s (%.2f) ", vocab[max_target].word, max_f);
1775 if(max_f > maxmax_f) {
1776 maxmax_f = max_f;
1777 maxmax_target = max_target;
1778 }
1779 } else {
1780 printf("\x1b[1m%s\x1b[0m ", vocab[d].word);
1781 }
1782 }
1783 max_f = -1;
1784 for (b = 0; b < vocab_size; b++) {
1785 if(target_sums[b] > max_f) {
1786 max_f = target_sums[b];
1787 max_target = b;
1788 }
1789 }
1790 printf(" – max sum: %s (%.2f), max resp.: \x1b[1m%s\x1b[0m (%.2f)\n",
Marc Kupietz0fb5d612016-03-18 11:01:21 +01001791 vocab[max_target].word, max_f,
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001792 vocab[maxmax_target].word, maxmax_f);
Marc Kupietz71996e72016-03-18 13:40:24 +01001793 for(b=0; b<N && bestf[b]>-1; b++)
Marc Kupietz79fd83d2016-03-18 14:09:07 +01001794 printf("%-32s %.2f %d\n", vocab[besti[b]].word, bestf[b], bestp[b]);
Marc Kupietz71996e72016-03-18 13:40:24 +01001795 printf("\n");
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001796 }
1797}
1798
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001799void TrainModel() {
1800 long a, b, c, d;
1801 FILE *fo;
Marc Kupietz8bc903d2026-08-09 15:59:12 +02001802 /* one more than num_threads: the monitor thread gets pt[num_threads] */
1803 pthread_t *pt = (pthread_t *) malloc((num_threads + 1) * sizeof(pthread_t));
Marc Kupietz202723e2016-07-14 09:12:00 +02001804 threadPos = malloc(num_threads * sizeof(long long));
1805 threadIters = malloc(num_threads * sizeof(int));
1806 char *timebuf = malloc(80);
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001807 printf("Starting training using file %s\n", train_file);
1808 starting_alpha = alpha;
1809 if (read_vocab_file[0] != 0)
1810 ReadVocab();
1811 else
1812 LearnVocabFromTrainFile();
1813 if (save_vocab_file[0] != 0)
1814 SaveVocab();
1815 if (output_file[0] == 0)
1816 return;
1817 InitNet();
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01001818 if(cc > 0)
1819 ShowCollocations();
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001820 if (negative > 0 || nce > 0)
1821 InitUnigramTable();
1822 if (negative_classes_file[0] != 0)
1823 InitClassUnigramTable();
Marc Kupietzb366bcd2018-01-11 21:29:41 +01001824 start = time(NULL);
1825 start_clock = clock();
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001826 for (a = 0; a < num_threads; a++)
1827 pthread_create(&pt[a], NULL, TrainModelThread, (void *) a);
Marc Kupietz202723e2016-07-14 09:12:00 +02001828 if(debug_mode > 1)
1829 pthread_create(&pt[num_threads], NULL, MonitorThread, (void *) a);
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001830 for (a = 0; a < num_threads; a++)
1831 pthread_join(pt[a], NULL);
Marc Kupietz202723e2016-07-14 09:12:00 +02001832 if(debug_mode > 1) {
1833 pthread_join(pt[num_threads], NULL);
Marc Kupietzb366bcd2018-01-11 21:29:41 +01001834 clock_t now = time(NULL);
1835 clock_t now_clock = clock();
1836 printf("\nFinished: %s - user: %lds - real: %lds\n", currentDateTime(timebuf, 0), (now_clock - start_clock) / CLOCKS_PER_SEC, now - start);
Marc Kupietz613edbf2018-01-11 21:38:03 +01001837 if(type == 5) // don't save vectorsmfor classic collocators
1838 return;
Marc Kupietz202723e2016-07-14 09:12:00 +02001839 printf("Saving vectors to %s ...", output_file);
1840 fflush(stdout);
1841 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001842 fo = fopen(output_file, "wb");
1843 if (classes == 0) {
1844 // Save the word vectors
1845 fprintf(fo, "%lld %lld\n", vocab_size, layer1_size);
1846 for (a = 0; a < vocab_size; a++) {
1847 fprintf(fo, "%s ", vocab[a].word);
1848 if (binary)
1849 for (b = 0; b < layer1_size; b++)
1850 fwrite(&syn0[a * layer1_size + b], sizeof(real), 1, fo);
1851 else
1852 for (b = 0; b < layer1_size; b++)
1853 fprintf(fo, "%lf ", syn0[a * layer1_size + b]);
1854 fprintf(fo, "\n");
1855 }
Marc Kupietz202723e2016-07-14 09:12:00 +02001856 if(debug_mode > 1)
1857 fprintf(stderr, "\n");
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001858 } else {
1859 // Run K-means on the word vectors
1860 int clcn = classes, iter = 10, closeid;
1861 int *centcn = (int *) malloc(classes * sizeof(int));
1862 int *cl = (int *) calloc(vocab_size, sizeof(int));
1863 real closev, x;
1864 real *cent = (real *) calloc(classes * layer1_size, sizeof(real));
1865 for (a = 0; a < vocab_size; a++)
1866 cl[a] = a % clcn;
1867 for (a = 0; a < iter; a++) {
1868 for (b = 0; b < clcn * layer1_size; b++)
1869 cent[b] = 0;
1870 for (b = 0; b < clcn; b++)
1871 centcn[b] = 1;
1872 for (c = 0; c < vocab_size; c++) {
1873 for (d = 0; d < layer1_size; d++)
1874 cent[layer1_size * cl[c] + d] += syn0[c * layer1_size + d];
1875 centcn[cl[c]]++;
1876 }
1877 for (b = 0; b < clcn; b++) {
1878 closev = 0;
1879 for (c = 0; c < layer1_size; c++) {
1880 cent[layer1_size * b + c] /= centcn[b];
1881 closev += cent[layer1_size * b + c]
1882 * cent[layer1_size * b + c];
1883 }
1884 closev = sqrt(closev);
1885 for (c = 0; c < layer1_size; c++)
1886 cent[layer1_size * b + c] /= closev;
1887 }
1888 for (c = 0; c < vocab_size; c++) {
1889 closev = -10;
1890 closeid = 0;
1891 for (d = 0; d < clcn; d++) {
1892 x = 0;
1893 for (b = 0; b < layer1_size; b++)
1894 x += cent[layer1_size * d + b]
1895 * syn0[c * layer1_size + b];
1896 if (x > closev) {
1897 closev = x;
1898 closeid = d;
1899 }
1900 }
1901 cl[c] = closeid;
1902 }
1903 }
1904 // Save the K-means classes
1905 for (a = 0; a < vocab_size; a++)
1906 fprintf(fo, "%s %d\n", vocab[a].word, cl[a]);
1907 free(centcn);
1908 free(cent);
1909 free(cl);
1910 }
1911 fclose(fo);
Marc Kupietz50de14a2026-07-31 14:48:02 +09001912 /* Write the memory mappable form right away. Otherwise derekovecs builds it
1913 on its first start, which takes a while and needs write access to the
1914 directory the models live in. The k-means classes are something else, so
1915 only word vectors are converted. */
1916 if (classes == 0) {
1917 if (debug_mode > 0) {
1918 printf("Converting %s to memory mappable structures\n", output_file);
1919 fflush(stdout);
1920 }
1921 if (convert_vecs_to_mmap(output_file) != 0)
1922 fprintf(stderr, "Could not write the memory mappable form of %s\n",
1923 output_file);
1924 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001925 if (save_net_file[0] != 0)
1926 SaveNet();
1927}
1928
1929int ArgPos(char *str, int argc, char **argv) {
1930 int a;
1931 for (a = 1; a < argc; a++)
1932 if (!strcmp(str, argv[a])) {
1933 if (a == argc - 1) {
1934 printf("Argument missing for %s\n", str);
1935 exit(1);
1936 }
1937 return a;
1938 }
1939 return -1;
1940}
1941
Marc Kupietzc7f773b2017-12-02 12:04:03 +01001942void print_help() {
Marc Kupietze3c7e642024-10-21 18:51:21 +02001943 printf("WORD VECTOR estimation toolkit v 0.9.1\n\n");
Marc Kupietzd6f9c712016-03-16 11:50:56 +01001944 printf("Options:\n");
1945 printf("Parameters for training:\n");
1946 printf("\t-train <file>\n");
1947 printf("\t\tUse text data from <file> to train the model\n");
1948 printf("\t-output <file>\n");
1949 printf(
1950 "\t\tUse <file> to save the resulting word vectors / word clusters\n");
1951 printf("\t-size <int>\n");
1952 printf("\t\tSet size of word vectors; default is 100\n");
1953 printf("\t-window <int>\n");
1954 printf("\t\tSet max skip length between words; default is 5\n");
1955 printf("\t-sample <float>\n");
1956 printf(
1957 "\t\tSet threshold for occurrence of words. Those that appear with higher frequency in the training data\n");
1958 printf(
1959 "\t\twill be randomly down-sampled; default is 1e-3, useful range is (0, 1e-5)\n");
1960 printf("\t-hs <int>\n");
1961 printf("\t\tUse Hierarchical Softmax; default is 0 (not used)\n");
1962 printf("\t-negative <int>\n");
1963 printf(
1964 "\t\tNumber of negative examples; default is 5, common values are 3 - 10 (0 = not used)\n");
1965 printf("\t-negative-classes <file>\n");
1966 printf("\t\tNegative classes to sample from\n");
1967 printf("\t-nce <int>\n");
1968 printf(
1969 "\t\tNumber of negative examples for nce; default is 0, common values are 3 - 10 (0 = not used)\n");
1970 printf("\t-threads <int>\n");
1971 printf("\t\tUse <int> threads (default 12)\n");
1972 printf("\t-iter <int>\n");
1973 printf("\t\tRun more training iterations (default 5)\n");
1974 printf("\t-min-count <int>\n");
1975 printf(
1976 "\t\tThis will discard words that appear less than <int> times; default is 5\n");
1977 printf("\t-alpha <float>\n");
1978 printf(
1979 "\t\tSet the starting learning rate; default is 0.025 for skip-gram and 0.05 for CBOW\n");
1980 printf("\t-classes <int>\n");
1981 printf(
1982 "\t\tOutput word classes rather than word vectors; default number of classes is 0 (vectors are written)\n");
1983 printf("\t-debug <int>\n");
1984 printf(
1985 "\t\tSet the debug mode (default = 2 = more info during training)\n");
1986 printf("\t-binary <int>\n");
1987 printf(
1988 "\t\tSave the resulting vectors in binary moded; default is 0 (off)\n");
1989 printf("\t-save-vocab <file>\n");
1990 printf("\t\tThe vocabulary will be saved to <file>\n");
1991 printf("\t-read-vocab <file>\n");
1992 printf(
1993 "\t\tThe vocabulary will be read from <file>, not constructed from the training data\n");
1994 printf("\t-read-net <file>\n");
1995 printf(
1996 "\t\tThe net parameters will be read from <file>, not initialized randomly\n");
1997 printf("\t-save-net <file>\n");
1998 printf("\t\tThe net parameters will be saved to <file>\n");
Marc Kupietze423f732017-12-22 17:57:03 +01001999 printf("\t-magic-stop-file <file>\n");
2000 printf("\t\tIf the magic file <file> exists training will stop after the current cycle.\n");
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01002001 printf("\t-show-cc <int>\n");
2002 printf("\t\tShow words with their collocators starting from word rank <int>. Depends on -read-vocab and -read-net.\n");
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002003 printf("\t-type <int>\n");
2004 printf(
Marc Kupietz613edbf2018-01-11 21:38:03 +01002005 "\t\tType of embeddings (0 for cbow, 1 for skipngram, 2 for cwindow, 3 for structured skipngram, 4 for senna type, 5 for store positional bigramms)\n");
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002006 printf("\t-cap <int>\n");
2007 printf(
2008 "\t\tlimit the parameter values to the range [-50, 50]; default is 0 (off)\n");
2009 printf("\nExamples:\n");
2010 printf(
Marc Kupietz83a67d42021-03-22 17:29:36 +01002011 "./dereko2vec -train data.txt -output vec.txt -size 200 -window 5 -sample 1e-4 -negative 5 -hs 0 -binary 0 -type 1 -iter 3\n\n");
Marc Kupietzc7f773b2017-12-02 12:04:03 +01002012}
2013
2014int main(int argc, char **argv) {
2015 int i;
2016 setlocale(LC_ALL, "");
2017 if (argc == 1) {
2018 print_help();
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002019 return 0;
2020 }
2021 output_file[0] = 0;
2022 save_vocab_file[0] = 0;
2023 read_vocab_file[0] = 0;
2024 save_net_file[0] = 0;
2025 read_net_file[0] = 0;
2026 negative_classes_file[0] = 0;
Marc Kupietzc7f773b2017-12-02 12:04:03 +01002027 if ((i = ArgPos((char *) "-h", argc, argv)) > 0) {
2028 print_help();
2029 return(0);
2030 }
2031 if ((i = ArgPos((char *) "-help", argc, argv)) > 0) {
2032 print_help();
2033 return(0);
2034 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002035 if ((i = ArgPos((char *) "-size", argc, argv)) > 0)
2036 layer1_size = atoi(argv[i + 1]);
2037 if ((i = ArgPos((char *) "-train", argc, argv)) > 0)
2038 strcpy(train_file, argv[i + 1]);
2039 if ((i = ArgPos((char *) "-save-vocab", argc, argv)) > 0)
2040 strcpy(save_vocab_file, argv[i + 1]);
2041 if ((i = ArgPos((char *) "-read-vocab", argc, argv)) > 0)
2042 strcpy(read_vocab_file, argv[i + 1]);
2043 if ((i = ArgPos((char *) "-save-net", argc, argv)) > 0)
2044 strcpy(save_net_file, argv[i + 1]);
2045 if ((i = ArgPos((char *) "-read-net", argc, argv)) > 0)
2046 strcpy(read_net_file, argv[i + 1]);
Marc Kupietze423f732017-12-22 17:57:03 +01002047 if ((i = ArgPos((char *) "-magic-stop-file", argc, argv)) > 0) {
2048 strcpy(magic_stop_file, argv[i + 1]);
2049 if (access(magic_stop_file, F_OK ) != -1) {
2050 printf("ERROR: magic stop file %s must not exist at start.\n", magic_stop_file);
2051 exit(1);
2052 }
2053 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002054 if ((i = ArgPos((char *) "-debug", argc, argv)) > 0)
2055 debug_mode = atoi(argv[i + 1]);
2056 if ((i = ArgPos((char *) "-binary", argc, argv)) > 0)
2057 binary = atoi(argv[i + 1]);
Marc Kupietz6b1f2ba2016-03-17 21:17:42 +01002058 if ((i = ArgPos((char *) "-show-cc", argc, argv)) > 0)
2059 cc = atoi(argv[i + 1]);
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002060 if ((i = ArgPos((char *) "-type", argc, argv)) > 0)
2061 type = atoi(argv[i + 1]);
2062 if ((i = ArgPos((char *) "-output", argc, argv)) > 0)
2063 strcpy(output_file, argv[i + 1]);
2064 if ((i = ArgPos((char *) "-window", argc, argv)) > 0)
2065 window = atoi(argv[i + 1]);
2066 if ((i = ArgPos((char *) "-sample", argc, argv)) > 0)
2067 sample = atof(argv[i + 1]);
2068 if ((i = ArgPos((char *) "-hs", argc, argv)) > 0)
2069 hs = atoi(argv[i + 1]);
2070 if ((i = ArgPos((char *) "-negative", argc, argv)) > 0)
2071 negative = atoi(argv[i + 1]);
2072 if ((i = ArgPos((char *) "-negative-classes", argc, argv)) > 0)
2073 strcpy(negative_classes_file, argv[i + 1]);
2074 if ((i = ArgPos((char *) "-nce", argc, argv)) > 0)
2075 nce = atoi(argv[i + 1]);
2076 if ((i = ArgPos((char *) "-threads", argc, argv)) > 0)
2077 num_threads = atoi(argv[i + 1]);
2078 if ((i = ArgPos((char *) "-iter", argc, argv)) > 0)
2079 iter = atoi(argv[i + 1]);
2080 if ((i = ArgPos((char *) "-min-count", argc, argv)) > 0)
2081 min_count = atoi(argv[i + 1]);
2082 if ((i = ArgPos((char *) "-classes", argc, argv)) > 0)
2083 classes = atoi(argv[i + 1]);
2084 if ((i = ArgPos((char *) "-cap", argc, argv)) > 0)
2085 cap = atoi(argv[i + 1]);
2086 if (type == 0 || type == 2 || type == 4)
2087 alpha = 0.05;
Marc Kupietz613edbf2018-01-11 21:38:03 +01002088 if (type==5) {
2089 sample = 0;
2090 cdb = open_collocatordb_for_write(output_file);
2091 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002092 if ((i = ArgPos((char *) "-alpha", argc, argv)) > 0)
2093 alpha = atof(argv[i + 1]);
2094 vocab = (struct vocab_word *) calloc(vocab_max_size,
2095 sizeof(struct vocab_word));
2096 vocab_hash = (int *) calloc(vocab_hash_size, sizeof(int));
2097 expTable = (real *) malloc((EXP_TABLE_SIZE + 1) * sizeof(real));
2098 for (i = 0; i < EXP_TABLE_SIZE; i++) {
2099 expTable[i] = exp((i / (real) EXP_TABLE_SIZE * 2 - 1) * MAX_EXP); // Precompute the exp() table
2100 expTable[i] = expTable[i] / (expTable[i] + 1); // Precompute f(x) = x / (x + 1)
2101 }
Marc Kupietz210b9d52016-04-02 21:48:13 +02002102 SaveArgs(argc, argv);
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002103 TrainModel();
Marc Kupietz42cda0b2026-08-02 14:06:03 +02002104 if (cdb != NULL) {
2105 /* Writes what is still in memory. The collocation database runs
2106 without a write ahead log, so the counts of the write buffers that
2107 were not flushed yet are lost without this. */
2108 if (debug_mode > 0) {
2109 printf("Closing the collocation database ...\n");
2110 fflush(stdout);
2111 }
2112 close_collocatordb(cdb);
2113 cdb = NULL;
2114 }
Marc Kupietzd6f9c712016-03-16 11:50:56 +01002115 return 0;
2116}
2117