画像の正規化方法で精度は変わる?/255・BatchNorm・LayerNormをCIFAR-10で比較【Keras実験】

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

BatchNormalization CIFAR-10 CNN Google Colab Keras LayerNormalization Rescaling 正規化 前処理

X f B! P L
画像の正規化方法で精度は変わる?/255・BatchNorm・LayerNormをCIFAR-10で比較【Keras実験】 アイキャッチ画像

なんとなく 255 で割っていませんか?

画像をKerasに入力するとき、x / 255.0 で正規化するのが"お約束"になっていませんか?
でも BatchNormalizationLayerNormalization を使う方法と、精度や収束速度はどう違うのでしょうか。

今回はGoogle ColabとCIFAR-10を使い、4種類の正規化方法を完全同一条件で比較しました。

📘 この記事でわかること
  • 前処理の正規化(/255)とモデル内正規化(BN・LN)の根本的な違い
  • CIFAR-10での精度・収束速度・学習時間の実験結果
  • どの正規化方法をいつ選ぶべきかの判断基準
⚠️ 既存記事との違い
当ブログのBatchNormalizationあり/なし比較BN×Dropout比較では「BatchNormを過学習対策の層」として扱いました。本記事では 「入力画像をどう前処理するか」 という観点に絞り、BatchNormを 前処理の代替 として使う場合の効果を検証します。

4つの正規化方法の違い

パターン 方法 適用タイミング 学習パラメータ
A:/255(手動) NumPyで x / 255.0 学習前に一括処理 なし
B:Rescaling層 Rescaling(1./255) をモデル先頭に追加 モデル内で自動処理 なし
C:BatchNormalization BatchNormalization() をモデル先頭に追加 ミニバッチ単位で動的に正規化 あり(γ・β)
D:LayerNormalization LayerNormalization() をモデル先頭に追加 サンプル単位で動的に正規化 あり(γ・β)

前処理の正規化 vs モデル内正規化の根本的な違い

A・B(固定スケーリング)は、全ピクセルを一律に [0, 1] に収める固定変換です。データセット全体の統計を使わず、「最大値が255」という前提で割り算するだけです。

C(BatchNorm)はミニバッチ内の平均・分散で正規化するため、バッチごとに異なる変換が適用されます。さらに学習可能なスケール(γ)とシフト(β)パラメータを持ちます。

D(LayerNorm)はサンプル1枚ごとにチャンネル軸で正規化します。バッチサイズに依存しないため、バッチサイズが小さい場合でも安定します。

💡 AとBは「計算上は同じ」
/255 と Rescaling(1./255) は数値的に完全に同等です。違いは「前処理をコード側でやるか、モデル内でやるか」だけ。B はモデルに前処理を内包できるため、推論時に別途正規化コードを書く必要がなくなります。

実験コード

使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10です。正規化方法以外の条件はすべて同一にし、正規化の影響だけを取り出します。

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

