質問編集履歴
1
最初の質問時には、tensorflow.jsを使用していました。今ではtensorflow.jsを使用していません。
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
console.log()で表示される値が、それより下の行の関数の有無によってNaNになるか否かが変わるのがなぜなのか、教えていただきたいです。
|
test
CHANGED
@@ -2,17 +2,37 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
-
JavaScript
|
5
|
+
JavaScriptを使い、word2vecを作ろうとしています。
|
6
|
+
|
6
|
-
|
7
|
+
console.log()で表示される内容が、それよりも下の行に、とある自作の関数があるかないかで変わってしまいます。
|
8
|
+
|
7
|
-
|
9
|
+
その関数がある場合には要素がすべてNaNになった配列が、その関数がない場合には意図したとおりの数字を要素とした配列が、console.log()で表示されます。
|
10
|
+
|
11
|
+
|
12
|
+
|
8
|
-
|
13
|
+
> console.log(w1);
|
14
|
+
|
15
|
+
console.log(w2);
|
16
|
+
|
17
|
+
document.write(w1)
|
18
|
+
|
19
|
+
document.write('<br>↑w1<br>')
|
20
|
+
|
21
|
+
document.write(w2)
|
22
|
+
|
23
|
+
document.write('<br>↑w2<br>')
|
24
|
+
|
25
|
+
trainWord() //26行をコメントアウトすると、w1,w2がconsole.log()上でNaNになることがない。trainWordの奥深く、94行だけをコメントアウトしても、w1,w2がconsole.log()上でNaNになることがない。
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
下記のソースコード26行目(trainWord())をコメントアウトするとw1,w2がconsole.log()でもdocument.write()でも意図したとおりの数字を表示します。
|
30
|
+
|
9
|
-
o
|
31
|
+
26行目があると、w1,w2がconsole.log()上で要素がNaNになります。しかし、document.write()では意図した数字を表示します。
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
32
|
+
|
14
|
-
|
33
|
+
|
34
|
+
|
15
|
-
|
35
|
+
trainWord()関数がそれより上の行のconsole.log()の結果に干渉しているのはなぜなのか、教えていただきたいです。
|
16
36
|
|
17
37
|
|
18
38
|
|
@@ -38,143 +58,269 @@
|
|
38
58
|
|
39
59
|
<button type="button" class="controler" id="start" onclick="startClicked()">Start</button>
|
40
60
|
|
41
|
-
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
|
42
|
-
|
43
61
|
|
44
62
|
|
45
63
|
<script>
|
46
64
|
|
65
|
+
|
66
|
+
|
67
|
+
//startボタンを押すと、テキストエリアの内容について、辞書化から教育までが、行われる。
|
68
|
+
|
69
|
+
function startClicked(){
|
70
|
+
|
71
|
+
text = document.getElementById('enterYourCode').value;
|
72
|
+
|
73
|
+
makeDictionary(text);
|
74
|
+
|
75
|
+
makeVectoredText();
|
76
|
+
|
77
|
+
oneHotVector = makeOneHotVector(dictionary.length);
|
78
|
+
|
79
|
+
w1 = createW(dictionary.length, hiddenSize);
|
80
|
+
|
81
|
+
w2 = createW(hiddenSize, dictionary.length);
|
82
|
+
|
83
|
+
console.log(w1);
|
84
|
+
|
85
|
+
console.log(w2);
|
86
|
+
|
87
|
+
document.write(w1)
|
88
|
+
|
89
|
+
document.write('<br>↑w1<br>')
|
90
|
+
|
91
|
+
document.write(w2)
|
92
|
+
|
93
|
+
document.write('<br>↑w2<br>')
|
94
|
+
|
95
|
+
trainWord() //26行をコメントアウトすると、w1,w2がconsole.log()上でNaNになることがない。trainWordの奥深く、94行だけをコメントアウトしても、w1,w2がconsole.log()上でNaNになることがない。
|
96
|
+
|
97
|
+
};
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
//基本的な関数の宣言
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
//合計
|
110
|
+
|
111
|
+
var sum = function(arr) {
|
112
|
+
|
113
|
+
return arr.reduce(function(prev, current, i, arr) {
|
114
|
+
|
115
|
+
return prev+current;
|
116
|
+
|
117
|
+
});
|
118
|
+
|
119
|
+
};
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
//行列の積
|
124
|
+
|
125
|
+
function dot(a, b) {
|
126
|
+
|
127
|
+
var aNumRows = a.length
|
128
|
+
|
129
|
+
var aNumCols = a[0].length
|
130
|
+
|
131
|
+
var bNumRows = b.length
|
132
|
+
|
133
|
+
var bNumCols = b[0].length
|
134
|
+
|
135
|
+
m = new Array(aNumRows); // initialize array of rows
|
136
|
+
|
137
|
+
for (var r = 0; r < aNumRows; ++r) {
|
138
|
+
|
139
|
+
m[r] = new Array(bNumCols); // initialize the current row
|
140
|
+
|
141
|
+
for (var c = 0; c < bNumCols; ++c) {
|
142
|
+
|
143
|
+
m[r][c] = 0; // initialize the current cell
|
144
|
+
|
145
|
+
for (var i = 0; i < aNumCols; ++i) {
|
146
|
+
|
147
|
+
m[r][c] += a[r][i] * b[i][c];
|
148
|
+
|
149
|
+
}
|
150
|
+
|
151
|
+
}
|
152
|
+
|
153
|
+
}
|
154
|
+
|
155
|
+
return m;
|
156
|
+
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
//ソフトマックス関数
|
162
|
+
|
163
|
+
function softMax(array){
|
164
|
+
|
165
|
+
return array.map(element => Math.exp(element)/sum(array.map(element => Math.exp(element))))
|
166
|
+
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
//w1で使用するランダムな重みを作るための関数
|
172
|
+
|
173
|
+
function rnorm(){
|
174
|
+
|
175
|
+
return Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random());
|
176
|
+
|
177
|
+
}
|
178
|
+
|
179
|
+
|
180
|
+
|
47
181
|
//各種変数の宣言
|
48
182
|
|
49
|
-
var hiddenSize = 300
|
50
|
-
|
51
|
-
var text = undefined
|
52
|
-
|
53
|
-
var dictionary = undefined
|
54
|
-
|
55
|
-
var textSplit = undefined
|
56
|
-
|
57
|
-
var oneHotVector = null
|
58
|
-
|
59
|
-
var w1 = undefined
|
60
|
-
|
61
|
-
var w2 = undefined
|
62
|
-
|
63
|
-
var vectoredText = undefined
|
64
|
-
|
65
|
-
const
|
66
|
-
|
67
|
-
const
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
183
|
+
var hiddenSize = 3; //隠れ層の数。本来は300
|
184
|
+
|
185
|
+
var text = undefined //もととなる文章
|
186
|
+
|
187
|
+
var dictionary = undefined //文章に出てきた単語から、重複するものを除いたもの
|
188
|
+
|
189
|
+
var textSplit = undefined //もととなる文章を、単語ごとの区切りで配列にしたもの
|
190
|
+
|
191
|
+
var oneHotVector = null //辞書に表れる単語を、ワンホットベクトルで表したもの
|
192
|
+
|
193
|
+
var w1 = undefined //1層目の重み
|
194
|
+
|
195
|
+
var w2 = undefined //2層目の重み
|
196
|
+
|
197
|
+
var vectoredText = undefined //単語で区切った文章を、ワンホットベクトル上のインデックスで表したもの
|
198
|
+
|
199
|
+
const learningRate = 0.01; //学習率
|
200
|
+
|
201
|
+
const epsilon = 0.00100000001; //微分に使用する極めて小さい数
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
function predict(foo,weight1,weight2){//foo には anIndex が入る予定
|
208
|
+
|
209
|
+
let b = []
|
210
|
+
|
211
|
+
b[0]= oneHotVector[vectoredText[foo]]
|
212
|
+
|
213
|
+
let inputToHidden = dot(b,weight1);
|
214
|
+
|
215
|
+
let HiddenToOutput = dot(inputToHidden,weight2)
|
216
|
+
|
217
|
+
return softMax(HiddenToOutput[0])
|
218
|
+
|
219
|
+
}
|
220
|
+
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
function loss(foo,logits){//foo には anIndex が入る予定, logits には predict()が入る予定
|
226
|
+
|
227
|
+
let resultVector = oneHotVector[vectoredText[foo]].map(x => x)
|
228
|
+
|
229
|
+
for(let i = 0; i<resultVector.length; i = i+1){
|
230
|
+
|
231
|
+
resultVector[i] = resultVector[i]*Math.log(logits[i]) //94行をコメントアウトすると、console.log()でw1,w2がNaNになることがない。
|
232
|
+
|
233
|
+
}
|
234
|
+
|
235
|
+
return -1*sum(resultVector)};
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
//入力されたテキストから、1回の単語が1回のみ表れる辞書を作る。ただし、所有格の’sは' `s'として、1つの単語として扱う。
|
240
|
+
|
241
|
+
function makeDictionary(){
|
242
|
+
|
243
|
+
let aposS = /'s/g;
|
244
|
+
|
245
|
+
let regex = /.|'|"|\,/g;
|
246
|
+
|
247
|
+
textSplit = text.toLowerCase().replace(aposS,' `s').replace(regex,' ').split(' ');
|
248
|
+
|
249
|
+
dictionary =[]
|
250
|
+
|
251
|
+
for(let i = 0; i < textSplit.length ; i = i+1){
|
252
|
+
|
253
|
+
if(dictionary.includes(textSplit[i])){
|
254
|
+
|
255
|
+
let j = textSplit.length;
|
256
|
+
|
257
|
+
textSplit = textSplit.filter(arg => arg !=textSplit[i]);
|
258
|
+
|
259
|
+
i = i - (j-textSplit.length);
|
260
|
+
|
261
|
+
} else {
|
262
|
+
|
263
|
+
dictionary.push(textSplit[i]);
|
264
|
+
|
265
|
+
};
|
266
|
+
|
267
|
+
};
|
268
|
+
|
269
|
+
return null;
|
80
270
|
|
81
271
|
}
|
82
272
|
|
83
273
|
|
84
274
|
|
85
|
-
//
|
275
|
+
//辞書に対応するワンホットベクトルを、対角成分が1の対角行列として作る
|
86
|
-
|
276
|
+
|
87
|
-
function make
|
277
|
+
function makeOneHotVector(number){
|
88
|
-
|
278
|
+
|
89
|
-
let a
|
279
|
+
let matrix= [...Array(number)]
|
90
|
-
|
91
|
-
|
280
|
+
|
92
|
-
|
93
|
-
textSplit = text.toLowerCase().replace(aposS,' `s').replace(regex,' ').split(' ');
|
94
|
-
|
95
|
-
dictionary =[]
|
96
|
-
|
97
|
-
for(let i = 0; i <
|
281
|
+
for(let i = 0; i < number; i = i +1){
|
98
|
-
|
99
|
-
|
282
|
+
|
100
|
-
|
101
|
-
let j = textSplit.length
|
102
|
-
|
103
|
-
|
283
|
+
matrix[i] = [...Array(number)].map(arg => 0);
|
104
|
-
|
105
|
-
|
284
|
+
|
106
|
-
|
107
|
-
} else {
|
108
|
-
|
109
|
-
|
285
|
+
matrix[i][i] = 1;
|
110
|
-
|
111
|
-
};
|
112
286
|
|
113
287
|
};
|
114
288
|
|
289
|
+
return matrix;
|
290
|
+
|
291
|
+
};
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
//テキストに現れる単語を、その単語の辞書内でのインデックスに突き合わせることで、テキストをもとにしたベクトルを作る。
|
296
|
+
|
297
|
+
function makeVectoredText(){
|
298
|
+
|
299
|
+
vectoredText = []
|
300
|
+
|
301
|
+
textSplit.forEach(element => vectoredText.push(dictionary.indexOf(element)));
|
302
|
+
|
115
303
|
return null;
|
116
304
|
|
117
305
|
}
|
118
306
|
|
119
307
|
|
120
308
|
|
121
|
-
//
|
309
|
+
//インプットサイズ(is)とアウトプットサイズ(os)をもとに、重みを表現する行列を作る。
|
122
|
-
|
310
|
+
|
123
|
-
function
|
311
|
+
function createW(inputSize, outputSize){
|
124
|
-
|
125
|
-
|
312
|
+
|
126
|
-
|
127
|
-
for(let i = 0; i < number; i = i +1){
|
128
|
-
|
129
|
-
|
313
|
+
return [...Array(inputSize)].map(() => [...Array(outputSize)].map(() => rnorm()/Math.sqrt(inputSize)));
|
130
|
-
|
131
|
-
matrix[i][i] = 1;
|
132
314
|
|
133
315
|
};
|
134
316
|
|
135
|
-
return matrix;
|
136
|
-
|
137
|
-
};
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
//テキストに現れる単語を、その単語の辞書内でのインデックスに突き合わせることで、テキストをもとにしたベクトルを作る。
|
142
|
-
|
143
|
-
function makeVectoredText(){
|
144
|
-
|
145
|
-
vectoredText = []
|
146
|
-
|
147
|
-
textSplit.forEach(element => vectoredText.push(dictionary.indexOf(element)));
|
148
|
-
|
149
|
-
return null;
|
150
|
-
|
151
|
-
}
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
//インプットサイズ(is)とアウトプットサイズ(os)をもとに、重みを表現する行列を作る。
|
156
|
-
|
157
|
-
function createW(is, os){
|
158
|
-
|
159
|
-
let matrix= [...Array(is)]
|
160
|
-
|
161
|
-
for(let i = 0; i < is; i = i +1){
|
162
|
-
|
163
|
-
matrix[i] = [...Array(os)].map(() => rnorm()/Math.sqrt(is));
|
164
|
-
|
165
|
-
};
|
166
|
-
|
167
|
-
return tf.variable(tf.tensor(matrix));
|
168
|
-
|
169
|
-
};
|
170
|
-
|
171
317
|
|
172
318
|
|
173
319
|
//textの(実際にはvectoredTextの)最初の単語から、windowサイズ5で、教育を行う。
|
174
320
|
|
175
321
|
function trainWord(){
|
176
322
|
|
177
|
-
for(i=0; i <= vectoredText.length-1 ; i= i+1){
|
323
|
+
for(let i=0; i <= vectoredText.length-1 ; i= i+1){
|
178
324
|
|
179
325
|
// target = makeOneHotVector[vectoredText[i]]
|
180
326
|
|
@@ -184,27 +330,65 @@
|
|
184
330
|
|
185
331
|
for(anIndex of indicesAroundTarget){
|
186
332
|
|
333
|
+
|
334
|
+
|
335
|
+
let copyOfW1 = w1.map(x => x);
|
336
|
+
|
337
|
+
let copyOfW2 = w2.map(x => x);
|
338
|
+
|
339
|
+
let newW1 = w1.map(x => x);
|
340
|
+
|
341
|
+
let newW2 = w2.map(x => x);
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
|
346
|
+
|
347
|
+
afterThen();
|
348
|
+
|
349
|
+
w1 = newW1.map(x => x);
|
350
|
+
|
351
|
+
w2 = newW2.map(x => x);
|
352
|
+
|
353
|
+
|
354
|
+
|
355
|
+
function afterThen(){
|
356
|
+
|
187
|
-
/
|
357
|
+
//w1の学習
|
188
|
-
|
189
|
-
|
358
|
+
|
190
|
-
|
191
|
-
document.write(tf.tensor(oneHotVector[vectoredText[anIndex]]).dot(w1).dot(w2).softmax()+'<br>')
|
192
|
-
|
193
|
-
|
359
|
+
for(let j = 0; j < newW1.length; j = j+1){
|
194
|
-
|
195
|
-
|
360
|
+
|
196
|
-
|
197
|
-
document.write(loss(predict(anIndex), oneHotVector[vectoredText[i]])+' is loss(predict(anIndex), oneHotVector[vectoredText[i]])<br>')
|
198
|
-
|
199
|
-
|
361
|
+
for(let k = 0; k < newW1[j].length; k = k+1){
|
362
|
+
|
200
|
-
|
363
|
+
let interimW1 = w1.map(x => x);
|
364
|
+
|
365
|
+
interimW1[j][k] = interimW1[j][k]+epsilon;
|
366
|
+
|
367
|
+
newW1[j][k] = interimW1[j][k]-learningRate*( loss(anIndex,predict(anIndex,interimW1,w2) - loss(anIndex,predict(anIndex,w1,w2))))/epsilon;
|
368
|
+
|
369
|
+
}
|
370
|
+
|
371
|
+
}
|
372
|
+
|
373
|
+
//w2の学習
|
374
|
+
|
375
|
+
for(let j = 0; j < newW2.length; j = j+1){
|
376
|
+
|
201
|
-
|
377
|
+
for(let k = 0; k < newW2[j].length; k = k+1){
|
202
|
-
|
378
|
+
|
203
|
-
|
379
|
+
let interimW2 = w2.map(x => x);
|
204
|
-
|
380
|
+
|
205
|
-
|
381
|
+
interimW2[j][k] = interimW2[j][k]+epsilon;
|
206
|
-
|
382
|
+
|
207
|
-
|
383
|
+
newW2[j][k] = interimW2[j][k]-learningRate*( loss(anIndex,predict(anIndex,w1,interimW2) - loss(anIndex,predict(anIndex,w1,w2))))/epsilon;
|
384
|
+
|
385
|
+
}
|
386
|
+
|
387
|
+
}
|
388
|
+
|
389
|
+
return null
|
390
|
+
|
391
|
+
}
|
208
392
|
|
209
393
|
}
|
210
394
|
|
@@ -214,34 +398,6 @@
|
|
214
398
|
|
215
399
|
|
216
400
|
|
217
|
-
|
218
|
-
|
219
|
-
//startボタンを押すと、テキストエリアの内容について、辞書化から教育までが、行われる。
|
220
|
-
|
221
|
-
function startClicked(){
|
222
|
-
|
223
|
-
text = document.getElementById('enterYourCode').value
|
224
|
-
|
225
|
-
makeDictionary(text);
|
226
|
-
|
227
|
-
makeVectoredText()
|
228
|
-
|
229
|
-
oneHotVector = makeOneHotVector(dictionary.length)
|
230
|
-
|
231
|
-
//hidden layer size = 300
|
232
|
-
|
233
|
-
w1 = createW(dictionary.length, hiddenSize)
|
234
|
-
|
235
|
-
w2 = createW(hiddenSize, dictionary.length)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
trainWord()
|
240
|
-
|
241
|
-
};
|
242
|
-
|
243
|
-
|
244
|
-
|
245
401
|
</script>
|
246
402
|
|
247
403
|
|
@@ -250,6 +406,4 @@
|
|
250
406
|
|
251
407
|
</html>
|
252
408
|
|
253
|
-
|
254
|
-
|
255
409
|
```
|