Data Augmentationを重ねすぎると精度が下がる?flip〜cropの5パターンをCIFAR-10で比較【Keras実験】

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

CIFAR-10 CNN Data Augmentation Google Colab Keras データ拡張 過学習 画像分類

X f B! P L
Data Augmentationを重ねすぎると精度が下がる?flip〜cropの5パターンをCIFAR-10で比較【Keras実験】 アイキャッチ画像

「flip + rotation は定番の組み合わせ」──そう信じて使っていませんか?
実際にCIFAR-10で試してみると、rotationを加えた途端に精度が約10%急落する結果になりました。
本記事ではGoogle Colab × CIFAR-10 × Kerasを使い、 Augmentationなし〜4種類組み合わせまでの5パターンを同一条件で比較し、 その意外な結果と理由を丁寧に解説します。

📘 この記事でわかること

  • Data Augmentationが過学習を抑えるメカニズム
  • flip・rotation・zoom・cropそれぞれの効果の違い
  • 多くかけすぎると逆効果になる理由
  • CIFAR-10での実験結果と使い分けの目安

Data Augmentationとは?──過学習を抑えるデータ水増しの仕組み

Data Augmentation(データ拡張)とは、既存の訓練画像に反転・回転・ズームなどの変換をランダムに加えて、 人工的にデータの多様性を増やす手法です。

なぜ過学習を抑えられるのか。理由はシンプルで、毎エポックで「少し違う画像」がモデルに入力されるため、 モデルが訓練画像のピクセル配置を丸暗記しにくくなるからです。 同じ飛行機の画像でも、少し傾いていたり、拡大されていたりすれば、 モデルは「形の本質」を学ばざるを得なくなります。

変換の種類概要主な効果
RandomFlip水平・垂直方向にランダム反転左右対称性の汎化
RandomRotation指定角度内でランダム回転向きへの過学習を防ぐ
RandomZoomランダムに拡大・縮小スケール変化への対応力
RandomCropランダムな位置で切り取り位置ズレへの頑健性


実験で比較する5パターン

Augmentation以外の条件(モデル構造・エポック数・バッチサイズ・オプティマイザ)はすべて同一にして、 拡張手法の違いだけを取り出します。

パターン設定狙い
A:なしAugmentationなしベースライン
B:flip水平反転のみ最小限の拡張
C:flip + rotation反転+回転(±15%)定番の組み合わせ
D:flip + rotation + zoomC+ズーム(±20%)スケール変化も加える
E:flip + rotation + zoom + cropD+ランダムクロップ最大限の拡張

実験コード

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

# ── 環境準備(最初に一度だけ実行)──────────────────────
!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 38s (220 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 14.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
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 145s 1us/step

Augmentationレイヤーの定義

# ── 5パターンのAugmentation定義 ────────────────────────
def get_augmentation(pattern):
    if pattern == 'none':
        return None # Return None when no augmentation is needed
    elif pattern == 'flip':
        return keras.Sequential([
            keras.layers.RandomFlip('horizontal'),
        ], name='aug_flip')
    elif pattern == 'flip_rot':
        return keras.Sequential([
            keras.layers.RandomFlip('horizontal'),
            keras.layers.RandomRotation(0.15),
        ], name='aug_flip_rot')
    elif pattern == 'flip_rot_zoom':
        return keras.Sequential([
            keras.layers.RandomFlip('horizontal'),
            keras.layers.RandomRotation(0.15),
            keras.layers.RandomZoom(0.2),
        ], name='aug_flip_rot_zoom')
    elif pattern == 'flip_rot_zoom_crop':
        return keras.Sequential([
            keras.layers.RandomFlip('horizontal'),
            keras.layers.RandomRotation(0.15),
            keras.layers.RandomZoom(0.2),
            keras.layers.RandomCrop(28, 28),
            keras.layers.Resizing(32, 32),
        ], name='aug_flip_rot_zoom_crop')

モデル構築関数

# ── モデル構築関数 ─────────────────────────────────────
def build_model(aug_pattern, name):
    augmentation = get_augmentation(aug_pattern)
    model = keras.Sequential([
        keras.layers.Input(shape=(32, 32, 3)),
        augmentation,
        keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(256, activation='relu'),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10, activation='softmax'),
    ], name=name)
    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

5パターンの学習実行

EPOCHS = 30
BATCH  = 64

configs = [
    ('none',               'A_none'),
    ('flip',               'B_flip'),
    ('flip_rot',           'C_flip_rot'),
    ('flip_rot_zoom',      'D_flip_rot_zoom'),
    ('flip_rot_zoom_crop', 'E_flip_rot_zoom_crop'),
]

