このシリーズではE資格対策として、シラバスの内容を項目別にまとめています。

E資格まとめ

試験概要 ディープラーニングの理論を理解し、適切な手法を選択して実装する能力や知識を有しているかを認定する。 1.応用数学 (1)確率・統計 (2)情報理論 2.機…

Layer正規化

Layer正規化の概要

Layer正規化は、各入力サンプルのすべての特徴を通じて正規化を行う手法です。バッチノーマライゼーションがバッチ内の各特徴で正規化を行うのに対して、Layer正規化は各データポイント内で正規化を行います。バッチノーマライゼーションがミニバッチのデータに対して正規化を行うのに対し、Layer正規化は各データ点に対して同じ平均と分散を用いて正規化します。具体的には、入力データの特徴量の次元に沿って平均と分散を計算します。

  1. 平均と分散の計算: 各データポイント内で、特徴全体の平均と分散を計算します。
  2. 正規化: 各特徴を平均0、分散1に正規化します。
  3. スケールとシフト: スケーリングパラメータ(ガンマ)とシフトパラメータ(ベータ)を使用して、正規化された値に対してスケーリングとシフトを行います。

数式で表すと以下のようになります。

特徴の平均の計算: 入力特徴の平均を計算します。この値は、各特徴の正規化に使用されます。

\[ \mu_l = \frac{1}{d}\sum_{i=1}^{d} x_i \]

特徴の分散の計算: 入力特徴の分散を計算します。この値も、正規化に使用されます。

\[ \begin{align*} \sigma_l^2 &= \frac{1}{d}\sum_{i=1}^{d}(x_i – \mu_l)^2 \\ \end{align*} \]

特徴の正規化: 各特徴を平均0、分散1に正規化します。ここでϵはゼロ除算を防ぐための小さな値です。

\[ \begin{align*} \hat{x}_i &= \frac{x_i – \mu_l}{\sqrt{\sigma_l^2 + \epsilon}} \\ \end{align*} \]

スケールとシフト: 正規化された値に対してスケーリングとシフトを行います。ここでγβは学習可能なパラメータです。

\[ \begin{align*} y_i &= \gamma \hat{x}_i + \beta \end{align*} \]

Layer正規化の特徴

バッチサイズに依存しない: Layer正規化は各データポイントの特徴に沿って正規化を行うため、バッチサイズに依存しません。これにより、異なるバッチサイズでの訓練が容易になります。
RNNとの親和性: Layer正規化は、時系列データを扱う再帰型ニューラルネットワーク(RNN)とよく合います。RNNではバッチサイズが変動することがあるため、Layer正規化がよく使用されます。

メリット
・バッチサイズに依存しない: バッチサイズに影響されず、小さいバッチサイズでも安定して動作します。
・RNNとの親和性: 時系列データに対するモデルでよく用いられます。

デメリット
・学習の加速効果が限定的: バッチノーマライゼーションほど学習の加速効果が得られないことがある。

Layer正規化の実装

class LayerNormalization:
    def __init__(self, gamma, beta, eps=1e-6):
        self.gamma = gamma
        self.beta = beta
        self.eps = eps
        self.input_shape = None
        self.x_normalized = None
        self.std_inv = None

    def forward(self, x):
        self.input_shape = x.shape
        N, D = x.shape
        mean = x.mean(axis=1, keepdims=True)
        std = np.sqrt(x.var(axis=1, keepdims=True) + self.eps)
        self.std_inv = 1 / std
        x_centered = x - mean
        self.x_normalized = x_centered * self.std_inv
        out = self.gamma * self.x_normalized + self.beta
        return out

    def backward(self, dout):
        N, D = dout.shape
        dbeta = np.sum(dout, axis=0)
        dgamma = np.sum(self.x_normalized * dout, axis=0)
        dx_normalized = self.gamma * dout
        dstd_inv = np.sum(dx_normalized * (self.x_normalized * -1), axis=1, keepdims=True)
        dvar = 0.5 * dstd_inv * self.std_inv
        dx_centered = (dx_normalized * self.std_inv) + ((2 / D) * self.x_normalized * dvar)
        dmean = np.sum(dx_centered * -1, axis=1, keepdims=True)
        dx = dx_centered + (dmean / D)
        
        self.dgamma = dgamma
        self.dbeta = dbeta
        
        return dx

順伝播メソッド forward: 平均と標準偏差を計算し、正規化します。スケールとオフセットのパラメーターも適用します。

逆伝播メソッド backward: 勾配を計算するため、順伝播で計算された中間値を使用します。特に、正規化されたxの勾配、標準偏差の逆数の勾配、分散の勾配、中心化されたxの勾配、平均の勾配などを計算します。

Instance正規化

Instance正規化は、バッチノーマライゼーションとLayer正規化とは異なる次元に沿って正規化を行う手法です。具体的には、各データ点と各チャンネルに対して独立に正規化を行います。この正規化手法は、特に画像生成タスクにおいて効果的で、スタイル変換や生成モデルに広く使用されています。

Instance正規化のプロセスは以下の通りです。

  1. 各データ点と各チャンネルで、平均と分散を計算
  2. 平均を引いて分散で割ることで正規化
  3. スケール変換とシフト変換

数式で表すと、以下のようになります。

\begin{align*} \mu_c & = \frac{1}{H \times W}\sum_{h=1}^{H}\sum_{w=1}^{W} x_{chw} & \text{(各チャンネルの平均を計算)} \\ \sigma_c^2 & = \frac{1}{H \times W}\sum_{h=1}^{H}\sum_{w=1}^{W} (x_{chw} – \mu_c)^2 & \text{(各チャンネルの分散を計算)} \\ \hat{x}_{chw} & = \frac{x_{chw} – \mu_c}{\sqrt{\sigma_c^2 + \epsilon}} & \text{(各データ点と各チャンネルで正規化)} \\ y_{chw} & = \gamma_c \hat{x}_{chw} + \beta_c & \text{(スケール変換とシフト変換を施す)} \end{align*}
class InstanceNormalization:
    def __init__(self, gamma, beta, eps=1e-6):
        self.gamma = gamma
        self.beta = beta
        self.eps = eps

    def forward(self, x):
        N, C, H, W = x.shape
        mean = x.mean(axis=(2, 3), keepdims=True)
        std = np.sqrt(x.var(axis=(2, 3), keepdims=True) + self.eps)
        x_normalized = (x - mean) / std
        out = self.gamma * x_normalized + self.beta
        return out

    def backward(self, dout):
        N, C, H, W = dout.shape
        dbeta = np.sum(dout, axis=(0, 2, 3), keepdims=True)
        dgamma = np.sum((self.x - self.mean) / self.std * dout, axis=(0, 2, 3), keepdims=True)
        dx_normalized = dout * self.gamma
        dvar = np.sum(dx_normalized * (self.x - self.mean) * -0.5 * (self.std ** -3), axis=(2, 3), keepdims=True)
        dmean = np.sum(dx_normalized * -1 / self.std, axis=(2, 3), keepdims=True) + dvar * np.sum(-2 * (self.x - self.mean), axis=(2, 3), keepdims=True) / (H * W)
        dx = dx_normalized / self.std + dvar * 2 * (self.x - self.mean) / (H * W) + dmean / (H * W)

        return dx

初期化メソッド init: スケール係数(gamma)とオフセット係数(beta)の初期化を行い、数値安定性のための小さな値(eps)も設定します。
順伝播メソッド forward: 各データポイント、各チャンネルに対して、平均と標準偏差を計算し、正規化します。
逆伝播メソッド backward: 入力データ、スケール係数、およびオフセット係数に対する勾配を計算します。

まとめ

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