MaxPooling vs AveragePooling(中間層)精度・過学習はどう変わる?【Keras×CIFAR-10実験】

投稿日:2026年5月24日日曜日 最終更新日:

AveragePooling CIFAR-10 CNN Google Colab Keras MaxPooling 過学習 画像分類

X f B! P L
MaxPooling vs AveragePooling(中間層)精度・過学習はどう変わる?【Keras×CIFAR-10実験】 アイキャッチ画像

CNNで「なんとなくMaxPoolingを使っている」という方は多いのではないでしょうか。

MaxPoolingはエッジや輝点などの「強い反応」を残し、AveragePoolingは領域全体の「平均的な特徴」を保持します。この違いが精度や過学習にどう影響するか、実験で確かめます。

なお、最終層のGlobal Average Pooling vs Global Max Poolingの比較は → GlobalAveragePooling vs GlobalMaxPooling の比較【Keras×CIFAR-10実験】 をご覧ください。本記事は中間層のPoolingに絞った比較です。

また、MNISTを使った基礎的な比較は → 【Keras】最大値プーリング vs 平均値プーリングの違いを実験で比較 で解説しています。本記事ではCIFAR-10(カラー自然画像)を使い、MNISTとは逆の結果になった理由まで掘り下げます。

📘 この記事でわかること
  • MaxPooling2DとAveragePooling2Dの動作の違い(何を残し何を捨てるか)
  • 中間層でのPooling種類による精度・過学習耐性の差(CIFAR-10実験)
  • MaxPooling・AveragePooling・両者の組み合わせ(Mix)の3パターン比較
  • MNISTではAvgが有利だったのに、CIFAR-10ではMaxが約4ポイント優位になった理由

MaxPoolingとAveragePoolingの違い

どちらも特徴マップを空間的に縮小(ダウンサンプリング)するレイヤーですが、縮小の方法が異なります。

種類 操作 残す情報 向いているタスク
MaxPooling2D ウィンドウ内の最大値を取る 最も強い反応(エッジ・輝点) 物体検出・テクスチャ識別
AveragePooling2D ウィンドウ内の平均値を取る 領域全体の平均的な特徴 滑らかな特徴・背景含む分類

直感的には「MaxPoolingの方が強い特徴を残すから精度が高い」と思われがちですが、タスクによっては平均情報の方が有効なこともあります。今回はCIFAR-10で3パターンを比較します。

実験設計

比較するのは以下の3パターンです。Pool種別以外(Conv2Dフィルター数、Dropout、最適化関数、エポック数)はすべて統一します。

パターン1回目Pooling2回目Pooling
A: MaxMaxPooling2DMaxPooling2D
B: AvgAveragePooling2DAveragePooling2D
C: Mix(Max→Avg)MaxPooling2DAveragePooling2D

MixパターンはEfficientNetなど実際のアーキテクチャで採用されている設計で、前段で鋭い特徴を抽出し、後段で滑らかにまとめるという考え方です。

実験コード

使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10です。

環境準備(最初に一度だけ実行)

