このシリーズではE資格対策として、シラバスの内容を項目別にまとめています。
Layer正規化
Layer正規化の概要
Layer正規化は、各入力サンプルのすべての特徴を通じて正規化を行う手法です。バッチノーマライゼーションがバッチ内の各特徴で正規化を行うのに対して、Layer正規化は各データポイント内で正規化を行います。バッチノーマライゼーションがミニバッチのデータに対して正規化を行うのに対し、Layer正規化は各データ点に対して同じ平均と分散を用いて正規化します。具体的には、入力データの特徴量の次元に沿って平均と分散を計算します。
- 平均と分散の計算: 各データポイント内で、特徴全体の平均と分散を計算します。
- 正規化: 各特徴を平均0、分散1に正規化します。
- スケールとシフト: スケーリングパラメータ(ガンマ)とシフトパラメータ(ベータ)を使用して、正規化された値に対してスケーリングとシフトを行います。
数式で表すと以下のようになります。
特徴の平均の計算: 入力特徴の平均を計算します。この値は、各特徴の正規化に使用されます。
特徴の分散の計算: 入力特徴の分散を計算します。この値も、正規化に使用されます。
特徴の正規化: 各特徴を平均0、分散1に正規化します。ここでϵはゼロ除算を防ぐための小さな値です。
スケールとシフト: 正規化された値に対してスケーリングとシフトを行います。ここでγとβは学習可能なパラメータです。
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正規化のプロセスは以下の通りです。
- 各データ点と各チャンネルで、平均と分散を計算
- 平均を引いて分散で割ることで正規化
- スケール変換とシフト変換
数式で表すと、以下のようになります。
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: 入力データ、スケール係数、およびオフセット係数に対する勾配を計算します。
まとめ
最後までご覧いただきありがとうございました。