LoginSignup
5
5

More than 5 years have passed since last update.

順伝播ニューラルネットワークを手で解く

Last updated at Posted at 2018-07-09

順伝播ニューラルネットワークは、入力層から出力層にかけて処理を行うニューラルネットワークモデルです。
ニューラルネットワークは、Python等のプログラム言語を使えば簡単に実装できます。
ですが、ここではプログラムの中身を理解するために、敢えてプログラムを使わずに(と言いつつ、検算でPythonを使いますが)順伝播ニューラルネットワークの出力値を計算してみます。

1.順伝播ニューラルネットワーク

まずは基本的な順伝播ニューラルネットワークモデル(入力層-中間層-出力層モデル)を考えます。

順伝播01.jpg

2.順伝播ニューラルネットワークモデルの出力値を計算で求めてみる

2.1.各層の計算

  • 入力層の計算
\boldsymbol{x}
  • 中間層の計算
\boldsymbol{u}^{(1)}=\boldsymbol{w}^{(1)}\cdot\boldsymbol{x}+ \boldsymbol{b}_1 \\
\boldsymbol{z}^{(1)} = f(\boldsymbol{u}^{(1)}) \\
  • 出力層の計算
\boldsymbol{u}^{(2)}=\boldsymbol{z}^{(1)}\cdot\boldsymbol{w}^{(2)} + \boldsymbol{b}_2 \\
\boldsymbol{z}^{(2)} = f(\boldsymbol{u}^{(2)})

順伝播02.jpg

2.2.初期条件の設定

インプット$\bf{x}$、重み$\bf{w}$、バイアス$\bf{b}$をそれぞれ下記の値とします。

\boldsymbol{x}=
\begin{pmatrix}
x_1\\
x_2
\end{pmatrix}
=
\begin{pmatrix}
1.0\\
5.0
\end{pmatrix}
\boldsymbol{w}^{(1)}=
\begin{pmatrix}
w_{11}^{(1)} & w_{12}^{(1)} \\
w_{21}^{(1)} & w_{22}^{(1)} \\
w_{31}^{(1)} & w_{32}^{(1)}
\end{pmatrix}
=
\begin{pmatrix}
0.1 & 0.2 \\
0.3 & 0.4 \\
0.5 & 0.6
\end{pmatrix}
\boldsymbol{b}^{(1)}=
\begin{pmatrix}
b_1^{(1)} \\
b_2^{(1)} \\
b_3^{(1)}
\end{pmatrix}
=
\begin{pmatrix}
0.1 \\
0.2 \\
0.3
\end{pmatrix}
\boldsymbol{w}^{(2)}=
\begin{pmatrix}
w_{11}^{(2)} & w_{12}^{(2)} & w_{13}^{(2)} \\
w_{21}^{(2)} & w_{22}^{(2)} & w_{23}^{(2)}
\end{pmatrix}
=
\begin{pmatrix}
0.1 & 0.2 & 0.3 \\
0.4 & 0.5 & 0.6
\end{pmatrix}
\boldsymbol{b}^{(2)}=
\begin{pmatrix}
b_1^{(2)} \\
b_2^{(2)}
\end{pmatrix}
=
\begin{pmatrix}
0.1 \\
0.2
\end{pmatrix}

2.3.順伝播型ニューラルネットワークの出力計算

中間層入力は、

\begin{equation}
\begin{split}
\boldsymbol{u}^{(1)} &= \boldsymbol{w}^{(1)}\cdot\boldsymbol{x}+ \boldsymbol{b}_1 \\
&=
\begin{pmatrix}
w_{11}^1 & w_{12}^1\\
w_{21}^1 & w_{22}^1\\
w_{31}^1 & w_{32}^1
\end{pmatrix}
\begin{pmatrix}
x_1\\
x_2
\end{pmatrix}
+
\begin{pmatrix}
b_{11} \\
b_{12} \\
b_{13}
\end{pmatrix} \\
&=
\begin{pmatrix}
0.1 & 0.2\\
0.3 & 0.4\\
0.5 & 0.6
\end{pmatrix}
\begin{pmatrix}
1.0\\
5.0
\end{pmatrix}
+
\begin{pmatrix}
0.1 \\
0.2 \\
0.3
\end{pmatrix} \\
&=
\begin{pmatrix}
1.2\\
2.5\\
3.8
\end{pmatrix}
\end{split}
\end{equation}

となります。
活性化関数はReLU関数とします。
ReLU関数は下記の式で与えられます。