histories, scores, times = {}, {}, {}

for aug_pattern, name in configs:
    print(f"\n=== {name} ===")
    model = build_model(aug_pattern, name)
    start = time.time()
    h = model.fit(
        x_train, y_train,
        epochs=EPOCHS,
        batch_size=BATCH,
        validation_split=0.2,
        verbose=1
    )
    elapsed = time.time() - start
    score = model.evaluate(x_test, y_test, verbose=0)
    label = name.split('_', 1)[1]   # 'none' / 'flip' / ...
    histories[label] = h
    scores[label]    = score
    times[label]     = elapsed
    print(f"学習時間:{elapsed:.1f}秒 test_accuracy:{score[1]:.4f}")
実行結果をクリックして内容を開く
=== A_none ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 10ms/step - accuracy: 0.2673 - loss: 1.9227 - val_accuracy: 0.3429 - val_loss: 1.7318
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3932 - loss: 1.6376 - val_accuracy: 0.4296 - val_loss: 1.5616
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4541 - loss: 1.4882 - val_accuracy: 0.4607 - val_loss: 1.4781
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.4875 - loss: 1.4028 - val_accuracy: 0.5010 - val_loss: 1.3610
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5106 - loss: 1.3396 - val_accuracy: 0.5263 - val_loss: 1.2864
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5309 - loss: 1.2947 - val_accuracy: 0.5407 - val_loss: 1.2541
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5446 - loss: 1.2532 - val_accuracy: 0.5578 - val_loss: 1.2265
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5605 - loss: 1.2120 - val_accuracy: 0.5598 - val_loss: 1.2065
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5736 - loss: 1.1850 - val_accuracy: 0.5742 - val_loss: 1.1671
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5858 - loss: 1.1529 - val_accuracy: 0.5878 - val_loss: 1.1445
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5925 - loss: 1.1253 - val_accuracy: 0.5979 - val_loss: 1.1016
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6075 - loss: 1.0951 - val_accuracy: 0.5901 - val_loss: 1.1177
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6137 - loss: 1.0760 - val_accuracy: 0.6189 - val_loss: 1.0528
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6252 - loss: 1.0462 - val_accuracy: 0.6178 - val_loss: 1.0573
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6331 - loss: 1.0262 - val_accuracy: 0.6332 - val_loss: 1.0196
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6407 - loss: 0.9996 - val_accuracy: 0.6227 - val_loss: 1.0336
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6455 - loss: 0.9886 - val_accuracy: 0.6448 - val_loss: 0.9765
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6525 - loss: 0.9663 - val_accuracy: 0.6426 - val_loss: 0.9890
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6597 - loss: 0.9519 - val_accuracy: 0.6575 - val_loss: 0.9466
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6664 - loss: 0.9318 - val_accuracy: 0.6448 - val_loss: 0.9853
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6713 - loss: 0.9171 - val_accuracy: 0.6546 - val_loss: 0.9577
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6792 - loss: 0.8992 - val_accuracy: 0.6590 - val_loss: 0.9337
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6827 - loss: 0.8844 - val_accuracy: 0.6615 - val_loss: 0.9296
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6858 - loss: 0.8711 - val_accuracy: 0.6528 - val_loss: 0.9485
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6913 - loss: 0.8674 - val_accuracy: 0.6658 - val_loss: 0.9330
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6963 - loss: 0.8496 - val_accuracy: 0.6770 - val_loss: 0.8987
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7014 - loss: 0.8385 - val_accuracy: 0.6844 - val_loss: 0.8859
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7033 - loss: 0.8248 - val_accuracy: 0.6925 - val_loss: 0.8566
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7105 - loss: 0.8143 - val_accuracy: 0.6931 - val_loss: 0.8550
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7130 - loss: 0.8043 - val_accuracy: 0.6865 - val_loss: 0.8876
学習時間:133.9秒 test_accuracy:0.6809

