Dense層の活性化関数を比較|relu vs sigmoid vs tanh vs linear【Keras×CIFAR-10実験】

投稿日:2026年6月2日火曜日 最終更新日:

CIFAR-10 CNN Dense Google Colab Keras 画像分類 活性化関数

X f B! P L
Dense層の活性化関数を比較|relu vs sigmoid vs tanh vs linear【Keras×CIFAR-10実験】 アイキャッチ画像

「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 最終)
sigmoid0.75510.76080.76060.2225(最小)
linear0.73430.76440.74620.2340
relu0.73310.74640.74640.2333
tanh0.70170.75040.70820.2757(最大)

精度グラフ

精度グラフ

損失グラフ

損失グラフ

最終エポック Train vs Val Accuracy

最終エポック 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(勾配消失の心配が少ない)
出力層のDensesoftmax(多クラス)/ 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を使い分ける(今回の比較対象外)

関連記事