konchangakita

KPSを一番楽しんでいたブログ 会社の看板を背負いません 転載はご自由にどうぞ

【DeepLearning特訓】MLPの基礎 誤差逆伝播までPython実装

E資格向けの自習アウトプット
自分用メモ

誤差逆伝播までの流れを一旦 python実装 してみる
 1.データ定義
 2.順伝播(アフィン変換、ReLU)
 3.コスト関数(誤差の計算)
 4.誤差逆伝播

とりあえず絵にしてみる
f:id:konchangakita:20210108224928p:plain
求めたいのはパラメータの勾配

入力データの定義

実際には、入力データと正解ラベルが対になっているが、とりあえず適当に数値を用意
(例:「車の画像」と「車」というラベル)
重みとバイアスもランダムな値で

import numpy as np

# 入力データの用意(1セットのみ適当なランダムな数値)
# 実際には1000かと1万とかもっといっぱいある
x1 = np.random.rand(1,3)
# 正解ラベル one-hot-vector
t = np.array((1,0,0))

# 重み w, バイアス b の初期設定
w1 = np.random.randn(3,4)
b1 = np.random.randn(4)
w2 = np.random.randn(4,3)
b2 = np.random.randn(3)


順伝播

入力データを「アフィン変換、ReLU関数」で中間層へ
ソフトマックスとで最後の

import numpy as np

# 順伝播:アフィン変換
def forward(x, w, b):
    y = np.dot(x, w) + b
    return y

# 順伝播:活性化関数 ReLU
# mask: 勾配の計算用
def relu(x):
    mask = (x <= 0)
    return np.maximum(0, x), mask

# 順伝播:出力ユニット ソフトマックス
def softmax(x):
    # ※[N, M] - [N]はできないので、 転置して[M, N] - [N]
    x = x.T             
    _x = x - np.max(x)
    _x = np.exp(x) / np.sum(np.exp(x), axis=0)
    return _x.T

# コスト関数 クロスエントロピー誤差
def cross_entropy_error(t, y):
    delta = 1e-8
    loss = -np.mean(t * np.log(y + delta))
    return loss


# 入力データの用意(1セットのみ適当なランダムな数値)
x1 = np.random.rand(1,3)
# 正解ラベル one-hot-vector
t = np.array((1,0,0))

# 重み w, バイアス b の初期設定
w1 = np.random.randn(3,4)
b1 = np.random.randn(4)
w2 = np.random.randn(4,3)
b2 = np.random.randn(3)


誤差逆伝播

順伝播で出力された「誤差」を持って、勾配を逆伝播していく
順伝播の中間層で一度算出された値の再利用を一度変数に収めているが、Python の Class を使えばもっとシンプルに書くことができる
今回は敢えて各層の計算で何が必要なのかを見やすくするために、関数のみで下記揃える

# 誤差逆伝播:ReLU
def drelu(dout, mask):
    dout[mask] = 0
    return dout

# 誤差逆伝播:アフィン変換
def backward(dout, x, w):
    dx = np.dot(dout, w.T)
    dw = np.dot(x.T, dout)
    db = np.sum(dout, axis=0)
    return dx, dw, db

# 誤差逆伝播
dout2 = y - t # ソフトマックスwithクロスエントロピーの勾配
dx2, dw2, db2 = backward(dout2, x2, w2)
dout1 = drelu(dx2, wmask1)
dx1, dw1, db1 = backward(dout1, x1, w1)

# 誤差
print('Loss: ', loss)
print('')

# 重み、バイアスの勾配
print('第1層の勾配')
print('w1:\n', w1)
print('b1:\n', b1)
print('')
print('第2層の勾配')
print('w2:\n', w2)
print('b2:\n', b2)

アウトプット

Loss:  0.4813766638499986

第1層の勾配
w1:
 [[-0.81608621  0.78189308 -1.98234178  0.52644459]
 [ 0.21205568  0.86098345  0.1558696  -0.62931689]
 [ 1.21615824 -0.51937533  0.33134833 -0.43714047]]
b1:
 [-0.58540344 -0.44224125  0.46466139 -0.06018246]

第2層の勾配
w2:
 [[ 0.01044176 -0.0790746  -0.70335393]
 [-0.65571456 -0.10833987  0.32557463]
 [-0.52371017  0.08358353 -0.26835567]
 [-0.77081821  0.52365595 -0.10367158]]
b2:
 [ 0.7871995   1.71908927 -1.39842447]

まとめ

誤差逆伝播を使って、パラメータの勾配を計算するところまではこんな感じ
学習モデルのステップとしては、パラメータをどう更新していくかを考えていく