=== B_flip ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 9ms/step - accuracy: 0.2801 - loss: 1.8915 - val_accuracy: 0.3571 - val_loss: 1.7026
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 7ms/step - accuracy: 0.3883 - loss: 1.6325 - val_accuracy: 0.4051 - val_loss: 1.5884
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4424 - loss: 1.5115 - val_accuracy: 0.4641 - val_loss: 1.4681
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4794 - loss: 1.4225 - val_accuracy: 0.4915 - val_loss: 1.3716
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5059 - loss: 1.3509 - val_accuracy: 0.5085 - val_loss: 1.3260
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5212 - loss: 1.3095 - val_accuracy: 0.5313 - val_loss: 1.2799
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5340 - loss: 1.2682 - val_accuracy: 0.5414 - val_loss: 1.2394
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5535 - loss: 1.2302 - val_accuracy: 0.5417 - val_loss: 1.2252
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5676 - loss: 1.1934 - val_accuracy: 0.5621 - val_loss: 1.1814
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5737 - loss: 1.1670 - val_accuracy: 0.5712 - val_loss: 1.1906
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5897 - loss: 1.1363 - val_accuracy: 0.5993 - val_loss: 1.1137
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5986 - loss: 1.1135 - val_accuracy: 0.5913 - val_loss: 1.1148
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6034 - loss: 1.0933 - val_accuracy: 0.6064 - val_loss: 1.0817
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6140 - loss: 1.0644 - val_accuracy: 0.6220 - val_loss: 1.0421
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6238 - loss: 1.0488 - val_accuracy: 0.6252 - val_loss: 1.0258
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6323 - loss: 1.0211 - val_accuracy: 0.6356 - val_loss: 1.0145
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6393 - loss: 1.0071 - val_accuracy: 0.6231 - val_loss: 1.0457
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6456 - loss: 0.9868 - val_accuracy: 0.6376 - val_loss: 0.9912
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6512 - loss: 0.9692 - val_accuracy: 0.6545 - val_loss: 0.9701
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6573 - loss: 0.9551 - val_accuracy: 0.6601 - val_loss: 0.9501
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6626 - loss: 0.9398 - val_accuracy: 0.6531 - val_loss: 0.9581
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6689 - loss: 0.9264 - val_accuracy: 0.6662 - val_loss: 0.9346
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6722 - loss: 0.9142 - val_accuracy: 0.6666 - val_loss: 0.9273
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6806 - loss: 0.8942 - val_accuracy: 0.6724 - val_loss: 0.9038
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6843 - loss: 0.8856 - val_accuracy: 0.6731 - val_loss: 0.9073
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6891 - loss: 0.8696 - val_accuracy: 0.6583 - val_loss: 0.9355
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6888 - loss: 0.8693 - val_accuracy: 0.6815 - val_loss: 0.8848
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6953 - loss: 0.8552 - val_accuracy: 0.6759 - val_loss: 0.9017
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7000 - loss: 0.8445 - val_accuracy: 0.6834 - val_loss: 0.8879
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7038 - loss: 0.8301 - val_accuracy: 0.6954 - val_loss: 0.8567
学習時間:138.3秒 test_accuracy:0.6935

=== C_flip_rot ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 10ms/step - accuracy: 0.2536 - loss: 1.9765 - val_accuracy: 0.3271 - val_loss: 1.8209
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3412 - loss: 1.7755 - val_accuracy: 0.3818 - val_loss: 1.6828
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.3791 - loss: 1.6869 - val_accuracy: 0.4130 - val_loss: 1.5908
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4141 - loss: 1.6095 - val_accuracy: 0.4586 - val_loss: 1.4916
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 11ms/step - accuracy: 0.4358 - loss: 1.5528 - val_accuracy: 0.4648 - val_loss: 1.4871
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.4546 - loss: 1.5048 - val_accuracy: 0.4927 - val_loss: 1.4089
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4702 - loss: 1.4656 - val_accuracy: 0.5048 - val_loss: 1.3548
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4764 - loss: 1.4418 - val_accuracy: 0.5119 - val_loss: 1.3422
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4896 - loss: 1.4153 - val_accuracy: 0.5331 - val_loss: 1.2964
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4986 - loss: 1.3867 - val_accuracy: 0.5115 - val_loss: 1.3513
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5037 - loss: 1.3712 - val_accuracy: 0.5319 - val_loss: 1.2983
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5128 - loss: 1.3482 - val_accuracy: 0.5342 - val_loss: 1.2893
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5173 - loss: 1.3351 - val_accuracy: 0.5370 - val_loss: 1.2807
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 10ms/step - accuracy: 0.5253 - loss: 1.3109 - val_accuracy: 0.5425 - val_loss: 1.2651
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5315 - loss: 1.2920 - val_accuracy: 0.5646 - val_loss: 1.2162
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 10ms/step - accuracy: 0.5381 - loss: 1.2773 - val_accuracy: 0.5700 - val_loss: 1.1915
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5450 - loss: 1.2656 - val_accuracy: 0.5628 - val_loss: 1.2025
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5468 - loss: 1.2550 - val_accuracy: 0.5765 - val_loss: 1.1791
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5507 - loss: 1.2430 - val_accuracy: 0.5748 - val_loss: 1.1934
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5566 - loss: 1.2307 - val_accuracy: 0.5753 - val_loss: 1.1784
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5623 - loss: 1.2168 - val_accuracy: 0.5622 - val_loss: 1.2274
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5655 - loss: 1.2036 - val_accuracy: 0.6013 - val_loss: 1.1220
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5690 - loss: 1.1949 - val_accuracy: 0.6026 - val_loss: 1.1119
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5778 - loss: 1.1763 - val_accuracy: 0.5808 - val_loss: 1.1613
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5771 - loss: 1.1729 - val_accuracy: 0.5814 - val_loss: 1.2011
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5804 - loss: 1.1570 - val_accuracy: 0.6103 - val_loss: 1.0966
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5874 - loss: 1.1490 - val_accuracy: 0.6039 - val_loss: 1.1281
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5908 - loss: 1.1382 - val_accuracy: 0.5968 - val_loss: 1.1330
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.5944 - loss: 1.1294 - val_accuracy: 0.6170 - val_loss: 1.0896
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5963 - loss: 1.1203 - val_accuracy: 0.5862 - val_loss: 1.1790
学習時間:194.0秒 test_accuracy:0.5871

