準備

Googleドライブのマウント

In [1]:
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive

sys.pathの設定

以下では,Googleドライブのマイドライブ直下にDNN_codeフォルダを置くことを仮定しています.必要に応じて,パスを変更してください.

In [2]:
import sys
sys.path.append('/content/drive/My Drive/DNN_code_colab_lesson_1_2')

importと関数定義

In [3]:
import numpy as np
from common import functions

def print_vec(text, vec):
    print("*** " + text + " ***")
    print(vec)
    print("shape: " + str(vec.shape))
    print("")
#【コメント】ベクトル、行列のprint汎用関数

順伝播(単層・単ユニット)

In [4]:
# 順伝播(単層・単ユニット)

# 重み
W = np.array([[0.1], [0.2]])

## 試してみよう_配列の初期化
#W = np.zeros(2)
#W = np.ones(2)
#W = np.random.rand(2)
#W = np.random.randint(5, size=(2))

print_vec("重み", W)


# バイアス
b = np.array(0.5)

## 試してみよう_数値の初期化
#b = np.random.rand() # 0~1のランダム数値
#b = np.random.rand() * 10 -5  # -5~5のランダム数値

print_vec("バイアス", b)

# 入力値
x = np.array([2, 3])
print_vec("入力", x)


# 総入力
u = np.dot(x, W) + b
print_vec("総入力", u)

# 中間層出力
z = functions.relu(u)
print_vec("中間層出力", z)

#【コメント】入力2個、1ノードの場合のコード
#【コメント】1ノードなのでバイアスがスカラー
*** 重み ***
[[0.1]
 [0.2]]
shape: (2, 1)

*** バイアス ***
0.5
shape: ()

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

*** 総入力 ***
[1.3]
shape: (1,)

*** 中間層出力 ***
[1.3]
shape: (1,)

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

In [5]:
# 順伝播(単層・複数ユニット)

# 重み
W = np.array([
    [0.1, 0.2, 0.3,0], 
    [0.2, 0.3, 0.4, 0.5], 
    [0.3, 0.4, 0.5, 1],
])

## 試してみよう_配列の初期化
#W = np.zeros((4,3))
#W = np.ones((4,3))
#W = np.random.rand(4,3)
#W = np.random.randint(5, size=(4,3))

print_vec("重み", W)

# バイアス
b = np.array([0.1, 0.2, 0.3])
print_vec("バイアス", b)

# 入力値
x = np.array([1.0, 5.0, 2.0, -1.0])
print_vec("入力", x)

#  総入力
u = np.dot(W, x) + b
print_vec("総入力", u)

# 中間層出力
z = functions.sigmoid(u)
print_vec("中間層出力", z)

#【コメント】入力4個、3ノードの場合のコード
#【コメント】複数ノードなのでバイアスがベクトル
*** 重み ***
[[0.1 0.2 0.3 0. ]
 [0.2 0.3 0.4 0.5]
 [0.3 0.4 0.5 1. ]]
shape: (3, 4)

*** バイアス ***
[0.1 0.2 0.3]
shape: (3,)

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

*** 総入力 ***
[1.8 2.2 2.6]
shape: (3,)

*** 中間層出力 ***
[0.85814894 0.90024951 0.93086158]
shape: (3,)

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

In [6]:
# 順伝播(3層・複数ユニット)

# ウェイトとバイアスを設定
# ネートワークを作成
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
#【コメント】入力3個、1層目10ノード,2層目5ノード,出力層4ノードの
#【コメント】重み行列、バイアスベクトルを乱数で生成する


# プロセスを作成
# 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()

y, z1, z2 = forward(network, x)
#【コメント】出力層は活性化関数なし?
*** 入力 ***
[1. 2. 4.]
shape: (3,)

##### ネットワークの初期化 #####
*** 重み1 ***
[[0.6255993  0.78962847 0.53748528 0.75227442 0.14878807 0.19279338
  0.92874515 0.08377495 0.13601139 0.58288624]
 [0.04515404 0.3063119  0.45865758 0.87529123 0.50742802 0.65101252
  0.30805865 0.99493452 0.44652794 0.08077196]
 [0.33475673 0.40713212 0.99575882 0.31537961 0.79202928 0.6427052
  0.04293503 0.53942464 0.94327343 0.26996871]]