# ── 環境準備(最初に一度だけ実行)──────────────────────
!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 (30.7 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 57.5 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 numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import time

# ── データ準備 ──────────────────────────────────────────
(x_train_raw, y_train), (x_test_raw, y_test) = keras.datasets.cifar10.load_data()

# A・B用:/255 で正規化済みデータ
x_train_norm = x_train_raw.astype('float32') / 255.0
x_test_norm  = x_test_raw.astype('float32')  / 255.0

# C・D用:正規化なし(uint8のまま float32 に変換のみ)
x_train_raw_f = x_train_raw.astype('float32')
x_test_raw_f  = x_test_raw.astype('float32')

NUM_CLASSES = 10
print("データ準備完了")
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 614s 4us/step
データ準備完了

モデル構築関数

def build_model(norm_type, name):
    """
    norm_type:
      'manual'  → 入力はすでに /255 済み。正規化層なし
      'rescale' → モデル先頭に Rescaling(1./255) を追加
      'bn'      → モデル先頭に BatchNormalization を追加
      'ln'      → モデル先頭に LayerNormalization を追加
    """
    norm_layers = {
        'manual':  [],
        'rescale': [keras.layers.Rescaling(1. / 255)],
        'bn':      [keras.layers.BatchNormalization()],
        'ln':      [keras.layers.LayerNormalization()],
    }

    layers = [keras.layers.Input(shape=(32, 32, 3))]
    layers += norm_layers[norm_type]
    layers += [
        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(NUM_CLASSES, activation='softmax'),
    ]
    return keras.Sequential(layers, name=name)

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

4パターンの学習実行

# (label, norm_type, 使用するx_train, 使用するx_test)
configs = [
    ('A_manual_255',  'manual',  x_train_norm,  x_test_norm),
    ('B_Rescaling',   'rescale', x_train_raw_f, x_test_raw_f),
    ('C_BatchNorm',   'bn',      x_train_raw_f, x_test_raw_f),
    ('D_LayerNorm',   'ln',      x_train_raw_f, x_test_raw_f),
]
histories, times, scores = {}, {}, {}

for label, norm_type, x_tr, x_te in configs:
    keras.backend.clear_session()
    print(f"\n=== {label} ===")
    model = build_model(norm_type, label)
    print(model.summary())
    h, t = compile_and_fit(model, x_tr, y_tr=y_train)
    s = model.evaluate(x_te, y_test, verbose=0)
    histories[label] = h
    times[label]     = t
    scores[label]    = s
    print(f"学習時間:{t:.1f}秒 test_accuracy:{s[1]:.4f}")
実行結果をクリックして内容を開く
=== A_manual_255 ===
Model: "A_manual_255"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 128)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,450 (365.04 KB)
 Trainable params: 93,450 (365.04 KB)
 Non-trainable params: 0 (0.00 B)
None
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 11s 9ms/step - accuracy: 0.2636 - loss: 1.9338 - val_accuracy: 0.3596 - val_loss: 1.7197
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3648 - loss: 1.6899 - val_accuracy: 0.3989 - val_loss: 1.6127
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4119 - loss: 1.5860 - val_accuracy: 0.4346 - val_loss: 1.5430
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4432 - loss: 1.5071 - val_accuracy: 0.4757 - val_loss: 1.4402
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4653 - loss: 1.4490 - val_accuracy: 0.4863 - val_loss: 1.3937
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4877 - loss: 1.3891 - val_accuracy: 0.5150 - val_loss: 1.3380
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5064 - loss: 1.3487 - val_accuracy: 0.5160 - val_loss: 1.3450
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5210 - loss: 1.3091 - val_accuracy: 0.5006 - val_loss: 1.3146
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5354 - loss: 1.2715 - val_accuracy: 0.5455 - val_loss: 1.2366
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5416 - loss: 1.2481 - val_accuracy: 0.5518 - val_loss: 1.2240
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5550 - loss: 1.2151 - val_accuracy: 0.5503 - val_loss: 1.2041
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5646 - loss: 1.1924 - val_accuracy: 0.5734 - val_loss: 1.1558
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5731 - loss: 1.1759 - val_accuracy: 0.5737 - val_loss: 1.1829
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5850 - loss: 1.1479 - val_accuracy: 0.5774 - val_loss: 1.1540
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5907 - loss: 1.1269 - val_accuracy: 0.5967 - val_loss: 1.0955
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5972 - loss: 1.1116 - val_accuracy: 0.6029 - val_loss: 1.0892
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6053 - loss: 1.0887 - val_accuracy: 0.6113 - val_loss: 1.0976
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6135 - loss: 1.0681 - val_accuracy: 0.6070 - val_loss: 1.0783
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6170 - loss: 1.0627 - val_accuracy: 0.6160 - val_loss: 1.0541
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6230 - loss: 1.0404 - val_accuracy: 0.6299 - val_loss: 1.0246
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6308 - loss: 1.0198 - val_accuracy: 0.6166 - val_loss: 1.0492
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6384 - loss: 1.0072 - val_accuracy: 0.6154 - val_loss: 1.0414
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6413 - loss: 0.9957 - val_accuracy: 0.6440 - val_loss: 0.9915
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6495 - loss: 0.9717 - val_accuracy: 0.6412 - val_loss: 0.9981
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6517 - loss: 0.9749 - val_accuracy: 0.6579 - val_loss: 0.9609
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6590 - loss: 0.9496 - val_accuracy: 0.6583 - val_loss: 0.9537
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6585 - loss: 0.9445 - val_accuracy: 0.6553 - val_loss: 0.9702
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6646 - loss: 0.9341 - val_accuracy: 0.6595 - val_loss: 0.9587
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6697 - loss: 0.9168 - val_accuracy: 0.6646 - val_loss: 0.9404
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6745 - loss: 0.9082 - val_accuracy: 0.6613 - val_loss: 0.9487
学習時間:129.7秒 test_accuracy:0.6565

