🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

828閲覧

console.log()で表示される値が、それより下の行の関数の有無によってNaNになるか否かが変わるのがなぜなのか、教えていただきたいです。

TakeshiSue

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/11/28 14:47

編集2020/12/02 15:07

前提・実現したいこと

JavaScriptを使い、word2vecを作ろうとしています。
console.log()で表示される内容が、それよりも下の行に、とある自作の関数があるかないかで変わってしまいます。
その関数がある場合には要素がすべてNaNになった配列が、その関数がない場合には意図したとおりの数字を要素とした配列が、console.log()で表示されます。

console.log(w1);

console.log(w2);
document.write(w1)
document.write('<br>↑w1<br>')
document.write(w2)
document.write('<br>↑w2<br>')
trainWord() //26行をコメントアウトすると、w1,w2がconsole.log()上でNaNになることがない。trainWordの奥深く、94行だけをコメントアウトしても、w1,w2がconsole.log()上でNaNになることがない。

下記のソースコード26行目(trainWord())をコメントアウトするとw1,w2がconsole.log()でもdocument.write()でも意図したとおりの数字を表示します。
26行目があると、w1,w2がconsole.log()上で要素がNaNになります。しかし、document.write()では意図した数字を表示します。

trainWord()関数がそれより上の行のconsole.log()の結果に干渉しているのはなぜなのか、教えていただきたいです。

該当のソースコード

html

1<!DOCTYPE html> 2<html> 3<head> 4 <title>word2vec</title> 5</head> 6<body> 7<textarea id="enterYourCode">Enter your text here.</textarea> 8<button type="button" class="controler" id="start" onclick="startClicked()">Start</button> 9 10<script> 11 12//startボタンを押すと、テキストエリアの内容について、辞書化から教育までが、行われる。 13function startClicked(){ 14 text = document.getElementById('enterYourCode').value; 15 makeDictionary(text); 16 makeVectoredText(); 17 oneHotVector = makeOneHotVector(dictionary.length); 18 w1 = createW(dictionary.length, hiddenSize); 19 w2 = createW(hiddenSize, dictionary.length); 20 console.log(w1); 21 console.log(w2); 22 document.write(w1) 23 document.write('<br>↑w1<br>') 24 document.write(w2) 25 document.write('<br>↑w2<br>') 26 trainWord() //26行をコメントアウトすると、w1,w2がconsole.log()上でNaNになることがない。trainWordの奥深く、94行だけをコメントアウトしても、w1,w2がconsole.log()上でNaNになることがない。 27}; 28 29 30 31//基本的な関数の宣言 32 33//合計 34var sum = function(arr) { 35 return arr.reduce(function(prev, current, i, arr) { 36 return prev+current; 37 }); 38}; 39 40//行列の積 41function dot(a, b) { 42 var aNumRows = a.length 43 var aNumCols = a[0].length 44 var bNumRows = b.length 45 var bNumCols = b[0].length 46 m = new Array(aNumRows); // initialize array of rows 47 for (var r = 0; r < aNumRows; ++r) { 48 m[r] = new Array(bNumCols); // initialize the current row 49 for (var c = 0; c < bNumCols; ++c) { 50 m[r][c] = 0; // initialize the current cell 51 for (var i = 0; i < aNumCols; ++i) { 52 m[r][c] += a[r][i] * b[i][c]; 53 } 54 } 55 } 56 return m; 57} 58 59//ソフトマックス関数 60function softMax(array){ 61 return array.map(element => Math.exp(element)/sum(array.map(element => Math.exp(element)))) 62} 63 64//w1で使用するランダムな重みを作るための関数 65function rnorm(){ 66 return Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random()); 67} 68 69//各種変数の宣言 70var hiddenSize = 3; //隠れ層の数。本来は300 71var text = undefined //もととなる文章 72var dictionary = undefined //文章に出てきた単語から、重複するものを除いたもの 73var textSplit = undefined //もととなる文章を、単語ごとの区切りで配列にしたもの 74var oneHotVector = null //辞書に表れる単語を、ワンホットベクトルで表したもの 75var w1 = undefined //1層目の重み 76var w2 = undefined //2層目の重み 77var vectoredText = undefined //単語で区切った文章を、ワンホットベクトル上のインデックスで表したもの 78const learningRate = 0.01; //学習率 79const epsilon = 0.00100000001; //微分に使用する極めて小さい数 80 81 82function predict(foo,weight1,weight2){//foo には anIndex が入る予定 83 let b = [] 84 b[0]= oneHotVector[vectoredText[foo]] 85 let inputToHidden = dot(b,weight1); 86 let HiddenToOutput = dot(inputToHidden,weight2) 87 return softMax(HiddenToOutput[0]) 88 } 89 90 91function loss(foo,logits){//foo には anIndex が入る予定, logits には predict()が入る予定 92 let resultVector = oneHotVector[vectoredText[foo]].map(x => x) 93 for(let i = 0; i<resultVector.length; i = i+1){ 94 resultVector[i] = resultVector[i]*Math.log(logits[i]) //94行をコメントアウトすると、console.log()でw1,w2がNaNになることがない。 95 } 96 return -1*sum(resultVector)}; 97 98//入力されたテキストから、1回の単語が1回のみ表れる辞書を作る。ただし、所有格の’sは' `s'として、1つの単語として扱う。 99function makeDictionary(){ 100 let aposS = /'s/g; 101 let regex = /.|'|"|\,/g; 102 textSplit = text.toLowerCase().replace(aposS,' `s').replace(regex,' ').split(' '); 103 dictionary =[] 104 for(let i = 0; i < textSplit.length ; i = i+1){ 105 if(dictionary.includes(textSplit[i])){ 106 let j = textSplit.length; 107 textSplit = textSplit.filter(arg => arg !=textSplit[i]); 108 i = i - (j-textSplit.length); 109 } else { 110 dictionary.push(textSplit[i]); 111 }; 112 }; 113 return null; 114} 115 116//辞書に対応するワンホットベクトルを、対角成分が1の対角行列として作る 117function makeOneHotVector(number){ 118 let matrix= [...Array(number)] 119 for(let i = 0; i < number; i = i +1){ 120 matrix[i] = [...Array(number)].map(arg => 0); 121 matrix[i][i] = 1; 122 }; 123 return matrix; 124 }; 125 126//テキストに現れる単語を、その単語の辞書内でのインデックスに突き合わせることで、テキストをもとにしたベクトルを作る。 127function makeVectoredText(){ 128 vectoredText = [] 129 textSplit.forEach(element => vectoredText.push(dictionary.indexOf(element))); 130 return null; 131} 132 133//インプットサイズ(is)とアウトプットサイズ(os)をもとに、重みを表現する行列を作る。 134function createW(inputSize, outputSize){ 135 return [...Array(inputSize)].map(() => [...Array(outputSize)].map(() => rnorm()/Math.sqrt(inputSize))); 136 }; 137 138//textの(実際にはvectoredTextの)最初の単語から、windowサイズ5で、教育を行う。 139function trainWord(){ 140 for(let i=0; i <= vectoredText.length-1 ; i= i+1){ 141 // target = makeOneHotVector[vectoredText[i]] 142 let indicesAroundTarget = [i-5,i-4,i-3,i-2,i-1,i+1,i+2,i+3,i+4,i+5].filter(element => element>0 && element < vectoredText.length); 143 144 for(anIndex of indicesAroundTarget){ 145 146 let copyOfW1 = w1.map(x => x); 147 let copyOfW2 = w2.map(x => x); 148 let newW1 = w1.map(x => x); 149 let newW2 = w2.map(x => x); 150 151 152 afterThen(); 153 w1 = newW1.map(x => x); 154 w2 = newW2.map(x => x); 155 156 function afterThen(){ 157 //w1の学習 158 for(let j = 0; j < newW1.length; j = j+1){ 159 for(let k = 0; k < newW1[j].length; k = k+1){ 160 let interimW1 = w1.map(x => x); 161 interimW1[j][k] = interimW1[j][k]+epsilon; 162 newW1[j][k] = interimW1[j][k]-learningRate*( loss(anIndex,predict(anIndex,interimW1,w2) - loss(anIndex,predict(anIndex,w1,w2))))/epsilon; 163 } 164 } 165 //w2の学習 166 for(let j = 0; j < newW2.length; j = j+1){ 167 for(let k = 0; k < newW2[j].length; k = k+1){ 168 let interimW2 = w2.map(x => x); 169 interimW2[j][k] = interimW2[j][k]+epsilon; 170 newW2[j][k] = interimW2[j][k]-learningRate*( loss(anIndex,predict(anIndex,w1,interimW2) - loss(anIndex,predict(anIndex,w1,w2))))/epsilon; 171 } 172 } 173 return null 174 } 175 } 176 } 177}; 178 179</script> 180 181</body> 182</html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

