「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 + zoom | C+ズーム(±20%) | スケール変化も加える |
| E:flip + rotation + zoom + crop | D+ランダムクロップ | 最大限の拡張 |
実験コード
環境準備(最初に一度だけ実行)
# ── 環境準備(最初に一度だけ実行)──────────────────────
!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
flip
flip_rot
flip_rot_zoom
flip_rot_zoom_crop
| パターン | 最終 val_accuracy | 最終 test_accuracy | 学習時間 |
|---|---|---|---|
| A:なし | 68.65% | 68.09% | 133.9秒 |
| B:flip | 69.54% | 69.35% | 138.3秒 |
| C:flip + rotation | 58.62% | 58.71% | 194.0秒 |
| D:flip + rotation + zoom | 58.67% | 57.82% | 222.6秒 |
| E:flip + rotation + zoom + crop | 54.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を見ながら慎重に追加していくのが現実的なアプローチです。
関連記事もあわせてどうぞ:
- Dropoutとの組み合わせ → Dropoutの割合(0.0 vs 0.2 vs 0.5)を変えると過学習はどう変わる?【Keras×CIFAR-10実験】
- BatchNormとDropoutの比較 → BatchNormalizationはDropoutと併用すべきか?Keras×MNISTで4パターン比較
- 過学習の判定方法 → CIFAR-10で学ぶ:過学習(オーバーフィッティング)の判定方法と実践的対策
- 学習曲線の見方 → Kerasで学習曲線を可視化する方法【過学習の発見と対策まで】
- 少量データでのAugmentation効果 → Few-shot learningとは?MNISTを使った少量データ画像分類の実験(Keras)








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