このシリーズではE資格対策として、書籍「ゼロから作るDeep Learning」を参考に学習に役立つ情報をまとめています。
<参考書籍>
ReLUレイヤ
ReLU(Rectified Linear Unit)活性化関数のクラスを実装します。ReLU関数は、ニューラルネットワークの活性化関数として広く使用されており、入力が0以下の場合には0を出力し、それ以外の場合には入力をそのまま出力します。また、逆伝播も考慮しています。
class Relu:
def __init__(self):
# mask変数を初期化
self.mask = None
def forward(self, x):
# xの要素が0以下の場合、Trueとなるマスクを作成
self.mask = (x <= 0)
# xのコピーを作成
out = x.copy()
# マスクがTrueの場合、outの対応する要素を0に設定
out[self.mask] = 0
# 出力を返す
return out
def backward(self, dout):
# マスクがTrueの場合、doutの対応する要素を0に設定
dout[self.mask] = 0
# dxにdoutを代入し、dxを返す
dx = dout
return dx
ReLUレイヤの実装
ここでは、適当な数値を持つnumpy配列を作成し、ReLUクラスのインスタンスを使って順伝播と逆伝播を実行してみます。
import numpy as np
# 適当な数値を持つnumpy配列を作成
x = np.array([-1.0, 0.0, 1.0, -0.5, 2.0, 3.0])
print("入力x:", x)
# ReLUクラスのインスタンスを作成
relu = Relu()
# 順伝播
out = relu.forward(x)
print("順伝播の結果:", out)
# 逆伝播のための適当な勾配を作成
dout = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
# 逆伝播
dx = relu.backward(dout)
print("逆伝播の結果:", dx)
実行結果:
入力x: [-1. 0. 1. -0.5 2. 3. ]
順伝播の結果: [0. 0. 1. 0. 2. 3.]
逆伝播の結果: [0. 0. 1. 0. 1. 1.]
- 順伝播の結果、ReLU関数は入力配列の要素が0以下の場合、0を出力し、それ以外の場合、入力要素をそのまま出力していることがわかります。
- 逆伝播の結果、入力配列の要素が0より大きい場合、勾配はそのまま伝搬されていますが、0以下の場合、勾配が0になっていることがわかります。これは、ReLU関数が線形領域(正の値)で微分可能であり、その導関数が1であるためです。一方、非線形領域(負の値)では、導関数が0であり、勾配が伝搬されません。
Sigmoidレイヤ
シグモイド活性化関数のクラスを実装しています。シグモイド関数は、ニューラルネットワークの活性化関数として広く使用されていましたが、現在ではReLU関数など他の関数に取って代わられつつあります。シグモイド関数は、入力を0から1の範囲に変換するため、確率に関連する問題で便利です。また、逆伝播も考慮しています。
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
class Sigmoid:
def __init__(self):
# out変数を初期化
self.out = None
def forward(self, x):
# シグモイド関数を適用して出力を計算
out = sigmoid(x)
# 出力をインスタンス変数に保存
self.out = out
# 出力を返す
return out
def backward(self, dout):
# 逆伝播の際の勾配を計算
dx = dout * (1.0 - self.out) * self.out
# 勾配を返す
return dx
Sigmoidレイヤの実装
適当な数値を持つnumpy配列を作成し、Sigmoidクラスのインスタンスを使って順伝播と逆伝播を実行してみます。
# 適当な数値を持つnumpy配列を作成
x = np.array([-1.0, 0.0, 1.0, -0.5, 2.0, 3.0])
print("入力x:", x)
# Sigmoidクラスのインスタンスを作成
sigmoid_layer = Sigmoid()
# 順伝播
out = sigmoid_layer.forward(x)
print("順伝播の結果:", out)
# 逆伝播のための適当な勾配を作成
dout = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
# 逆伝播
dx = sigmoid_layer.backward(dout)
print("逆伝播の結果:", dx)
実行結果:
入力x: [-1. 0. 1. -0.5 2. 3. ]
順伝播の結果: [0.26894142 0.5 0.73105858 0.37754067 0.88079708 0.95257413]
逆伝播の結果: [0.19661193 0.25 0.19661193 0.23500371 0.10499359 0.04517666]
- 順伝播の結果、シグモイド関数は入力配列の要素を0から1の範囲に変換しています。シグモイド関数は、連続的で微分可能な関数であり、確率に関連する問題で役立ちます。
- 逆伝播の結果、シグモイド関数の勾配が計算されています。この勾配は、シグモイド関数の導関数である
sigmoid(x) * (1 - sigmoid(x))
に基づいています。逆伝播の際、この勾配が前の層に伝搬されます。シグモイド関数の勾配は、0から0.25の範囲になります。これは、シグモイド関数が飽和すると(入力の絶対値が大きくなると)、勾配が小さくなり、勾配消失問題が発生することを示しています。これが、現在ではReLU関数など他の活性化関数に取って代わられつつある理由の1つです。
まとめ
最後までご覧いただきありがとうございました。