=== D_flip_rot_zoom ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 11ms/step - accuracy: 0.2476 - loss: 1.9881 - val_accuracy: 0.3191 - val_loss: 1.8658
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3260 - loss: 1.8097 - val_accuracy: 0.3762 - val_loss: 1.7147
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.3696 - loss: 1.7160 - val_accuracy: 0.3759 - val_loss: 1.6868
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4011 - loss: 1.6452 - val_accuracy: 0.3896 - val_loss: 1.6803
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4281 - loss: 1.5767 - val_accuracy: 0.4597 - val_loss: 1.4917
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4419 - loss: 1.5364 - val_accuracy: 0.4725 - val_loss: 1.4192
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4589 - loss: 1.4956 - val_accuracy: 0.4444 - val_loss: 1.5341
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.4665 - loss: 1.4716 - val_accuracy: 0.4981 - val_loss: 1.3908
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.4769 - loss: 1.4490 - val_accuracy: 0.4827 - val_loss: 1.4434
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 11ms/step - accuracy: 0.4879 - loss: 1.4212 - val_accuracy: 0.5062 - val_loss: 1.3883
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4918 - loss: 1.4105 - val_accuracy: 0.5121 - val_loss: 1.3564
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5000 - loss: 1.3888 - val_accuracy: 0.5200 - val_loss: 1.3634
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5053 - loss: 1.3664 - val_accuracy: 0.5312 - val_loss: 1.2910
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 10ms/step - accuracy: 0.5129 - loss: 1.3509 - val_accuracy: 0.5451 - val_loss: 1.2677
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5190 - loss: 1.3318 - val_accuracy: 0.5270 - val_loss: 1.3551
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 12s 12ms/step - accuracy: 0.5245 - loss: 1.3187 - val_accuracy: 0.5451 - val_loss: 1.2891
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5283 - loss: 1.3100 - val_accuracy: 0.5512 - val_loss: 1.2483
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.5329 - loss: 1.2949 - val_accuracy: 0.5427 - val_loss: 1.2621
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5365 - loss: 1.2828 - val_accuracy: 0.5410 - val_loss: 1.2804
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5404 - loss: 1.2685 - val_accuracy: 0.5113 - val_loss: 1.4502
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.5466 - loss: 1.2552 - val_accuracy: 0.5615 - val_loss: 1.2362
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5540 - loss: 1.2468 - val_accuracy: 0.5684 - val_loss: 1.2112
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5550 - loss: 1.2310 - val_accuracy: 0.5743 - val_loss: 1.1933
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5598 - loss: 1.2249 - val_accuracy: 0.5609 - val_loss: 1.2501
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.5640 - loss: 1.2161 - val_accuracy: 0.5732 - val_loss: 1.1991
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.5707 - loss: 1.2045 - val_accuracy: 0.5856 - val_loss: 1.1616
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5687 - loss: 1.2041 - val_accuracy: 0.5988 - val_loss: 1.1343
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5713 - loss: 1.1950 - val_accuracy: 0.5891 - val_loss: 1.1638
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5724 - loss: 1.1853 - val_accuracy: 0.5817 - val_loss: 1.1907
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 10ms/step - accuracy: 0.5813 - loss: 1.1720 - val_accuracy: 0.5867 - val_loss: 1.1941
学習時間:222.6秒 test_accuracy:0.5782

