このシリーズではE資格対策として、書籍「ゼロから作るDeep Learning」を参考に学習に役立つ情報をまとめています。

<参考書籍>

Affineレイヤ

アフィン変換(線形変換とバイアスの追加)を実行するAffineクラスを定義しています。アフィン変換は、ニューラルネットワークの線形変換部分で用いられます。

# Affineクラスを定義します
class Affine:
    # インスタンス化時に重みWとバイアスbを初期化します
    def __init__(self, W, b):
        self.W = W
        self.b = b
        
        # 入力x、元のxの形状、勾配dW、勾配dbを初期化します
        self.x = None
        self.original_x_shape = None
        self.dW = None
        self.db = None

    # 順伝播を実行するforwardメソッドを定義します
    def forward(self, x):
        # 入力xの形状を記憶します
        self.original_x_shape = x.shape
        # 入力xを2次元にリシェイプします(バッチサイズ、特徴量数)
        x = x.reshape(x.shape[0], -1)
        # リシェイプしたxをインスタンス変数に格納します
        self.x = x

        # 順伝播の計算を実行し、出力を返します
        out = np.dot(self.x, self.W) + self.b

        return out

    # 逆伝播を実行するbackwardメソッドを定義します
    def backward(self, dout):
        # 逆伝播の計算を実行し、dxを求めます
        dx = np.dot(dout, self.W.T)
        # 重みの勾配dWを求めます
        self.dW = np.dot(self.x.T, dout)
        # バイアスの勾配dbを求めます
        self.db = np.sum(dout, axis=0)
        
        # dxを元のxの形状にリシェイプし、返します
        dx = dx.reshape(*self.original_x_shape)  
        return dx
  1. __init__(self, W, b): イニシャライザ。重み行列 W とバイアスベクトル b を受け取り、インスタンス変数に保存します。また、入力データ、重み・バイアスパラメータの微分、元の入力データの形状を保存するためのインスタンス変数も定義しています。
  2. forward(self, x): 順伝播を行うメソッド。入力データ x を受け取り、アフィン変換を実行して出力を返します。テンソル対応のため、入力データの形状を保存し、2次元配列に変換しています。
  3. backward(self, dout): 逆伝播を行うメソッド。出力データの誤差(勾配) dout を受け取り、重み W とバイアス b の勾配(dW, db)を計算します。また、入力データ x に対する勾配 dx も計算し、元の形状に戻して返します。

この Affine クラスは、ニューラルネットワークの学習や予測時にアフィン変換を行う際に使用されます。順伝播(forward)では、入力データ x を重み行列 W とのドット積を計算し、バイアスベクトル b を加算します。逆伝播(backward)では、パラメータ W と b の勾配を計算し、入力データ x に対する勾配を求めます。

実装例

この Affine クラスを使って簡単な順伝播(forward)と逆伝播(backward)の例を示します。numpyをインポートして、簡単なデータと重み、バイアスを作成して実行します。

import numpy as np

# 入力データ
x = np.array([[1.0, 0.5], [-0.4, 0.3]])

# 重み行列 W とバイアスベクトル b
W = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
b = np.array([0.1, 0.2, 0.3])

# Affine クラスのインスタンス化
affine = Affine(W, b)

# 順伝播
out = affine.forward(x)
print("Forward output:")
print(out)

# 出力の勾配(例として適当な値を使用)
dout = np.array([[1.0, 0.5, -0.2], [0.4, -0.1, 0.2]])

# 逆伝播
dx = affine.backward(dout)
print("Backward dx:")
print(dx)
print("Backward dW:")
print(affine.dW)
print("Backward db:")
print(affine.db)

実行結果:

Forward output:
[[0.3  0.7  1.1 ]
 [0.12 0.2  0.28]]
Backward dx:
[[0.15 0.28]
 [0.11 0.16]]
Backward dW:
[[ 0.84  0.54 -0.28]
 [ 0.62  0.22 -0.04]]