=== B_Rescaling ===
Model: "B_Rescaling"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ rescaling (Rescaling)           │ (None, 32, 32, 3)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d (Conv2D)                 │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 128)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,450 (365.04 KB)
 Trainable params: 93,450 (365.04 KB)
 Non-trainable params: 0 (0.00 B)
None
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2680 - loss: 1.9157 - val_accuracy: 0.3432 - val_loss: 1.7222
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.3623 - loss: 1.6897 - val_accuracy: 0.3933 - val_loss: 1.6190
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4137 - loss: 1.5806 - val_accuracy: 0.4474 - val_loss: 1.5069
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4488 - loss: 1.4948 - val_accuracy: 0.4838 - val_loss: 1.4155
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4797 - loss: 1.4199 - val_accuracy: 0.5009 - val_loss: 1.3662
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4982 - loss: 1.3727 - val_accuracy: 0.5151 - val_loss: 1.3196
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5143 - loss: 1.3319 - val_accuracy: 0.5237 - val_loss: 1.2990
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5298 - loss: 1.2932 - val_accuracy: 0.5222 - val_loss: 1.2999
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5389 - loss: 1.2602 - val_accuracy: 0.5562 - val_loss: 1.2121
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5494 - loss: 1.2367 - val_accuracy: 0.5556 - val_loss: 1.2072
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5643 - loss: 1.2020 - val_accuracy: 0.5639 - val_loss: 1.1953
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5695 - loss: 1.1849 - val_accuracy: 0.5764 - val_loss: 1.1516
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5827 - loss: 1.1518 - val_accuracy: 0.6050 - val_loss: 1.1044
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5875 - loss: 1.1368 - val_accuracy: 0.5964 - val_loss: 1.1033
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5979 - loss: 1.1177 - val_accuracy: 0.6078 - val_loss: 1.0827
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6043 - loss: 1.0926 - val_accuracy: 0.6011 - val_loss: 1.0995
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6094 - loss: 1.0730 - val_accuracy: 0.6224 - val_loss: 1.0437
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6180 - loss: 1.0549 - val_accuracy: 0.6189 - val_loss: 1.0354
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6228 - loss: 1.0414 - val_accuracy: 0.6237 - val_loss: 1.0447
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6299 - loss: 1.0194 - val_accuracy: 0.6400 - val_loss: 1.0036
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6362 - loss: 1.0105 - val_accuracy: 0.6333 - val_loss: 1.0235
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6420 - loss: 0.9929 - val_accuracy: 0.6326 - val_loss: 1.0211
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6499 - loss: 0.9754 - val_accuracy: 0.6405 - val_loss: 0.9904
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6524 - loss: 0.9618 - val_accuracy: 0.6443 - val_loss: 0.9703
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6574 - loss: 0.9491 - val_accuracy: 0.6548 - val_loss: 0.9662
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6611 - loss: 0.9441 - val_accuracy: 0.6627 - val_loss: 0.9289
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6679 - loss: 0.9271 - val_accuracy: 0.6691 - val_loss: 0.9264
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6684 - loss: 0.9187 - val_accuracy: 0.6480 - val_loss: 0.9763
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6724 - loss: 0.9083 - val_accuracy: 0.6637 - val_loss: 0.9385
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6769 - loss: 0.8975 - val_accuracy: 0.6575 - val_loss: 0.9488
学習時間:125.7秒 test_accuracy:0.6549

=== C_BatchNorm ===
Model: "C_BatchNorm"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ batch_normalization             │ (None, 32, 32, 3)      │            12 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d (Conv2D)                 │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 128)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,462 (365.09 KB)
 Trainable params: 93,456 (365.06 KB)
 Non-trainable params: 6 (24.00 B)
