ゼロから作るDeep Learning
1n1型2層ニューラルネットワークの実装(学習なし)
昨今注目を集めている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層挟み込まれたモデルを考えます。 その中でも元も単純な入力層と出力層のニューロンが1つ、挟み込まれた1層(隠れ層)のニューロンがn個のモデルを想定します(「1n1型」ニューラルネットワークと呼ぶことにします)。 このモデルを用いて次項では任意の関数を学習させてみます。
計算アルゴリズム
上記のモデルにおける入力層(0層目)に対する隠れ層(1層目)と出力層(2層目)のニューロン値は次の計算式で与えられます。
JavaScriptによる実装
上記のモデルに対応したニューラルネットワークをコンストラクタの第二引数にバイアス、第三引数に隠れ層の活性化関数、第四引数に出力層の活性化関数を与えることでNNクラスを定義します。
//ニューラルネットワーク var NN = function( W, B, h, sigma ){ //重み this.W = W; //W.length : 層数 //W[].length : 列(後ニューロン数) //W[][].length : 行(前ニューロン数) //バイアス this.B = B; //活性化関数 this.h = h; this.sigma = sigma; //ニューロンの初期化 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 ] ); this.addVectors ( this.X[ i+1 ], this.B[ i ], this.X[ i+1 ] ); //活性化関数の実行 if( i<W.length-1 ){ //隠れ層 this.adoptAFh( this.X[ i+1 ], this.X[ i+1 ] ); } else { //出力層 this.adoptAFsigma( this.X[ i+1 ], this.X[ i+1 ] ); } } return this.X[ this.X.length -1 ]; } //行列×ベクトルの計算 NN.prototype.multiplayMatrixVector = function( M, V, C ){ C = C || []; var Mgyou = M.length; var Mretu = M[ 0 ].length; for( var i = 0; i < Mgyou; i++ ){ C[ i ] =0; for( var j = 0; j < Mretu; j++ ){ C[ i ] += M[ i ][ j ] * V[ j ]; } } return C; } //ベクトルの和 NN.prototype.addVectors = function( V1, V2, V3 ){ V3 = V3 || []; for( var i = 0; i < V1.length; i++ ){ V3[ i ] = V1[ i ] + V2[ i ]; } return V3; } //活性化関数の実行 NN.prototype.adoptAFh = function( V_in, V_out ){ V_out = V_out || []; for( var i = 0; i < V_in.length; i++ ){ V_out[ i ] = this.h( V_in[ i ] ); } return V_out; } NN.prototype.adoptAFsigma = function( V_in, V_out ){ V_out = V_out || []; for( var i = 0; i < V_in.length; i++ ){ V_out[ i ] = this.sigma( V_in[ i ] ); } return V_out; }
計算チェック
第1層(隠れ層)のニューロン数を指定すると、それに必要な重みとバイアスを多重配列を生成して、-0.5から0.5まで値をランダムに与えます。 なお、隠れ層と出力層に与える活性化関数にはReLU関数と恒等関数をそれぞれ与えています(「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」p.71まで)。入力層(ニューロン1個)へのインプットを1としてコンソール(「F12」で表示)に出力します。
//第1層のニューロン数 var N1 = 10; //入力層 var X0 = [ 1 ]; //重み var W = []; W[ 0 ] = [];//0層目→1層目 for( var i = 0; i < N1; i++){ var w = Math.random() - 0.5; W[ 0 ][ i ] = [ w ]; //W^{(0)}_i0 } W[ 1 ] = [];//1層目→2層目 W[ 1 ][ 0 ] = []; for( var i = 0; i < N1; i++){ var w = Math.random() - 0.5; W[ 1 ][ 0 ][ i ] = w; //W^{(1)}_0i } //バイアス var B = []; B[ 0 ] = []; for( var i = 0; i < N1; i++){ var b = Math.random() - 0.5; B[ 0 ][ i ] = b; //b^{(0)}_i } B[ 1 ] = [ 0 ]; //b^{(1)}_0 //活性化関数(ReLU関数) var h = function( x ){ if( x >= 0 ) return x; else return 0; } //活性化関数(恒等関数) var sigma = function( x ){ return x; } //ニューラルネットワークの生成 var nn = new NN( W, B, h, sigma ); //入力層へのインプット nn.setInput( X0 ); //出力層へのアウトプット nn.getOutput(); //結果の表示 console.log( nn.X[2] );