Backward db:
[1.4 0.4 0. ]

Softmax-with-Lossレイヤ

ソフトマックス関数と交差エントロピー誤差を組み合わせて損失値を計算し、勾配を求めるための逆伝播を実行します。

# SoftmaxWithLoss クラス: ソフトマックス関数と損失関数(交差エントロピー誤差)を組み合わせたクラス
class SoftmaxWithLoss:
    # コンストラクタ
    def __init__(self):
        self.loss = None    # 損失値
        self.y = None       # ソフトマックス関数の出力
        self.t = None       # 教師データ(正解ラベル)

    # 順伝播メソッド
    def forward(self, x, t):
        self.t = t                      # 教師データをセット
        self.y = softmax(x)             # ソフトマックス関数で計算
        self.loss = cross_entropy_error(self.y, self.t)  # 交差エントロピー誤差で損失を計算
        
        return self.loss                # 損失値を返す

    # 逆伝播メソッド
    def backward(self, dout=1):
        batch_size = self.t.shape[0]    # バッチサイズを取得
        # 教師データがone-hot-vectorの場合
        if self.t.size == self.y.size:  
            dx = (self.y - self.t) / batch_size
        else:
            dx = self.y.copy()
            dx[np.arange(batch_size), self.t] -= 1
            dx = dx / batch_size
        
        return dx  # 勾配を返す

ニューラルネットワークで多クラス分類問題を解く際に使用される、ソフトマックス関数と交差エントロピー誤差を組み合わせた損失レイヤーであるSoftmaxWithLossクラスを実装しています。このクラスは、順伝播によって損失値を計算し、逆伝播によって勾配を求めます。

  1. __init__ メソッド:
    • コンストラクタで、損失値、ソフトマックス関数の出力、教師データをそれぞれ初期化しています。
  2. forward メソッド:
    • 順伝播を行います。このメソッドは、入力データ x と教師データ t を引数に取ります。
    • softmax関数を使用して、入力データ x を確率分布に変換し、self.y に格納します。
    • cross_entropy_error関数を使用して、ソフトマックス関数の出力 self.y と教師データ self.t の交差エントロピー誤差を計算し、self.loss に格納します。
    • 損失値 self.loss を返します。
  3. backward メソッド:
    • 逆伝播を行います。このメソッドは、dout(デフォルトは1)を引数に取ります。
    • バッチサイズを取得します。
    • 教師データがone-hotベクトルの場合、ソフトマックス関数の出力 self.y と教師データ self.t の差を計算し、バッチサイズで割ります。これにより、入力データ x に対する損失の勾配 dx を求めます。
    • 教師データがone-hotベクトルでない場合、ソフトマックス関数の出力 self.y のコピーを作成し、教師データ self.t のインデックスに該当する要素を1減らします。その後、バッチサイズで割ります。これにより、入力データ x に対する損失の勾配 dx を求めます。
    • 勾配 dx を返します。

このSoftmaxWithLossクラスは、ニューラルネットワークの最後の層として使用され、訓練時に損失値を計算し、勾配を求めるために使用されます。損失値は、ネットワークの訓練がうまく進んでいるかどうかを評価するために使われ、最小化することが目標です。勾配は、ネットワークのパラメータを更新する際に使用される重要な情報で、損失を最小化する方向へパラメータを調整するために使われます。

SoftmaxWithLossクラスは、一般的なニューラルネットワークの実装において、訓練の最適化プロセスに不可欠な役割を果たします。多クラス分類問題を解く際、ソフトマックス関数は、ネットワークの出力を確率分布に変換し、交差エントロピー誤差は、その確率分布と教師データとの間の誤差を計算します。この誤差が小さくなるようにネットワークのパラメータを調整することで、訓練データに対する予測精度が向上し、汎化性能が高まることが期待されます。

まとめ

最後までご覧いただきありがとうございました。