shape: (3, 10)

*** 重み2 ***
[[0.34634289 0.77373701 0.95124605 0.00706561 0.02240267]
 [0.53595183 0.03428832 0.6184747  0.8737514  0.60826376]
 [0.9329723  0.67977529 0.34959643 0.56661882 0.50232073]
 [0.98741475 0.43813647 0.99684265 0.142663   0.16816321]
 [0.58221515 0.49280483 0.40765528 0.47637675 0.29242637]
 [0.41918548 0.87950842 0.98951329 0.0562278  0.1767523 ]
 [0.47655983 0.00883622 0.53646617 0.2092623  0.46153495]
 [0.73149418 0.14658967 0.36723581 0.03486363 0.09186488]
 [0.00785002 0.01491101 0.80038771 0.32333323 0.77561621]
 [0.67182756 0.22900551 0.37775378 0.06673369 0.23356598]]
shape: (10, 5)

*** 重み3 ***
[[0.97974021 0.07095583 0.8125921  0.42988843]
 [0.96085362 0.56709998 0.12609496 0.04241878]
 [0.68755302 0.83188945 0.83394205 0.9690634 ]
 [0.06310235 0.93514253 0.27843019 0.65410455]
 [0.84037405 0.03981152 0.37033596 0.59930241]]
shape: (5, 4)

*** バイアス1 ***
[0.76847229 0.49215084 0.57081816 0.12950887 0.72169203 0.69781374
 0.92161715 0.64920832 0.79421577 0.24389548]
shape: (10,)

*** バイアス2 ***
[0.89722607 0.06852493 0.11593063 0.7573999  0.58004385]
shape: (5,)

*** バイアス3 ***
[0.53116674 0.70996466 0.94267512 0.92443771]
shape: (4,)

##### 順伝播開始 #####
*** 総入力1 ***
[2.82340656 3.52293161 6.00865389 3.89388419 5.05345326 4.76345294
 2.63821972 4.88055087 5.59637676 2.06820047]
shape: (10,)

*** 中間層出力1 ***
[2.82340656 3.52293161 6.00865389 3.89388419 5.05345326 4.76345294
 2.63821972 4.88055087 5.59637676 2.06820047]
shape: (10,)

*** 中間層出力2 ***
[24.41373804 16.14017186 26.20446009 13.16057796 15.26864466]
shape: (5,)

*** 総入力2 ***
[24.41373804 16.14017186 26.20446009 13.16057796 15.26864466]
shape: (5,)

*** 出力 ***
[71.63742207 46.30945061 53.98811151 55.25698045]
shape: (4,)

出力合計: 227.191964642833
In [7]:
np.random.rand(3, 3)
Out[7]:
array([[0.51687908, 0.94430206, 0.2463157 ],
       [0.48138302, 0.20009162, 0.3399848 ],
       [0.95185991, 0.85846035, 0.57186343]])

多クラス分類(2-3-4ネットワーク)

In [8]:
# 多クラス分類
# 2-3-4ネットワーク

# !試してみよう_ノードの構成を 3-5-6 に変更してみよう

# ウェイトとバイアスを設定
# ネートワークを作成
def init_network():
    print("##### ネットワークの初期化 #####")

    #試してみよう
    #_各パラメータのshapeを表示
    #_ネットワークの初期値ランダム生成

    network = {}
    
    input_layer_size = 3
    hidden_layer_size=5
    output_layer_size = 6
    
    #試してみよう
    #_各パラメータのshapeを表示
    #_ネットワークの初期値ランダム生成
    network['W1'] = np.random.rand(input_layer_size, hidden_layer_size)
    network['W2'] = np.random.rand(hidden_layer_size,output_layer_size)

    network['b1'] =  np.random.rand(hidden_layer_size)
    network['b2'] =  np.random.rand(output_layer_size)
    
    print_vec("重み1", network['W1'] )
    print_vec("重み2", network['W2'] )
    print_vec("バイアス1", network['b1'] )
    print_vec("バイアス2", network['b2'] )

    return network

