ニューラルネットワークの実装

math.jsを用いたニューラルネットワーク(NN)の実装例として三層のNNを構築した。

ニューラルネットワークの基本的構造

NNはn次元のデータを入力とし、m次元の結果として出力する処理機構である。 その内容は行列演算による線形変換と、活性化関数による非線形変換によって構成される。 NNのある一層における演算は次のような式で書ける。

\[ L^a_b: X^j\mapsto Z^i=f(W^i_j X^j + B^i) \]

(写像$L$は抽象添字記法を用いてテンソル記法で表した。)
ここで$W$は$X$にかかる行列で$m\times n$の成分を持ち、 $B$はバイアスベクトルで$m$成分を持つ。 $f$は活性化関数と呼ばれる任意の実関数であり、 シグモイド関数のような非線形なものを用いる。 このようにNNの一層はアフィン変換に活性化関数を噛ませたものとなっている。 活性化関数を除けば、1レイヤーにつき$n\times m + m$の実数パラメータ自由度がある。

NN全体はこの操作を繰り返すことで構成され、その回数は隠れ層の数と呼ばれる。 入力ベクトルを$X$とすれば上で定義した写像$L$から全体のNNは次のように書くことができる。

\[ (\text{NN})=L^{a_N}_{a_{N-1}}\cdots L^{a_2}_{a_1}L^{a_1}_{a_0} : X^j \mapsto Z^i \]

よってニューラルネットワークは$\reals^n\rightarrow\reals^m$の関数として機能する。 また、各レイヤーのパラメータを調整(学習)することによって任意の関数を表現できると期待される。

math.jsによる実装

基本的に行列演算なのでmath.matrix()を用いて計算を行う。 Pythonと違いJS(ES)では二項演算子はNumber型にしか使えない。 ただし、math.jsではほぼすべてのオブジェクトにchainメソッドが使えるので、これを活用するとスッキリ書くことができる。

例えば上のアフィン変換の操作については
let A1 = math.chain(x).multiply(W1).add(B1).done();
とワンライナーに書くことができる。 通常のmatrixオブジェクトに戻すには最後にdone()をする必要がある点に注意。 また、math.jsのmatrixオブジェクトからJSのArrayオブジェクトに戻すにはvalueOf()メソッドを用いる。

ベクトルの各成分に活性化関数を適用する部分についてはmap()メソッドを用いる。 forEach()メソッドは返り値がないのでここではmap()のほうがいい。

plotly.jsによる可視化

可視化と言っても表にしただけだが、plotly.jsを使うと比較的楽にdocumentに結果を出力できる。