f(x) = ReLU(x) = \left\{
\begin{array}{l}
x & (x > 0) \\
0 & (otherwise)
\end{array}
\right.

よって中間層出力は、

\boldsymbol{z}^{(1)}
=
\begin{pmatrix}
z_1^{(1)} \\
z_2^{(1)} \\
z_3^{(1)}
\end{pmatrix}
=
\begin{pmatrix}
ReLU(u_1^{(1)}) \\
ReLU(u_2^{(1)}) \\
ReLU(u_3^{(1)})
\end{pmatrix}
=
\begin{pmatrix}
ReLU(1.2) \\
ReLU(2.5) \\
ReLU(3.8)
\end{pmatrix}
=
\begin{pmatrix}
1.2\\
2.5\\
3.8
\end{pmatrix}

となります。
同様に、出力層入力は、

\begin{equation}
\begin{split}
\boldsymbol{u}^{(2)} &= \boldsymbol{w}^{(2)}\cdot\boldsymbol{z}^{(1)}+ \boldsymbol{b}_2 \\
&=
\begin{pmatrix}
w_{11}^{(2)} & w_{12}^{(2)} & w_{13}^{(2)}\\
w_{21}^{(2)} & w_{22}^{(2)} & w_{23}^{(2)}
\end{pmatrix}
\begin{pmatrix}
z_1^{(1)}\\
z_2^{(1)}\\
z_3^{(1)}
\end{pmatrix}
+
\begin{pmatrix}
b_{21} \\
b_{22}
\end{pmatrix} \\
&=
\begin{pmatrix}
0.1 & 0.2 & 0.3 \\
0.4 & 0.5 & 0.6
\end{pmatrix}
\begin{pmatrix}
1.2\\
2.5\\
3.8
\end{pmatrix}
+
\begin{pmatrix}
0.1 \\
0.2
\end{pmatrix} \\
&=
\begin{pmatrix}
1.86\\
4.21
\end{pmatrix}
\end{split}
\end{equation}

となります。
今回は多クラス分類問題を想定しているため、出力層の活性化関数にはSoftmax関数を用います。
Softmax関数は下記で与えられます。

f(x) = Softmax(x) = \frac{exp(x_k)}{\sum_{i=1}^n exp(x_i)}

よって最終出力は、

\boldsymbol{z}^{(2)}
=
\begin{pmatrix}
z_1^{(1)} \\
z_2^{(2)}
\end{pmatrix}
=
\begin{pmatrix}
Softmax(u_1^{(2)}) \\
Softmax(u_2^{(2)})
\end{pmatrix}
=
\begin{pmatrix}
Softmax(1.86) \\
Softmax(4.21)
\end{pmatrix}
=
\begin{pmatrix}
\frac{exp(1.86)}{exp(1.86) + exp(4.21)} \\
\frac{exp(4.21)}{exp(1.86) + exp(4.21)}
\end{pmatrix}
=
\begin{pmatrix}
0.0870… \\
0.9129…
\end{pmatrix}

となります。

順伝播型03.jpg

3.Pythonを用いて検算をする

実際にPythonに計算させて、手で解いた値が正しいかを検算します。

forward_network.py
import numpy as np
import sys

# 順伝播型ネットワークの実行
def main():

    args = sys.argv
    x = np.array([[float(args[1]), float(args[2])]])
    network =  init_network()
    y, z1 = forward(network, x)
    print(y)

# ネートワークを作成
def init_network():
    print("##### ネットワークの初期化 #####")

    network = {}
    network['W1'] = np.array([
        [0.1, 0.3, 0.5],
        [0.2, 0.4, 0.6]
    ])

    network['W2'] = np.array([
        [0.1, 0.4],
        [0.2, 0.5],
        [0.3, 0.6]
    ])

    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['b2'] = np.array([0.1, 0.2])

    print_vec("重み1", network['W1'])
    print_vec("重み2", network['W2'])
    print_vec("バイアス1", network['b1'])
    print_vec("バイアス2", network['b2'])

    return network

# 順伝播
def forward(network, x):
    print("##### 順伝播開始 #####")

    W1, W2 = network['W1'], network['W2']
    b1, b2 = network['b1'], network['b2']

    u1 = np.dot(x, W1) + b1
    z1 = relu(u1)
    u2 = np.dot(z1, W2) + b2
    y = softmax(u2)

    print_vec("総入力1", u1)
    print_vec("中間層出力1", z1)
    print_vec("総入力2", u2)
    print_vec("出力", y)
    print("出力合計: " + str(np.sum(y)))

    return y, z1

# 表示
def print_vec(text, vec):
    print("*** " + text + " ***")
    print(vec)
    print("")

# 中間層の活性化関数
# ReLU関数
def relu(x):
    return np.maximum(0, x)

# 出力層の活性化関数
# ソフトマックス関数
def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x))

if __name__ == '__main__':
    main()

このプログラムを実行してみます。
ターミナルを開いて下記コマンドで実行します。

$ python forward_network.py 1.0 5.0

出力結果は下記の通りとなり、結果が一致していることがわかります。

##### ネットワークの初期化 #####
*** 重み1 ***
[[0.1 0.3 0.5]
 [0.2 0.4 0.6]]

*** 重み2 ***
[[0.1 0.4]
 [0.2 0.5]
 [0.3 0.6]]

*** バイアス1 ***
[0.1 0.2 0.3]

*** バイアス2 ***
[0.1 0.2]

##### 順伝播開始 #####
*** 総入力1 ***
[[1.2 2.5 3.8]]

*** 中間層出力1 ***
[[1.2 2.5 3.8]]

*** 総入力2 ***
[[1.86 4.21]]

*** 出力 ***
[[0.08706577 0.91293423]]

出力合計: 1.0
[[0.08706577 0.91293423]]

4.終わりに

次は、逆伝播を手で解いてみたいと思います。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5