「Dense層の活性化関数はreluでいいの?sigmoidやtanhと何が違う?」
今回はGoogle ColabとCIFAR-10を使い、Dense層(隠れ層)の活性化関数をrelu / sigmoid / tanh / linearの4パターンで比較しました。精度だけでなく、過学習の挙動や収束の安定性にも注目します。
- Dense層の活性化関数(relu / sigmoid / tanh / linear)が精度・過学習にどう影響するか
- なぜDense層にreluが標準とされているか(そして例外があるケース)
- sigmoid・tanhを使うと何が起きるか(勾配消失との関係)
- BatchNorm環境でlinearが意外に機能する理由
活性化関数とは
Dense層の活性化関数は、ニューロンの出力に非線形変換を加える関数です。これがないと、何層重ねても線形変換の組み合わせにしかならず、表現力が上がりません。
今回比較する4種の特徴を整理します。
| 活性化関数 | 出力範囲 | 勾配消失リスク | 主な用途 |
|---|---|---|---|
| relu | [0, ∞) | 低(Dying ReLU問題はあり) | 隠れ層の標準 |
| sigmoid | (0, 1) | 高(飽和領域で勾配≒0) | 二値分類の出力層 |
| tanh | (-1, 1) | 中(sigmoidより緩和) | RNNなど |
| linear(なし) | (-∞, ∞) | なし | 回帰の出力層 |
各関数の数式はこちらです。
ReLU:\( f(x) = \max(0, x) \)
Sigmoid:\( f(x) = \dfrac{1}{1 + e^{-x}} \)
Tanh:\( f(x) = \dfrac{e^x - e^{-x}}{e^x + e^{-x}} \)
Linear:\( f(x) = x \)
sigmoid と tanh は出力が飽和する領域(sigmoid: 0や1付近、tanh: -1や+1付近)で勾配がほぼ0になり、勾配消失が起きやすくなります。reluはその問題を回避しますが、入力が負のニューロンは常に0を出力するため「Dying ReLU」と呼ばれる別の問題があります。
実験コード
使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10です。Dense層の活性化関数以外の条件はすべて同一にして、活性化関数の影響だけを取り出します。
環境準備(最初に一度だけ実行)
# ── 環境準備(最初に一度だけ実行)──────────────────────
!apt-get -y install fonts-ipafont-gothic
!rm -rf /root/.cache/matplotlib
!pip install -q japanize_matplotlib
print("環境準備完了")
実行結果をクリックして内容を開く
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
fonts-ipafont-mincho
The following NEW packages will be installed:
fonts-ipafont-gothic fonts-ipafont-mincho
0 upgraded, 2 newly installed, 0 to remove and 51 not upgraded.
Need to get 8,237 kB of archives.
After this operation, 28.7 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-gothic all 00303-21ubuntu1 [3,513 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-mincho all 00303-21ubuntu1 [4,724 kB]
Fetched 8,237 kB in 0s (23.9 MB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 122402 files and directories currently installed.)
Preparing to unpack .../fonts-ipafont-gothic_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-gothic (00303-21ubuntu1) ...
Selecting previously unselected package fonts-ipafont-mincho.
Preparing to unpack .../fonts-ipafont-mincho_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-mincho (00303-21ubuntu1) ...
Setting up fonts-ipafont-mincho (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-mincho/ipam.ttf to provide /usr/share/fonts/truetype/fonts-japanese-mincho.ttf (fonts-japanese-mincho.ttf) in auto mode
Setting up fonts-ipafont-gothic (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-gothic/ipag.ttf to provide /usr/share/fonts/truetype/fonts-japanese-gothic.ttf (fonts-japanese-gothic.ttf) in auto mode
Processing triggers for fontconfig (2.13.1-4.2ubuntu5) ...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.1/4.1 MB 57.9 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了
import・データ準備・モデル構築関数
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
# ── 再現性の固定 ────────────────────────────────────────
SEED = 42
tf.random.set_seed(SEED)
np.random.seed(SEED)
# ── データ準備 ──────────────────────────────────────────
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
y_train = y_train.flatten()
y_test = y_test.flatten()
# ── モデル構築関数(dense_activation以外は固定)────────────
def build_model(dense_activation):
inputs = keras.Input(shape=(32, 32, 3))
x = layers.Conv2D(64, 3, padding="same", activation="relu")(inputs)
x = layers.BatchNormalization()(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Conv2D(128, 3, padding="same", activation="relu")(x)
x = layers.BatchNormalization()(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Conv2D(128, 3, padding="same", activation="relu")(x)
x = layers.BatchNormalization()(x)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(128, activation=dense_activation)(x) # ← ここを変える
x = layers.Dropout(0.3)(x)
outputs = layers.Dense(10, activation="softmax")(x)
model = keras.Model(inputs, outputs)
model.compile(
optimizer=keras.optimizers.Adam(1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 69s 0us/step
4パターン比較・実験ループ
configs = {
"relu": "relu",
"sigmoid": "sigmoid",
"tanh": "tanh",
"linear": "linear",
}
EPOCHS = 30
BATCH = 128
histories = {}
test_accs = {}
for name, act in configs.items():
tf.random.set_seed(SEED)
np.random.seed(SEED)
print(f"\n▶ Dense活性化関数: {name}")
model = build_model(act)
history = model.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH,
validation_split=0.1,
verbose=1
)
histories[name] = history
_, test_acc = model.evaluate(x_test, y_test, verbose=0)
test_accs[name] = test_acc
print(f" テスト精度: {test_acc:.4f}")
実行結果をクリックして内容を開く
▶ Dense活性化関数: relu Epoch 1/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 20s 26ms/step - accuracy: 0.4921 - loss: 1.3925 - val_accuracy: 0.1224 - val_loss: 7.1146 Epoch 2/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.6419 - loss: 1.0105 - val_accuracy: 0.5248 - val_loss: 1.3994 Epoch 3/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 11ms/step - accuracy: 0.7052 - loss: 0.8391 - val_accuracy: 0.6378 - val_loss: 1.0561 Epoch 4/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7509 - loss: 0.7119 - val_accuracy: 0.5868 - val_loss: 1.3017 Epoch 5/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7871 - loss: 0.6143 - val_accuracy: 0.6070 - val_loss: 1.2324 Epoch 6/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8145 - loss: 0.5313 - val_accuracy: 0.4280 - val_loss: 2.1888 Epoch 7/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8416 - loss: 0.4585 - val_accuracy: 0.4858 - val_loss: 1.7341 Epoch 8/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8617 - loss: 0.4033 - val_accuracy: 0.4390 - val_loss: 2.0049 Epoch 9/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8796 - loss: 0.3510 - val_accuracy: 0.4884 - val_loss: 2.0311 Epoch 10/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.8908 - loss: 0.3120 - val_accuracy: 0.5930 - val_loss: 1.4468 Epoch 11/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9049 - loss: 0.2738 - val_accuracy: 0.5486 - val_loss: 1.6033 Epoch 12/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9156 - loss: 0.2431 - val_accuracy: 0.6442 - val_loss: 1.2386 Epoch 13/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9236 - loss: 0.2176 - val_accuracy: 0.6398 - val_loss: 1.2844 Epoch 14/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9354 - loss: 0.1838 - val_accuracy: 0.7030 - val_loss: 1.1765 Epoch 15/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9441 - loss: 0.1612 - val_accuracy: 0.7304 - val_loss: 1.1246 Epoch 16/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9489 - loss: 0.1446 - val_accuracy: 0.7052 - val_loss: 1.3162 Epoch 17/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9534 - loss: 0.1303 - val_accuracy: 0.7198 - val_loss: 1.2602 Epoch 18/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9559 - loss: 0.1228 - val_accuracy: 0.7048 - val_loss: 1.3318 Epoch 19/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9634 - loss: 0.1049 - val_accuracy: 0.7054 - val_loss: 1.5264 Epoch 20/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9654 - loss: 0.1008 - val_accuracy: 0.6896 - val_loss: 1.5663 Epoch 21/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9672 - loss: 0.0934 - val_accuracy: 0.7194 - val_loss: 1.4043 Epoch 22/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 15ms/step - accuracy: 0.9675 - loss: 0.0905 - val_accuracy: 0.6662 - val_loss: 1.6153 Epoch 23/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9735 - loss: 0.0745 - val_accuracy: 0.7264 - val_loss: 1.3795 Epoch 24/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9731 - loss: 0.0768 - val_accuracy: 0.7268 - val_loss: 1.3202 Epoch 25/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 14ms/step - accuracy: 0.9768 - loss: 0.0680 - val_accuracy: 0.7090 - val_loss: 1.4972 Epoch 26/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9768 - loss: 0.0656 - val_accuracy: 0.6694 - val_loss: 1.7210 Epoch 27/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9760 - loss: 0.0691 - val_accuracy: 0.7150 - val_loss: 1.6696 Epoch 28/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9766 - loss: 0.0666 - val_accuracy: 0.6928 - val_loss: 1.6659 Epoch 29/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9809 - loss: 0.0563 - val_accuracy: 0.7172 - val_loss: 1.6113 Epoch 30/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9797 - loss: 0.0588 - val_accuracy: 0.7464 - val_loss: 1.3567 テスト精度: 0.7331 ▶ Dense活性化関数: sigmoid Epoch 1/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 13s 24ms/step - accuracy: 0.4616 - loss: 1.4682 - val_accuracy: 0.1670 - val_loss: 3.4533 Epoch 2/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.6248 - loss: 1.0580 - val_accuracy: 0.5268 - val_loss: 1.3336 Epoch 3/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.6903 - loss: 0.8876 - val_accuracy: 0.6108 - val_loss: 1.0542 Epoch 4/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7326 - loss: 0.7693 - val_accuracy: 0.6028 - val_loss: 1.1555 Epoch 5/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7694 - loss: 0.6694 - val_accuracy: 0.6656 - val_loss: 1.0134 Epoch 6/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8005 - loss: 0.5851 - val_accuracy: 0.6236 - val_loss: 1.1962 Epoch 7/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8219 - loss: 0.5191 - val_accuracy: 0.5724 - val_loss: 1.5250 Epoch 8/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.8445 - loss: 0.4573 - val_accuracy: 0.6778 - val_loss: 0.9935 Epoch 9/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.8614 - loss: 0.4035 - val_accuracy: 0.6306 - val_loss: 1.2187 Epoch 10/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8766 - loss: 0.3558 - val_accuracy: 0.6054 - val_loss: 1.6256 Epoch 11/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.8972 - loss: 0.3008 - val_accuracy: 0.6972 - val_loss: 1.1060 Epoch 12/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9078 - loss: 0.2707 - val_accuracy: 0.6934 - val_loss: 1.1470 Epoch 13/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9227 - loss: 0.2265 - val_accuracy: 0.7094 - val_loss: 1.1352 Epoch 14/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9334 - loss: 0.1981 - val_accuracy: 0.7172 - val_loss: 1.1440 Epoch 15/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9399 - loss: 0.1747 - val_accuracy: 0.6968 - val_loss: 1.1259 Epoch 16/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9459 - loss: 0.1562 - val_accuracy: 0.7290 - val_loss: 1.1084 Epoch 17/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9512 - loss: 0.1386 - val_accuracy: 0.7370 - val_loss: 1.0225 Epoch 18/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9587 - loss: 0.1208 - val_accuracy: 0.7358 - val_loss: 1.1568 Epoch 19/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9606 - loss: 0.1133 - val_accuracy: 0.7152 - val_loss: 1.3524 Epoch 20/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9637 - loss: 0.1057 - val_accuracy: 0.7266 - val_loss: 1.2573 Epoch 21/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 12ms/step - accuracy: 0.9651 - loss: 0.0996 - val_accuracy: 0.7282 - val_loss: 1.3263 Epoch 22/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9719 - loss: 0.0828 - val_accuracy: 0.7440 - val_loss: 1.2566 Epoch 23/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9720 - loss: 0.0810 - val_accuracy: 0.7226 - val_loss: 1.3259 Epoch 24/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9762 - loss: 0.0698 - val_accuracy: 0.7274 - val_loss: 1.3275 Epoch 25/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9741 - loss: 0.0732 - val_accuracy: 0.7554 - val_loss: 1.2192 Epoch 26/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9780 - loss: 0.0639 - val_accuracy: 0.7606 - val_loss: 1.2468 Epoch 27/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9802 - loss: 0.0576 - val_accuracy: 0.7474 - val_loss: 1.3655 Epoch 28/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9799 - loss: 0.0585 - val_accuracy: 0.7608 - val_loss: 1.2587 Epoch 29/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9819 - loss: 0.0534 - val_accuracy: 0.7574 - val_loss: 1.3157 Epoch 30/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9831 - loss: 0.0506 - val_accuracy: 0.7606 - val_loss: 1.2238 テスト精度: 0.7551 ▶ Dense活性化関数: tanh Epoch 1/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 14s 25ms/step - accuracy: 0.5220 - loss: 1.3277 - val_accuracy: 0.1114 - val_loss: 4.9669 Epoch 2/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.6665 - loss: 0.9448 - val_accuracy: 0.6470 - val_loss: 1.0080 Epoch 3/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7327 - loss: 0.7660 - val_accuracy: 0.6384 - val_loss: 1.0943 Epoch 4/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.7748 - loss: 0.6481 - val_accuracy: 0.6224 - val_loss: 1.1971 Epoch 5/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8082 - loss: 0.5530 - val_accuracy: 0.6636 - val_loss: 1.0474 Epoch 6/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8374 - loss: 0.4717 - val_accuracy: 0.6320 - val_loss: 1.2594 Epoch 7/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8621 - loss: 0.4046 - val_accuracy: 0.6370 - val_loss: 1.2492 Epoch 8/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8817 - loss: 0.3479 - val_accuracy: 0.5662 - val_loss: 1.6376 Epoch 9/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8967 - loss: 0.3007 - val_accuracy: 0.6188 - val_loss: 1.2622 Epoch 10/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9118 - loss: 0.2528 - val_accuracy: 0.6426 - val_loss: 1.1502 Epoch 11/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9225 - loss: 0.2239 - val_accuracy: 0.5322 - val_loss: 1.7056 Epoch 12/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9311 - loss: 0.1973 - val_accuracy: 0.5664 - val_loss: 1.5724 Epoch 13/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9408 - loss: 0.1710 - val_accuracy: 0.6228 - val_loss: 1.4274 Epoch 14/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9481 - loss: 0.1502 - val_accuracy: 0.6462 - val_loss: 1.5804 Epoch 15/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9546 - loss: 0.1298 - val_accuracy: 0.6994 - val_loss: 1.2750 Epoch 16/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9616 - loss: 0.1087 - val_accuracy: 0.6786 - val_loss: 1.5906 Epoch 17/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9610 - loss: 0.1098 - val_accuracy: 0.7176 - val_loss: 1.4041 Epoch 18/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9663 - loss: 0.0958 - val_accuracy: 0.6930 - val_loss: 1.6238 Epoch 19/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9705 - loss: 0.0843 - val_accuracy: 0.7504 - val_loss: 1.2467 Epoch 20/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9720 - loss: 0.0810 - val_accuracy: 0.7142 - val_loss: 1.4597 Epoch 21/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9755 - loss: 0.0720 - val_accuracy: 0.7388 - val_loss: 1.3285 Epoch 22/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9741 - loss: 0.0752 - val_accuracy: 0.7480 - val_loss: 1.2182 Epoch 23/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9739 - loss: 0.0725 - val_accuracy: 0.7248 - val_loss: 1.4613 Epoch 24/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9762 - loss: 0.0688 - val_accuracy: 0.6834 - val_loss: 1.8664 Epoch 25/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9738 - loss: 0.0739 - val_accuracy: 0.7386 - val_loss: 1.4307 Epoch 26/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9778 - loss: 0.0627 - val_accuracy: 0.7374 - val_loss: 1.4674 Epoch 27/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9810 - loss: 0.0543 - val_accuracy: 0.7014 - val_loss: 1.7784 Epoch 28/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9829 - loss: 0.0506 - val_accuracy: 0.7024 - val_loss: 1.8337 Epoch 29/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9830 - loss: 0.0477 - val_accuracy: 0.7264 - val_loss: 1.5645 Epoch 30/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9839 - loss: 0.0469 - val_accuracy: 0.7082 - val_loss: 1.9152 テスト精度: 0.7017 ▶ Dense活性化関数: linear Epoch 1/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 14s 23ms/step - accuracy: 0.5170 - loss: 1.3389 - val_accuracy: 0.2162 - val_loss: 7.6176 Epoch 2/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.6680 - loss: 0.9370 - val_accuracy: 0.5750 - val_loss: 1.1947 Epoch 3/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7334 - loss: 0.7660 - val_accuracy: 0.5526 - val_loss: 1.3360 Epoch 4/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.7733 - loss: 0.6542 - val_accuracy: 0.6000 - val_loss: 1.3112 Epoch 5/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8058 - loss: 0.5636 - val_accuracy: 0.5658 - val_loss: 1.6103 Epoch 6/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8321 - loss: 0.4839 - val_accuracy: 0.6908 - val_loss: 0.9789 Epoch 7/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.8571 - loss: 0.4162 - val_accuracy: 0.6726 - val_loss: 1.0431 Epoch 8/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.8720 - loss: 0.3702 - val_accuracy: 0.6224 - val_loss: 1.2903 Epoch 9/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.8911 - loss: 0.3117 - val_accuracy: 0.6494 - val_loss: 1.1575 Epoch 10/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9055 - loss: 0.2744 - val_accuracy: 0.6600 - val_loss: 1.2565 Epoch 11/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9179 - loss: 0.2361 - val_accuracy: 0.6912 - val_loss: 1.0719 Epoch 12/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9300 - loss: 0.2012 - val_accuracy: 0.6540 - val_loss: 1.3482 Epoch 13/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9382 - loss: 0.1763 - val_accuracy: 0.6810 - val_loss: 1.2802 Epoch 14/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9453 - loss: 0.1537 - val_accuracy: 0.7210 - val_loss: 1.1596 Epoch 15/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9529 - loss: 0.1352 - val_accuracy: 0.6700 - val_loss: 1.4967 Epoch 16/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9560 - loss: 0.1252 - val_accuracy: 0.7420 - val_loss: 1.0737 Epoch 17/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9628 - loss: 0.1063 - val_accuracy: 0.7336 - val_loss: 1.1466 Epoch 18/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9637 - loss: 0.1031 - val_accuracy: 0.7348 - val_loss: 1.3919 Epoch 19/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9637 - loss: 0.1015 - val_accuracy: 0.7080 - val_loss: 1.5002 Epoch 20/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9695 - loss: 0.0851 - val_accuracy: 0.7088 - val_loss: 1.5464 Epoch 21/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9701 - loss: 0.0855 - val_accuracy: 0.6788 - val_loss: 1.7640 Epoch 22/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9712 - loss: 0.0812 - val_accuracy: 0.7502 - val_loss: 1.2054 Epoch 23/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9756 - loss: 0.0704 - val_accuracy: 0.7628 - val_loss: 1.2483 Epoch 24/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9744 - loss: 0.0734 - val_accuracy: 0.7542 - val_loss: 1.2849 Epoch 25/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 5s 13ms/step - accuracy: 0.9770 - loss: 0.0657 - val_accuracy: 0.7644 - val_loss: 1.1909 Epoch 26/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9816 - loss: 0.0546 - val_accuracy: 0.7560 - val_loss: 1.3470 Epoch 27/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9793 - loss: 0.0604 - val_accuracy: 0.7588 - val_loss: 1.2773 Epoch 28/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9793 - loss: 0.0571 - val_accuracy: 0.7278 - val_loss: 1.4771 Epoch 29/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 12ms/step - accuracy: 0.9820 - loss: 0.0536 - val_accuracy: 0.7466 - val_loss: 1.4481 Epoch 30/30 352/352 ━━━━━━━━━━━━━━━━━━━━ 4s 13ms/step - accuracy: 0.9802 - loss: 0.0576 - val_accuracy: 0.7462 - val_loss: 1.4020 テスト精度: 0.7343
結果グラフ
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("Dense層の活性化関数比較(CIFAR-10)", fontsize=14)
colors = ["steelblue", "tomato", "seagreen", "darkorange"]
# Validation Accuracy 曲線
ax = axes[0, 0]
for (name, hist), c in zip(histories.items(), colors):
ax.plot(hist.history["val_accuracy"], label=name, color=c)
ax.set_title("Validation Accuracy")
ax.set_xlabel("Epoch")
ax.set_ylabel("Accuracy")
ax.legend()
# Validation Loss 曲線
ax = axes[0, 1]
for (name, hist), c in zip(histories.items(), colors):
ax.plot(hist.history["val_loss"], label=name, color=c)
ax.set_title("Validation Loss")
ax.set_xlabel("Epoch")
ax.set_ylabel("Loss")
ax.legend()
# 最終エポック Train vs Val Accuracy
names = list(histories.keys())
train_accs = [h.history["accuracy"][-1] for h in histories.values()]
val_accs = [h.history["val_accuracy"][-1] for h in histories.values()]
x_pos = np.arange(len(names))
ax = axes[1, 0]
ax.bar(x_pos - 0.2, train_accs, 0.4, label="Train", color="steelblue")
ax.bar(x_pos + 0.2, val_accs, 0.4, label="Val", color="tomato")
ax.set_xticks(x_pos)
ax.set_xticklabels(names)
ax.set_ylim(0, 1)
ax.set_title("最終エポック Train vs Val Accuracy")
ax.legend()
# テスト精度(棒グラフ)
ax = axes[1, 1]
t_vals = [test_accs[n] for n in names]
bars = ax.bar(x_pos, t_vals, 0.5, color=colors)
ax.set_xticks(x_pos)
ax.set_xticklabels(names)
ax.set_ylim(0.5, 0.85)
ax.set_title("テスト精度")
for bar, v in zip(bars, t_vals):
ax.text(bar.get_x() + bar.get_width()/2, v + 0.003, f"{v:.4f}",
ha="center", va="bottom", fontsize=10)
plt.tight_layout()
plt.savefig("dense_activation_comparison.png", dpi=150)
plt.show()
print("グラフ保存完了")
実行結果をクリックして内容を開く
グラフ保存完了
結果表
import pandas as pd
rows = []
for name, hist in histories.items():
val_max = max(hist.history["val_accuracy"])
val_last = hist.history["val_accuracy"][-1]
train_last = hist.history["accuracy"][-1]
gap = train_last - val_last
rows.append({
"活性化関数": name,
"テスト精度": f"{test_accs[name]:.4f}",
"Val最高値": f"{val_max:.4f}",
"Train精度(最終)": f"{train_last:.4f}",
"Val精度(最終)": f"{val_last:.4f}",
"過学習ギャップ": f"{gap:.4f}",
})
df = pd.DataFrame(rows)
df = df.sort_values("テスト精度", ascending=False).reset_index(drop=True)
print(df.to_string(index=False))
最終結果
活性化関数 テスト精度 Val最高値 Train精度(最終) Val精度(最終) 過学習ギャップ sigmoid 0.7551 0.7608 0.9831 0.7606 0.2225 linear 0.7343 0.7644 0.9802 0.7462 0.2340 relu 0.7331 0.7464 0.9797 0.7464 0.2333 tanh 0.7017 0.7504 0.9839 0.7082 0.2757
実験結果
| 活性化関数 | テスト精度 | Val最高値 | Val精度(最終) | 過学習ギャップ (train−val 最終) |
|---|---|---|---|---|
| sigmoid | 0.7551 | 0.7608 | 0.7606 | 0.2225(最小) |
| linear | 0.7343 | 0.7644 | 0.7462 | 0.2340 |
| relu | 0.7331 | 0.7464 | 0.7464 | 0.2333 |
| tanh | 0.7017 | 0.7504 | 0.7082 | 0.2757(最大) |
精度グラフ
損失グラフ
最終エポック Train vs Val Accuracy
テスト精度
実験の再現性に注意が必要です。同じコード・同じシードでも、GPUの非決定的な並列処理により実行ごとに結果が変わります。今回は sigmoid が最高精度でしたが、別の実行では順位が入れ替わることがあります。1回の結果だけで判断せず、複数回実行して傾向を確認することを推奨します。
考察
① sigmoidが1位になった理由:今回は安定収束した
sigmoid は飽和による勾配消失が懸念されますが、Dense層が1層だけの構成では影響が限定的です。val_last(0.7606)≈ val_max(0.7608)という数字が示すとおり、後半まで崩れずに安定して収束しました。過学習ギャップ(0.2225)も4種の中で最小です。
② reluとlinearが同水準(2・3位)
relu は val_last = val_max(0.7464)で最終エポックがそのまま最高値です。前回の実行で見られたDying ReLUによる後半崩壊は今回は発生しませんでした。GPU非決定性による実行ごとの差がそのまま順位差として現れています。
linear は Val最高値(0.7644)が全4種で最高ですが、後半に若干低下してテスト精度は0.7343でした。BatchNorm後のDense 1層という構成上、活性化なしでも前段の非線形性で十分機能しています。
③ tanhが最下位
過学習ギャップ(0.2757)が最大で、val_last(0.7082)も低い。Val最高値(0.7504)はそれなりですが、後半でval_accが0.0422落ちており、収束後に過学習が進みやすいという特性が出ました。
実務での推奨
| 状況 | 推奨 |
|---|---|
| EarlyStopping(restore_best_weights=True)あり | どれでも大差なし。reluが無難 |
| EarlyStopping なし・安定重視 | sigmoid または relu(後半崩壊が起きにくい) |
| BatchNorm なし・Dense が多層 | relu(勾配消失の心配が少ない) |
| 出力層のDense | softmax(多クラス)/ sigmoid(二値)/ linear(回帰) |
今回の結果は「BatchNormあり・30epoch固定・EarlyStoppingなし」という特定条件下のものです。条件が変われば順位も変わります。
- 今回の実験では sigmoid が最高精度(0.7551)、後半も安定収束してギャップも最小
- relu・linear は同水準(約0.733)。BatchNorm環境では linear でも十分機能する
- tanh は過学習ギャップが最大(0.2757)で最下位。後半にval_accが低下しやすい
- ただしGPUの非決定性により実行ごとに順位が変わることがある。1回の結果で判断しない
- 出力層のDenseは用途に応じてsoftmax / sigmoid / linearを使い分ける(今回の比較対象外)





0 件のコメント:
コメントを投稿