None
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 10ms/step - accuracy: 0.3212 - loss: 1.8223 - val_accuracy: 0.4143 - val_loss: 1.5765
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4467 - loss: 1.5224 - val_accuracy: 0.5011 - val_loss: 1.3863
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5045 - loss: 1.3707 - val_accuracy: 0.5343 - val_loss: 1.2914
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5408 - loss: 1.2768 - val_accuracy: 0.5515 - val_loss: 1.2419
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5654 - loss: 1.2150 - val_accuracy: 0.5794 - val_loss: 1.1609
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5857 - loss: 1.1542 - val_accuracy: 0.5883 - val_loss: 1.1476
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6015 - loss: 1.1135 - val_accuracy: 0.6031 - val_loss: 1.0899
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6175 - loss: 1.0739 - val_accuracy: 0.6152 - val_loss: 1.0542
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6264 - loss: 1.0421 - val_accuracy: 0.6308 - val_loss: 1.0145
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6344 - loss: 1.0225 - val_accuracy: 0.6248 - val_loss: 1.0362
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6463 - loss: 0.9921 - val_accuracy: 0.6498 - val_loss: 0.9838
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6516 - loss: 0.9725 - val_accuracy: 0.6444 - val_loss: 0.9863
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6594 - loss: 0.9540 - val_accuracy: 0.6530 - val_loss: 0.9556
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6650 - loss: 0.9338 - val_accuracy: 0.6662 - val_loss: 0.9300
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6720 - loss: 0.9132 - val_accuracy: 0.6725 - val_loss: 0.9105
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6791 - loss: 0.8963 - val_accuracy: 0.6694 - val_loss: 0.9147
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6836 - loss: 0.8848 - val_accuracy: 0.6847 - val_loss: 0.8788
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6918 - loss: 0.8649 - val_accuracy: 0.6838 - val_loss: 0.8889
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6939 - loss: 0.8527 - val_accuracy: 0.6727 - val_loss: 0.9179
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7012 - loss: 0.8433 - val_accuracy: 0.6904 - val_loss: 0.8689
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7050 - loss: 0.8261 - val_accuracy: 0.6791 - val_loss: 0.8926
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.7117 - loss: 0.8117 - val_accuracy: 0.6841 - val_loss: 0.8883
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7183 - loss: 0.7957 - val_accuracy: 0.7059 - val_loss: 0.8348
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7203 - loss: 0.7857 - val_accuracy: 0.6972 - val_loss: 0.8592
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.7242 - loss: 0.7750 - val_accuracy: 0.7090 - val_loss: 0.8231
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7264 - loss: 0.7609 - val_accuracy: 0.7174 - val_loss: 0.8022
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7323 - loss: 0.7483 - val_accuracy: 0.6958 - val_loss: 0.8747
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.7369 - loss: 0.7397 - val_accuracy: 0.7183 - val_loss: 0.8075
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7403 - loss: 0.7323 - val_accuracy: 0.7202 - val_loss: 0.8023
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7446 - loss: 0.7187 - val_accuracy: 0.7080 - val_loss: 0.8383
学習時間:131.8秒 test_accuracy:0.6992

=== D_LayerNorm ===
Model: "D_LayerNorm"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ layer_normalization             │ (None, 32, 32, 3)      │             6 │
│ (LayerNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d (Conv2D)                 │ (None, 32, 32, 64)     │         1,792 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 64)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 16, 16, 128)    │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 128)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 93,456 (365.06 KB)
 Trainable params: 93,456 (365.06 KB)
 Non-trainable params: 0 (0.00 B)
