なぜ重みの初期化が重要なのか?
ニューラルネットワークは、学習前にランダムな重みを持ちます。この「重みの初期化」が不適切だと、以下のような問題が発生します:
- 勾配消失・爆発によって学習が進まない
- 出力がすぐに0や1で飽和し、活性化関数の意味がなくなる
- 層の役割が固定されてしまい、ネットワーク全体が学習できなくなる
そのため、適切な初期化手法を選ぶことが、深層学習では非常に重要です。
活性化関数の仕組みと重みの関係
ReLU(f(x) = max(0, x))などの活性化関数は、**前の層の出力に対して“通す or 切る”**という判断を行います。
この「出力を活かすかどうか」は、前段の重み付き和(wx + b)に依存しています。
例えば:
# ReLUの例
import torch
x = torch.tensor([-1.0, 0.0, 0.8])
relu = torch.nn.ReLU()
print(relu(x)) # tensor([0.0000, 0.0000, 0.8000])
また、以下は双曲線正接関数 tanh の例です:
# tanhの例
import torch
x = torch.tensor([-1.0, 0.0, 1.0])
tanh = torch.nn.Tanh()
print(tanh(x)) # tensor([-0.7616, 0.0000, 0.7616])
これらの関数の入力値は、重みによって変化します。つまり、重みの初期値が偏っていると、活性化関数の入力が偏ってしまい、学習がスムーズに進まないことがあるのです。
ここの例だと [-1.0, 0.0, 1.0] が重み付き和を計算した結果の値に相当します。
もし初期の重みが偏っていると、この入力値が [-10.0, -20.0, -5.0] といった極端な値になってしまい、ReLU の出力は常に [0.0, 0.0, 0.0]、tanh の出力は常に [-0.999, -0.999, -0.999] のように飽和してしまいます。こうなると、勾配が流れず学習が進まなくなるのです。
なお、活性化関数に入力される「重み付き和」は、層の出力に強く影響します。たとえば、画像の中で犬の足の部分を認識するタスクでは、ある層では足の輪郭が重要でも、別の層ではその情報が重要でないこともあります。このような異なる層での判断を柔軟にするためには、重み付き和が広い範囲で適切に分布していることが必要です。
重み付き和とは?
重み付き和(weighted sum)とは、ニューラルネットワークの各ニューロンで行われる基本的な計算で、以下の式で表されます:
ここで:
- :入力値(例:画像のピクセルや音声特徴量)
- :各入力の重み(重要度)
- :バイアス項
この計算結果 が、ReLUやtanhなどの活性化関数に渡され、最終的な出力が決まります。画像や音声、テキストなど、すべてのAIタスクで使われる基礎処理です。
バイアスも初期化すべき?
はい。通常、初期値0.0で問題がないことが多いですが、バイアスも重みと同様に学習されるパラメータであり、必要に応じて明示的に初期化されることがあります。
多くのケースでは PyTorch によりゼロで初期化されますが、以下のように手動で設定することも可能です:
# バイアスを定数で初期化
nn.init.constant_(layer.bias, 0.0)
一方、重みは活性化関数との相性や勾配消失・爆発の問題を防ぐために、XavierやKaimingなどの手法で明示的に初期化することが多いのが実情です。
よく使われる初期化方法
1. Xavier初期化(Glorot初期化)
中間層がtanhなど対称な活性化関数を使う場合に有効。
import torch.nn as nn
nn.init.xavier_uniform_(layer.weight)
2. Kaiming初期化(He初期化)
ReLU系の活性化関数と相性がよく、最近のモデルで主流。
nn.init.kaiming_normal_(layer.weight, mode='fan_in', nonlinearity='relu')
PyTorchで初期化を適用するには?
自作のモデルに対して、以下のようにapply()
を使うと、全層に初期化が可能です。
def init_weights(m):
if isinstance(m, nn.Linear):
nn.init.kaiming_normal_(m.weight, mode='fan_in', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0.0)
model = MyModel()
model.apply(init_weights)
初期化 vs シード固定:違いは?
初期化は「どんな重みやバイアスで学習を始めるか」を決める処理。一方で、シードの固定は再現性のために「毎回同じ乱数を使う」設定です。
import torch, random, numpy as np
def set_seed(seed=42):
torch.manual_seed(seed)
random.seed(seed)
np.random.seed(seed)
初期化の精度検証や比較には、シード固定が必須です。
学習が進まないときにチェックすべきこと
- 活性化関数と初期化方法が適切か?
- 重みとバイアスの初期化が適用されているか?
- シードが固定されているか?(再現性の確認)
まとめ
重みとバイアスの初期化は、モデル学習の「出発点」。スタート地点が偏っていると、ゴールにはたどり着けません。PyTorchでは簡単に設定できるので、自分のモデルに適切な初期化を試してみましょう。
また、活性化関数が意味を持つためには、前段の重み付き和が適切に分布していることが重要です。正しい初期化で、効率の良い学習をスタートさせましょう。