本題!まずはメモ!
構成単位である人工ニューロンとは?
ニューロンは、電気信号を受けてしきい値を超えたら、次のニューロンに電気信号を送る
これを数式では以下のように表現している。
u = Σxi・wi - v
i
z = f(u)
Σはシグマ。数列の和を示す記号
詳細は以下を参照
わかりやすくΣ(シグマ)の意味を説明 / 数学B by となりがトトロ |マナペディア|
人工ニューロンの計算詳細は以下の通り
①入力x×重みwをx1~xnで計算する。
②①を足す
③②から閾値vを引く
④関数fでuを処理した結果をzとして、出力する
①~④の処理をシグマで記述したのが、上記記述。
関数fは色々なものが利用される。
良く利用されるのは、
①ステップ関数
入力が0以上であれば1を返す
入力が0未満であれば0を返す
②シグモイド関数
f(u) = 1 / 1(1 + e-u)
※-uは右上添字
良く分からないけど、0 or 1、0~1を返す関数と覚える
ステップ関数は非線形
シグモイドは緩やかな線形
ニューラルネットワークとは?
ニューラルネットワークは、人工ニューロンを複数つなぎ合わせること。
人工ニューロンと同様に、この重み・閾値を適切に調節する事が学習になる。
※単体より複雑なパターンを表現できるって事でしょう。
論理回路(AND,OR等)と同じ動きも可能。
人工ニューロンの接続方法により種類が分かれるあり
フィードフォワード型ネットワーク(左から右へ)
階層型ネットワーク(左から右へ)
リカレントネットワーク(ループ構成)
ニューラルネットワークの学習の流れ(教師ありの場合)
①全ての重みと閾値をランダムに初期化
②以下を適当な回数繰り返す
1) 学習データセットから一つの学習例を選び、ニューラルネットに与えて出力を計算する
2) 教師データとニューラルネットの出力を比較し、誤差が小さくなるよう重みと閾値を調整する。
教師データとニューラルネットの出力が一致すれば学習は終了
ポイントはこの重みと閾値の調整方法
→遺伝的アルゴリズムを使っても調整は可能(?)
しかし、「バックプロパゲーション」が最も効率的な手法として知られている。
バックプロパゲーションとは?
階層型ネットワークで良く用いられる手法
パーセプトロンという手法をベース
パーセプトロンでは最後の出力層の重み・閾値しか調整できない
中間層の重み・閾値も調整できるのが、バックプロパゲーション
バックプロパゲーションはback propagetionの略で「逆向きに何かを伝える」の意味
バックプロパゲーションは誤差を逆向きに伝える。
*
人工ニューロンサンプルプログラム
参考書籍のneuton.cをPython化。少しはしょったかも。
# coding: utf-8 import sys W1 = 10 W2 = 10 TH = 15 def main(): inputs = sys.stdin.readlines() for i in inputs: i = i.strip() inp1, inp2 = i.strip().split() ret = forward(int(inp1),int(inp2)) print("Inp1:" + inp1 + " Inp2:" + inp2 + " Out:" + ret) def forward(inp1,inp2): u = (inp1 * W1 + inp2 * W2) - TH # Step関数処理 if u >= 0: return "1" else: return "0" main()
人工ニューロンサンプルプログラム実行結果
# echo -e "0 0\n0 1\n1 0\n1 1" | python ./an.py Inp1:0 Inp2:0 Out:0 Inp1:0 Inp2:1 Out:0 Inp1:1 Inp2:0 Out:0 Inp1:1 Inp2:1 Out:1
この場合は、AND論理素子と同じ動き
ニューラルネットサンプルプログラム
参考書籍のnn.cをPython化。
# coding: utf-8 import sys import math n1_omomi = [-2.0, 3.0] n1_shikii = -1.0 n2_omomi = [-2.0, 1.0] n2_shikii = 0.5 n3_omomi = [-60.0, 94.0] n3_shikii = -1.0 def main(): inputs = sys.stdin.readlines() num = 1 for line in inputs: data = line.strip().split() data = change_float(data) n1_out = forward(data, n1_omomi, n1_shikii) n2_out = forward(data, n2_omomi, n2_shikii) n3_out = forward([n1_out, n2_out], n3_omomi, n3_shikii) print('Num: %d Data1: %f Data2: %f Output: %f' % (num, data[0], data[1], n3_out)) num += 1 def change_float(data): ret = list() for i in data: ret.append(float(i)) return ret def forward(data, omomi, shikii): out_src = (data[0] * omomi[0]) + (data[1] * omomi[1]) - shikii return dentatsu_kansu(out_src) def dentatsu_kansu(out_src): # Step関数 if out_src >= 0.0: return 1.0 else: return 0.0 # # シグモイド関数 # out_src = out_src * -1.0 # return 1.0 / (1.0 + math.exp(out_src)) main()
ニューラルネットサンプルプログラム実行結果
STEP関数の時
# cat ./data 0 0 0 1 1 0 1 1 # python ./nn.py < ./data Num: 1 Data1: 0.000000 Data2: 0.000000 Output: 0.000000 Num: 2 Data1: 0.000000 Data2: 1.000000 Output: 1.000000 Num: 3 Data1: 1.000000 Data2: 0.000000 Output: 1.000000 Num: 4 Data1: 1.000000 Data2: 1.000000 Output: 0.000000 #
この場合は、AND論理素子と同じ動き
処理を手計算でやると、以下の通り
########## 入力1処理 ############# 0 0 # 中間層1 # -2 3 -1 0 * -2 = 0 0 * 3 = 0 (0 + 0) - -1 = 1 f(1) = 1 # 中間層2 # -2 1 0.5 0 * -2 = 0 0 * 1 = 0 (0 + 0) - 0.5 = -0.5 f(-0.5) = 0 # 出力層 # -60 94 -1 1 * -60 = -60 0 * 94 = 0 (-60 + 0) - -1 = -59 # f伝達関数 u >= 0 => 1 else 0 # 出力結果 0 ########## 入力2処理 ############# 0 1 # 中間層1 # -2 3 -1 0 * -2 = 0 1 * 3 = 3 (0 + 3) - -1 = 4 f(4) = 1 # 中間層2 # -2 1 0.5 0 * -2 = 0 1 * 1 = 1 (0 + 1) - 0.5 = 0.5 f(0.5) = 1 # 出力層 # -60 94 -1 1 * -60 = -60 1 * 94 = 94 (-60 + 94) - -1 = 35 # f伝達関数 u >= 0 => 1 else 0 # 出力結果 1 ########## 入力3処理 ############# 1 0 # 中間層1 # -2 3 -1 1 * -2 = -2 0 * 3 = 0 (-2 + 0) - -1 = -1 f(-1) = 0 # 中間層2 # -2 1 1 1 * -2 = -2 0 * 1 = 0 (-2 + 0) - 1 = -3 f(-3) = 0 # 出力層 # -60 94 -1 0 * -60 = 0 0 * 94 = 0 (0 + 0) - -1 = 1 # f伝達関数 u >= 0 => 1 else 0 # 出力結果 1 ########## 入力4処理 ############# 1 1 # 中間層1 # -2 3 -1 1 * -2 = -2 1 * 3 = 3 (-2 + 3) - -1 = 2 f(2) = 1 # 中間層2 # -2 1 1 1 * -2 = -2 1 * 1 = 1 (-2 + 1) - 1 = -2 f(-2) = 0 # 出力層 # -60 94 -1 1 * -60 = -60 0 * 94 = 0 (-60 + 0) - -1 = -59 # f伝達関数 u >= 0 => 1 else 0 # 出力結果 0
シグモイド関数の時
# python ./nn.py < ./data Num: 1 Data1: 0.000000 Data2: 0.000000 Output: 0.000627 Num: 2 Data1: 0.000000 Data2: 1.000000 Output: 0.643445 Num: 3 Data1: 1.000000 Data2: 0.000000 Output: 0.000333 Num: 4 Data1: 1.000000 Data2: 1.000000 Output: 0.000000
動きが変わる。