# プロセスを作成
# x:入力値
def forward(network, x):
    
    print("##### 順伝播開始 #####")
    W1, W2 = network['W1'], network['W2']
    b1, b2 = network['b1'], network['b2']
    
    # 1層の総入力
    u1 = np.dot(x, W1) + b1

    # 1層の総出力
    z1 = functions.relu(u1)

    # 2層の総入力
    u2 = np.dot(z1, W2) + b2
    
    # 出力値
    y = functions.softmax(u2)
    
    print_vec("総入力1", u1)
    print_vec("中間層出力1", z1)
    print_vec("総入力2", u2)
    print_vec("出力1", y)
    print("出力合計: " + str(np.sum(y)))
        
    return y, z1

## 事前データ
# 入力値
x = np.array([1., 2.,  3.])

# 目標出力
d = np.array([0, 0, 0, 1, 0, 0])

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

# 出力
y, z1 = forward(network, x)

# 誤差
loss = functions.cross_entropy_error(d, y)

## 表示
print("\n##### 結果表示 #####")
print_vec("出力", y)
print_vec("訓練データ", d)
print_vec("交差エントロピー誤差",  loss)

#【コメント】順伝搬で出力し目標との誤差を表示
#【コメント】重みバイアスを乱数できめているため実行ごとに誤差が異なる
##### ネットワークの初期化 #####
*** 重み1 ***
[[0.6054533  0.95221801 0.49091798 0.18560827 0.16028321]
 [0.31638482 0.42407428 0.79753019 0.64700437 0.71265307]
 [0.420665   0.32183892 0.74512118 0.75667532 0.03924799]]
shape: (3, 5)

*** 重み2 ***
[[9.18848729e-01 6.50910415e-01 8.11122415e-01 1.00107254e-02
  1.10836373e-02 9.61689613e-01]
 [4.18394629e-01 4.30955798e-01 4.22573269e-01 7.00802588e-01
  8.64910256e-01 8.73418241e-01]
 [6.39422287e-01 5.18307685e-01 3.34479009e-02 2.72609444e-03
  8.10501021e-01 4.25212642e-01]
 [2.92856567e-04 5.96036741e-01 2.36659630e-05 6.86069554e-01
  5.11577560e-01 7.82891586e-01]
 [6.63078376e-01 4.94511676e-01 1.40930122e-01 4.86439235e-01
  2.69567573e-01 3.86154375e-01]]
shape: (5, 6)

*** バイアス1 ***
[0.66516332 0.44750339 0.52107077 0.07252875 0.79944144]
shape: (5,)

*** バイアス2 ***
[0.73004011 0.01918725 0.35337944 0.0193168  0.94790661 0.27061018]
shape: (6,)

##### 順伝播開始 #####
*** 総入力1 ***
[3.16538125 3.21338673 4.84241265 3.82217174 2.50277476]
shape: (5,)

*** 中間層出力1 ***
[3.16538125 3.21338673 4.84241265 3.82217174 2.50277476]
shape: (5,)

*** 総入力2 ***
[ 9.74001214  9.49006034  4.79355781  6.15587867 10.31706629 12.13921363]
shape: (6,)

*** 出力1 ***
[6.84515632e-02 5.33127005e-02 4.86592657e-04 1.90026419e-03
 1.21897502e-01 7.53951378e-01]
shape: (6,)

出力合計: 1.0

##### 結果表示 #####
*** 出力 ***
[6.84515632e-02 5.33127005e-02 4.86592657e-04 1.90026419e-03
 1.21897502e-01 7.53951378e-01]
shape: (6,)

*** 訓練データ ***
[0 0 0 1 0 0]
shape: (6,)

*** 交差エントロピー誤差 ***
6.265709733367789
shape: ()

回帰(2-3-2ネットワーク)

In [9]:
# 回帰
# 2-3-2ネットワーク

# !試してみよう_ノードの構成を 3-5-4 に変更してみよう

# ウェイトとバイアスを設定
# ネートワークを作成
def init_network():
    print("##### ネットワークの初期化 #####")

    input_layer_size = 3
    hidden_layer_size=5
    output_layer_size = 2
    
    #試してみよう
    #_各パラメータのshapeを表示
    #_ネットワークの初期値ランダム生成
    network['W1'] = np.random.rand(input_layer_size, hidden_layer_size)
    network['W2'] = np.random.rand(hidden_layer_size,output_layer_size)

    network['b1'] =  np.random.rand(hidden_layer_size)
    network['b2'] =  np.random.rand(output_layer_size)
    
    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 = functions.relu(u1)
    # 出力層の総入力
    u2 = np.dot(z1, W2) + b2
    # 出力層の総出力
    y = u2
    
    print_vec("総入力1", u1)
    print_vec("中間層出力1", z1)
    print_vec("総入力2", u2)
    print_vec("出力1", y)
    print("出力合計: " + str(np.sum(y)))
    
    return y, z1

# 入力値
x = np.array([1., 2., 3.])
network =  init_network()
y, z1 = forward(network, x)
# 目標出力
d = np.array([2., 4.])
# 誤差
loss = functions.mean_squared_error(d, y)

## 表示
print("\n##### 結果表示 #####")
print_vec("中間層出力", z1)
print_vec("出力", y)
print_vec("訓練データ", d)
print_vec("二乗誤差",  loss)

#【コメント】順伝搬で出力し目標との誤差を表示
#【コメント】重みバイアスを乱数できめているため実行ごとに誤差が異なる
##### ネットワークの初期化 #####
*** 重み1 ***
[[0.93595806 0.56096916 0.4891143  0.74443612 0.24681168]
 [0.12483792 0.58417674 0.22411535 0.89745767 0.89257202]
 [0.74406656 0.55077758 0.31514566 0.11467386 0.20594923]]
shape: (3, 5)

*** 重み2 ***
[[0.33446125 0.23590874]
 [0.58952237 0.19394462]
 [0.21616611 0.76372301]
 [0.17336893 0.2510052 ]
 [0.66386655 0.94309241]]
shape: (5, 2)

*** バイアス1 ***
[0.7503248  0.75665996 0.14151637 0.22895389 0.32505334]
shape: (5,)

*** バイアス2 ***
[0.89792352 0.11348257]
shape: (2,)

##### 順伝播開始 #####
*** 総入力1 ***
[4.16815837 4.13831536 2.02429834 3.11232692 2.97485675]
shape: (5,)

*** 中間層出力1 ***
[4.16815837 4.13831536 2.02429834 3.11232692 2.97485675]
shape: (5,)

*** 総入力2 ***
[7.68371381 7.03216985]
shape: (2,)

*** 出力1 ***
[7.68371381 7.03216985]
shape: (2,)

出力合計: 14.715883661078069

##### 結果表示 #####
*** 中間層出力 ***
[4.16815837 4.13831536 2.02429834 3.11232692 2.97485675]
shape: (5,)

*** 出力 ***
[7.68371381 7.03216985]
shape: (2,)

*** 訓練データ ***
[2. 4.]
shape: (2,)

*** 二乗誤差 ***
10.374664172150595
shape: ()

2値分類(2-3-1ネットワーク)

In [10]:
# 2値分類
# 2-3-1ネットワーク

# !試してみよう_ノードの構成を 5-10-20-1 に変更してみよう

# ウェイトとバイアスを設定
# ネートワークを作成
def init_network():
    print("##### ネットワークの初期化 #####")

    network = {}
    network['W1'] = np.array([
        [0.1, 0.3, 0.5,0.1, 0.3, 0.5,0.1, 0.3, 0.5, 0.1],
        [0.1, 0.3, 0.5,0.1, 0.3, 0.5,0.1, 0.3, 0.5, 0.1],
        [0.1, 0.3, 0.5,0.1, 0.3, 0.5,0.1, 0.3, 0.5, 0.1],
        [0.1, 0.3, 0.5,0.1, 0.3, 0.5,0.1, 0.3, 0.5, 0.1],
        [0.1, 0.3, 0.5,0.1, 0.3, 0.5,0.1, 0.3, 0.5, 0.1]
    ])
    network['W2'] = np.random.rand(10, 20)
    network['W3'] = np.random.rand(20, 1)

    network['b1'] = np.random.rand(10)
    network['b2'] =np.random.rand(20)
    network['b3'] =np.random.rand(1)

    return network


# プロセスを作成
def forward(network, x):
    print("##### 順伝播開始 #####")
    
    W1, W2, W3 = network['W1'], network['W2'],network['W3']
    b1, b2, b3 = network['b1'], network['b2'],network['b3']

    # 隠れ層の総入力
    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
    z3 = functions.sigmoid(u3)
    y = z3    
    print_vec("総入力1", u1)
    print_vec("中間層出力1", z1)
    print_vec("総入力2", u2)
    print_vec("総入力3", u3)
    print_vec("出力1", y)
    print("出力合計: " + str(np.sum(y)))

    return y, z1

# 入力値
x = np.array([1., 2.,2.,4.,5.])

# 目標出力
d = np.array([1])
network =  init_network()
y, z1 = forward(network, x)
# 誤差
loss = functions.cross_entropy_error(d, y)

## 表示
print("\n##### 結果表示 #####")
print_vec("中間層出力", z1)
print_vec("出力", y)
print_vec("訓練データ", d)
print_vec("交差エントロピー誤差",  loss)

#【コメント】順伝搬で出力し目標との誤差を表示
#【コメント】W1以外は乱数できめているのに実行ごとにy変わらない
#【コメント】u3が200くらいになっているのでシグモイド関数で1になる
#【コメント】重み、バイアスが大きすぎる?
##### ネットワークの初期化 #####
##### 順伝播開始 #####
*** 総入力1 ***
[1.5853682  4.63408494 7.85011715 1.60934991 4.74390506 7.47380022
 1.7508456  4.31062689 7.97256774 1.72617325]
shape: (10,)

*** 中間層出力1 ***
[1.5853682  4.63408494 7.85011715 1.60934991 4.74390506 7.47380022
 1.7508456  4.31062689 7.97256774 1.72617325]
shape: (10,)

*** 総入力2 ***
[31.62843591 14.51901344 15.15351819 16.5175263  17.54257616 18.53508125
 23.38185193 24.7277357  15.3631875  22.83482586 17.25438767 17.10192856
 25.17201404 18.54716329 20.99663318 14.72958812 17.76286215 24.99036829
 21.67339732 18.9609411 ]
shape: (20,)

*** 総入力3 ***
[215.09321859]
shape: (1,)

*** 出力1 ***
[1.]
shape: (1,)

出力合計: 1.0

##### 結果表示 #####
*** 中間層出力 ***
[1.5853682  4.63408494 7.85011715 1.60934991 4.74390506 7.47380022
 1.7508456  4.31062689 7.97256774 1.72617325]
shape: (10,)

*** 出力 ***
[1.]
shape: (1,)

*** 訓練データ ***
[1]
shape: (1,)

*** 交差エントロピー誤差 ***
-9.999999505838704e-08
shape: ()

In [11]:
import numpy as np
# 中間層の活性化関数
# シグモイド関数(ロジスティック関数)
def sigmoid(x):
    return 1/(1 + np.exp(-x))

# ReLU関数
def relu(x):
    return np.maximum(0, x)

# ステップ関数(閾値0)
def step_function(x):
    return np.where( x > 0, 1, 0) 
In [13]:
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
In [25]:
#【コメント】活性化関数をプロットしてみる
fig, ax = plt.subplots(facecolor="w")

x = np.arange(-3,3,0.01)

ax.plot(x,step_function(x),label="step")
ax.plot(x,sigmoid(x),label="sigmoid")
ax.plot(x,relu(x),label="relu")
ax.legend()
Out[25]:
<matplotlib.legend.Legend at 0x7f4c167f6a50>