前回の記事では、
RandomRotation(0.15) を加えた途端に精度が約10%急落するという予想外の結果になりました。
原因は 0.15 = 最大±54度という強すぎる回転 がCIFAR-10の32×32画像を歪めていたことでした。
では、どの角度なら精度が上がるのか? 今回は RandomRotation の値だけを5段階に変えて比較実験しました。
結論を先に言うと、0.03という小さい角度でも test accuracy は約3.1ポイント低下し、今回の実験条件ではrotationを使わない flip のみが最も良い結果になりました。
📘 この記事でわかること
RandomRotationの数値が実際に何度の回転を意味するか- CIFAR-10(32×32)に最適なrotation角度
- 角度を上げるほど精度が下がる理由と学習時間への影響
- 解像度別のrotation推奨設定
RandomRotation(0.15)はなぜ強すぎたのか──前回の振り返り
Kerasの RandomRotation(factor) の factor は、
「全体(360度)に対する割合」 で指定します。
| factor の値 | 最大回転角度 | イメージ |
|---|---|---|
0.03 | ±10.8度 | わずかに傾く程度 |
0.05 | ±18度 | やや傾いた画像 |
0.10 | ±36度 | 明らかに斜めになる |
0.15 | ±54度 | ほぼ横倒し(前回の設定) |
32×32ピクセルという小さな画像を±54度回転させると、
コーナーに大きな黒い余白が生まれ、被写体の形が大きく失われます。
モデルは「歪んだ画像」を学習することになり、精度が落ちました。
今回は より小さい角度(0.03・0.05)でも効果があるか を確かめます。
📌 前回記事:Data Augmentationを重ねすぎると精度が下がる?flip〜cropの5パターンをCIFAR-10で比較【Keras実験】
実験で比較する5段階
全パターンに RandomFlip('horizontal') を統一適用し、
RandomRotation の値だけを変えます。
その他の条件(モデル構造・エポック数・バッチサイズ・オプティマイザ)はすべて同一です。
| パターン | rotation値 | 最大回転角度 | 狙い |
|---|---|---|---|
| A:0.00 | rotationなし | 0度 | flipのみのベースライン |
| B:0.03 | 0.03 | ±10.8度 | 最小限の回転 |
| C:0.05 | 0.05 | ±18度 | よく推奨される値 |
| D:0.10 | 0.10 | ±36度 | 中程度の回転 |
| E:0.15 | 0.15 | ±54度 | 前回と同じ設定(比較用) |
実験コード
環境準備(最初に一度だけ実行)
# ── 環境準備(最初に一度だけ実行)──────────────────────
!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 0s (27.2 MB/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 21.8 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了
import・データ準備・Augmentationレイヤーの定義
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
# ── rotation値ごとのAugmentation定義 ───────────────────
def get_augmentation(rotation_factor):
layers = [keras.layers.RandomFlip('horizontal')]
if rotation_factor > 0:
layers.append(keras.layers.RandomRotation(rotation_factor))
return keras.Sequential(layers, name=f'aug_rot{rotation_factor}')
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 536s 3us/step
モデル構築関数
# ── モデル構築関数 ─────────────────────────────────────
def build_model(rotation_factor, name):
augmentation = get_augmentation(rotation_factor)
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 = [
(0.00, 'A_rot0.00'),
(0.03, 'B_rot0.03'),
(0.05, 'C_rot0.05'),
(0.10, 'D_rot0.10'),
(0.15, 'E_rot0.15'),
]
histories, scores, times = {}, {}, {}
for rot, name in configs:
print(f"\n=== {name} ===")
model = build_model(rot, 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] # 'rot0.00' / 'rot0.03' / ...
histories[label] = h
scores[label] = score
times[label] = elapsed
print(f"学習時間:{elapsed:.1f}秒 test_accuracy:{score[1]:.4f}")
実行結果をクリックして内容を開く
=== A_rot0.00 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 19s 14ms/step - accuracy: 0.2744 - loss: 1.9079 - val_accuracy: 0.3617 - val_loss: 1.7098 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 6ms/step - accuracy: 0.4021 - loss: 1.6187 - val_accuracy: 0.4338 - val_loss: 1.5376 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4571 - loss: 1.4856 - val_accuracy: 0.4934 - val_loss: 1.4091 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.4902 - loss: 1.4010 - val_accuracy: 0.4905 - val_loss: 1.3708 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5098 - loss: 1.3428 - val_accuracy: 0.5190 - val_loss: 1.3100 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5270 - loss: 1.2990 - val_accuracy: 0.5465 - val_loss: 1.2341 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5391 - loss: 1.2603 - val_accuracy: 0.5382 - val_loss: 1.2495 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5529 - loss: 1.2269 - val_accuracy: 0.5605 - val_loss: 1.1948 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5678 - loss: 1.1929 - val_accuracy: 0.5812 - val_loss: 1.1545 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5721 - loss: 1.1656 - val_accuracy: 0.5826 - val_loss: 1.1441 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5885 - loss: 1.1327 - val_accuracy: 0.6023 - val_loss: 1.0893 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5991 - loss: 1.1047 - val_accuracy: 0.6116 - val_loss: 1.0676 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6103 - loss: 1.0805 - val_accuracy: 0.6005 - val_loss: 1.0794 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6130 - loss: 1.0692 - val_accuracy: 0.6223 - val_loss: 1.0356 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6238 - loss: 1.0389 - val_accuracy: 0.6192 - val_loss: 1.0320 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6342 - loss: 1.0200 - val_accuracy: 0.6356 - val_loss: 1.0027 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6385 - loss: 1.0043 - val_accuracy: 0.6376 - val_loss: 0.9984 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6439 - loss: 0.9818 - val_accuracy: 0.6316 - val_loss: 1.0195 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6507 - loss: 0.9690 - val_accuracy: 0.6420 - val_loss: 0.9700 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6617 - loss: 0.9397 - val_accuracy: 0.6580 - val_loss: 0.9522 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6664 - loss: 0.9264 - val_accuracy: 0.6637 - val_loss: 0.9418 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6716 - loss: 0.9198 - val_accuracy: 0.6613 - val_loss: 0.9461 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6806 - loss: 0.8975 - val_accuracy: 0.6723 - val_loss: 0.9311 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6833 - loss: 0.8905 - val_accuracy: 0.6760 - val_loss: 0.9005 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6849 - loss: 0.8835 - val_accuracy: 0.6824 - val_loss: 0.8971 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6902 - loss: 0.8705 - val_accuracy: 0.6852 - val_loss: 0.8812 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6943 - loss: 0.8567 - val_accuracy: 0.6910 - val_loss: 0.8645 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7011 - loss: 0.8397 - val_accuracy: 0.6940 - val_loss: 0.8572 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7043 - loss: 0.8326 - val_accuracy: 0.6795 - val_loss: 0.8997 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7073 - loss: 0.8221 - val_accuracy: 0.6773 - val_loss: 0.9078 学習時間:140.9秒 test_accuracy:0.6842 === B_rot0.03 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.2691 - loss: 1.9205 - val_accuracy: 0.3570 - val_loss: 1.7302 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3818 - loss: 1.6529 - val_accuracy: 0.4122 - val_loss: 1.5883 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4353 - loss: 1.5366 - val_accuracy: 0.4683 - val_loss: 1.4702 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4673 - loss: 1.4528 - val_accuracy: 0.4665 - val_loss: 1.4456 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4894 - loss: 1.3949 - val_accuracy: 0.4969 - val_loss: 1.3778 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5095 - loss: 1.3437 - val_accuracy: 0.5096 - val_loss: 1.3448 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5211 - loss: 1.3109 - val_accuracy: 0.5449 - val_loss: 1.2387 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5338 - loss: 1.2772 - val_accuracy: 0.5555 - val_loss: 1.2306 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5483 - loss: 1.2459 - val_accuracy: 0.5556 - val_loss: 1.2326 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5586 - loss: 1.2179 - val_accuracy: 0.5499 - val_loss: 1.2403 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5637 - loss: 1.2000 - val_accuracy: 0.5770 - val_loss: 1.1418 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5782 - loss: 1.1648 - val_accuracy: 0.5767 - val_loss: 1.1719 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5828 - loss: 1.1492 - val_accuracy: 0.5976 - val_loss: 1.1033 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5896 - loss: 1.1317 - val_accuracy: 0.6014 - val_loss: 1.1091 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.5986 - loss: 1.1128 - val_accuracy: 0.6041 - val_loss: 1.1063 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6050 - loss: 1.0955 - val_accuracy: 0.6271 - val_loss: 1.0472 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6083 - loss: 1.0818 - val_accuracy: 0.6181 - val_loss: 1.0575 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6151 - loss: 1.0693 - val_accuracy: 0.6360 - val_loss: 1.0292 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.6219 - loss: 1.0490 - val_accuracy: 0.6303 - val_loss: 1.0247 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6238 - loss: 1.0386 - val_accuracy: 0.6269 - val_loss: 1.0362 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6327 - loss: 1.0212 - val_accuracy: 0.6342 - val_loss: 1.0085 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6352 - loss: 1.0114 - val_accuracy: 0.6433 - val_loss: 0.9872 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6404 - loss: 0.9975 - val_accuracy: 0.6443 - val_loss: 0.9870 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6445 - loss: 0.9895 - val_accuracy: 0.6472 - val_loss: 0.9808 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.6490 - loss: 0.9789 - val_accuracy: 0.6573 - val_loss: 0.9667 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6499 - loss: 0.9675 - val_accuracy: 0.6446 - val_loss: 0.9946 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6542 - loss: 0.9638 - val_accuracy: 0.6365 - val_loss: 1.0170 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6600 - loss: 0.9490 - val_accuracy: 0.6634 - val_loss: 0.9427 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6658 - loss: 0.9330 - val_accuracy: 0.6590 - val_loss: 0.9613 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6679 - loss: 0.9278 - val_accuracy: 0.6538 - val_loss: 0.9898 学習時間:176.8秒 test_accuracy:0.6531 === C_rot0.05 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 9ms/step - accuracy: 0.2677 - loss: 1.9208 - val_accuracy: 0.3310 - val_loss: 1.7778 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3799 - loss: 1.6664 - val_accuracy: 0.4334 - val_loss: 1.5437 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4322 - loss: 1.5520 - val_accuracy: 0.4630 - val_loss: 1.4581 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4645 - loss: 1.4677 - val_accuracy: 0.4893 - val_loss: 1.3979 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.4832 - loss: 1.4170 - val_accuracy: 0.4751 - val_loss: 1.4209 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5034 - loss: 1.3643 - val_accuracy: 0.5127 - val_loss: 1.3192 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5210 - loss: 1.3255 - val_accuracy: 0.5387 - val_loss: 1.2721 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5320 - loss: 1.2919 - val_accuracy: 0.5323 - val_loss: 1.2855 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.5396 - loss: 1.2718 - val_accuracy: 0.5511 - val_loss: 1.2196 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5510 - loss: 1.2420 - val_accuracy: 0.5424 - val_loss: 1.2480 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5562 - loss: 1.2181 - val_accuracy: 0.5796 - val_loss: 1.1670 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5649 - loss: 1.1999 - val_accuracy: 0.5796 - val_loss: 1.1815 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5744 - loss: 1.1751 - val_accuracy: 0.5808 - val_loss: 1.1512 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5850 - loss: 1.1550 - val_accuracy: 0.5895 - val_loss: 1.1338 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5882 - loss: 1.1425 - val_accuracy: 0.5925 - val_loss: 1.1208 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5927 - loss: 1.1311 - val_accuracy: 0.5958 - val_loss: 1.1140 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6001 - loss: 1.1067 - val_accuracy: 0.6116 - val_loss: 1.0762 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 9ms/step - accuracy: 0.6068 - loss: 1.0893 - val_accuracy: 0.5896 - val_loss: 1.1248 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.6114 - loss: 1.0780 - val_accuracy: 0.6106 - val_loss: 1.0794 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6182 - loss: 1.0626 - val_accuracy: 0.6171 - val_loss: 1.0768 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6208 - loss: 1.0540 - val_accuracy: 0.6232 - val_loss: 1.0446 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6226 - loss: 1.0462 - val_accuracy: 0.6322 - val_loss: 1.0266 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6295 - loss: 1.0353 - val_accuracy: 0.6226 - val_loss: 1.0633 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6320 - loss: 1.0231 - val_accuracy: 0.6467 - val_loss: 0.9822 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6388 - loss: 1.0080 - val_accuracy: 0.6328 - val_loss: 1.0222 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6452 - loss: 0.9926 - val_accuracy: 0.6418 - val_loss: 0.9965 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.6465 - loss: 0.9897 - val_accuracy: 0.6455 - val_loss: 0.9811 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6508 - loss: 0.9829 - val_accuracy: 0.6490 - val_loss: 0.9945 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6502 - loss: 0.9787 - val_accuracy: 0.6460 - val_loss: 0.9834 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6552 - loss: 0.9647 - val_accuracy: 0.6494 - val_loss: 0.9847 学習時間:184.9秒 test_accuracy:0.6540 === D_rot0.10 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 9ms/step - accuracy: 0.2546 - loss: 1.9605 - val_accuracy: 0.3124 - val_loss: 1.8404 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3609 - loss: 1.7128 - val_accuracy: 0.4269 - val_loss: 1.5755 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4117 - loss: 1.6005 - val_accuracy: 0.4477 - val_loss: 1.5301 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4523 - loss: 1.5092 - val_accuracy: 0.4901 - val_loss: 1.4127 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4706 - loss: 1.4570 - val_accuracy: 0.4978 - val_loss: 1.3762 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4839 - loss: 1.4155 - val_accuracy: 0.5068 - val_loss: 1.3634 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4991 - loss: 1.3806 - val_accuracy: 0.5100 - val_loss: 1.3643 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5113 - loss: 1.3471 - val_accuracy: 0.4884 - val_loss: 1.4069 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5212 - loss: 1.3242 - val_accuracy: 0.5429 - val_loss: 1.2499 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.5275 - loss: 1.3025 - val_accuracy: 0.5519 - val_loss: 1.2414 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5363 - loss: 1.2785 - val_accuracy: 0.5644 - val_loss: 1.2161 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5411 - loss: 1.2646 - val_accuracy: 0.5737 - val_loss: 1.1769 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5503 - loss: 1.2397 - val_accuracy: 0.5393 - val_loss: 1.2892 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.5569 - loss: 1.2269 - val_accuracy: 0.5725 - val_loss: 1.1877 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5630 - loss: 1.2117 - val_accuracy: 0.5756 - val_loss: 1.1833 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5709 - loss: 1.1929 - val_accuracy: 0.5941 - val_loss: 1.1171 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5735 - loss: 1.1804 - val_accuracy: 0.6028 - val_loss: 1.0990 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5803 - loss: 1.1691 - val_accuracy: 0.6077 - val_loss: 1.0925 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5878 - loss: 1.1500 - val_accuracy: 0.6057 - val_loss: 1.1135 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5928 - loss: 1.1389 - val_accuracy: 0.6103 - val_loss: 1.1030 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5964 - loss: 1.1219 - val_accuracy: 0.6215 - val_loss: 1.0613 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 8ms/step - accuracy: 0.6038 - loss: 1.1097 - val_accuracy: 0.6167 - val_loss: 1.0877 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6050 - loss: 1.1048 - val_accuracy: 0.6262 - val_loss: 1.0578 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6080 - loss: 1.0905 - val_accuracy: 0.6319 - val_loss: 1.0309 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6136 - loss: 1.0810 - val_accuracy: 0.6193 - val_loss: 1.0652 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.6152 - loss: 1.0710 - val_accuracy: 0.6332 - val_loss: 1.0384 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6179 - loss: 1.0602 - val_accuracy: 0.6300 - val_loss: 1.0470 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6227 - loss: 1.0602 - val_accuracy: 0.6502 - val_loss: 0.9847 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6272 - loss: 1.0453 - val_accuracy: 0.6451 - val_loss: 1.0119 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6309 - loss: 1.0393 - val_accuracy: 0.6276 - val_loss: 1.0680 学習時間:180.9秒 test_accuracy:0.6310 === E_rot0.15 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2444 - loss: 1.9918 - val_accuracy: 0.3297 - val_loss: 1.7916 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.3325 - loss: 1.7941 - val_accuracy: 0.3883 - val_loss: 1.6463 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.3862 - loss: 1.6784 - val_accuracy: 0.4449 - val_loss: 1.5338 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4192 - loss: 1.6011 - val_accuracy: 0.4748 - val_loss: 1.4583 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4425 - loss: 1.5390 - val_accuracy: 0.4814 - val_loss: 1.4213 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4581 - loss: 1.4973 - val_accuracy: 0.4884 - val_loss: 1.4191 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4681 - loss: 1.4641 - val_accuracy: 0.4969 - val_loss: 1.3823 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.4833 - loss: 1.4305 - val_accuracy: 0.5127 - val_loss: 1.3456 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.4915 - loss: 1.4057 - val_accuracy: 0.5221 - val_loss: 1.3229 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 9ms/step - accuracy: 0.5015 - loss: 1.3781 - val_accuracy: 0.4918 - val_loss: 1.3633 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5127 - loss: 1.3566 - val_accuracy: 0.5417 - val_loss: 1.2713 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5152 - loss: 1.3346 - val_accuracy: 0.5226 - val_loss: 1.3361 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5222 - loss: 1.3206 - val_accuracy: 0.5441 - val_loss: 1.2608 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5296 - loss: 1.3036 - val_accuracy: 0.5617 - val_loss: 1.2032 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5353 - loss: 1.2858 - val_accuracy: 0.5645 - val_loss: 1.1977 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5409 - loss: 1.2734 - val_accuracy: 0.5571 - val_loss: 1.2262 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5425 - loss: 1.2566 - val_accuracy: 0.5649 - val_loss: 1.1971 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5524 - loss: 1.2461 - val_accuracy: 0.5583 - val_loss: 1.2249 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5566 - loss: 1.2284 - val_accuracy: 0.5637 - val_loss: 1.2113 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5596 - loss: 1.2216 - val_accuracy: 0.5888 - val_loss: 1.1548 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5698 - loss: 1.2053 - val_accuracy: 0.5671 - val_loss: 1.2066 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5652 - loss: 1.2014 - val_accuracy: 0.5887 - val_loss: 1.1532 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5719 - loss: 1.1900 - val_accuracy: 0.5887 - val_loss: 1.1494 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5753 - loss: 1.1824 - val_accuracy: 0.6012 - val_loss: 1.1156 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5807 - loss: 1.1654 - val_accuracy: 0.5567 - val_loss: 1.2562 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5818 - loss: 1.1645 - val_accuracy: 0.5981 - val_loss: 1.1244 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.5872 - loss: 1.1485 - val_accuracy: 0.6051 - val_loss: 1.1288 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5894 - loss: 1.1471 - val_accuracy: 0.6061 - val_loss: 1.1161 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5919 - loss: 1.1407 - val_accuracy: 0.6161 - val_loss: 1.0930 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5972 - loss: 1.1232 - val_accuracy: 0.5818 - val_loss: 1.1949 学習時間:182.7秒 test_accuracy:0.5826
グラフ描画・サマリー
# ── 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('rotation_val.png', dpi=150)
plt.show()
# ── train vs val(過学習の乖離)────────────────────────
fig2, axes2 = plt.subplots(1, 2, figsize=(14, 5))
for ax, label in zip(axes2, ['rot0.00', 'rot0.05']):
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('rotation_overfit.png', dpi=150)
plt.show()
# ── サマリー ─────────────────────────────────────────────
print("\n===== 最終結果サマリー =====")
print(f"{'Pattern':>10} | {'Max Angle':>10} | {'Val Acc':>8} | {'Test Acc':>9} | {'Time(s)':>8}")
print("-" * 58)
angle_map = {'rot0.00': '0度', 'rot0.03': '±10.8度', 'rot0.05': '±18度',
'rot0.10': '±36度', 'rot0.15': '±54度'}
for label, h in histories.items():
val_acc = h.history['val_accuracy'][-1]
test_acc = scores[label][1]
t = times[label]
angle = angle_map[label]
print(f"{label:>10} | {angle:>10} | {val_acc:>8.4f} | {test_acc:>9.4f} | {t:>8.1f}")
print("-" * 58)
最終結果サマリー
===== 最終結果サマリー ===== Pattern | Max Angle | Val Acc | Test Acc | Time(s) ---------------------------------------------------------- rot0.00 | 0度 | 0.6773 | 0.6842 | 140.9 rot0.03 | ±10.8度 | 0.6538 | 0.6531 | 176.8 rot0.05 | ±18度 | 0.6494 | 0.6540 | 184.9 rot0.10 | ±36度 | 0.6276 | 0.6310 | 180.9 rot0.15 | ±54度 | 0.5818 | 0.5826 | 182.7 ----------------------------------------------------------
実験結果
精度グラフ
損失グラフ
rot0.00
rot0.05
| パターン | 最大回転角度 | 最終 val_accuracy | 最終 test_accuracy | 学習時間 |
|---|---|---|---|---|
| A:rot0.00 | 0度(flipのみ) | 67.73% | 68.42% | 140.9秒 |
| B:rot0.03 | ±10.8度 | 65.38% | 65.31% | 176.8秒 |
| C:rot0.05 | ±18度 | 64.94% | 65.40% | 184.9秒 |
| D:rot0.10 | ±36度 | 62.76% | 63.10% | 180.9秒 |
| E:rot0.15 | ±54度(前回と同じ) | 58.18% | 58.26% | 182.7秒 |
予想に反して、最も良かったのはrotationなし(flipのみ)のパターンAでした。
rotation 0.03という最小限の角度でさえ約3.1ポイント低下、
角度を上げるほど単調に精度が低下しています。
さらに学習時間はrotationを加えた途端に約40秒増加し、精度が下がりながら時間だけが増えるという結果になりました。
考察
① なぜ0.03という小さい角度でも精度が下がったのか
±10.8度という回転は「わずかに傾く程度」に見えますが、 32×32ピクセルという極小解像度では1〜2ピクセルのずれが特徴量全体に大きく影響します。 高解像度画像では「少し傾いた犬」も犬に見えますが、 32×32ではわずかな回転でエッジや輪郭の情報が失われてしまいます。
② 角度を大きくするほど概ね低下した理由
今回の結果では、rot0.03(-3.1%)→ rot0.05(-3.5%)→ rot0.10(-5.3%)→ rot0.15(-10.2%)と、 角度に対してほぼ単調に精度が低下しています。 これはCIFAR-10の32×32においては、回転という変換が百害あって一利なしであることを示しています。 回転によって生まれる余白の補完処理(nearest/reflect)が、 低解像度ではノイズとしてモデルの学習を妨げています。
③ 学習時間が急増した理由
rot0.00(140.9秒)に対してrot0.03以降は176〜184秒と、 今回の実行では rotation を加えた条件で学習時間が長くなる傾向が見られました。 角度の大きさによる差はほぼなく、「rotationレイヤーが存在するかどうか」が 学習時間の主な分岐点です。精度が下がりながら時間が増えるという、 コストパフォーマンスが最悪な結果です。
④ 2回の実験を通じてわかったこと
前回の実験(flip〜cropの5パターン比較)では「rotationが強すぎる」という結論でした。
今回は「では弱くすれば?」という問いへの答えとして、
CIFAR-10においてはrotationの強度に関わらずflipのみが最良という結果になりました。
2回の実験を合わせると、次の結論が導けます。
- CIFAR-10(32×32)では RandomFlip のみ が最もシンプルかつ効果的(低解像度では幾何変換の情報損失コストが大きい)
- RandomRotation は 解像度が高いデータセットで有効 な手法
- 「定番の組み合わせ」はデータセットの解像度を前提としており、そのままコピーしてはいけない
まとめ:CIFAR-10でのRandomRotation結論と解像度別推奨設定
今回の実験結果を踏まえた結論です。
今回の実験条件では、RandomRotation(0.03) のような小さい回転でも test accuracy は低下し、CIFAR-10(32×32)では flipのみが最も良い結果 になりました。
| データセット・解像度 | RandomRotation の推奨 | 理由 |
|---|---|---|
| CIFAR-10(32×32) | 使わない | どの角度でも精度が下がる |
| 中解像度(64×64〜128×128) | 0.03〜0.05 で検証 | 小さい角度から様子を見る |
| 高解像度(224×224以上) | 0.10〜0.15 | 被写体の特徴が十分残る |
CIFAR-10では RandomFlip のみを使うのが最善です。
Augmentationは「多く使うほど良い」でも「弱くすれば良い」でもなく、
データセットの解像度と特性に合った手法を選ぶことが重要です。
関連記事もあわせてどうぞ:
- 前回記事(flip〜cropの5パターン比較)→ Data Augmentationを重ねすぎると精度が下がる?flip〜cropの5パターンをCIFAR-10で比較【Keras実験】
- Dropoutとの組み合わせ → Dropoutの割合(0.0 vs 0.2 vs 0.5)を変えると過学習はどう変わる?【Keras×CIFAR-10実験】
- 過学習の判定方法 → CIFAR-10で学ぶ:過学習(オーバーフィッティング)の判定方法と実践的対策
- 学習曲線の見方 → Kerasで学習曲線を可視化する方法【過学習の発見と対策まで】





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