None
Epoch 1/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 9ms/step - accuracy: 0.2540 - loss: 2.0004 - val_accuracy: 0.3074 - val_loss: 1.8922
Epoch 2/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.3334 - loss: 1.8245 - val_accuracy: 0.3705 - val_loss: 1.7488
Epoch 3/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3756 - loss: 1.7169 - val_accuracy: 0.3831 - val_loss: 1.6901
Epoch 4/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.4017 - loss: 1.6559 - val_accuracy: 0.4068 - val_loss: 1.6202
Epoch 5/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4176 - loss: 1.6120 - val_accuracy: 0.4235 - val_loss: 1.5898
Epoch 6/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4294 - loss: 1.5760 - val_accuracy: 0.4313 - val_loss: 1.5640
Epoch 7/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4410 - loss: 1.5438 - val_accuracy: 0.4504 - val_loss: 1.5235
Epoch 8/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4514 - loss: 1.5153 - val_accuracy: 0.4576 - val_loss: 1.5042
Epoch 9/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4631 - loss: 1.4945 - val_accuracy: 0.4590 - val_loss: 1.4919
Epoch 10/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4708 - loss: 1.4689 - val_accuracy: 0.4748 - val_loss: 1.4626
Epoch 11/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4766 - loss: 1.4484 - val_accuracy: 0.4663 - val_loss: 1.4840
Epoch 12/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4854 - loss: 1.4345 - val_accuracy: 0.4721 - val_loss: 1.4661
Epoch 13/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4893 - loss: 1.4203 - val_accuracy: 0.4796 - val_loss: 1.4466
Epoch 14/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4958 - loss: 1.4008 - val_accuracy: 0.4874 - val_loss: 1.4270
Epoch 15/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5029 - loss: 1.3835 - val_accuracy: 0.4855 - val_loss: 1.4394
Epoch 16/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5067 - loss: 1.3713 - val_accuracy: 0.4785 - val_loss: 1.4607
Epoch 17/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5126 - loss: 1.3589 - val_accuracy: 0.4924 - val_loss: 1.4287
Epoch 18/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5181 - loss: 1.3417 - val_accuracy: 0.4903 - val_loss: 1.4296
Epoch 19/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5203 - loss: 1.3316 - val_accuracy: 0.4942 - val_loss: 1.4160
Epoch 20/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5235 - loss: 1.3256 - val_accuracy: 0.4936 - val_loss: 1.4238
Epoch 21/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5276 - loss: 1.3096 - val_accuracy: 0.4977 - val_loss: 1.4095
Epoch 22/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5322 - loss: 1.3007 - val_accuracy: 0.5026 - val_loss: 1.3982
Epoch 23/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5378 - loss: 1.2887 - val_accuracy: 0.4952 - val_loss: 1.4304
Epoch 24/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5394 - loss: 1.2782 - val_accuracy: 0.4996 - val_loss: 1.4121
Epoch 25/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5448 - loss: 1.2638 - val_accuracy: 0.5106 - val_loss: 1.3751
Epoch 26/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5507 - loss: 1.2530 - val_accuracy: 0.5088 - val_loss: 1.3860
Epoch 27/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5541 - loss: 1.2434 - val_accuracy: 0.5071 - val_loss: 1.3898
Epoch 28/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.5563 - loss: 1.2392 - val_accuracy: 0.5064 - val_loss: 1.3933
Epoch 29/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5590 - loss: 1.2268 - val_accuracy: 0.5091 - val_loss: 1.3931
Epoch 30/30
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5626 - loss: 1.2153 - val_accuracy: 0.4986 - val_loss: 1.4326
学習時間:136.3秒 test_accuracy:0.4975

グラフ+サマリー

# ── 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(fontsize=9); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('normalization_comparison.png', dpi=150)
plt.show()

