CutOut / Random Erasingで過学習は防げるか?【Keras×CIFAR-10実験】

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

CIFAR-10 CNN Data Augmentation Dropout Google Colab Keras データ拡張 過学習 過学習対策

X f B! P L
CutOut / Random Erasingで過学習は防げるか?【Keras×CIFAR-10実験】 アイキャッチ画像

「過学習を防ぐにはDropoutを入れれば十分」——そう思って試してみたら、まだtrain_lossとval_lossが乖離している……そんな経験はありませんか?
今回はCutOutRandom Erasingという「画像の一部をマスクするデータ拡張」を使い、過学習への効果をKerasとCIFAR-10で実験しました。

なお、Dropoutの割合比較は → Dropoutの割合を変えると過学習はどう変わる?【Keras×CIFAR-10実験】、MixUpの効果検証は → MixUpの効果検証【Keras×CIFAR-10実験】 もご覧ください。

📘 この記事でわかること
  • CutOut・Random Erasingとは何か、どう違うのか
  • Kerasで両手法を自作してCIFAR-10に適用する方法
  • なし・CutOut・Random Erasingの3パターンで精度と過学習の度合いを比較した実験結果
  • DropoutとCutOut系手法を組み合わせるときの注意点

CutOut と Random Erasing はどう違うのか

どちらも「画像の矩形領域をゼロ埋め(または乱数)で消す」という発想は同じです。違いは何で埋めるかサイズ・位置の決め方にあります。

手法 提案年 埋める値 領域の決め方
CutOut 2017 固定値(0 またはグレー) 固定サイズの正方形をランダム位置に配置
Random Erasing 2020 ランダムな値([0,1] の乱数) 面積比・アスペクト比をランダムにサンプリング

CutOutは「黒い四角を貼り付ける」イメージ。Random Erasingは「ノイズパッチを貼り付ける」イメージです。どちらもモデルに「一部が見えなくても正解を当てろ」という制約を課し、特定の局所特徴への過依存を防ぎます。

⚠️ ハマりポイント
  • 正規化後に適用すること。/255でスケーリングしたあとにCutOutを適用しないと、ゼロ埋めの意味が変わります(ゼロ=黒 になるのは正規化後が前提)。
  • マスクサイズが大きすぎると精度が下がる。CIFAR-10(32×32px)では cutout_size=8〜12 程度が目安。16以上にすると情報が消えすぎて学習が不安定になります。
  • Random Erasingの面積比(sl, sh)を広げすぎるのも同様にNG。論文デフォルト(sl=0.02, sh=0.4)からスタートしましょう。
  • Keras の tf.data パイプラインでランダム処理を入れる場合、tf.py_function を使うと GPU 転送の効率が落ちることがあります。今回はNumPy関数として実装し、map() で呼び出す方式にしています。

実験コード

使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10です。CutOut / Random Erasingの有無以外の条件は全て同一にして、手法の影響だけを取り出します。

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

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

import・データ準備・CutOut / Random Erasing の実装

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

# ── データ読み込み・正規化 ─────────────────────────────
(x_train_raw, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train_raw = x_train_raw.astype('float32') / 255.0
x_test      = x_test.astype('float32')      / 255.0

# ── CutOut ──────────────────────────────────────────────
def cutout(image, cutout_size=10):
    """画像の矩形領域をゼロで塗りつぶす(CutOut)"""
    h, w, c = image.shape
    cx = np.random.randint(0, w)
    cy = np.random.randint(0, h)
    x1 = max(0, cx - cutout_size // 2)
    y1 = max(0, cy - cutout_size // 2)
    x2 = min(w, cx + cutout_size // 2)
    y2 = min(h, cy + cutout_size // 2)
    image = image.copy()
    image[y1:y2, x1:x2, :] = 0.0
    return image

def apply_cutout(images, cutout_size=10):
    return np.array([cutout(img, cutout_size) for img in images])

# ── Random Erasing ──────────────────────────────────────
def random_erasing(image, sl=0.02, sh=0.4, r1=0.3, r2=3.3):
    """画像の矩形領域をランダムな値で塗りつぶす(Random Erasing)"""
    h, w, c = image.shape
    area = h * w
    for _ in range(100):  # 試行回数の上限
        target_area = np.random.uniform(sl, sh) * area
        aspect_ratio = np.random.uniform(r1, r2)
        rect_h = int(round(np.sqrt(target_area * aspect_ratio)))
        rect_w = int(round(np.sqrt(target_area / aspect_ratio)))
        if rect_h < h and rect_w < w:
            x1 = np.random.randint(0, w - rect_w)
            y1 = np.random.randint(0, h - rect_h)
            image = image.copy()
            image[y1:y1+rect_h, x1:x1+rect_w, :] = np.random.uniform(0, 1, (rect_h, rect_w, c))
            return image
    return image  # 領域が見つからない場合はそのまま返す

def apply_random_erasing(images, **kwargs):
    return np.array([random_erasing(img, **kwargs) for img in images])
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 407s 2us/step

適用例の可視化(確認用)

# ── 適用例を可視化して確認 ──────────────────────────────
fig, axes = plt.subplots(3, 5, figsize=(12, 7))
class_names = ['airplane','automobile','bird','cat','deer',
               'dog','frog','horse','ship','truck']
titles = ['オリジナル', 'CutOut', 'Random Erasing']
x_sample = x_train_raw[:5]

for row, (title, imgs) in enumerate(zip(titles, [
    x_sample,
    apply_cutout(x_sample),
    apply_random_erasing(x_sample),
])):
    for col in range(5):
        axes[row, col].imshow(imgs[col])
        axes[row, col].axis('off')
        if row == 0:
            axes[row, col].set_title(class_names[int(y_train[col])], fontsize=9)
    axes[row, 0].set_ylabel(title, fontsize=11, rotation=90, labelpad=10)

plt.suptitle('CutOut / Random Erasing の適用例', fontsize=13)
plt.tight_layout()
plt.savefig('cutout_samples.png', dpi=150)
plt.show()

実行例

CutOut / Random Erasing の適用例

モデル構築・学習関数

# ── モデル構築(3パターン共通) ──────────────────────────
def build_model(name):
    return keras.Sequential([
        keras.layers.Input(shape=(32, 32, 3)),
        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(128, activation='relu'),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10,  activation='softmax'),
    ], name=name)

def compile_and_fit(model, x_train_aug):
    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    start = time.time()
    history = model.fit(x_train_aug, y_train,
                        epochs=30, batch_size=64,
                        validation_split=0.2, verbose=1)
    return history, time.time() - start

3パターンの学習実行

# ── 3パターンで学習 ─────────────────────────────────────
configs = {
    'A_none':          x_train_raw,
    'B_cutout':        apply_cutout(x_train_raw, cutout_size=10),
    'C_random_erasing': apply_random_erasing(x_train_raw),
}

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

for name, x_aug in configs.items():
    print(f"\n=== {name} ===")
    model = build_model(name)
    h, t  = compile_and_fit(model, x_aug)
    s     = model.evaluate(x_test, y_test, verbose=0)
    label = name.split('_', 1)[1]   # 'none' / 'cutout' / 'random_erasing'
    histories[label] = h
    times[label]     = t
    scores[label]    = s
    params[label]    = model.count_params()
    print(f"学習時間:{t:.1f}秒 パラメータ数:{model.count_params():,} test_accuracy:{s[1]:.4f}")
実行結果をクリックして内容を開く
=== A_none ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2696 - loss: 1.9064 - val_accuracy: 0.3598 - val_loss: 1.6940
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3722 - loss: 1.6694 - val_accuracy: 0.4241 - val_loss: 1.5736
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4336 - loss: 1.5321 - val_accuracy: 0.4679 - val_loss: 1.4801
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4746 - loss: 1.4427 - val_accuracy: 0.5023 - val_loss: 1.3774
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4963 - loss: 1.3708 - val_accuracy: 0.5247 - val_loss: 1.3078
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5168 - loss: 1.3321 - val_accuracy: 0.5042 - val_loss: 1.3531
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5319 - loss: 1.2873 - val_accuracy: 0.5286 - val_loss: 1.2826
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5396 - loss: 1.2621 - val_accuracy: 0.5587 - val_loss: 1.2144
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5526 - loss: 1.2306 - val_accuracy: 0.5651 - val_loss: 1.1859
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5645 - loss: 1.2024 - val_accuracy: 0.5743 - val_loss: 1.1643
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5713 - loss: 1.1748 - val_accuracy: 0.5910 - val_loss: 1.1324
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5824 - loss: 1.1466 - val_accuracy: 0.5882 - val_loss: 1.1284
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5878 - loss: 1.1350 - val_accuracy: 0.5833 - val_loss: 1.1438
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5987 - loss: 1.1103 - val_accuracy: 0.6014 - val_loss: 1.1153
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6039 - loss: 1.0883 - val_accuracy: 0.6071 - val_loss: 1.0744
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6165 - loss: 1.0700 - val_accuracy: 0.6253 - val_loss: 1.0262
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6190 - loss: 1.0588 - val_accuracy: 0.6048 - val_loss: 1.0823
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6271 - loss: 1.0351 - val_accuracy: 0.6189 - val_loss: 1.0421
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6335 - loss: 1.0181 - val_accuracy: 0.6326 - val_loss: 1.0108
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6358 - loss: 1.0115 - val_accuracy: 0.6374 - val_loss: 0.9963
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6452 - loss: 0.9925 - val_accuracy: 0.6358 - val_loss: 1.0086
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6435 - loss: 0.9865 - val_accuracy: 0.6252 - val_loss: 1.0338
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6536 - loss: 0.9685 - val_accuracy: 0.6521 - val_loss: 0.9610
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6577 - loss: 0.9595 - val_accuracy: 0.6332 - val_loss: 1.0114
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6622 - loss: 0.9413 - val_accuracy: 0.6680 - val_loss: 0.9322
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6668 - loss: 0.9299 - val_accuracy: 0.6504 - val_loss: 0.9623
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6723 - loss: 0.9178 - val_accuracy: 0.6455 - val_loss: 0.9822
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6739 - loss: 0.9082 - val_accuracy: 0.6142 - val_loss: 1.0635
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6781 - loss: 0.8998 - val_accuracy: 0.6771 - val_loss: 0.9042
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6810 - loss: 0.8871 - val_accuracy: 0.6758 - val_loss: 0.9122
学習時間:120.8秒 パラメータ数:93,450 test_accuracy:0.6711

=== B_cutout ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2546 - loss: 1.9626 - val_accuracy: 0.3259 - val_loss: 1.8309
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3577 - loss: 1.7152 - val_accuracy: 0.4102 - val_loss: 1.6063
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4090 - loss: 1.5979 - val_accuracy: 0.4444 - val_loss: 1.4999
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4476 - loss: 1.5027 - val_accuracy: 0.4581 - val_loss: 1.4903
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4705 - loss: 1.4405 - val_accuracy: 0.5019 - val_loss: 1.3808
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4891 - loss: 1.3963 - val_accuracy: 0.5024 - val_loss: 1.3810
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5032 - loss: 1.3562 - val_accuracy: 0.5167 - val_loss: 1.3222
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5142 - loss: 1.3271 - val_accuracy: 0.5271 - val_loss: 1.2949
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5278 - loss: 1.2969 - val_accuracy: 0.5245 - val_loss: 1.2968
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5383 - loss: 1.2681 - val_accuracy: 0.5452 - val_loss: 1.2682
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5464 - loss: 1.2417 - val_accuracy: 0.5658 - val_loss: 1.1975
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5581 - loss: 1.2184 - val_accuracy: 0.5758 - val_loss: 1.1798
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5677 - loss: 1.1888 - val_accuracy: 0.5817 - val_loss: 1.1710
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5760 - loss: 1.1680 - val_accuracy: 0.5782 - val_loss: 1.1695
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5839 - loss: 1.1442 - val_accuracy: 0.5704 - val_loss: 1.1602
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5933 - loss: 1.1281 - val_accuracy: 0.5798 - val_loss: 1.1628
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6014 - loss: 1.1101 - val_accuracy: 0.5940 - val_loss: 1.1122
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6021 - loss: 1.0944 - val_accuracy: 0.6077 - val_loss: 1.0754
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6136 - loss: 1.0730 - val_accuracy: 0.6239 - val_loss: 1.0494
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6159 - loss: 1.0661 - val_accuracy: 0.6143 - val_loss: 1.0572
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6245 - loss: 1.0488 - val_accuracy: 0.5937 - val_loss: 1.1145
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6302 - loss: 1.0277 - val_accuracy: 0.6271 - val_loss: 1.0246
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6356 - loss: 1.0161 - val_accuracy: 0.6268 - val_loss: 1.0411
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6399 - loss: 1.0044 - val_accuracy: 0.6147 - val_loss: 1.0688
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6439 - loss: 0.9936 - val_accuracy: 0.6415 - val_loss: 1.0038
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6507 - loss: 0.9762 - val_accuracy: 0.6148 - val_loss: 1.0463
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6533 - loss: 0.9634 - val_accuracy: 0.6443 - val_loss: 0.9910
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6578 - loss: 0.9547 - val_accuracy: 0.6332 - val_loss: 0.9998
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6645 - loss: 0.9388 - val_accuracy: 0.6368 - val_loss: 1.0093
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6647 - loss: 0.9367 - val_accuracy: 0.6435 - val_loss: 0.9899
学習時間:120.7秒 パラメータ数:93,450 test_accuracy:0.6603

=== C_random_erasing ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2201 - loss: 2.0558 - val_accuracy: 0.3230 - val_loss: 1.8502
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3327 - loss: 1.7888 - val_accuracy: 0.3669 - val_loss: 1.7175
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3777 - loss: 1.6805 - val_accuracy: 0.4063 - val_loss: 1.6134
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4047 - loss: 1.6136 - val_accuracy: 0.4308 - val_loss: 1.5502
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4260 - loss: 1.5621 - val_accuracy: 0.4524 - val_loss: 1.4980
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4480 - loss: 1.5060 - val_accuracy: 0.4540 - val_loss: 1.4905
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4625 - loss: 1.4706 - val_accuracy: 0.4732 - val_loss: 1.4415
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4735 - loss: 1.4375 - val_accuracy: 0.4766 - val_loss: 1.4409
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4897 - loss: 1.3986 - val_accuracy: 0.4904 - val_loss: 1.3846
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4961 - loss: 1.3748 - val_accuracy: 0.4920 - val_loss: 1.3646
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5076 - loss: 1.3505 - val_accuracy: 0.5146 - val_loss: 1.3231
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5156 - loss: 1.3283 - val_accuracy: 0.5268 - val_loss: 1.2977
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5224 - loss: 1.3056 - val_accuracy: 0.5169 - val_loss: 1.3095
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5300 - loss: 1.2866 - val_accuracy: 0.5310 - val_loss: 1.2683
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5365 - loss: 1.2733 - val_accuracy: 0.5340 - val_loss: 1.2558
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5421 - loss: 1.2541 - val_accuracy: 0.5433 - val_loss: 1.2456
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5485 - loss: 1.2385 - val_accuracy: 0.5426 - val_loss: 1.2442
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5569 - loss: 1.2207 - val_accuracy: 0.5606 - val_loss: 1.2013
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5572 - loss: 1.2082 - val_accuracy: 0.5378 - val_loss: 1.2444
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5660 - loss: 1.1954 - val_accuracy: 0.5350 - val_loss: 1.2505
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5717 - loss: 1.1810 - val_accuracy: 0.5601 - val_loss: 1.1898
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5745 - loss: 1.1659 - val_accuracy: 0.5570 - val_loss: 1.2088
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5804 - loss: 1.1573 - val_accuracy: 0.5583 - val_loss: 1.2045
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5865 - loss: 1.1426 - val_accuracy: 0.5647 - val_loss: 1.1862
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5899 - loss: 1.1306 - val_accuracy: 0.5823 - val_loss: 1.1451
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5941 - loss: 1.1230 - val_accuracy: 0.5769 - val_loss: 1.1567
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5981 - loss: 1.1104 - val_accuracy: 0.5839 - val_loss: 1.1351
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6045 - loss: 1.0912 - val_accuracy: 0.5879 - val_loss: 1.1205
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6046 - loss: 1.0894 - val_accuracy: 0.5860 - val_loss: 1.1282
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6087 - loss: 1.0763 - val_accuracy: 0.5982 - val_loss: 1.1012
学習時間:119.5秒 パラメータ数:93,450 test_accuracy:0.6518

グラフ+サマリー

# ── val_accuracy / val_loss 比較グラフ ───────────────────
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
label_map = {'none': 'A:なし', 'cutout': 'B:CutOut', 'random_erasing': 'C:Random Erasing'}
for label, h in histories.items():
    axes[0].plot(h.history['val_accuracy'], label=label_map[label])
    axes[1].plot(h.history['val_loss'],     label=label_map[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('cutout_comparison.png', dpi=150)
plt.show()

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

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

最終結果サマリー

===== 最終結果サマリー =====
           Pattern |  Val Acc |  Test Acc |  Time(s) |     Params
-----------------------------------------------------------------
              A:なし |   0.6758 |    0.6711 |    120.8 |     93,450
          B:CutOut |   0.6435 |    0.6603 |    120.7 |     93,450
  C:Random Erasing |   0.5982 |    0.6518 |    119.5 |     93,450
-----------------------------------------------------------------

実験結果

精度グラフ

精度グラフ

損失グラフ

損失グラフ

A:なし

A:なし

B:CutOut

B:CutOut

C:Random Erasing

C:Random Erasing
パターン 最終 val_accuracy 最終 test_accuracy パラメータ数 学習時間
A:なし 67.58% 67.11% 93,450 120.8秒
B:CutOut 64.35% 66.03% 93,450 120.7秒
C:Random Erasing 59.82% 65.18% 93,450 119.5秒

考察

① 予想に反して「なし」が val_accuracy 最高という結果に

今回の実験では、val_accuracy は A:なし(67.58%)> B:CutOut(64.35%)> C:Random Erasing(59.82%)という順になりました。直感に反する結果ですが、これは「マスクが強すぎてモデルが学習できていない」状態、いわゆるunderfitting(学習不足)に陥っている可能性が高いです。

CIFAR-10 の画像は 32×32px と非常に小さく、情報量が元から少ない状態です。そこに大きなマスクをかけると、モデルが正解を学ぶための手がかり自体が失われてしまいます。

② CutOut は test_accuracy では「なし」を上回っている

val_accuracy ではなしに劣った CutOut ですが、test_accuracy は 66.03%(なし 67.11%)と −1.08% で下回る結果となりました。今回の再実験では CutOut も test_accuracy でなしを上回ることができませんでした。ただし val_accuracy(64.35%)と test_accuracy(66.03%)の差が約1.7%あり、val と test で乖離が生じている点は注目です。val_accuracy だけで判断すると実際の汎化性能を誤読するリスクがある点に注意が必要です。

③ Random Erasing は val_accuracy が大きく落ちた——パラメータが問題

Random Erasing は val_accuracy が 59.82% と大幅に低下しました。原因は今回使用したパラメータ(sl=0.02, sh=0.4)が CIFAR-10 に対して強すぎたことです。sh=0.4 は画像面積の最大40%を消すことを意味します。32×32px の画像では 10×10px 超のパッチが消える計算になり、識別に必要な情報が根本から失われます。

⚠️ Random Erasingのパラメータは画像サイズに合わせて調整が必須
論文デフォルト(sl=0.02, sh=0.4)は ImageNet(224×224px)向けの設定です。CIFAR-10(32×32px)のような小画像に使うと過剰なマスクになります。
CIFAR-10 での目安:sl=0.02, sh=0.15〜0.2 程度に下げて再実験してみましょう(追加実験を下記に掲載)。

④ パラメータ数は全パターン同一——コストゼロで試せる

データ拡張はモデルのアーキテクチャに影響しないため、パラメータ数は全パターン同一(93,450)です。学習時間の差も最大 1.5秒(約1%)とほぼ無視できるレベルです。「失敗しても戻すコストがほぼゼロ」な手法なので、まずためしてみる価値は十分あります。

⑤ 「なし」より良くなるかどうかは画像サイズとパラメータ次第

CutOut・Random Erasing は「情報を意図的に壊してロバスト性を上げる」手法です。効果が出る条件は、画像の情報量がマスクで失われても正解できる余裕があること。高解像度・情報密度の高い画像(ImageNet, 医療画像など)では有効に働きますが、CIFAR-10 のような極小解像度では過剰になりやすいです。

追加実験:Random Erasing のパラメータを CIFAR-10 向けに調整

sh=0.4 が強すぎた可能性があるため、sh=0.15 に絞って再実験します。また、CutOut のマスクサイズも 8px に縮小したパターンを追加します。

# ── 追加実験:パラメータを CIFAR-10 向けに調整 ───────────
configs_extra = {
    'D_cutout_s8':         apply_cutout(x_train_raw, cutout_size=8),
    'E_random_erasing_s':  apply_random_erasing(x_train_raw, sl=0.02, sh=0.15),
}

for name, x_aug in configs_extra.items():
    print(f"\n=== {name} ===")
    model = build_model(name)
    h, t  = compile_and_fit(model, x_aug)
    s     = model.evaluate(x_test, y_test, verbose=0)
    label = name.split('_', 1)[1]
    histories[label] = h
    times[label]     = t
    scores[label]    = s
    params[label]    = model.count_params()
    print(f"学習時間:{t:.1f}秒 test_accuracy:{s[1]:.4f}")

# ── 追加実験の比較表出力 ────────────────────────────────
print("\n===== 追加実験サマリー =====")
all_labels = ['none', 'cutout', 'random_erasing', 'cutout_s8', 'random_erasing_s']
label_map_ext = {
    'none':              'A:なし',
    'cutout':            'B:CutOut(size=10)',
    'random_erasing':    'C:RE(sh=0.40)',
    'cutout_s8':         'D:CutOut(size=8)',
    'random_erasing_s':  'E:RE(sh=0.15)',
}
print(f"{'Pattern':>22} | {'Val Acc':>8} | {'Test Acc':>9}")
print("-" * 48)
for label in all_labels:
    val_acc  = histories[label].history['val_accuracy'][-1]
    test_acc = scores[label][1]
    print(f"{label_map_ext[label]:>22} | {val_acc:>8.4f} | {test_acc:>9.4f}")
実行結果をクリックして内容を開く
=== D_cutout_s8 ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2585 - loss: 1.9509 - val_accuracy: 0.3469 - val_loss: 1.7733
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3473 - loss: 1.7279 - val_accuracy: 0.3988 - val_loss: 1.6318
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4063 - loss: 1.6017 - val_accuracy: 0.4409 - val_loss: 1.5249
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4464 - loss: 1.5074 - val_accuracy: 0.4726 - val_loss: 1.4270
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4722 - loss: 1.4414 - val_accuracy: 0.4864 - val_loss: 1.3859
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4963 - loss: 1.3856 - val_accuracy: 0.5083 - val_loss: 1.3329
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5066 - loss: 1.3495 - val_accuracy: 0.5221 - val_loss: 1.3081
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5188 - loss: 1.3162 - val_accuracy: 0.5219 - val_loss: 1.3059
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5305 - loss: 1.2869 - val_accuracy: 0.5331 - val_loss: 1.2729
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5428 - loss: 1.2590 - val_accuracy: 0.5493 - val_loss: 1.2284
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5530 - loss: 1.2283 - val_accuracy: 0.5559 - val_loss: 1.2196
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5598 - loss: 1.2102 - val_accuracy: 0.5683 - val_loss: 1.1727
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5709 - loss: 1.1846 - val_accuracy: 0.5742 - val_loss: 1.1735
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5757 - loss: 1.1647 - val_accuracy: 0.5837 - val_loss: 1.1497
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5863 - loss: 1.1459 - val_accuracy: 0.5710 - val_loss: 1.1680
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5943 - loss: 1.1214 - val_accuracy: 0.5826 - val_loss: 1.1473
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6007 - loss: 1.1065 - val_accuracy: 0.5977 - val_loss: 1.0971
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6051 - loss: 1.0935 - val_accuracy: 0.6170 - val_loss: 1.0639
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6133 - loss: 1.0730 - val_accuracy: 0.6094 - val_loss: 1.0770
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6208 - loss: 1.0564 - val_accuracy: 0.6124 - val_loss: 1.0551
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6285 - loss: 1.0357 - val_accuracy: 0.6179 - val_loss: 1.0458
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6287 - loss: 1.0286 - val_accuracy: 0.6085 - val_loss: 1.0813
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6374 - loss: 1.0120 - val_accuracy: 0.6265 - val_loss: 1.0436
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6410 - loss: 1.0023 - val_accuracy: 0.6433 - val_loss: 0.9953
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6439 - loss: 0.9855 - val_accuracy: 0.6327 - val_loss: 1.0133
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6488 - loss: 0.9799 - val_accuracy: 0.6413 - val_loss: 1.0079
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6547 - loss: 0.9626 - val_accuracy: 0.6504 - val_loss: 0.9748
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6608 - loss: 0.9539 - val_accuracy: 0.6573 - val_loss: 0.9621
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6655 - loss: 0.9392 - val_accuracy: 0.6467 - val_loss: 0.9820
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6679 - loss: 0.9323 - val_accuracy: 0.6523 - val_loss: 0.9731
学習時間:122.7秒 test_accuracy:0.6647

=== E_random_erasing_s ===
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2498 - loss: 1.9693 - val_accuracy: 0.3329 - val_loss: 1.7824
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3469 - loss: 1.7342 - val_accuracy: 0.3771 - val_loss: 1.6588
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3997 - loss: 1.6183 - val_accuracy: 0.4266 - val_loss: 1.5474
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4373 - loss: 1.5278 - val_accuracy: 0.4598 - val_loss: 1.4650
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4625 - loss: 1.4643 - val_accuracy: 0.4791 - val_loss: 1.4128
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4830 - loss: 1.4039 - val_accuracy: 0.5030 - val_loss: 1.3518
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5012 - loss: 1.3642 - val_accuracy: 0.5106 - val_loss: 1.3300
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5167 - loss: 1.3247 - val_accuracy: 0.5178 - val_loss: 1.3073
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5309 - loss: 1.2917 - val_accuracy: 0.5388 - val_loss: 1.2640
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5402 - loss: 1.2675 - val_accuracy: 0.5527 - val_loss: 1.2164
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5469 - loss: 1.2440 - val_accuracy: 0.5418 - val_loss: 1.2506
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5588 - loss: 1.2178 - val_accuracy: 0.5589 - val_loss: 1.2125
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5675 - loss: 1.1961 - val_accuracy: 0.5646 - val_loss: 1.1898
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5735 - loss: 1.1761 - val_accuracy: 0.5383 - val_loss: 1.2276
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5810 - loss: 1.1538 - val_accuracy: 0.5877 - val_loss: 1.1256
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5905 - loss: 1.1299 - val_accuracy: 0.5899 - val_loss: 1.1285
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5975 - loss: 1.1141 - val_accuracy: 0.5946 - val_loss: 1.1050
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6015 - loss: 1.1000 - val_accuracy: 0.5934 - val_loss: 1.1104
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6066 - loss: 1.0863 - val_accuracy: 0.6082 - val_loss: 1.0754
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6144 - loss: 1.0689 - val_accuracy: 0.5977 - val_loss: 1.1039
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6206 - loss: 1.0488 - val_accuracy: 0.6153 - val_loss: 1.0559
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6284 - loss: 1.0339 - val_accuracy: 0.6104 - val_loss: 1.0765
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6324 - loss: 1.0194 - val_accuracy: 0.6230 - val_loss: 1.0366
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6374 - loss: 1.0091 - val_accuracy: 0.6153 - val_loss: 1.0360
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6387 - loss: 1.0001 - val_accuracy: 0.6334 - val_loss: 1.0077
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6468 - loss: 0.9801 - val_accuracy: 0.6325 - val_loss: 1.0190
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6518 - loss: 0.9696 - val_accuracy: 0.6168 - val_loss: 1.0636
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6547 - loss: 0.9641 - val_accuracy: 0.6386 - val_loss: 1.0029
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6571 - loss: 0.9542 - val_accuracy: 0.6460 - val_loss: 0.9717
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6628 - loss: 0.9390 - val_accuracy: 0.6438 - val_loss: 0.9774
学習時間:121.5秒 test_accuracy:0.6745

===== 追加実験サマリー =====
               Pattern |  Val Acc |  Test Acc
------------------------------------------------
                  A:なし |   0.6758 |    0.6711
     B:CutOut(size=10) |   0.6435 |    0.6603
         C:RE(sh=0.40) |   0.5982 |    0.6518
      D:CutOut(size=8) |   0.6523 |    0.6647
         E:RE(sh=0.15) |   0.6438 |    0.6745

追加実験の結果と読み方

パターン val_accuracy test_accuracy なしとの差(test)
A:なし 67.58% 67.11%
B:CutOut(size=10) 64.35% 66.03% −1.08%
C:Random Erasing(sh=0.40) 59.82% 65.18% −1.93%
D:CutOut(size=8) 65.23% 66.47% −0.64%
E:Random Erasing(sh=0.15) 64.38% 67.45% +0.34%

パラメータを調整しても val_accuracy はなしを下回る結果となりました。ただし E:RE(sh=0.15) の test_accuracy は 67.45% でなしの 67.11% を +0.34% 上回り、唯一「なし超え」を達成しました。「val_accuracy では見えない汎化性能の改善」がパラメータ調整後に現れた形です。

val_accuracy が低いのに test_accuracy が高いのは矛盾に見えますが、これはマスクによってval セット(訓練データの一部)への特化が抑えられ、真の汎化性能が上がっているためと解釈できます。最終的な判断は test_accuracy で行うことが重要です。

まとめ
  • デフォルトパラメータのままでは、CIFAR-10(32×32px)に対してマスクが過剰になりunderfittingを引き起こす。
  • パラメータを調整(RE: sh=0.15)すると、test_accuracy でなしを上回る結果が得られた(+0.34%)。
  • val_accuracy と test_accuracy が逆転することがある。汎化性能の評価は test_accuracy で行うこと。
  • 論文デフォルトのパラメータは大画像(ImageNet等)向け。小画像へ転用するときはsh を 0.15 前後に縮小して調整する。
  • CutOut・Random Erasing ともにモデルのパラメータ数・学習時間への影響はほぼゼロ。試すコストは低い。

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