「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>深層学習(deep learning)]]
--[[パーセプトロン]]
--[[ニューラルネットワーク]]
---ニューラルネットワーク(推論)
---[[ニューラルネットワーク(学習)]]

*目次 [#x49ef019]
#contents

*概要 [#rfb3c4eb]
推論フェーズでは、信号は順方向に伝播する。

*行列の積による実装 [#laa37ea3]

**簡単なニューラルネットワークの実装 [#u375e15b]

***対象 [#m553499c]
バイアスと活性化関数を省略し重みだけとする。
>X行列 * W行列=Y行列

 ┌      ┐ ┌          ┐   ┌                               ┐
 │a1  b1│ │a2  b2  c2│ = │a1a2+b1d2  a1b2+b1e2  a1c2+b1f2│
 └      ┘ │          │   └                               ┘
            │d2  e2  f2│
            └          ┘
   X行列       W行列                     Y行列
   1行2列       2行3列                     1行3列
      ─        ─
      └────┘

#ref(simple.png,left,nowrap,簡単なニューラルネットワークの実装,60%)

 ┌    ┐   ┌       ┐      ┌                   ┐
 │a  b│   │1  3  5│   =  │1a+2b  3a+4b  5a+6b│
 └    ┘   │       │      └                   ┘
            │2  4  6│
            └       ┘
   X行列     W行列                Y行列
   1行2列     2行3列                1行3列
      ─      ─
      └───┘

***実装 [#qbef5163]
 >>> x=np.array([1,2])
 >>> x
 array([1, 2])
 >>> w=np.array([[1,3,5],[2,4,6]])
 >>> w
 array([[1, 3, 5],
        [2, 4, 6]])
 >>> y=np.dot(x,w)
 >>> y
 array([ 5, 11, 17])

**3層のニューラルネットワークの実装 [#pbae7d55]
***対象 [#j4d0a806]
前述の「[[簡単なニューラルネットワーク>#m553499c]]」を3層化する。

#ref(3tier.png,left,nowrap,3層のニューラルネットワークの実装,60%)

-第一層目の計算の例~
入力が1行2列、出力が1行3列
--重み付き信号とバイアスの和
---a(1)1 = w(1)11 x1 + w(1)12 x2 + b(1)1
---a(1)2 = w(1)21 x1 + w(1)22 x2 + b(1)2
---a(1)3 = w(1)31 x1 + w(1)32 x2 + b(1)3

--これを行列で表すと、~
入力が1行2列、出力が1行3列だから、
 A(1) = x(1) W(1) + B(1)
---X(1) = [x1 x2]
---A(1) = [a(1)1 a(1)2 a(1)3]
---W(1) = W(1)は、2行3列
 ┌                    ┐
 │w(1)11 w(1)21 w(1)31│
 │w(1)12 w(1)22 w(1)32│
 └                    ┘
---B(1) = 出力が1行3列だから、
 [b(1)1 b(1)2 b(1)3]

---活性化関数~
[[Sigmoid関数>ニューラルネットワーク#u0ac8472]]を使用する。
 h(A(1)) = Z(1)

-第二層目の計算の例~
入力が1行3列、出力が1行2列だから、
--第一層目と大方、同じ。
---X(2) = 1行3列
---A(2) = 1行2列
---W(2) = 入力が1行3列、出力が1行2列だから、W(2)は、3行2列
---b(2) = 出力と同じ、1行2列

-第三層目の計算の例~
入力が1行2列、出力が1行2列だから、
--第一層目と大方、同じ。
---X(3) = 1行2列
---A(3) = 1行2列
---W(2) = 入力が1行2列、出力が1行2列だから、W(2)は、2行2列
---b(3) = 出力と同じ、1行2列

--活性化関数だけ異なる。
---[[出力層の活性化関数>#w9eba652]]は問題によって異なる。
---ここでは、[[恒等関数>#u6563984]]を使用する。
 σ(A(3)) = Z(3)

***実装 [#sbb7f972]
そのまんま実装した。

 """This is a test program."""
 
 import numpy as np
 
 def sigmoid(x_1):
     """sigmoid."""
     return 1 / (1 + np.exp(-x_1))
 
 def identity_function(y_1):
     """出力層の活性化関数"""
     return y_1
 
 # 第一層
 X1 = np.array([1.0, 0.5])
 W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
 B1 = np.array([0.1, 0.2, 0.3])
 
 print("第一層")
 A1 = np.dot(X1, W1) + B1
 print("A1:" + str(A1))
 Z1 = sigmoid(A1)
 print("Z1:" + str(Z1))
 
 # 第二層
 X2 = Z1
 W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
 B2 = np.array([0.1, 0.2])
 
 print("第二層")
 A2 = np.dot(X2, W2) + B2
 print("A2:" + str(A2))
 Z2 = sigmoid(A2)
 print("Z2:" + str(Z2))
 
 # 第三層
 X3 = Z2
 W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
 B3 = np.array([0.1, 0.2])
 
 print("第三層")
 A3 = np.dot(X3, W3) + B3
 print("A3:" + str(A3))
 Z3 = identity_function(A3)
 print("Z3:" + str(Z3))

***慣例的実装 [#r9753caf]
-init_networkで、ニューラルネットワークを定義/初期化し、
-forwardで入力から出力方向への伝達処理を行う。

 """This is a test program."""
 
 import numpy as np
 
 def sigmoid(x_1):
     """sigmoid."""
     return 1 / (1 + np.exp(-x_1))
 
 def identity_function(y_1):
     """出力層の活性化関数"""
     return y_1
 
 def init_network():
     """ニューラルネットワーク"""
     network = {}
     networkw = {}
     networkw[0] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
     networkw[1] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
     networkw[2] = np.array([[0.1, 0.3], [0.2, 0.4]])
     networkb = {}
     networkb[0] = np.array([0.1, 0.2, 0.3])
     networkb[1] = np.array([0.1, 0.2])
     networkb[2] = np.array([0.1, 0.2])
     network["W"] = networkw
     network["b"] = networkb
     return network
 
 def forward(network, zzz):
     """ニューラルネットワークの実行"""
     tier = len(network["W"])
 
     for num in range(tier - 1):
         print("第" + str(num + 1) + "層")
         xxx = zzz
         aaa = np.dot(xxx, network["W"][num]) + network["b"][num]
         print("A" + str(num + 1) + ":" + str(aaa))
         zzz = sigmoid(aaa)
         print("Z" + str(num + 1) + ":" + str(zzz))
 
     print("第" + str(tier) + "層")
     xxx = zzz
     aaa = np.dot(xxx, network["W"][tier -1]) + network["b"][tier -1]
     print("A" + str(tier) + ":" + str(aaa))
     zzz = identity_function(aaa) # 出力層の活性化関数
     print("Z" + str(tier) + ":" + str(zzz))
 
     return zzz
 
 print(forward(init_network(), np.array([1.0, 0.5])))

*出力層の設計 [#p221ffd8]

**活性化関数 [#w9eba652]
-ニューラルネットワークは
--分類問題と
---入力データがどのクラスに属するか?
---例:写真から男性・女性を識別する。
--回帰問題に
---入力データから連続的な数値を予測する。
---例:写真からその人の体重を予測する。

>用いることができる。

-一般的に、出力層の活性関数は、
--回帰問題 : [[恒等関数>#u6563984]]
--分類問題 :
---[[Sigmoid関数>#qc025e6f]]
---[[Softmax関数>#b77bdfd7]]

>を利用する。

**恒等関数 [#u6563984]
-回帰問題で使用。
-入力をそのまま返す。
-式
 f(x) = x

-特徴
--回帰問題で使用。
--入力をそのまま返す。

-グラフ
#ref(identity.png,left,nowrap,恒等関数,60%)

**Sigmoid関数 [#qc025e6f]
-2クラス分類の機械学習で使用される。
-xで条件付けされたyの[[ベルヌーイ分布>統計解析#aa908967]]を推定。
-[[オッズの対数を取ったロジット関数の逆関数>統計解析#ge055200]]らしい。
-実装などについては[[コチラ>ニューラルネットワーク#u0ac8472]]
-中間層の活性化関数として既出なので、実装など詳細については[[コチラ>ニューラルネットワーク#u0ac8472]]

**Softmax関数 [#b77bdfd7]
-多クラス分類の機械学習で使用される。
-xで条件付けされたyの[[マルチヌーイ分布>統計解析#t1a00fea]]を推定。
-[[Sigmoid関数>#qc025e6f]]を多クラスに拡張、一般化したもの。

-Softmax関数の結果は
--0 - 1 の実数になり、その総和は 1.0 になる。
--従って、Softmax関数の結果は「確率」として解釈できる。
--これは多クラス分類問題で使用できる。
--分類では、一番大きい値のみを使用する。
--Softmax関数を使用しても値の大小関係は変わらないので~
順方向の推論フェーズにおいては、Softmax関数は省略可能である。

***対象 [#ga31b4f9]
             exp(Ak)
 Yk = ───────────
             n
            Σexp(Ai)
            i=1

[[Sigmoid関数>ニューラルネットワーク#u0ac8472]]の項で説明した通り、
-exp(x)とは、eのx乗を意味する。
-eは[[ネイピア数>DS:数学的基礎 - 微分・偏微分#adabdb73]](2.7182)の実数を表す。

#ref(softmax.png,left,nowrap,Softmax関数,60%)

***実装 [#z0de2e5f]
-そのまま実装
 >>> a=np.array([0.3, 2.9, 4.0])
 >>> a
 array([ 0.3,  2.9,  4. ])
 >>> exp_a = np.exp(a)
 >>> exp_a
 array([  1.34985881,  18.17414537,  54.59815003])
 >>> sum_exp_a = np.sum(exp_a)
 >>> sum_exp_a
 74.122154210163302
 >>> y = exp_a / sum_exp_a
 >>> y
 array([ 0.01821127,  0.24519181,  0.73659691])
 >>>

-関数化
 """This is a test program."""
 
 import numpy as np
 
 def softmax(aaa):
     """Softmax関数"""
     exp_a = np.exp(aaa)
     sum_exp_a = np.sum(exp_a)
     return exp_a / sum_exp_a
 
 print(softmax(np.array([0.3, 2.9, 4.0])))

***オーバーフロー対策の実装 [#id0a8627]
Softmax関数は指数関数を使用するため、オーバーフローし易い。~
従って、ここでは、オーバーフロー対策について考える。

-以下のように変形できる。
             exp(Ak)
 Yk = ───────────
             n
            Σexp(Ai)
            i=1

>
           C exp(Ak)
    = ───────────
             n
          C Σexp(Ai)
            i=1

>
             exp(Ak + logeC)
    = ───────────
             n
            Σexp(Ai + logeC)
            i=1

--例えば、
---10の3乗は、10の1乗*10の2乗 = 1,000
---10の4乗は、10の2乗*10の2乗 = 10,000
---なので、下のような変形ができるということになる。
  (a+b)    a    b
 X      = X  * X

--Xb=Cは、b=logxCであるから、下のようになる。
    a    a    logxC     (a+logxC)
 C X  = X  * X       = X
 
             exp(Ak + C')
    = ───────────
             n
            Σexp(Ai + C')
            i=1

-Cは、入力信号中の最大値を使用する。~
これによって、オーバーフローが発生し難くなる。以下に実装を示す。
 """This is a test program."""
 
 import numpy as np
 
 def softmax(aaa):
     """Softmax関数"""
     exp_a = np.exp(aaa - np.max(aaa))
     sum_exp_a = np.sum(exp_a)
     return exp_a / sum_exp_a
 
 # print(softmax(np.array([0.3, 2.9, 4.0])))
 print(softmax(np.array([1010, 1000, 990])))

**ニューロンの数 [#o46593dd]
出力層のニューロンの数は、問題に合わせて決定する。

-分類問題 : 分類する数に合わせる。
-回帰問題 : 多分、1つにする。

*手書き数字画像の認識 [#zf703d94]
-実践的な手書き数字画像の認識を行う。
-ここでは、学習済みのパラメタを使用して実装をする。

**MNISTデータセット [#c18ded2a]
機械学習分野で最も有名なデータセット

***概要 [#l74156dc]
-手書き数字の画像セット
--数字の0-9で構成され、以下の画像を使用して学習/推論を行う。
---学習用の訓練画像 :60,000枚
---推論用のテスト画像:10,000枚
-28*28の単一チャンネル、グレー画像
--画像の1つのピクセルは、0-255の8ビット
--画像には、正解を意味するラベルが与えられている。
--白黒画像は行列で表現でき、カラー画像は[[テンソル>NumPy#h768806a]](行列 * RGB)で表現できる。

***データの取得 [#y26372f0]
-以下にアクセスして[Download ZIP]する。
--oreilly-japan/deep-learning-from-scratch:~
『ゼロから作る Deep Learning』のリポジトリ~
https://github.com/oreilly-japan/deep-learning-from-scratch
-Cドラ直下にZIP解凍したら、CMDでch03ディレクトリに移動する。
-ここでpythonで[[mnist_show.py>https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch03/mnist_show.py]]を実行し、[[mnist.py>https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/dataset/mnist.py]]経由でデータセットを取得する。
 c:\deep-learning-from-scratch-master\ch03>python mnist_show.py
 Downloading train-images-idx3-ubyte.gz ...
 Done
 Downloading train-labels-idx1-ubyte.gz ...
 Done
 Downloading t10k-images-idx3-ubyte.gz ...
 Done
 Downloading t10k-labels-idx1-ubyte.gz ...
 Done
 Converting train-images-idx3-ubyte.gz to NumPy Array ...
 Done
 Converting train-labels-idx1-ubyte.gz to NumPy Array ...
 Done
 Converting t10k-images-idx3-ubyte.gz to NumPy Array ...
 Done
 Converting t10k-labels-idx1-ubyte.gz to NumPy Array ...
 Done
 Creating pickle file ...
 Done!
 5
 (784,)
 (28, 28)
 
 c:\deep-learning-from-scratch-master\ch03>python mnist_show.py
 5
 (784,)
 (28, 28)

-一回目はWebからのダウンロードは成功したが、画像表示ができなかった。~
二回目以降は、ローカル保存した*.pklからデータを読み込むようで、画像表示できた。~
なお、*.pklファイルは、pythonのbinaryserialize的なpickleによって生成されている。
--\dataset\mnist.pkl は、MNISTデータ
--\ch03\sample_weight.pkl は、重みパラメタ

**推論処理 [#r85fa43b]
***ニューロン構成 [#g604f173]
-入力層が784個、出力層が10個のする。
--入力層が784個 = 28 * 28 のピクセル数
--出力層が10個 = 分類問題なので、0 - 9 のクラス
-中間層(隠れ層)の数は任意だが、ココでは以下の値に設定。
--第一層:50個
--第二層:100個

***実行 [#oda0dcb6]
以下のように[[neuralnet_mnist.py>https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch03/neuralnet_mnist.py]]を実行すると、
 >python neuralnet_mnist.py
-推論用のテスト画像:10,000枚の分類結果の正解率が表示される。
-なお、ここでは、画像データに正規化(normalize)の前処理(preprocessing)を行っている。


**[[バッチ>ニューラルネットワーク(学習)#h15bc15d]]化 [#c7726cc3]

***ニューロン構成 [#u17966f5]
-上記の[[neuralnet_mnist.py>https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch03/neuralnet_mnist.py]]処理中の重みパラメタを確認すると、~
この、ニューラルネットワークが以下の様なものであることを確認できる。

#ref(batch1.png,left,nowrap,batch1)

-バッチ化は、X行列、Y行列の行を増やして~
データを纏めて投入できるようにするだけで良い。~
ソレに合わせてW行列も変わるがbに変更はない(1行n列)。

#ref(batch2.png,left,nowrap,batch2)

***実行 [#p03f2958]
以下のように[[neuralnet_mnist_batch.py>https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch03/neuralnet_mnist_batch.py]]を実行すると、
 >python neuralnet_mnist_batch.py
-neuralnet_mnistと比べ、100枚づつのバッチ処理が行われ、高速化される。
-正解の判定処理は、true値をsumするという方法を使用している。
-なお、np.argmaxの引数、axis=1は行方向の最大値となる要素のインデックスを求める。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS