.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

推論フェーズでは、信号は順方向に伝播する。

行列の積による実装

簡単なニューラルネットワークの実装

対象

バイアスと活性化関数を省略し重みだけとする。

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列
     ─        ─
     └────┘
簡単なニューラルネットワークの実装
┌    ┐   ┌       ┐      ┌                   ┐
│a  b│   │1  3  5│   =  │1a+2b  3a+4b  5a+6b│
└    ┘   │       │      └                   ┘
           │2  4  6│
           └       ┘
  X行列     W行列                Y行列
  1行2列     2行3列                1行3列
     ─      ─
     └───┘

実装

>>> 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層のニューラルネットワークの実装

対象

前述の「簡単なニューラルネットワーク」を3層化する。

3層のニューラルネットワークの実装
  • 第一層目の計算の例
    入力が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]
  • 第二層目の計算の例
    入力が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列

実装

そのまんま実装した。

"""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))

慣例的実装

  • 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])))

出力層の設計

活性化関数

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

用いることができる。

を利用する。

恒等関数

入力をそのまま返す。

恒等関数

ソフトマックス関数

  • 以下のソフトマックス関数の結果の総和は1になる。
  • 従って、ソフトマックス関数の結果は「確率」として解釈できる。
  • これは分類問題で使用できる。分類では、一番大きい値のみを使用する。
  • ソフトマックス関数を使用しても値の大小関係は変わらないので
    順方向の推論フェーズにおいては、ソフトマックス関数は省略可能である。

対象

            exp(Ak)
Yk = ───────────
            n
           Σexp(Ai)
           i=1

シグモイド関数の項で説明した通り、

  • exp(x)とは、eのx乗を意味する。
  • eはネイピア数(2.7182)の実数を表す。
ソフトマックス関数

実装

  • そのまま実装
    >>> 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):
        """ソフトマックス関数"""
        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])))

オーバーフロー対策の実装

ソフトマックス関数は指数関数を使用するため、オーバーフローし易い。
従って、ここでは、オーバーフロー対策について考える。

  • 以下のように変形できる。
                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):
        """ソフトマックス関数"""
        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])))

ニューロンの数

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

  • 分類問題 : 分類する数に合わせる。
  • 回帰問題 : ・・・

手書き数字画像の認識

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

MNISTデータセット

機械学習分野で最も有名なデータセット

概要

  • 手書き数字の画像セット
    • 数字の0-9で構成され、以下の画像を使用して学習/推論を行う。
      • 学習用の訓練画像 :60,000枚
      • 推論用のテスト画像:10,000枚
  • 28*28の単一チャンネル、グレー画像
    • 画像の1つのピクセルは、0-255の8ビット
    • 画像には、正解を意味するラベルが与えられている。

データの取得

  • 以下にアクセスして[Download ZIP]する。
  • Cドラ直下にZIP解凍したら、CMDでch03ディレクトリに移動する。
  • ここでpythonでmnist_show.pyを実行し、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 は、重みパラメタ

推論処理

ニューロン構成

  • 入力層が784個、出力層が10個のする。
    • 入力層が784個 = 28 * 28 のピクセル数
    • 出力層が10個 = 分類問題なので、0 - 9 のクラス
  • 中間層(隠れ層)の数は任意だが、ココでは以下の値に設定。
    • 第一層:50個
    • 第二層:100個

実行

以下のようにneuralnet_mnist.pyを実行すると、

>python neuralnet_mnist.py
  • 推論用のテスト画像:10,000枚の分類結果の正解率が表示される。
  • なお、ここでは、画像データに正規化(normalize)の前処理(preprocessing)を行っている。

バッチ化

ニューロン構成

  • 上記のneuralnet_mnist.py処理中の重みパラメタを確認すると、
    この、ニューラルネットワークが以下の様なものであることを確認できる。
    X行列     W1行列   W2行列   W3行列   → Y行列
    1行784列   784行50列  50行100列  100行10列     1行10列
        ↑      ↑        ↑          ↑             ↑
        └───┘        │          │             │
         1行50列          │          │             │
            ↑            │          │             │
            └──────┘          │             │
                 1行100列             │             │
                    ↑                │             │
                    └────────┘             │
                           1行10列 ─────────┘
  • バッチ化は、X行列、Y行列の行を増やして
    データを纏めて投入できるようにするだけで良い。
    ソレに合わせてW行列も変わるがbに変更はない(1行n列)。
X行列      W(1)行列 W(2)行列 W(3)行列   → Y行列
100行784列  784行50列  50行100列  100行10列      100行10列
      ↑    ↑        ↑          ↑             ↑
      └──┘        │          │             │
Y行列 100行50列      │          │             │
          ↑          │          │             │
          └─────┘          │             │
   Y行列 100行100列              │             │
                ↑                │             │
                └────────┘             │
              Y行列 100行10列 ─────────┘

実行

以下のようにneuralnet_mnist_batch.pyを実行すると、

>python neuralnet_mnist_batch.py
  • neuralnet_mnistと比べ、100枚づつのバッチ処理が行われ、高速化される。
  • 正解の判定処理は、true値をsumするという方法を使用している。
  • なお、np.argmaxの引数、axis=1は行方向の最大値となる要素のインデックスを求める。

添付ファイル: filetemp.pptx 37件 [詳細] filesoftmax.png 78件 [詳細] filesimple.png 124件 [詳細] fileidentity.png 84件 [詳細] file3tier.png 85件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-07-28 (金) 19:01:48 (599d)