# ── train_loss vs val_loss(過学習の乖離)────────────────
fig2, axes2 = plt.subplots(4, 1, figsize=(7, 18))
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)
    axes2[i].set_xlabel('Epoch'); axes2[i].legend(); axes2[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('normalization_overfit.png', dpi=150)
plt.show()

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

最終結果サマリー

===== 最終結果サマリー =====
             Pattern |  Val Acc |  Test Acc |  Val Loss |  Time(s)
--------------------------------------------------------------------
        A_manual_255 |   0.6613 |    0.6565 |    0.9487 |    129.7
         B_Rescaling |   0.6575 |    0.6549 |    0.9488 |    125.7
         C_BatchNorm |   0.7080 |    0.6992 |    0.8383 |    131.8
         D_LayerNorm |   0.4986 |    0.4975 |    1.4326 |    136.3
--------------------------------------------------------------------

実験結果

実験はGoogle Colab(T4 GPU)、CIFAR-10、エポック数30・バッチサイズ64の条件で実施しました。

精度グラフ

精度グラフ

損失グラフ

損失グラフ

A_manual_255

画像の正規化方法 manual_255

B_Rescaling

画像の正規化方法 Rescaling

C_BatchNorm

画像の正規化方法 BatchNorm

D_LayerNorm

画像の正規化方法 LayerNorm
パターン val_accuracy test_accuracy val_loss 学習時間
A:/255(手動) 66.13% 65.65% 0.9487 129.7秒
B:Rescaling層 65.75% 65.49% 0.9488 125.7秒
C:BatchNormalization ✅ 70.80% 69.92% 0.8383 131.8秒
D:LayerNormalization ⚠️ 49.86% 49.75% 1.4326 136.3秒

考察

① A と B は「数値的に同一」を実験で確認

A(/255手動)とB(Rescaling層)のtest_accuracyの差はわずか0.16%(65.65% vs 65.49%)、val_lossも0.9487 vs 0.9488とほぼ同値です。x / 255.0Rescaling(1./255) は数値的に完全に同等であることが実験でも裏付けられました。

学習時間はBの方が4秒短く(125.7秒 vs 129.7秒)、モデル内で処理する分のオーバーヘッドはほぼ無視できます。推論時に正規化コードを別途書く手間を省きたいならRescaling層を使うのがシンプルな選択です。

② BatchNormalization が圧倒的に高精度だった

最も驚きの結果がC:BatchNormalization(69.92%)です。ベースライン(A:65.65%)と比べて+4.27%という大幅な改善で、val_lossも0.8383と5パターン中最小でした。

今回のCは「モデルの先頭にBatchNormalizationを1層置き、入力は正規化なしの生ピクセル値(0〜255)」という構成です。BatchNormがミニバッチ単位で平均・分散を計算して動的に正規化するため、固定の /255 よりもデータの実際の分布に即した正規化が行われます。結果として収束が安定し、精度が大きく向上したと考えられます。

比較test_accuracy の差
A(/255)vs C(BatchNorm) +4.27%(BatchNormが上)
A(/255)vs B(Rescaling) −0.16%(実質同等)

③ LayerNormalization は画像CNNの先頭には向かない

最も注目すべき結果がD:LayerNormalization(49.75%)です。ランダム予測(10クラスで50%)とほぼ同水準で、実質的に学習が機能していない状態です。val_lossも1.4326と突出して大きく、収束が完全に乱れています。

原因はLayerNormalizationの正規化の方向にあります。LayerNormは1サンプルの全チャンネル・全空間位置にわたって平均と分散を計算します。CIFAR-10の入力(32×32×3)は空間情報が正規化の対象に含まれるため、画像の空間的な特徴(エッジ・テクスチャ)が均されてしまい、CNNが学習すべき局所的なパターンが失われます。

LayerNormalizationはTransformerのように系列データや特徴ベクトル単位で使う場合に本来の力を発揮します。画像CNNの入力正規化には不向きと覚えておきましょう。

④ 「なんとなく /255」より BatchNorm の方が精度が高い理由

/255 はピクセルの最大値(255)で割る固定変換で、データセット全体の統計を考慮しません。一方、BatchNormは学習中にミニバッチの平均(μ)と分散(σ²)を計算し、データの実際の分布に合わせて正規化します。

CIFAR-10のピクセル平均は約0.49(≒125/255)で、/255 後の平均は0に近くなりません。BatchNormはこの偏りをミニバッチ単位で自動補正するため、勾配の流れが改善されて学習が安定します。さらに学習可能なγ・βパラメータが最適なスケールとシフトを自動で学ぶ点も精度向上に貢献しています。


まとめ

正規化方法 test_accuracy パラメータ こんな場面におすすめ
A:/255(手動) 65.65% なし シンプルに試したいとき
B:Rescaling層 65.49% なし 前処理をモデルに内包したいとき
C:BatchNormalization ✅ 69.92% あり(γ・β) 精度を追求したいとき・バッチサイズが十分なとき
D:LayerNormalization ⚠️ 49.75% あり(γ・β) 画像CNNには不向き。Transformerで使う
💡 ひとことまとめ
「なんとなく /255」よりモデル先頭にBatchNormalizationを置く方が+4%精度が高いことが実験で確認できました。一方、LayerNormalizationを画像CNNの先頭に使うと学習がほぼ機能しなくなります。画像CNNの前処理ならBatchNorm、Transformerや系列モデルならLayerNormと使い分けるのが正解です。

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