blob: 897e7b1736faf3e7569a927bd073060607e4c6a0 [file] [log] [blame]
Marc Kupietzdc22b982015-10-09 09:19:34 +02001#!/usr/local/bin/perl
2use Inline C;
3use Mojolicious::Lite;
Marc Kupietz247500f2015-10-09 11:29:01 +02004use Encode qw(decode encode);
Marc Kupietz7bc85fd2016-02-24 11:42:41 +01005use Mojo::Server::Daemon;
Marc Kupietzdc22b982015-10-09 09:19:34 +02006
Marc Kupietz7bc85fd2016-02-24 11:42:41 +01007# -cbow 1 -size 200 -window 8 -negative 25 -hs 0 -sample 1e-4 -threads 40 -binary 1 -iter 15
8init_net("vectors15.bin");
Marc Kupietzdc22b982015-10-09 09:19:34 +02009
10get '/' => sub {
11 my $c = shift;
12 my $word=$c->param('word');
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010013 my $no_nbs=$c->param('n') || 50;
Marc Kupietz247500f2015-10-09 11:29:01 +020014 my $list;
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010015 if(defined($word) && $word !~ /^\s*$/) {
16 $c->inactivity_timeout(300);
17 $c->app->log->debug('Looking for neighbours of '.$word);
18 $list = get_neighbours(encode("iso-8859-1", $word), $no_nbs);
Marc Kupietz247500f2015-10-09 11:29:01 +020019 }
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010020 $c->render(template=>"index", word=>$word, no_nbs=>$no_nbs, list=> $list);
Marc Kupietzdc22b982015-10-09 09:19:34 +020021};
22
23app->start;
24
25exit;
26
27__END__
28
29__C__
30#include <stdio.h>
31#include <string.h>
32#include <math.h>
33#include <malloc.h>
34#include <stdlib.h> //strlen
35
36#define max_size 2000
37#define max_w 50
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010038#define MAX_NEIGHBOURS 1000
Marc Kupietzdc22b982015-10-09 09:19:34 +020039
40//the thread function
41void *connection_handler(void *);
42
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010043char *bestw[MAX_NEIGHBOURS];
Marc Kupietzdc22b982015-10-09 09:19:34 +020044char file_name[max_size], st[100][max_size];
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010045float dist, len, bestd[MAX_NEIGHBOURS], vec[max_size];
Marc Kupietzdc22b982015-10-09 09:19:34 +020046long long words, size, a, b, c, d, cn, bi[100];
47char ch;
48float *M;
49char *vocab;
50char *stringBuffer;
51
52int init_net(char *file_name) {
53 FILE *f;
54
55 stringBuffer = malloc(64000);
56 f = fopen(file_name, "rb");
57 if (f == NULL) {
58 printf("Input file %s not found\n", file_name);
59 return -1;
60 }
61 fscanf(f, "%lld", &words);
62 fscanf(f, "%lld", &size);
63 vocab = (char *)malloc((long long)words * max_w * sizeof(char));
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010064 for (a = 0; a < MAX_NEIGHBOURS; a++) bestw[a] = (char *)malloc(max_size * sizeof(char));
Marc Kupietzdc22b982015-10-09 09:19:34 +020065 M = (float *)malloc((long long)words * (long long)size * sizeof(float));
66 if (M == NULL) {
67 printf("Cannot allocate memory: %lld MB %lld %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
68 return -1;
69 }
70 for (b = 0; b < words; b++) {
71 a = 0;
72 while (1) {
73 vocab[b * max_w + a] = fgetc(f);
74 if (feof(f) || (vocab[b * max_w + a] == ' ')) break;
75 if ((a < max_w) && (vocab[b * max_w + a] != '\n')) a++;
76 }
77 vocab[b * max_w + a] = 0;
78 for (a = 0; a < size; a++) fread(&M[a + b * size], sizeof(float), 1, f);
79 len = 0;
80 for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
81 len = sqrt(len);
82 for (a = 0; a < size; a++) M[a + b * size] /= len;
83 }
84 fclose(f);
85 return 0;
86}
87
Marc Kupietz7bc85fd2016-02-24 11:42:41 +010088SV *get_neighbours(char *st1, int N) {
89 if(N>MAX_NEIGHBOURS) N=MAX_NEIGHBOURS;
90
Marc Kupietzdc22b982015-10-09 09:19:34 +020091 FILE *out=stdout;
92 *stringBuffer=0;
93
94 for (a = 0; a < N; a++) bestd[a] = 0;
95 for (a = 0; a < N; a++) bestw[a][0] = 0;
96 a = 0;
97 cn = 0;
98 b = 0;
99 c = 0;
100 while (1) {
101 st[cn][b] = st1[c];
102 b++;
103 c++;
104 st[cn][b] = 0;
105 if (st1[c] == 0) break;
106 if (st1[c] == ' ') {
107 cn++;
108 b = 0;
109 c++;
110 }
111 }
112 cn++;
113 for (a = 0; a < cn; a++) {
114 for (b = 0; b < words; b++) if (!strcmp(&vocab[b * max_w], st[a])) break;
115 if (b == words) b = -1;
116 bi[a] = b;
117 sprintf(stringBuffer, "\n<pre>Word: \"%s\" Position in vocabulary: %lld</pre>\n", st[a], bi[a]);
118 if (b == -1) {
119 sprintf(stringBuffer+strlen(stringBuffer), "Out of dictionary word!\n");
120 break;
121 }
122 }
Marc Kupietz247500f2015-10-09 11:29:01 +0200123 if (b == -1) goto end;
Marc Kupietzdc22b982015-10-09 09:19:34 +0200124 for (a = 0; a < size; a++) vec[a] = 0;
125 for (b = 0; b < cn; b++) {
126 if (bi[b] == -1) continue;
127 for (a = 0; a < size; a++) vec[a] += M[a + bi[b] * size];
128 }
129 len = 0;
130 for (a = 0; a < size; a++) len += vec[a] * vec[a];
131 len = sqrt(len);
132 for (a = 0; a < size; a++) vec[a] /= len;
133 for (a = 0; a < N; a++) bestd[a] = -1;
134 for (a = 0; a < N; a++) bestw[a][0] = 0;
135 for (c = 0; c < words; c++) {
136 a = 0;
137 for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
138 if (a == 1) continue;
139 dist = 0;
140 for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
141 for (a = 0; a < N; a++) {
142 if (dist > bestd[a]) {
143 for (d = N - 1; d > a; d--) {
144 bestd[d] = bestd[d - 1];
145 strcpy(bestw[d], bestw[d - 1]);
146 }
147 bestd[a] = dist;
148 strcpy(bestw[a], &vocab[c * max_w]);
149 break;
150 }
151 }
152 }
Marc Kupietz247500f2015-10-09 11:29:01 +0200153 AV* array = newAV();
154 for (a = 0; a < N; a++) {
155 HV* hash = newHV();
156 hv_store(hash, "word", strlen("word"), newSVpvf(bestw[a], 0), 0);
157 hv_store(hash, "dist", strlen("dist"), newSVnv(bestd[a]), 0);
158 av_push(array, newRV_noinc((SV*)hash));
159 }
160 end:
161 return newRV_noinc((SV*)array);
Marc Kupietzdc22b982015-10-09 09:19:34 +0200162}
163
Marc Kupietz7bc85fd2016-02-24 11:42:41 +0100164
Marc Kupietzdc22b982015-10-09 09:19:34 +0200165__DATA__
166
167@@ index.html.ep
168<!DOCTYPE html>
169<html>
Marc Kupietz247500f2015-10-09 11:29:01 +0200170<head><title>DeReKo-Word-Vector-Distances</title></head>
Marc Kupietzdc22b982015-10-09 09:19:34 +0200171<body>
Marc Kupietz7bc85fd2016-02-24 11:42:41 +0100172 <p>Word vector model based on DeReKo-2015-II. Trained with <a href="https://code.google.com/p/word2vec/">word2vec</a> using the following parameters:</p>
Marc Kupietz247500f2015-10-09 11:29:01 +0200173 <pre>
Marc Kupietz7bc85fd2016-02-24 11:42:41 +0100174-cbow 1 -size 300 -window 7 -negative 5 -hs 0 -sample 1e-5 -threads 44 -binary 1 -iter 5
Marc Kupietz247500f2015-10-09 11:29:01 +0200175</pre>
176</p>
Marc Kupietzdc22b982015-10-09 09:19:34 +0200177 <form action="<%=url_for('/')->to_abs%>" method="GET">
Marc Kupietz7bc85fd2016-02-24 11:42:41 +0100178 Word: <input type="text" name="word" value="<%= $word %>">
179 Neighbours: <input type="text" name="n" value="<%= $no_nbs %>">
Marc Kupietzdc22b982015-10-09 09:19:34 +0200180 <input type="submit" value="Show neighbours">
181 </form>
182 <br>
Marc Kupietz247500f2015-10-09 11:29:01 +0200183 % if($list) {
Marc Kupietz7bc85fd2016-02-24 11:42:41 +0100184 <h3>Nearest neighbours of "<%= $word %>"</h3>
Marc Kupietz247500f2015-10-09 11:29:01 +0200185 <table>
186 <tr>
187 <th align="right">Pos.</th><th align="left">Word</th><th align="right">Cosine dist.</th>
188 </tr>
189 % my $i=1; for my $item (@$list) {
190 <tr>
191 <td align="right">
192 <%= $i++ %>.
193 </td>
194 <td>
195 <a href="/?word=<%= $item->{word} %>">
196 <%= $item->{word} %>
197 </a>
198 </td>
199 <td align="right">
200 <%= sprintf("%.3f", $item->{dist}) %>
201 </td>
202 </tr>
203 % }
204 </table>
205 % }
Marc Kupietzdc22b982015-10-09 09:19:34 +0200206</body>
207</html>
208