=== E_flip_rot_zoom_crop ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 11ms/step - accuracy: 0.2350 - loss: 2.0164 - val_accuracy: 0.2782 - val_loss: 1.8949
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.3195 - loss: 1.8337 - val_accuracy: 0.3437 - val_loss: 1.8277
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.3702 - loss: 1.7222 - val_accuracy: 0.3459 - val_loss: 1.8763
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.3959 - loss: 1.6540 - val_accuracy: 0.4139 - val_loss: 1.6068
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 10ms/step - accuracy: 0.4173 - loss: 1.6069 - val_accuracy: 0.4295 - val_loss: 1.5884
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.4323 - loss: 1.5658 - val_accuracy: 0.4173 - val_loss: 1.6234
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4450 - loss: 1.5307 - val_accuracy: 0.4402 - val_loss: 1.5874
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.4545 - loss: 1.5154 - val_accuracy: 0.4450 - val_loss: 1.5885
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.4615 - loss: 1.4838 - val_accuracy: 0.4326 - val_loss: 1.5928
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4696 - loss: 1.4651 - val_accuracy: 0.4551 - val_loss: 1.5311
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.4764 - loss: 1.4469 - val_accuracy: 0.4861 - val_loss: 1.4466
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.4838 - loss: 1.4308 - val_accuracy: 0.4750 - val_loss: 1.4790
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.4872 - loss: 1.4127 - val_accuracy: 0.4262 - val_loss: 1.6899
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 12ms/step - accuracy: 0.4964 - loss: 1.4011 - val_accuracy: 0.4933 - val_loss: 1.4349
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4979 - loss: 1.3886 - val_accuracy: 0.4893 - val_loss: 1.4694
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5028 - loss: 1.3793 - val_accuracy: 0.4767 - val_loss: 1.4940
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 11ms/step - accuracy: 0.5057 - loss: 1.3718 - val_accuracy: 0.4649 - val_loss: 1.5237
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5097 - loss: 1.3529 - val_accuracy: 0.4893 - val_loss: 1.4449
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5140 - loss: 1.3445 - val_accuracy: 0.5063 - val_loss: 1.4185
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5208 - loss: 1.3356 - val_accuracy: 0.4999 - val_loss: 1.4656
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 11ms/step - accuracy: 0.5227 - loss: 1.3225 - val_accuracy: 0.5261 - val_loss: 1.3375
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5276 - loss: 1.3119 - val_accuracy: 0.5171 - val_loss: 1.3890
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5288 - loss: 1.3059 - val_accuracy: 0.5232 - val_loss: 1.3761
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5281 - loss: 1.3030 - val_accuracy: 0.5202 - val_loss: 1.3948
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5350 - loss: 1.2939 - val_accuracy: 0.5210 - val_loss: 1.4004
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.5379 - loss: 1.2828 - val_accuracy: 0.5126 - val_loss: 1.4225
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.5383 - loss: 1.2786 - val_accuracy: 0.5531 - val_loss: 1.2889
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 12ms/step - accuracy: 0.5432 - loss: 1.2730 - val_accuracy: 0.5158 - val_loss: 1.4078
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.5448 - loss: 1.2635 - val_accuracy: 0.5260 - val_loss: 1.3806
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5466 - loss: 1.2574 - val_accuracy: 0.5440 - val_loss: 1.3140
学習時間:227.2秒 test_accuracy:0.5360

グラフ描画・サマリー

# ── 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('augmentation_val.png', dpi=150)
plt.show()

# ── train vs val(過学習の乖離)────────────────────────
fig2, axes2 = plt.subplots(1, 2, figsize=(14, 5))
for ax, label in zip(axes2, ['none', 'flip_rot_zoom']):
    h = histories[label]
    ax.plot(h.history['loss'],     label='train_loss')
    ax.plot(h.history['val_loss'], label='val_loss')
    ax.set_title(f'{label}:train vs val loss')
    ax.set_xlabel('Epoch'); ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('augmentation_overfit.png', dpi=150)
plt.show()

