KerasでConv2Dを書くとき、padding='same' と padding='valid' のどちらを使うか意識していますか?
「とりあえずsameにしている」という方も多いと思いますが、実際に精度・特徴マップサイズ・パラメータ数にどんな違いが出るのか、CIFAR-10で実験して比較しました。
📘 この記事でわかること
- same と valid でそれぞれ特徴マップサイズがどう変わるか
- CIFAR-10(低解像度画像)での精度・学習時間の差
- paddingの選び方の基準
same と valid の違い
padding はConv2Dが入力の端をどう扱うかを決めます。
| padding | 動作 | 出力サイズ(kernel=3×3, stride=1) |
|---|---|---|
same |
入力の周囲にゼロを追加し、出力サイズを入力と同じに保つ | 入力と同じ(例:32×32 → 32×32) |
valid |
パディングなし。カーネルが収まる範囲のみ畳み込む | 入力より小さくなる(例:32×32 → 30×30) |
valid では畳み込みのたびに特徴マップが小さくなります。CIFAR-10のように元の解像度が32×32と低い場合、層を重ねるごとに情報が急速に失われる可能性があります。
特徴マップサイズの変化(CIFAR-10・kernel=3×3の場合)
| 層 | same のサイズ | valid のサイズ |
|---|---|---|
| 入力 | 32×32 | 32×32 |
| Conv2D(1回目)後 | 32×32 | 30×30 |
| MaxPooling後 | 16×16 | 15×15 |
| Conv2D(2回目)後 | 16×16 | 13×13 |
| MaxPooling後 | 8×8 | 6×6 |
実験コード
使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10です。padding以外の条件は全て同一にして、paddingの影響だけを取り出します。
環境準備(最初に一度だけ実行)
# ── 環境準備(最初に一度だけ実行)──────────────────────
!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 42 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 2s (4,006 kB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 122354 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 32.1 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(padding, name):
return keras.Sequential([
keras.layers.Input(shape=(32, 32, 3)),
keras.layers.Conv2D(64, (3, 3), activation='relu', padding=padding),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(128, (3, 3), activation='relu', padding=padding),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.GlobalAveragePooling2D(),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dropout(0.2),
keras.layers.Dense(10, activation='softmax'),
], name=name)
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 ━━━━━━━━━━━━━━━━━━━━ 6s 0us/step
2パターンの学習実行
results = {}
for padding, name in [('same', 'A_same'), ('valid', 'B_valid')]:
print(f"\n=== {name} ===")
model = build_model(padding, name)
print(model.summary())
h, t = compile_and_fit(model)
s = model.evaluate(x_test, y_test, verbose=0)
results[name] = {'history': h, 'time': t, 'score': s,
'params': model.count_params()}
print(f"学習時間:{t:.1f}秒 パラメータ数:{model.count_params():,} test_accuracy:{s[1]:.4f}")
実行結果をクリックして内容を開く
=== A_same === Model: "A_same" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ 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) None Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 18s 14ms/step - accuracy: 0.2695 - loss: 1.9178 - val_accuracy: 0.3521 - val_loss: 1.7118 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 6ms/step - accuracy: 0.3769 - loss: 1.6657 - val_accuracy: 0.4342 - val_loss: 1.5519 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.4240 - loss: 1.5560 - val_accuracy: 0.4476 - val_loss: 1.4884 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4620 - loss: 1.4637 - val_accuracy: 0.4884 - val_loss: 1.3945 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4814 - loss: 1.4095 - val_accuracy: 0.5116 - val_loss: 1.3415 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5031 - loss: 1.3565 - val_accuracy: 0.5245 - val_loss: 1.3035 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5195 - loss: 1.3182 - val_accuracy: 0.5316 - val_loss: 1.2758 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5345 - loss: 1.2805 - val_accuracy: 0.5524 - val_loss: 1.2337 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5429 - loss: 1.2487 - val_accuracy: 0.5589 - val_loss: 1.1953 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5602 - loss: 1.2165 - val_accuracy: 0.5547 - val_loss: 1.2026 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5671 - loss: 1.1938 - val_accuracy: 0.5649 - val_loss: 1.1798 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5781 - loss: 1.1668 - val_accuracy: 0.5808 - val_loss: 1.1386 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5850 - loss: 1.1449 - val_accuracy: 0.5993 - val_loss: 1.1053 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5939 - loss: 1.1216 - val_accuracy: 0.6048 - val_loss: 1.0837 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5996 - loss: 1.1098 - val_accuracy: 0.5965 - val_loss: 1.0972 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6097 - loss: 1.0864 - val_accuracy: 0.6123 - val_loss: 1.0742 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6160 - loss: 1.0662 - val_accuracy: 0.6242 - val_loss: 1.0392 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6198 - loss: 1.0501 - val_accuracy: 0.6066 - val_loss: 1.0792 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6276 - loss: 1.0398 - val_accuracy: 0.6269 - val_loss: 1.0237 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6335 - loss: 1.0225 - val_accuracy: 0.6326 - val_loss: 1.0104 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.6373 - loss: 1.0087 - val_accuracy: 0.6361 - val_loss: 1.0012 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6425 - loss: 0.9930 - val_accuracy: 0.6437 - val_loss: 0.9895 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.6519 - loss: 0.9747 - val_accuracy: 0.6470 - val_loss: 0.9772 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6537 - loss: 0.9635 - val_accuracy: 0.6482 - val_loss: 0.9712 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 13ms/step - accuracy: 0.6586 - loss: 0.9531 - val_accuracy: 0.6232 - val_loss: 1.0330 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6617 - loss: 0.9421 - val_accuracy: 0.6659 - val_loss: 0.9301 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6685 - loss: 0.9288 - val_accuracy: 0.6527 - val_loss: 0.9631 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6700 - loss: 0.9199 - val_accuracy: 0.6580 - val_loss: 0.9451 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6774 - loss: 0.9035 - val_accuracy: 0.6555 - val_loss: 0.9610 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6798 - loss: 0.8930 - val_accuracy: 0.6717 - val_loss: 0.9190 学習時間:145.3秒 パラメータ数:93,450 test_accuracy:0.6691 === B_valid === Model: "B_valid" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv2d_2 (Conv2D) │ (None, 30, 30, 64) │ 1,792 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_2 (MaxPooling2D) │ (None, 15, 15, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_3 (Conv2D) │ (None, 13, 13, 128) │ 73,856 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_3 (MaxPooling2D) │ (None, 6, 6, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ 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) None Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2736 - loss: 1.8819 - val_accuracy: 0.3384 - val_loss: 1.7135 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 5ms/step - accuracy: 0.3766 - loss: 1.6477 - val_accuracy: 0.4285 - val_loss: 1.5407 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4405 - loss: 1.5176 - val_accuracy: 0.4800 - val_loss: 1.4326 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4749 - loss: 1.4378 - val_accuracy: 0.4787 - val_loss: 1.4253 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.4975 - loss: 1.3874 - val_accuracy: 0.5253 - val_loss: 1.3249 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5142 - loss: 1.3434 - val_accuracy: 0.5296 - val_loss: 1.2950 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5270 - loss: 1.3081 - val_accuracy: 0.5389 - val_loss: 1.2688 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5405 - loss: 1.2785 - val_accuracy: 0.5578 - val_loss: 1.2266 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5517 - loss: 1.2510 - val_accuracy: 0.5667 - val_loss: 1.2163 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5603 - loss: 1.2250 - val_accuracy: 0.5630 - val_loss: 1.2181 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5654 - loss: 1.2054 - val_accuracy: 0.5747 - val_loss: 1.1794 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5758 - loss: 1.1880 - val_accuracy: 0.5760 - val_loss: 1.1611 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5832 - loss: 1.1614 - val_accuracy: 0.5661 - val_loss: 1.1896 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5906 - loss: 1.1388 - val_accuracy: 0.5932 - val_loss: 1.1172 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 5ms/step - accuracy: 0.6024 - loss: 1.1139 - val_accuracy: 0.6072 - val_loss: 1.0928 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6067 - loss: 1.1021 - val_accuracy: 0.6060 - val_loss: 1.0882 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6096 - loss: 1.0909 - val_accuracy: 0.6095 - val_loss: 1.0838 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6173 - loss: 1.0716 - val_accuracy: 0.6276 - val_loss: 1.0414 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6201 - loss: 1.0575 - val_accuracy: 0.6284 - val_loss: 1.0342 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 6ms/step - accuracy: 0.6321 - loss: 1.0361 - val_accuracy: 0.6378 - val_loss: 1.0223 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6362 - loss: 1.0224 - val_accuracy: 0.6277 - val_loss: 1.0359 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6401 - loss: 1.0068 - val_accuracy: 0.6420 - val_loss: 1.0092 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6447 - loss: 0.9933 - val_accuracy: 0.6301 - val_loss: 1.0310 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.6511 - loss: 0.9817 - val_accuracy: 0.6481 - val_loss: 0.9782 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6567 - loss: 0.9636 - val_accuracy: 0.6592 - val_loss: 0.9605 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6596 - loss: 0.9524 - val_accuracy: 0.6542 - val_loss: 0.9592 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 6ms/step - accuracy: 0.6691 - loss: 0.9376 - val_accuracy: 0.6625 - val_loss: 0.9503 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6697 - loss: 0.9272 - val_accuracy: 0.6494 - val_loss: 0.9691 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6772 - loss: 0.9162 - val_accuracy: 0.6615 - val_loss: 0.9561 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6792 - loss: 0.9060 - val_accuracy: 0.6728 - val_loss: 0.9307 学習時間:124.4秒 パラメータ数:93,450 test_accuracy:0.6626
グラフ+サマリー
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for name, r in results.items():
axes[0].plot(r['history'].history['val_accuracy'], label=name)
axes[1].plot(r['history'].history['val_loss'], label=name)
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('padding_comparison.png', dpi=150)
plt.show()
print("\n===== 最終結果サマリー =====")
print(f"{'Pattern':>8} | {'Val Acc':>8} | {'Test Acc':>9} | {'Time(s)':>8} | {'Params':>12}")
print("-" * 58)
for name, r in results.items():
val_acc = r['history'].history['val_accuracy'][-1]
test_acc = r['score'][1]
print(f"{name:>8} | {val_acc:>8.4f} | {test_acc:>9.4f} | {r['time']:>8.1f} | {r['params']:>12,}")
print("-" * 58)
最終結果サマリー
===== 最終結果サマリー ===== Pattern | Val Acc | Test Acc | Time(s) | Params ---------------------------------------------------------- A_same | 0.6717 | 0.6691 | 145.3 | 93,450 B_valid | 0.6728 | 0.6626 | 124.4 | 93,450 ----------------------------------------------------------
実験結果
精度グラフ
損失グラフ
| パターン | 最終 val_accuracy | 最終 test_accuracy | パラメータ数 | 学習時間 |
|---|---|---|---|---|
| A:padding='same' | 67.17% | 66.91% | 93,450 | 145.3秒 |
| B:padding='valid' | 67.28% | 66.26% | 93,450 | 124.4秒 |
考察
① パラメータ数は同じ——GAPがサイズ差を吸収した
model.summary()で確認すると、AとBのパラメータ数は両方とも93,450で完全に同じです。
理由はGlobalAveragePooling2D(GAP)にあります。GAPはその時点の特徴マップをチャンネルあたり1つの平均値に集約するため、same(8×8×128)でも valid(6×6×128)でも、GAP後は同じ128次元ベクトルになります。そのためDense層への入力次元が変わらず、パラメータ数に差が出ませんでした。
なお、FlattenをGAPの代わりに使った場合はこの限りではありません。Flattenは特徴マップをそのまま展開するため、valid(6×6×128=4,608次元)と same(8×8×128=8,192次元)でDense層のパラメータ数が大きく変わります。
② 精度差は誤差の範囲——どちらが「勝った」とは言いにくい
精度の差を整理すると以下の通りです。
| 指標 | A:same | B:valid | 差 |
|---|---|---|---|
| val_accuracy | 67.17% | 67.28% | 0.11%(valid優位) |
| test_accuracy | 66.91% | 66.26% | 0.65%(same優位) |
| 学習時間 | 145.3秒 | 124.4秒 | 20.9秒(valid優位) |
val_accuracyではBが0.11%上、test_accuracyではAが0.65%上という指標によって勝敗が逆転する結果になりました。差も最大0.65%と非常に小さく、実質的に誤差の範囲内です。
この結果は「paddingの違いがGAP使用モデルでは精度にほぼ影響しない」ことを示しています。①で述べたようにGAPがサイズ差を吸収するため、same で8×8の特徴マップを丁寧に保持しても、valid で6×6に縮小しても、Dense層への入力の質に大きな差が生じなかったと考えられます。
③ 学習時間の差はvalidが有利
valid はパディングの計算が不要で特徴マップも小さいため、1エポックあたりの計算量が少なくなります。今回は約21秒(約14%)の短縮となりました。精度がほぼ同じであれば、計算コストの観点からは valid に一定のメリットがあります。
ただしこれはGAP使用モデル限定の話です。Flattenを使う場合、valid では特徴マップが小さくなることで情報損失が精度に直接影響するため、same を選ぶ理由が強くなります。
まとめ
- GAP使用モデルでは
sameとvalidのパラメータ数は同じ(GAPがサイズ差を吸収するため) - 精度差は最大0.65%と誤差の範囲内。GAP使用モデルではpaddingが精度にほぼ影響しないことが確認できた
- 学習時間は
validが約21秒(約14%)短い。精度が同等なら計算コスト面でvalidに一定のメリットがある - Flattenを使う場合は話が変わる。
validでは特徴マップ縮小がDense層のパラメータ数と精度に直接影響するためsameが有利になりやすい - 迷ったら
padding='same'を基本にするのが安全。GAP使用モデルでは大きな差は出ないが、後でFlattenに変えたときのリスクを避けられる
関連記事もあわせてどうぞ:
- Conv2Dのkernel_size比較 → Conv2Dのkernel_sizeを変えると精度はどう変わる?(3×3 vs 5×5 vs 1×1)【Keras×CIFAR-10実験】
- Conv2Dのフィルター数の選び方 → Conv2DのFilters数(32 vs 64 vs 128)を変えると精度はどう変わる?【CIFAR-10実験】
- MaxPoolingのpool_size比較 → GAPモデルでMaxPoolingのpool_sizeを変えると精度はどう変わる?【Keras実験・予想外の結果】
- model.summary()の読み方 → Kerasのmodel.summary()の読み方を徹底解説|パラメータ数の計算方法【初心者向け】



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