はじめに:活性化関数の重要性
ニューラルネットワークにおいて「活性化関数(Activation Function)」は、各ニューロンの出力に非線形性を加える重要な役割を持ちます。適切な関数を選ぶことで、学習のスピードや精度が大きく変わります。
本記事では代表的な4つの活性化関数 ReLU・LeakyReLU・ELU・GELU を比較し、それぞれの特徴と違いを解説します。
比較する活性化関数
- ReLU(Rectified Linear Unit、「レルー」と読む):最も一般的な活性化関数。シンプルで高速。
- LeakyReLU(Leaky Rectified Linear Unit):ReLUの欠点(死んだReLU)を緩和。
- ELU(Exponential Linear Unit):学習初期の安定性に強い。
- GELU(Gaussian Error Linear Unit):最近注目の関数。BERTなどで使用。
実験概要
4つの活性化関数を用いて、それぞれ同じ構造のCNNモデルをMNISTデータセットで訓練し、精度・学習速度を比較します。
環境とライブラリ
import tensorflow as tf
from tensorflow.keras import layers, models
import numpy as np
import matplotlib.pyplot as plt
# GELUは tf.nn.gelu で使用可能
データ準備(MNIST)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
モデル構築関数
def build_model(activation_fn):
model = models.Sequential([
layers.Input(shape=(28, 28, 1)),
layers.Conv2D(32, (3, 3)),
activation_fn,
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64),
activation_fn,
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
return model
それぞれのモデル
models_dict = {
'ReLU': build_model(layers.Activation('relu')),
'LeakyReLU': build_model(layers.LeakyReLU(negative_slope=0.1)),
'ELU': build_model(layers.ELU(alpha=1.0)),
'GELU': build_model(layers.Activation(tf.nn.gelu))
}
訓練と精度の記録
history_dict = {}
for name, model in models_dict.items():
print(f"Training with {name}")
history = model.fit(x_train, y_train, epochs=5, batch_size=128,
validation_split=0.1, verbose=1)
history_dict[name] = history
実行結果
Training with ReLU Epoch 1/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 7s 9ms/step - accuracy: 0.8406 - loss: 0.5529 - val_accuracy: 0.9693 - val_loss: 0.1072 Epoch 2/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9713 - loss: 0.0998 - val_accuracy: 0.9815 - val_loss: 0.0692 Epoch 3/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9819 - loss: 0.0631 - val_accuracy: 0.9857 - val_loss: 0.0553 Epoch 4/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9873 - loss: 0.0452 - val_accuracy: 0.9837 - val_loss: 0.0617 Epoch 5/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9891 - loss: 0.0373 - val_accuracy: 0.9878 - val_loss: 0.0506 Training with LeakyReLU Epoch 1/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.8536 - loss: 0.5220 - val_accuracy: 0.9730 - val_loss: 0.0992 Epoch 2/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9719 - loss: 0.0961 - val_accuracy: 0.9820 - val_loss: 0.0665 Epoch 3/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9823 - loss: 0.0607 - val_accuracy: 0.9838 - val_loss: 0.0608 Epoch 4/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 0.9864 - loss: 0.0464 - val_accuracy: 0.9837 - val_loss: 0.0568 Epoch 5/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9893 - loss: 0.0353 - val_accuracy: 0.9865 - val_loss: 0.0546 Training with ELU Epoch 1/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.8654 - loss: 0.4912 - val_accuracy: 0.9700 - val_loss: 0.1047 Epoch 2/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 0.9677 - loss: 0.1089 - val_accuracy: 0.9800 - val_loss: 0.0689 Epoch 3/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9801 - loss: 0.0657 - val_accuracy: 0.9805 - val_loss: 0.0689 Epoch 4/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9874 - loss: 0.0440 - val_accuracy: 0.9833 - val_loss: 0.0598 Epoch 5/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 0.9898 - loss: 0.0341 - val_accuracy: 0.9847 - val_loss: 0.0564 Training with GELU Epoch 1/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.8462 - loss: 0.5652 - val_accuracy: 0.9703 - val_loss: 0.1155 Epoch 2/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9631 - loss: 0.1264 - val_accuracy: 0.9825 - val_loss: 0.0694 Epoch 3/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9800 - loss: 0.0713 - val_accuracy: 0.9825 - val_loss: 0.0670 Epoch 4/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 3s 3ms/step - accuracy: 0.9855 - loss: 0.0488 - val_accuracy: 0.9847 - val_loss: 0.0526 Epoch 5/5 422/422 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9891 - loss: 0.0375 - val_accuracy: 0.9872 - val_loss: 0.0498
結果の可視化(バリデーション精度)
for name, history in history_dict.items():
plt.plot(history.history['val_accuracy'], label=name)
plt.title('Validation Accuracy per Epoch')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.grid()
plt.show()
精度グラフ
考察
各活性化関数の訓練結果を比較すると、最終的な精度(accuracy)はどの関数も非常に高く、0.989前後に到達しており、明確な差は見られませんでした。ただし、学習の進み方や汎化性能(val_accuracy)には微妙な違いがありました。
活性化関数 | 最終Accuracy | 最終Loss | Val Accuracy | Val Loss |
---|---|---|---|---|
ReLU | 0.9891 | 0.0373 | 0.9878 | 0.0506 |
LeakyReLU | 0.9893 | 0.0353 | 0.9865 | 0.0546 |
ELU | 0.9898 | 0.0341 | 0.9847 | 0.0564 |
GELU | 0.9891 | 0.0375 | 0.9872 | 0.0498 |
- ReLU:シンプルかつ高速で、依然として高性能なベースライン。
- LeakyReLU:ReLUよりやや滑らかで、若干の性能向上が見られる場面も。
- ELU:収束が速くLossも最小だが、汎化性能では少し劣る。
- GELU:最新のモデルで使われる関数。精度・損失ともに安定。
まとめ
活性化関数はモデルの学習挙動に影響を与える重要な要素です。今回の比較では、大きな性能差は見られなかったものの、ELUやGELUはより滑らかで安定した学習挙動を示しました。
一方で、ReLUは依然として堅実でシンプルな選択肢であることが分かりました。タスクやデータに応じて適切な関数を選択することが、より良いモデル構築につながります。
0 件のコメント:
コメントを投稿