入力層〜中間層の実装演習

はじめに

深層学習day1の「Section1:入力層〜中間層」の実装演習を以下にまとめる。

実装演習

ネットワーク構造

取り組んだ実装演習は、3層のニューラルネットワークである。入力層(第0層)は3個、一つ目の隠れ層(第1層)は10個、二つ目の隠れ層(第2層)は5つ、出力層(第3層)は4つのニューロンからなるネットワークである。

コード

# 順伝播(3層・複数ユニット)

# 自分の環境で、ダウンロードした共通関数の格納フォルダのパス
import sys
sys.path.append('DNN_code_colab_lesson_1_2')

import numpy as np
from common import functions

def print_vec(text, vec):
    print("*** " + text + " ***")
    print(vec)
    print("shape: " + str(vec.shape))
    print("")
# ウェイトとバイアスを設定
# ネートワークを作成
def init_network():
    print("##### ネットワークの初期化 #####")
    network = {}
    
    # ネットワーク構造を定義
    input_layer_size = 3
    hidden_layer_size_1=10
    hidden_layer_size_2=5
    output_layer_size = 4
    
    # 各層の重み、バイアスを表示
    # それぞれのパラメータの次元の大きさをshapeで表示する
    network['W1'] = np.random.rand(input_layer_size, hidden_layer_size_1)
    network['W2'] = np.random.rand(hidden_layer_size_1,hidden_layer_size_2)
    network['W3'] = np.random.rand(hidden_layer_size_2,output_layer_size)

    network['b1'] =  np.random.rand(hidden_layer_size_1)
    network['b2'] =  np.random.rand(hidden_layer_size_2)
    network['b3'] =  np.random.rand(output_layer_size)

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

    return network
# 順伝播関数を定義
# x:入力値
def forward(network, x):
    
    print("##### 順伝播開始 #####")

    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    
    # 1層の総入力
    u1 = np.dot(x, W1) + b1
    
    # 1層の総出力
    z1 = functions.relu(u1)
    
    # 2層の総入力
    u2 = np.dot(z1, W2) + b2
    
    # 2層の総出力
    z2 = functions.relu(u2)

    # 出力層の総入力
    u3 = np.dot(z2, W3) + b3
    
    # 出力層の総出力
    y = u3
    
    print_vec("総入力1", u1)
    print_vec("中間層出力1", z1)
    print_vec("中間層出力2", z2)
    print_vec("総入力2", u2)
    print_vec("出力", y)
    print("出力合計: " + str(np.sum(y)))

    return y, z1, z2
# 入力値を定義
x = np.array([1., 2., 4.])
print_vec("入力", x)

# ネットワークを初期化
network =  init_network()

# 順伝播を実行
# 戻り値は、forward関数の中でprintされている。
y, z1, z2 = forward(network, x)

実行結果

*** 入力 ***
[1. 2. 4.]
shape: (3,)

##### ネットワークの初期化 #####
*** 重み1 ***
[[0.39377589 0.26543079 0.68575859 0.77044132 0.34758829 0.51529297
  0.97757656 0.61613076 0.28205748 0.40023244]
 [0.97433398 0.17493442 0.42837458 0.19662558 0.46118665 0.38609746
  0.39862823 0.08104316 0.37901295 0.5514943 ]
 [0.69429441 0.30303621 0.19865559 0.0517742  0.60997245 0.77926625
  0.60138945 0.04339023 0.47008209 0.5297549 ]]
shape: (3, 10)

*** 重み2 ***
[[0.52030676 0.76920658 0.10363616 0.78694994 0.34321369]
 [0.07943449 0.66188279 0.60170061 0.91921633 0.61721198]
 [0.60349089 0.36379732 0.86318401 0.12610421 0.76728614]
 [0.8272942  0.62011653 0.76860535 0.63298283 0.17604553]
 [0.69705507 0.39543528 0.0975826  0.87777558 0.74377917]
 [0.69669233 0.69363791 0.22243266 0.86751254 0.49265603]
 [0.11511029 0.93966428 0.99956427 0.88645115 0.97045599]
 [0.13552136 0.86091974 0.23541534 0.38202188 0.03147588]
 [0.21348788 0.45977318 0.51277281 0.55570694 0.15498767]
 [0.49276799 0.07601975 0.52168331 0.21889023 0.00590776]]
shape: (10, 5)

*** 重み3 ***
[[0.71376166 0.39251574 0.32280405 0.4562419 ]
 [0.06564796 0.38797656 0.69508703 0.22043952]
 [0.71365031 0.66907685 0.60482941 0.02429602]
 [0.76227587 0.51837433 0.38741856 0.23045885]
 [0.74978824 0.31510837 0.01838684 0.95428928]]
shape: (5, 4)

*** バイアス1 ***
[0.73443236 0.17534643 0.67800249 0.01246753 0.32426885 0.6821211
 0.11201273 0.84094531 0.59938663 0.60708438]
shape: (10,)

*** バイアス2 ***
[0.18955545 0.01285192 0.60137212 0.65958923 0.76607236]
shape: (5,)

*** バイアス3 ***
[0.76990169 0.31552078 0.37156246 0.26452867]
shape: (4,)

##### 順伝播開始 #####
*** 総入力1 ***
[5.85405386 2.00279088 3.01513258 1.38325681 4.03412022 5.08667398
 4.29240356 1.79272332 3.51979838 4.22932502]
shape: (10,)

*** 中間層出力1 ***
[5.85405386 2.00279088 3.01513258 1.38325681 4.03412022 5.08667398
 4.29240356 1.79272332 3.51979838 4.22932502]
shape: (10,)

*** 中間層出力2 ***
[16.28692836 20.43629279 16.3278324  23.68863899 16.86739858]
shape: (5,)

*** 総入力2 ***
[16.28692836 20.43629279 16.3278324  23.68863899 16.86739858]
shape: (5,)

*** 出力 ***
[56.09310543 43.15641452 39.19716085 34.15260983]
shape: (4,)

出力合計: 172.59929062309325

考察

本文でも少し触れたが、順伝播関数内で実行している内積計算が成り立っていることを確認した。

このネットワークでは、次のような配列の形状となっていることが出力結果からわかる。

パラメータ $\boldsymbol{x}$ $\boldsymbol{W1}$ $\boldsymbol{W2}$ $\boldsymbol{W3}$ $\boldsymbol{y}$
形状 3 3×10 10×5 5×4 4

上記のように隣り合う層の要素数が一致(例えば、$\boldsymbol{W1},\boldsymbol{W2}$では10)していることが分かる。


も参照してください