ゼロから作るDeep Learning
1層ニューラルネットワークの実装(バイアスなし、活性化関数なし、学習なし)
昨今注目を集めているAI(人工知能)を学びたいと思い立ち、ディープラーニング(Deep Learning、深層学習)と呼ばれるAIの数理モデルである多層構造のニューラルネットワークを書籍「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」を参考にを独習していきたいと思います。本書籍ではプログラミング言語としてPythonが利用されていますが、本項ではJavaScriptで実装していきます。
目次
- 準備1:行列の和と積を計算する関数の実装
- 準備2:ベクトルと行列の積を計算する関数の実装
- 準備3:多変数関数の数値微分と極小値の探索
- 1.1層ニューラルネットワークの実装(バイアスなし、活性化関数なし、学習なし)
- 2.1層ニューラルネットワークへのバイアスと活性化関数の追加
- 3.1n1型2層ニューラルネットワークの実装(学習なし)
- 4.1変数関数を学習させてみる1:勾配法による学習計算アルゴリズム
- 5.1変数関数を学習させてみる2:勾配法による学習計算アルゴリズムの実装
- 6.1変数関数を学習させてみる3:ニューロン数による学習効果の違い
- 7.誤差逆伝搬法(バックプロパゲーション)の導出
- 8.順伝播型ニューラルネットワーク「FFNNクラス」の実装(JavaScript)
- 9.三角関数のサンプリング学習(WebWorkersによる並列計算)
- 10.学習後の各層ニューロンの重みの可視化
- 11.層数とニューロン数による学習効果の違い
1層ニューラルネットワーク(バイアスなし、活性化関数なし、学習なし)のモデル
書籍「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」のp.60の1層ニューラルネットワークのモデルを示します。
ただし、書籍では重みを表すWの層番号を表すインデックスが次の層を表しますが、上記のモデルでは前の層を表します。 このように定義することでプログラミング時に重みを表す多重配列「W」のインデックスを0からスタートすることができてミスを減らすことができます。
計算アルゴリズム
上記のモデルにおける入力層(0層目)に対する出力層(1層目)のニューロン値は次の計算式で与えられます。
この関係式を行列で表すと次の2通りあります。
各層のニューロンを上段は縦ベクトル、下段は横ベクトルで表している点が異なります。この違いによって重み行列の縦横が反転(転置)して、積算の順番が反対になっています。
両者は本質的には同じですので、どちらの形式でも好きな方を利用することができます。書籍では後者(横ベクトル)を採用していますが、本項では前者(縦ベクトル)を採用します。
(縦ベクトルを採用するとベクトルに積算する重み行列の成分が行(一行)となるので、横ベクトル時よりもプログラミングが直感的となるためです。)
JavaScriptによる実装
各層のニューロンを表すXと各層をつなぐ重みを表すWはモデルに合わせて多重配列X[n][i]とW[n][i][j]で定義します。 上記のモデルに則したニューラルネットワークをNNクラスとして定義します。コンストラクタの引数で重みW(多重配列)を与えます。 ニューラルネットワークの層数はWの第一要素数、各層でのニューロン数はWの第二要素数で決まります。
//ニューラルネットワーク var NN = function( W ){ this.W = W; //W.length : 層数 //W[].length : 列(後ニューロン数) //W[][].length : 行(前ニューロン数) this.X = []; for( var i = 0; i < W.length; i++ ){ this.X[ i ] = []; for( var j = 0; j < W[ i ][ 0 ].length; j++ ){ this.X[ i ][ j ] = 0; } } //出力層 this.X[ W.length ] = []; for( var j = 0; j < W[ W.length-1 ].length; j++ ){ this.X[ W.length ][ j ] = 0; } } //入力層(0層目ニューロン値)へのインプット NN.prototype.setInput = function( Input ){ for( var i = 0; i < Input.length; i++ ){ this.X[ 0 ][ i ] = Input[ i ]; } } //出力層へのアウトプット NN.prototype.getOutput = function(){ for( var i = 0; i < W.length; i++ ){ this.multiplayMatrixVector ( this.W[ i ], this.X[ i ], this.X[ i+1 ] ); } return this.X[ this.X.length -1 ]; } //行列×ベクトルの計算 NN.prototype.multiplayMatrixVector = function( M, V, C ){ C = C || []; var Mgyou = M[ 0 ].length; var Mretu = M.length; for( var i = 0; i < Mretu; i++ ){ C[ i ] =0; for( var j = 0; j < Mgyou; j++ ){ C[ i ] += M[ i ][ j ] * V[ j ]; } } return C; }
計算チェック
上記のNNクラスに次の重みを与えて計算して、コンソール(「F12」で表示)に出力します。 入力 [1,2,3] に対して [0.6, 1.2] が出力されます。
//各層ニューロンの値 X0 = [ 1, 2, 3 ]; //重み var W = []; W[ 0 ] = [ [ 0.1, 0.1, 0.1 ], //W^{(0)}_{00}, W^{(0)}_{01}, W^{(0)}_{02} [ 0.2, 0.2, 0.2 ] //W^{(0)}_{10}, W^{(0)}_{10}, W^{(0)}_{12} ]; //ニューラルネットワークの生成 var nn = new NN( W ); //入力層へのインプット nn.setInput( X0 ); //出力層へのアウトプット nn.getOutput(); //結果の表示 console.log( nn.X ); //出力[ 0.6, 1.2 ]