# ── サマリー ─────────────────────────────────────────────
print("\n===== 最終結果サマリー =====")
print(f"{'Pattern':>20} | {'Val Acc':>8} | {'Test Acc':>9} | {'Time(s)':>8}")
print("-" * 55)
for label, h in histories.items():
    val_acc  = h.history['val_accuracy'][-1]
    test_acc = scores[label][1]
    t        = times[label]
    print(f"{label:>20} | {val_acc:>8.4f} | {test_acc:>9.4f} | {t:>8.1f}")
print("-" * 55)

最終結果サマリー

===== 最終結果サマリー =====
             Pattern |  Val Acc |  Test Acc |  Time(s)
----------------------------------------------------------
                none |   0.6865 |    0.6809 |    133.9
                flip |   0.6954 |    0.6935 |    138.3
            flip_rot |   0.5862 |    0.5871 |    194.0
       flip_rot_zoom |   0.5867 |    0.5782 |    222.6
  flip_rot_zoom_crop |   0.5440 |    0.5360 |    227.2
----------------------------------------------------------

実験結果

精度グラフ

精度グラフ

損失グラフ

損失グラフ

none

none

flip

flip

flip_rot

flip_rot

flip_rot_zoom

flip_rot_zoom

flip_rot_zoom_crop

flip_rot_zoom_crop
パターン 最終 val_accuracy 最終 test_accuracy 学習時間
A:なし68.65%68.09%133.9秒
B:flip69.54%69.35%138.3秒
C:flip + rotation58.62%58.71%194.0秒
D:flip + rotation + zoom58.67%57.82%222.6秒
E:flip + rotation + zoom + crop54.40%53.60%227.2秒

予想に反して、最も良かったのはflipのみ(パターンB)でした。
rotation以降は精度が約10%急落し、cropまで加えたパターンEは最低精度となりました。


考察

① なぜflipだけが最も効果的だったのか

水平反転は画像の「内容」を変えません。飛行機は反転しても飛行機です。 一方、rotation(回転)はCIFAR-10の32×32という極小解像度では破壊的な変換になります。 32×32ピクセルの画像を±54度(0.15 × 360度)回転させると、 コーナー部分に黒い余白が生まれ、被写体が大きく歪みます。 モデルは「本物の犬」ではなく「斜めに傾いた歪んだ犬」を学習することになり、精度が落ちます。

② rotationで約10%も精度が落ちた理由

Kerasの RandomRotation(0.15)「全体の15%の回転角度」を意味します。 つまり最大で ±54度(0.15 × 360°)の回転がかかります。 CIFAR-10のような小さな画像ではこれは強すぎる変換です。 実用的には RandomRotation(0.05)(±18度程度)から試すべきでした。

③ zoom・cropをさらに加えると悪化した理由

すでにrotationで画像が歪んでいる状態に、さらにzoomとcropを重ねることで 「元の画像の面影がほとんどない」訓練データが生成されます。 モデルが学ぶべき特徴がノイズに埋もれてしまい、精度がさらに低下しました。 Augmentationの重ね掛けは「それぞれが独立して効く」わけではなく、 相乗的に変換が強くなることを示しています。

④ 学習時間への影響

パターンAに対してパターンEは約1.7倍の学習時間がかかりました(134秒→227秒)。 精度が下がりながら時間だけが増えているため、このケースではコストパフォーマンスが最悪です。 Augmentationを重ねるほど計算コストが増えることも、慎重に設定すべき理由のひとつです。

⑤ 一般的な「定番の組み合わせ」がなぜ今回は効かなかったか

「flip + rotation は定番」というのは、ImageNetなど高解像度(224×224以上)の画像を前提とした話です。 32×32のCIFAR-10では同じ設定値では変換が強すぎます。 データセットの解像度や特性に合わせてAugmentationの強度を調整することが重要であり、 「定番設定をそのままコピーしない」ことがこの実験の最大の教訓です。


まとめ:Data Augmentationの使い分け目安

今回の実験結果を踏まえた実践的な指針です。

状況推奨理由
CIFAR-10など低解像度(32×32)flip のみrotationは強すぎて逆効果になりやすい
rotationを使いたい場合RandomRotation(0.05) 以下±18度程度が低解像度には適切
高解像度画像(224×224以上)flip + rotation + zoom解像度が高いほど変換の影響が緩やかになる
cropを使う場合単独または弱いrotationと組み合わせ他の変換との重ね掛けは過剰になりやすい

Augmentationは「強ければ良い」ではなく、データセットの解像度と特性に合わせた調整が必要です。
まずflipだけで試し、val_lossを見ながら慎重に追加していくのが現実的なアプローチです。


関連記事もあわせてどうぞ: