from google.colab import drive
drive.mount('/content/drive')
以下では,Googleドライブのマイドライブ直下にDNN_codeフォルダを置くことを仮定しています.必要に応じて,パスを変更してください.
import sys
sys.path.append('/content/drive/My Drive/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("")
#【コメント】ベクトル、行列のprint汎用関数
# 順伝播(単層・単ユニット)
# 重み
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ノードなのでバイアスがスカラー
# 順伝播(単層・複数ユニット)
# 重み
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ノードの場合のコード
#【コメント】複数ノードなのでバイアスがベクトル
# 順伝播(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)
#【コメント】出力層は活性化関数なし?
np.random.rand(3, 3)
# 多クラス分類
# 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)
#【コメント】順伝搬で出力し目標との誤差を表示
#【コメント】重みバイアスを乱数できめているため実行ごとに誤差が異なる
# 回帰
# 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)
#【コメント】順伝搬で出力し目標との誤差を表示
#【コメント】重みバイアスを乱数できめているため実行ごとに誤差が異なる
# 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になる
#【コメント】重み、バイアスが大きすぎる?
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)
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
#【コメント】活性化関数をプロットしてみる
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()
# 出力層の活性化関数
# ソフトマックス関数
def softmax(x):#ここが①
if x.ndim == 2:#2次元の場合は
x = x.T#転置する
x = x - np.max(x, axis=0)#0軸の最大値を引く
y = np.exp(x) / np.sum(np.exp(x), axis=0)#各要素/0軸の総和
return y.T#転置してリターン
x = x - np.max(x) # オーバーフロー対策#最大値を引く(値自体ではなく大小関係が重要?)
return np.exp(x) / np.sum(np.exp(x))#分子が②,分母が③#各要素/総和
# クロスエントロピー
def cross_entropy_error(d, y):#ここが①
if y.ndim == 1:#横ベクトルの場合
d = d.reshape(1, d.size)#縦に変更
y = y.reshape(1, y.size)#縦に変更
# 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
if d.size == y.size:
d = d.argmax(axis=1)#1軸の一番大きい値のインデックス
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size#ここが②
#1e-7を足す意味:logを-無限に収束させないため。ごくわずかな値を足しておく