不確定特異点

広く深く、ところどころ超深く

学習とニューラルネットワーク (3)

ニューロンを使った関数近似

前回使った勾配法をニューロンの学習に応用してみます。例として、2入力1出力の関数 f(x1, x2) を考え、これを単一のニューロンで近似することを考えます。f の入出力関係は以下のように6サンプル定義します。

入力値  : (0 1) (1 0) (0 0) (1 3) (2 1) (1.5 2)
目標出力: 0.000 0.000 0.000 1.000 1.000 1.000

ニューロンへの入力は x1, x2 と、バイアス重み用に追加する固定値 1 の 3 入力になります。これら 3 つの入力に対して重みを w1, w2, w3(バイアス) のように割り当て、シグモイド関数を通した近似出力と目標出力とが近づくように重みを調整して行くことになります。このときの目標出力との誤差は二乗誤差をとり、この二乗誤差を重みの関数と見て勾配を降下することで最適解を探ります。次のプログラムではサンプルごとに重みを更新し、全6サンプルを 100 回学習させました。

単一ニューロンを使った関数近似

実行結果

まずは学習回数を 10 回程度にしてみます。

CL-USER> (test-sample 10)
訓練誤差 (1 回目) = 0.49730793
訓練誤差 (2 回目) = 0.5389906
訓練誤差 (3 回目) = 0.4283402
訓練誤差 (4 回目) = 0.33211482
訓練誤差 (5 回目) = 0.27234232
訓練誤差 (6 回目) = 0.23149137
訓練誤差 (7 回目) = 0.20178686
訓練誤差 (8 回目) = 0.17907418
訓練誤差 (9 回目) = 0.1610578
訓練誤差 (10 回目) = 0.14637698

学習結果: 重み ws = 0.7347231 0.65961254
          閾値 theta = 1.2067086
入力値  : (0 1) (1 0) (0 0) (1 3) (2 1) (1.5 2)
目標出力: 0.000 0.000 0.000 1.000 1.000 1.000
素子出力: 0.251 0.280 0.082 0.953 0.864 0.919
NIL
CL-USER> 

なんとなく目標出力に近づいてますが、まだ足りないようです。もう少し回数を増やしてみましょう。(長いので出力は途中省略)

CL-USER> (test-sample 100)
訓練誤差 (1 回目) = 0.49730793
訓練誤差 (2 回目) = 0.5389906
訓練誤差 (3 回目) = 0.4283402
訓練誤差 (4 回目) = 0.33211482
訓練誤差 (5 回目) = 0.27234232
訓練誤差 (6 回目) = 0.23149137
訓練誤差 (7 回目) = 0.20178686
訓練誤差 (8 回目) = 0.17907418
訓練誤差 (9 回目) = 0.1610578
訓練誤差 (10 回目) = 0.14637698
…
訓練誤差 (90 回目) = 0.017596059
訓練誤差 (91 回目) = 0.017403184
訓練誤差 (92 回目) = 0.017214462
訓練誤差 (93 回目) = 0.017029736
訓練誤差 (94 回目) = 0.016848937
訓練誤差 (95 回目) = 0.016671902
訓練誤差 (96 回目) = 0.016498512
訓練誤差 (97 回目) = 0.016328664
訓練誤差 (98 回目) = 0.016162256
訓練誤差 (99 回目) = 0.015999172
訓練誤差 (100 回目) = 0.01583934

学習結果: 重み ws = 1.3552754 1.1581724
          閾値 theta = 2.5280619
入力値  : (0 1) (1 0) (0 0) (1 3) (2 1) (1.5 2)
目標出力: 0.000 0.000 0.000 1.000 1.000 1.000
素子出力: 0.061 0.087 0.006 0.990 0.936 0.974
NIL
CL-USER> 

100 回学習させたところで、目標出力をおおむね近似できているようです。この問題の場合は回数を増やせば増やすほど、近似の精度は上がっていくようです。

次によく言われる XOR の問題を学習させてみました。

CL-USER> (test-xor 10)
訓練誤差 (1 回目) = 0.7393377
訓練誤差 (2 回目) = 0.73489934
訓練誤差 (3 回目) = 0.7327632
訓練誤差 (4 回目) = 0.7318481
訓練誤差 (5 回目) = 0.73160195
訓練誤差 (6 回目) = 0.73173594
訓練誤差 (7 回目) = 0.7320949
訓練誤差 (8 回目) = 0.7325923
訓練誤差 (9 回目) = 0.7331773
訓練誤差 (10 回目) = 0.73381853

学習結果: 重み ws = -0.1481037 -0.061754227
          閾値 theta = -0.01982613
入力値  : (0 0) (0 1) (1 0) (1 1)
目標出力: 0.000 1.000 1.000 0.000
素子出力: 0.510 0.479 0.436 0.406
NIL
CL-USER> 

10 回程度ではダメ。100 回はどうかというと…(長いので出力は途中省略)

CL-USER> (test-xor 100)
訓練誤差 (1 回目) = 0.7393377
訓練誤差 (2 回目) = 0.73489934
訓練誤差 (3 回目) = 0.7327632
訓練誤差 (4 回目) = 0.7318481
訓練誤差 (5 回目) = 0.73160195
訓練誤差 (6 回目) = 0.73173594
訓練誤差 (7 回目) = 0.7320949
訓練誤差 (8 回目) = 0.7325923
訓練誤差 (9 回目) = 0.7331773
訓練誤差 (10 回目) = 0.73381853
...
訓練誤差 (90 回目) = 0.75306654
訓練誤差 (91 回目) = 0.75308204
訓練誤差 (92 回目) = 0.7530967
訓練誤差 (93 回目) = 0.75311047
訓練誤差 (94 回目) = 0.75312364
訓練誤差 (95 回目) = 0.7531361
訓練誤差 (96 回目) = 0.7531479
訓練誤差 (97 回目) = 0.7531589
訓練誤差 (98 回目) = 0.75316954
訓練誤差 (99 回目) = 0.7531795
訓練誤差 (100 回目) = 0.7531889

学習結果: 重み ws = -0.27855366 -0.13894826
          閾値 theta = -0.13874665
入力値  : (0 0) (0 1) (1 0) (1 1)
目標出力: 0.000 1.000 1.000 0.000
素子出力: 0.569 0.500 0.431 0.364
NIL
CL-USER> 

全然目標に近づく気配がありません。このように入力層と出力層だけからなる 2 層フィードフォワードニューラルネットワークを使っている限り、いくら学習回数を増やしても近似不可能な問題が存在するんですね。実は任意の多変数関数を近似する 3 層フィードフォワードニューラルネットワークが存在することは証明されているため、次は隠れ層を増やしてこれを近似できるネットワークを作ってみたいと思います。

学習とニューラルネットワーク (電子情報通信工学シリーズ)

学習とニューラルネットワーク (電子情報通信工学シリーズ)