「該当のソースコード」は、問題となる行がコメントアウトされていないので、そのまま実行した場合は「要素がすべてNaNになった配列」が出力される、という認識で合っていますでしょうか?

「該当のソースコード」をそのままオンライン上で動かしてみましたが、「要素がすべてNaNになった配列」は出力されませんでした。
jsfiddleで動かしてみたもの

また、コピペしてローカルに作ったhtmlでも実行してみましたが、「要素がすべてNaNになった配列」は出力されませんでした。

最初のテキストエリアの入力を、デフォルトの「Enter your text here.」のままstartボタンを押しているのですが、現象を再現させるのに必要な入力値がありますでしょうか?

投稿2020/12/08 12:38

yamekodev

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakeshiSue

2020/12/09 11:00

現象を再現させるのに必要な入力値はありません。デフォルトの「Enter your text here.」で、自分の環境だとNaNが発生します。 Windows 10でGoogleChromeを使用しています。 JSFiddleという便利なサービスを、初めて知りました。JSFiddleではNaNが発生しないので、引き続きJSFiddleで作成を続けていきたいと思います。
yamekodev

2020/12/10 00:42

取り急ぎjsfiddleで作業を続けられるとのこと、承知しました。 私の環境もWin10+chromeなので、何か見えていない別要因があるのだと思いますが、ちょっと思い当たる点がありません。 もし、今後この問題の原因と対策が判明した場合、かつ、teratailに質問したことを思い出されたときは、お手数ですが、この質問へセルフ回答する形で情報を頂けたら幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問