# ── 環境準備(最初に一度だけ実行)──────────────────────
!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 (24.6 MB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 122363 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 77.2 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
  Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了

import・データ準備・モデル構築関数

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import japanize_matplotlib
import time

(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

def build_model(pool1_type, pool2_type, name):
    """
    pool_type: 'max' or 'avg'
    中間層のPooling種別だけを変え、他の条件は統一する
    """
    def pool_layer(pool_type):
        if pool_type == 'max':
            return keras.layers.MaxPooling2D((2, 2))
        else:
            return keras.layers.AveragePooling2D((2, 2))

    model = keras.Sequential([
        keras.layers.Input(shape=(32, 32, 3)),
        keras.layers.Conv2D(64,  (3, 3), activation='relu', padding='same'),
        pool_layer(pool1_type),                  # ← ここを変える(1回目)
        keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        pool_layer(pool2_type),                  # ← ここを変える(2回目)
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(128, activation='relu'),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10,  activation='softmax'),
    ], name=name)
    return model

def compile_and_fit(model):
    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    start = time.time()
    history = model.fit(x_train, y_train, epochs=30, batch_size=64,
                        validation_split=0.2, verbose=1)
    return history, time.time() - start
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 20s 0us/step

3パターンの学習実行

configs = [
    ('max', 'max', 'A_MaxMax'),
    ('avg', 'avg', 'B_AvgAvg'),
    ('max', 'avg', 'C_MaxAvg'),
]
histories, times, scores, params = {}, {}, {}, {}

for pool1, pool2, name in configs:
    print(f"\n=== {name} ===")
    model = build_model(pool1, pool2, name)
    model.summary()
    h, t = compile_and_fit(model)
    s = model.evaluate(x_test, y_test, verbose=0)
    label = name
    histories[label] = h
    times[label]     = t
    scores[label]    = s
    params[label]    = model.count_params()
    print(f"学習時間:{t:.1f}秒 パラメータ数:{model.count_params():,} test_accuracy:{s[1]:.4f}")
実行結果をクリックして内容を開く
=== A_MaxMax ===
Model: "A_MaxMax"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 128)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,450 (365.04 KB)
 Trainable params: 93,450 (365.04 KB)
 Non-trainable params: 0 (0.00 B)
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.2726 - loss: 1.9051 - val_accuracy: 0.3662 - val_loss: 1.6983
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3800 - loss: 1.6635 - val_accuracy: 0.4248 - val_loss: 1.5717
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4341 - loss: 1.5407 - val_accuracy: 0.4618 - val_loss: 1.4751
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.4680 - loss: 1.4511 - val_accuracy: 0.4791 - val_loss: 1.4270
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.4876 - loss: 1.3934 - val_accuracy: 0.5108 - val_loss: 1.3464
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5119 - loss: 1.3340 - val_accuracy: 0.5171 - val_loss: 1.3153
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5237 - loss: 1.2979 - val_accuracy: 0.5446 - val_loss: 1.2484
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5356 - loss: 1.2689 - val_accuracy: 0.5445 - val_loss: 1.2518
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5494 - loss: 1.2349 - val_accuracy: 0.5646 - val_loss: 1.2026
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5624 - loss: 1.2112 - val_accuracy: 0.5738 - val_loss: 1.1862
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5699 - loss: 1.1868 - val_accuracy: 0.5700 - val_loss: 1.1919
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5799 - loss: 1.1586 - val_accuracy: 0.5842 - val_loss: 1.1342
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5885 - loss: 1.1406 - val_accuracy: 0.5867 - val_loss: 1.1250
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5930 - loss: 1.1222 - val_accuracy: 0.5819 - val_loss: 1.1634
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6036 - loss: 1.0975 - val_accuracy: 0.6046 - val_loss: 1.0980
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6122 - loss: 1.0802 - val_accuracy: 0.6247 - val_loss: 1.0477
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6181 - loss: 1.0601 - val_accuracy: 0.6282 - val_loss: 1.0349
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6255 - loss: 1.0424 - val_accuracy: 0.6242 - val_loss: 1.0430
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6312 - loss: 1.0297 - val_accuracy: 0.6372 - val_loss: 1.0050
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6342 - loss: 1.0114 - val_accuracy: 0.6500 - val_loss: 0.9880
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6414 - loss: 0.9968 - val_accuracy: 0.6393 - val_loss: 0.9957
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6462 - loss: 0.9866 - val_accuracy: 0.6417 - val_loss: 0.9924
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6517 - loss: 0.9684 - val_accuracy: 0.6442 - val_loss: 1.0061
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6558 - loss: 0.9586 - val_accuracy: 0.6614 - val_loss: 0.9427
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6646 - loss: 0.9407 - val_accuracy: 0.6647 - val_loss: 0.9461
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6663 - loss: 0.9321 - val_accuracy: 0.6707 - val_loss: 0.9273
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6676 - loss: 0.9258 - val_accuracy: 0.6644 - val_loss: 0.9334
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6715 - loss: 0.9124 - val_accuracy: 0.6680 - val_loss: 0.9390
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6780 - loss: 0.9003 - val_accuracy: 0.6717 - val_loss: 0.9251
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6836 - loss: 0.8849 - val_accuracy: 0.6798 - val_loss: 0.9012
学習時間:124.7秒 パラメータ数:93,450 test_accuracy:0.6747

=== B_AvgAvg ===
Model: "B_AvgAvg"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d_2 (Conv2D)               │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ average_pooling2d               │ (None, 16, 16, 64)     │             0 │
│ (AveragePooling2D)              │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_3 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ average_pooling2d_1             │ (None, 8, 8, 128)      │             0 │
│ (AveragePooling2D)              │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d_1      │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_2 (Dense)                 │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_1 (Dropout)             │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_3 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,450 (365.04 KB)
 Trainable params: 93,450 (365.04 KB)
 Non-trainable params: 0 (0.00 B)
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 7ms/step - accuracy: 0.2435 - loss: 1.9774 - val_accuracy: 0.3170 - val_loss: 1.7838
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.3367 - loss: 1.7450 - val_accuracy: 0.3732 - val_loss: 1.6669
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.3787 - loss: 1.6539 - val_accuracy: 0.4102 - val_loss: 1.5744
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4081 - loss: 1.5814 - val_accuracy: 0.4313 - val_loss: 1.5285
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4382 - loss: 1.5227 - val_accuracy: 0.4603 - val_loss: 1.4761
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4600 - loss: 1.4707 - val_accuracy: 0.4809 - val_loss: 1.4121
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4740 - loss: 1.4247 - val_accuracy: 0.4609 - val_loss: 1.4670
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4904 - loss: 1.3980 - val_accuracy: 0.5049 - val_loss: 1.3402
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4968 - loss: 1.3678 - val_accuracy: 0.5161 - val_loss: 1.3212
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5099 - loss: 1.3433 - val_accuracy: 0.5119 - val_loss: 1.3140
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5197 - loss: 1.3149 - val_accuracy: 0.5289 - val_loss: 1.2927
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 5ms/step - accuracy: 0.5264 - loss: 1.3002 - val_accuracy: 0.5225 - val_loss: 1.2914
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5329 - loss: 1.2828 - val_accuracy: 0.5382 - val_loss: 1.2622
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5371 - loss: 1.2650 - val_accuracy: 0.5441 - val_loss: 1.2346
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5479 - loss: 1.2483 - val_accuracy: 0.5515 - val_loss: 1.2215
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5549 - loss: 1.2270 - val_accuracy: 0.5539 - val_loss: 1.2066
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5619 - loss: 1.2119 - val_accuracy: 0.5740 - val_loss: 1.1687
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5656 - loss: 1.2009 - val_accuracy: 0.5795 - val_loss: 1.1539
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.5726 - loss: 1.1799 - val_accuracy: 0.5706 - val_loss: 1.1774
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5753 - loss: 1.1669 - val_accuracy: 0.5816 - val_loss: 1.1557
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5816 - loss: 1.1548 - val_accuracy: 0.5835 - val_loss: 1.1323
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5904 - loss: 1.1364 - val_accuracy: 0.6055 - val_loss: 1.0913
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.5953 - loss: 1.1247 - val_accuracy: 0.6011 - val_loss: 1.1000
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5994 - loss: 1.1115 - val_accuracy: 0.5875 - val_loss: 1.1192
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6041 - loss: 1.1004 - val_accuracy: 0.5963 - val_loss: 1.1039
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6071 - loss: 1.0882 - val_accuracy: 0.6112 - val_loss: 1.0679
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6079 - loss: 1.0771 - val_accuracy: 0.6086 - val_loss: 1.0625
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6173 - loss: 1.0645 - val_accuracy: 0.6193 - val_loss: 1.0454
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6217 - loss: 1.0538 - val_accuracy: 0.6103 - val_loss: 1.0718
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6243 - loss: 1.0398 - val_accuracy: 0.6265 - val_loss: 1.0340
学習時間:100.0秒 パラメータ数:93,450 test_accuracy:0.6330

=== C_MaxAvg ===
Model: "C_MaxAvg"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d_4 (Conv2D)               │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_2 (MaxPooling2D)  │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_5 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ average_pooling2d_2             │ (None, 8, 8, 128)      │             0 │
│ (AveragePooling2D)              │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d_2      │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_4 (Dense)                 │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_2 (Dropout)             │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_5 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,450 (365.04 KB)
 Trainable params: 93,450 (365.04 KB)
 Non-trainable params: 0 (0.00 B)
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 7ms/step - accuracy: 0.2544 - loss: 1.9429 - val_accuracy: 0.3267 - val_loss: 1.7442
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3417 - loss: 1.7235 - val_accuracy: 0.3870 - val_loss: 1.6365
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.3922 - loss: 1.6201 - val_accuracy: 0.4345 - val_loss: 1.5325
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4304 - loss: 1.5400 - val_accuracy: 0.4644 - val_loss: 1.4632
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4663 - loss: 1.4594 - val_accuracy: 0.4883 - val_loss: 1.3876
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4874 - loss: 1.4001 - val_accuracy: 0.4829 - val_loss: 1.3786
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.5002 - loss: 1.3643 - val_accuracy: 0.5159 - val_loss: 1.3176
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5153 - loss: 1.3302 - val_accuracy: 0.5403 - val_loss: 1.2553
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5253 - loss: 1.3028 - val_accuracy: 0.5288 - val_loss: 1.2509
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5409 - loss: 1.2659 - val_accuracy: 0.5637 - val_loss: 1.2059
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5491 - loss: 1.2430 - val_accuracy: 0.5621 - val_loss: 1.2135
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5580 - loss: 1.2195 - val_accuracy: 0.5530 - val_loss: 1.2092
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5631 - loss: 1.2003 - val_accuracy: 0.5751 - val_loss: 1.1738
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5735 - loss: 1.1762 - val_accuracy: 0.5920 - val_loss: 1.1235
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5782 - loss: 1.1614 - val_accuracy: 0.5955 - val_loss: 1.1134
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5860 - loss: 1.1397 - val_accuracy: 0.6032 - val_loss: 1.1147
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.5905 - loss: 1.1292 - val_accuracy: 0.6047 - val_loss: 1.0877
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5982 - loss: 1.1119 - val_accuracy: 0.6067 - val_loss: 1.0863
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6058 - loss: 1.0929 - val_accuracy: 0.6188 - val_loss: 1.0446
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6101 - loss: 1.0809 - val_accuracy: 0.6197 - val_loss: 1.0496
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6170 - loss: 1.0636 - val_accuracy: 0.5958 - val_loss: 1.0900
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6207 - loss: 1.0499 - val_accuracy: 0.6386 - val_loss: 1.0064
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6245 - loss: 1.0452 - val_accuracy: 0.6266 - val_loss: 1.0249
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6273 - loss: 1.0304 - val_accuracy: 0.6325 - val_loss: 1.0235
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6341 - loss: 1.0182 - val_accuracy: 0.6435 - val_loss: 0.9884
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6388 - loss: 1.0043 - val_accuracy: 0.6322 - val_loss: 0.9977
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6415 - loss: 0.9960 - val_accuracy: 0.6487 - val_loss: 0.9749
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.6455 - loss: 0.9874 - val_accuracy: 0.6391 - val_loss: 1.0003
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6478 - loss: 0.9746 - val_accuracy: 0.6495 - val_loss: 0.9700
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6520 - loss: 0.9632 - val_accuracy: 0.6486 - val_loss: 0.9743
学習時間:114.1秒 パラメータ数:93,450 test_accuracy:0.6436

グラフ+サマリー

# ── val_accuracy / val_loss 比較グラフ ───────────────
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for label, h in histories.items():
    axes[0].plot(h.history['val_accuracy'], label=label)
    axes[1].plot(h.history['val_loss'],     label=label)
axes[0].set_title('val_accuracy の比較(全30エポック)')
axes[1].set_title('val_loss の比較(全30エポック)')
for ax in axes:
    ax.set_xlabel('Epoch'); ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('pooling_comparison.png', dpi=150)
plt.show()

# ── train_loss vs val_loss(過学習の乖離)────────────
fig2, axes2 = plt.subplots(3, 1, figsize=(7, 14))
for i, (label, h) in enumerate(histories.items()):
    axes2[i].plot(h.history['loss'],     label='train_loss')
    axes2[i].plot(h.history['val_loss'], label='val_loss')
    axes2[i].set_title(label)
    axes2[i].set_xlabel('Epoch'); axes2[i].legend(); axes2[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('pooling_overfit.png', dpi=150)
plt.show()

print("\n===== 最終結果サマリー =====")
print(f"{'Pattern':>12} | {'Val Acc':>8} | {'Test Acc':>9} | {'Time(s)':>8} | {'Params':>12}")
print("-" * 62)
for label in ['A_MaxMax', 'B_AvgAvg', 'C_MaxAvg']:
    val_acc  = histories[label].history['val_accuracy'][-1]
    test_acc = scores[label][1]
    t        = times[label]
    p        = params[label]
    print(f"{label:>12} | {val_acc:>8.4f} | {test_acc:>9.4f} | {t:>8.1f} | {p:>12,}")
print("-" * 62)

最終結果サマリー

===== 最終結果サマリー =====
     Pattern |  Val Acc |  Test Acc |  Time(s) |       Params
--------------------------------------------------------------
    A_MaxMax |   0.6798 |    0.6747 |    124.7 |       93,450
    B_AvgAvg |   0.6265 |    0.6330 |    100.0 |       93,450
    C_MaxAvg |   0.6486 |    0.6436 |    114.1 |       93,450
--------------------------------------------------------------

実験結果

精度グラフ

精度グラフ

損失グラフ

損失グラフ

MaxPooling2D x MaxPooling2D

MaxPooling2D x MaxPooling2D

AveragePooling2D x AveragePooling2D

AveragePooling2D x AveragePooling2D

MaxPooling2D x AveragePooling2D

MaxPooling2D x AveragePooling2D
パターン 最終 val_accuracy 最終 test_accuracy パラメータ数 学習時間
A: MaxMax67.98%67.47%93,450124.7秒
B: AvgAvg62.65%63.30%93,450100.0秒
C: MaxAvg(Mix)64.86%64.36%93,450114.1秒

3パターンのパラメータ数はすべて同一(93,450)です。Poolingレイヤー自体に学習パラメータはなく、違いは特徴の取捨選択だけです。

考察

① MaxMaxが明確に優位——精度差は約4ポイント

MaxMax(test_accuracy 67.47%)はAvgAvg(63.30%)を約4.2ポイント上回りました。MixパターンはMaxMaxには届かず(64.36%)、MaxMaxが最も高い精度となっています。

CIFAR-10は「飛行機・犬・馬・自動車」など物体の輪郭やテクスチャが分類の決め手になる自然画像データセットです。MaxPoolingがエッジや局所的な強い反応を保持することで、後段のConv層により豊かな特徴が渡され、分類に有利に働いたと考えられます。

② MNISTとは逆の結果になった理由

以前の実験(MNIST版)ではAveragePoolingがわずかにMaxPoolingを上回っていました(val_accuracy: Avg 98.90% vs Max 98.65%)。今回のCIFAR-10では逆転し、Maxが約4ポイント優位という結果になっています。この違いはデータの性質から説明できます。

データセット 画像の特性 有利なPooling 理由
MNIST 白背景に黒い線画・単純な輪郭 AveragePooling 線画は背景との境界が明確で、輪郭の保持より全体の形状把握が重要。平均化により余分なノイズも抑制される
CIFAR-10 複雑な自然画像・テクスチャ・背景あり MaxPooling 物体の輪郭・毛並み・タイヤのエッジなど「局所的に強い反応」が分類の決め手。最大値保持が有効

つまり「MaxとAvgどちらが良いか」の答えはデータの複雑さと特徴の性質に依存します。シンプルな線画はAvg、自然画像はMaxが傾向として優位です。

③ Mix(Max→Avg)はなぜMaxMaxに届かなかったか

MixパターンはMaxMaxとAvgAvgの中間(64.36%)に落ち着きました。前段でMaxPoolingにより強い特徴を保持しても、後段のAveragePoolingでその強い反応が平滑化されてしまうためと考えられます。CIFAR-10のような自然画像では、強い特徴をできるだけ最後まで保持する方が精度に有利なようです。

④ 学習時間の差に注目

AvgAvgの学習時間(100.0秒)はMaxMaxより約25秒短くなっています。AveragePoolingは加算と除算という単純な演算のみで、MaxPoolingの「比較+最大値選択」より計算コストが低いためです。精度を多少犠牲にしてでも学習速度を優先したい場面では、AveragePoolingも選択肢になります。

⚠️ ハマりポイント:MaxPooling2DとAveragePooling2Dはどちらも学習パラメータを持ちません(Param # = 0)。model.summary()を見ても3パターンのパラメータ数がすべて93,450と同じなのはそのためです。「パラメータ数が同じなのに精度が最大4ポイント違う」のは、どの特徴を次の層に渡すかという情報の取捨選択の違いだけが原因です。
まとめ
  • CIFAR-10(自然画像)ではMaxMaxがAvgAvgを約4.2ポイント上回った(test_accuracy: 67.47% vs 63.30%)
  • MNISTではAvgが有利だったが、CIFAR-10では逆転——データの複雑さと特徴の性質がPooling選択に影響する
  • Mix(Max→Avg)はMaxMaxに届かず中間の結果(64.36%)——自然画像では強い特徴を最後まで保持する方が有利
  • 3パターンのパラメータ数はすべて同一(93,450)——違いは学習パラメータではなく「何の情報を渡すか」だけ
  • AvgAvgはMaxMaxより約25秒学習が速い——精度 vs 速度のトレードオフとして覚えておく価値がある
  • 判断基準:線画・単純な形状 → Avg、自然画像・テクスチャが重要 → Max が目安

関連記事