pikesaku’s blog

個人的な勉強メモです。記載内容について一切の責任は持ちません。

人工知能(AI)勉強メモ ニューラルネットワーク

本題!まずはメモ!

ニューラルネットとは?

神経細胞(neuron)をモデル化した計算素子である人工ニューロンを複数組み合わせたもの

構成単位である人工ニューロンとは?

ニューロンは、電気信号を受けてしきい値を超えたら、次のニューロンに電気信号を送る


f:id:pikesaku:20160919153359p:plain


これを数式では以下のように表現している。

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等)と同じ動きも可能。

f:id:pikesaku:20160919162039p:plain

人工ニューロンの接続方法により種類が分かれるあり

フィードフォワード型ネットワーク(左から右へ)
階層型ネットワーク(左から右へ)
リカレントネットワーク(ループ構成)

ニューラルネットワークの学習の流れ(教師ありの場合)

①全ての重みと閾値をランダムに初期化
②以下を適当な回数繰り返す
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

動きが変わる。