model.fit()のcallbacks=[]にEarlyStopping・ReduceLROnPlateau・ModelCheckpointを並べるとき、その順番を意識したことはありますか?
「複数のcallbackはそれぞれ独立して動くため、通常は順番を意識する必要はない」——そう考えることが多いでしょう。今回はこの前提を疑い、callbacksの並び順を変えて同じ実験を複数パターン実行しました。実際にやってみると、最初の実験では「順番によって結果が変わったように見える」という予想外の結果が出て、原因を切り分けるための再実験が必要になりました。その一部始終をそのまま記事化します。
📘 この記事でわかること
- Kerasはcallbacksをどの順番で・どのタイミングで呼び出しているか
- EarlyStopping・ReduceLROnPlateau・ModelCheckpointの並び順を変えても学習結果は変わらないのか(実際に確認)
- 「順番による差」に見えたものが、実は比較実験の設計ミス(別々のfit()呼び出し+GPUの非決定性)だったと切り分ける方法
- 「順番が本当に結果を左右するケース」が実装のどこに潜んでいるか(optimizer.learning_rateの読み取りタイミング)
callbacksはどの順番で呼ばれているのか
Kerasのmodel.fit()は、1エポックが終わるたびにcallbacksリストの先頭から順番に on_epoch_end(epoch, logs) を呼び出します。logsにはそのエポックのloss・val_lossなどが辞書として渡され、EarlyStoppingやReduceLROnPlateauはこのlogsを読んで自分の内部状態(best値・patienceカウンタなど)を更新します。
| ケース | 他のcallbackの影響を受けるか | 理由 | ①logsを参照して判断する場合(今回のEarlyStopping・ReduceLROnPlateau・ModelCheckpoint) |
通常は受けない | モデル構造・ハイパーパラメータを同一にし、各パターンで同じシードを設定したうえで、callbacksの並び順だけを変えて比較します。ただし、GPU上の演算には非決定性が含まれる場合があるため、この時点では完全に同一の学習軌道になるとは限りません。 |
|---|---|---|
②あるcallbackがmodel.optimizer.learning_rateなどミュータブルな共有状態を読む場合 | 受ける | ReduceLROnPlateauは条件を満たすとon_epoch_endの中で学習率を直接書き換える。後続のcallbackがそれを読むと「もう書き換わった後の値」を見ることになる |
実験デザイン
実験①:標準3callbacksの並び順を変える
EarlyStopping(ES)・ReduceLROnPlateau(RLR)・ModelCheckpoint(MC)を、以下の3パターンの順番でcallbacks=[]に渡します。モデル構造・シード・ハイパーパラメータはすべて同一にし、並び順だけを変えます。
| パターン | callbacksの順番 |
|---|---|
| A | [ES, RLR, MC] |
| B | [RLR, ES, MC] |
| C | [MC, ES, RLR] |
実験②:学習率を記録するcallbackをRLRの前後に配置する
各epoch終了時の学習率を記録するだけのカスタムcallback LRLogger を、ReduceLROnPlateauの前に置く場合(D)と後に置く場合(E)で比較します。
実験コード・実験①
環境準備(最初に一度だけ実行)
!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 53 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 2s (4,639 kB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 122403 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 65.2 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了
import・データ準備・モデル構築関数
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np
import time
# ── シード固定(比較実験のため必須)──────────────────
SEED = 42
keras.utils.set_random_seed(SEED)
(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
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_model(model):
model.compile(optimizer=keras.optimizers.Adam(learning_rate=1e-3),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 1773s 10us/step
実験①:標準3callbacksの並び順を変えて学習
def build_callbacks(order, ckpt_path):
"""order: 'ES','RLR','MC' のリストで並び順を指定"""
es = keras.callbacks.EarlyStopping(
monitor='val_loss', patience=7, restore_best_weights=True)
rlr = keras.callbacks.ReduceLROnPlateau(
monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6, verbose=1)
mc = keras.callbacks.ModelCheckpoint(
ckpt_path, monitor='val_loss', save_best_only=True, verbose=0)
lookup = {'ES': es, 'RLR': rlr, 'MC': mc}
return [lookup[key] for key in order], es, rlr, mc
patterns_exp1 = [
('A_ES_RLR_MC', ['ES', 'RLR', 'MC']),
('B_RLR_ES_MC', ['RLR', 'ES', 'MC']),
('C_MC_ES_RLR', ['MC', 'ES', 'RLR']),
]
histories1, stopped_epoch1, final_lr1, best_epoch1, times1 = {}, {}, {}, {}, {}
for label, order in patterns_exp1:
print(f"\n=== {label}(順番:{order}) ===")
keras.utils.set_random_seed(SEED) # 各パターンで初期重みを揃える
model = compile_model(build_model(label))
cbs, es, rlr, mc = build_callbacks(order, f'/content/{label}_best.keras')
start = time.time()
history = model.fit(
x_train, y_train, epochs=50, batch_size=64,
validation_split=0.2, callbacks=cbs, verbose=1)
elapsed = time.time() - start
histories1[label] = history
stopped_epoch1[label] = len(history.epoch)
final_lr1[label] = float(model.optimizer.learning_rate.numpy())
best_epoch1[label] = es.best_epoch if hasattr(es, 'best_epoch') else None
times1[label] = elapsed
print(f"停止epoch:{stopped_epoch1[label]} 最終lr:{final_lr1[label]:.6f} 学習時間:{elapsed:.1f}秒")
実行結果をクリックして内容を開く
=== A_ES_RLR_MC(順番:['ES', 'RLR', 'MC']) === Epoch 1/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 18s 17ms/step - accuracy: 0.2581 - loss: 1.9311 - val_accuracy: 0.3551 - val_loss: 1.7170 - learning_rate: 0.0010 Epoch 2/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.3602 - loss: 1.6949 - val_accuracy: 0.4205 - val_loss: 1.5897 - learning_rate: 0.0010 Epoch 3/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4184 - loss: 1.5793 - val_accuracy: 0.4616 - val_loss: 1.4799 - learning_rate: 0.0010 Epoch 4/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4578 - loss: 1.4809 - val_accuracy: 0.4901 - val_loss: 1.3992 - learning_rate: 0.0010 Epoch 5/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4844 - loss: 1.4056 - val_accuracy: 0.5080 - val_loss: 1.3510 - learning_rate: 0.0010 Epoch 6/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5007 - loss: 1.3590 - val_accuracy: 0.5227 - val_loss: 1.3112 - learning_rate: 0.0010 Epoch 7/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5190 - loss: 1.3188 - val_accuracy: 0.5319 - val_loss: 1.2826 - learning_rate: 0.0010 Epoch 8/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5311 - loss: 1.2857 - val_accuracy: 0.5375 - val_loss: 1.2517 - learning_rate: 0.0010 Epoch 9/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5445 - loss: 1.2540 - val_accuracy: 0.5545 - val_loss: 1.2209 - learning_rate: 0.0010 Epoch 10/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5547 - loss: 1.2258 - val_accuracy: 0.5618 - val_loss: 1.2058 - learning_rate: 0.0010 Epoch 11/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5666 - loss: 1.1954 - val_accuracy: 0.5711 - val_loss: 1.1737 - learning_rate: 0.0010 Epoch 12/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5749 - loss: 1.1720 - val_accuracy: 0.5810 - val_loss: 1.1590 - learning_rate: 0.0010 Epoch 13/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5860 - loss: 1.1509 - val_accuracy: 0.5967 - val_loss: 1.1232 - learning_rate: 0.0010 Epoch 14/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5961 - loss: 1.1238 - val_accuracy: 0.6060 - val_loss: 1.0966 - learning_rate: 0.0010 Epoch 15/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6038 - loss: 1.1037 - val_accuracy: 0.6097 - val_loss: 1.0776 - learning_rate: 0.0010 Epoch 16/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6095 - loss: 1.0865 - val_accuracy: 0.6177 - val_loss: 1.0613 - learning_rate: 0.0010 Epoch 17/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6157 - loss: 1.0655 - val_accuracy: 0.6238 - val_loss: 1.0471 - learning_rate: 0.0010 Epoch 18/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6235 - loss: 1.0525 - val_accuracy: 0.6245 - val_loss: 1.0355 - learning_rate: 0.0010 Epoch 19/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6285 - loss: 1.0328 - val_accuracy: 0.6372 - val_loss: 1.0070 - learning_rate: 0.0010 Epoch 20/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6356 - loss: 1.0175 - val_accuracy: 0.6361 - val_loss: 1.0128 - learning_rate: 0.0010 Epoch 21/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6403 - loss: 1.0046 - val_accuracy: 0.6418 - val_loss: 0.9893 - learning_rate: 0.0010 Epoch 22/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6448 - loss: 0.9908 - val_accuracy: 0.6497 - val_loss: 0.9713 - learning_rate: 0.0010 Epoch 23/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6523 - loss: 0.9776 - val_accuracy: 0.6553 - val_loss: 0.9638 - learning_rate: 0.0010 Epoch 24/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.6554 - loss: 0.9628 - val_accuracy: 0.6618 - val_loss: 0.9489 - learning_rate: 0.0010 Epoch 25/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6586 - loss: 0.9509 - val_accuracy: 0.6606 - val_loss: 0.9486 - learning_rate: 0.0010 Epoch 26/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6671 - loss: 0.9360 - val_accuracy: 0.6640 - val_loss: 0.9394 - learning_rate: 0.0010 Epoch 27/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6692 - loss: 0.9263 - val_accuracy: 0.6710 - val_loss: 0.9261 - learning_rate: 0.0010 Epoch 28/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6734 - loss: 0.9149 - val_accuracy: 0.6700 - val_loss: 0.9209 - learning_rate: 0.0010 Epoch 29/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6772 - loss: 0.9009 - val_accuracy: 0.6724 - val_loss: 0.9170 - learning_rate: 0.0010 Epoch 30/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6818 - loss: 0.8929 - val_accuracy: 0.6698 - val_loss: 0.9249 - learning_rate: 0.0010 Epoch 31/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6863 - loss: 0.8824 - val_accuracy: 0.6765 - val_loss: 0.9108 - learning_rate: 0.0010 Epoch 32/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6878 - loss: 0.8773 - val_accuracy: 0.6720 - val_loss: 0.9252 - learning_rate: 0.0010 Epoch 33/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6936 - loss: 0.8646 - val_accuracy: 0.6815 - val_loss: 0.8929 - learning_rate: 0.0010 Epoch 34/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6929 - loss: 0.8576 - val_accuracy: 0.6787 - val_loss: 0.9074 - learning_rate: 0.0010 Epoch 35/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6995 - loss: 0.8480 - val_accuracy: 0.6758 - val_loss: 0.9013 - learning_rate: 0.0010 Epoch 36/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.7020 - loss: 0.8390 - val_accuracy: 0.6809 - val_loss: 0.8905 - learning_rate: 0.0010 Epoch 37/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7064 - loss: 0.8277 - val_accuracy: 0.6868 - val_loss: 0.8814 - learning_rate: 0.0010 Epoch 38/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7097 - loss: 0.8184 - val_accuracy: 0.6805 - val_loss: 0.8998 - learning_rate: 0.0010 Epoch 39/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7113 - loss: 0.8116 - val_accuracy: 0.6888 - val_loss: 0.8808 - learning_rate: 0.0010 Epoch 40/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7136 - loss: 0.8031 - val_accuracy: 0.6820 - val_loss: 0.9048 - learning_rate: 0.0010 Epoch 41/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7178 - loss: 0.7947 - val_accuracy: 0.6880 - val_loss: 0.8842 - learning_rate: 0.0010 Epoch 42/50 623/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7165 - loss: 0.7981 Epoch 42: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7179 - loss: 0.7930 - val_accuracy: 0.6862 - val_loss: 0.8838 - learning_rate: 0.0010 Epoch 43/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.7313 - loss: 0.7584 - val_accuracy: 0.7056 - val_loss: 0.8326 - learning_rate: 5.0000e-04 Epoch 44/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7321 - loss: 0.7508 - val_accuracy: 0.7054 - val_loss: 0.8359 - learning_rate: 5.0000e-04 Epoch 45/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7364 - loss: 0.7429 - val_accuracy: 0.7040 - val_loss: 0.8342 - learning_rate: 5.0000e-04 Epoch 46/50 616/625 ━━━━━━━━━━━━━━━━━━━━ 0s 6ms/step - accuracy: 0.7375 - loss: 0.7395 Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7371 - loss: 0.7383 - val_accuracy: 0.7031 - val_loss: 0.8424 - learning_rate: 5.0000e-04 Epoch 47/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7462 - loss: 0.7165 - val_accuracy: 0.7096 - val_loss: 0.8276 - learning_rate: 2.5000e-04 Epoch 48/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7468 - loss: 0.7130 - val_accuracy: 0.7121 - val_loss: 0.8254 - learning_rate: 2.5000e-04 Epoch 49/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7502 - loss: 0.7094 - val_accuracy: 0.7114 - val_loss: 0.8264 - learning_rate: 2.5000e-04 Epoch 50/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7515 - loss: 0.7028 - val_accuracy: 0.7102 - val_loss: 0.8235 - learning_rate: 2.5000e-04 停止epoch:50 最終lr:0.000250 学習時間:220.9秒 === B_RLR_ES_MC(順番:['RLR', 'ES', 'MC']) === Epoch 1/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2607 - loss: 1.9303 - val_accuracy: 0.3672 - val_loss: 1.7125 - learning_rate: 0.0010 Epoch 2/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3659 - loss: 1.6879 - val_accuracy: 0.4234 - val_loss: 1.5783 - learning_rate: 0.0010 Epoch 3/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4258 - loss: 1.5629 - val_accuracy: 0.4738 - val_loss: 1.4583 - learning_rate: 0.0010 Epoch 4/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4646 - loss: 1.4629 - val_accuracy: 0.4990 - val_loss: 1.3841 - learning_rate: 0.0010 Epoch 5/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4913 - loss: 1.3918 - val_accuracy: 0.5103 - val_loss: 1.3389 - learning_rate: 0.0010 Epoch 6/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5076 - loss: 1.3492 - val_accuracy: 0.5271 - val_loss: 1.2970 - learning_rate: 0.0010 Epoch 7/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5232 - loss: 1.3099 - val_accuracy: 0.5450 - val_loss: 1.2613 - learning_rate: 0.0010 Epoch 8/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5347 - loss: 1.2784 - val_accuracy: 0.5468 - val_loss: 1.2419 - learning_rate: 0.0010 Epoch 9/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5475 - loss: 1.2472 - val_accuracy: 0.5627 - val_loss: 1.2073 - learning_rate: 0.0010 Epoch 10/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5571 - loss: 1.2183 - val_accuracy: 0.5722 - val_loss: 1.1856 - learning_rate: 0.0010 Epoch 11/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5698 - loss: 1.1889 - val_accuracy: 0.5811 - val_loss: 1.1512 - learning_rate: 0.0010 Epoch 12/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5775 - loss: 1.1695 - val_accuracy: 0.5843 - val_loss: 1.1573 - learning_rate: 0.0010 Epoch 13/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5845 - loss: 1.1513 - val_accuracy: 0.5888 - val_loss: 1.1400 - learning_rate: 0.0010 Epoch 14/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5943 - loss: 1.1241 - val_accuracy: 0.6082 - val_loss: 1.0958 - learning_rate: 0.0010 Epoch 15/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6011 - loss: 1.1055 - val_accuracy: 0.6119 - val_loss: 1.0863 - learning_rate: 0.0010 Epoch 16/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6102 - loss: 1.0847 - val_accuracy: 0.6154 - val_loss: 1.0700 - learning_rate: 0.0010 Epoch 17/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6155 - loss: 1.0681 - val_accuracy: 0.6152 - val_loss: 1.0748 - learning_rate: 0.0010 Epoch 18/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6227 - loss: 1.0487 - val_accuracy: 0.6208 - val_loss: 1.0466 - learning_rate: 0.0010 Epoch 19/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6317 - loss: 1.0304 - val_accuracy: 0.6362 - val_loss: 1.0159 - learning_rate: 0.0010 Epoch 20/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6344 - loss: 1.0169 - val_accuracy: 0.6368 - val_loss: 1.0206 - learning_rate: 0.0010 Epoch 21/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6432 - loss: 0.9976 - val_accuracy: 0.6434 - val_loss: 0.9958 - learning_rate: 0.0010 Epoch 22/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6482 - loss: 0.9839 - val_accuracy: 0.6500 - val_loss: 0.9789 - learning_rate: 0.0010 Epoch 23/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6546 - loss: 0.9693 - val_accuracy: 0.6511 - val_loss: 0.9826 - learning_rate: 0.0010 Epoch 24/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6589 - loss: 0.9557 - val_accuracy: 0.6570 - val_loss: 0.9673 - learning_rate: 0.0010 Epoch 25/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6626 - loss: 0.9438 - val_accuracy: 0.6576 - val_loss: 0.9566 - learning_rate: 0.0010 Epoch 26/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6717 - loss: 0.9280 - val_accuracy: 0.6617 - val_loss: 0.9483 - learning_rate: 0.0010 Epoch 27/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6730 - loss: 0.9161 - val_accuracy: 0.6663 - val_loss: 0.9339 - learning_rate: 0.0010 Epoch 28/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6778 - loss: 0.9029 - val_accuracy: 0.6664 - val_loss: 0.9307 - learning_rate: 0.0010 Epoch 29/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6800 - loss: 0.8904 - val_accuracy: 0.6738 - val_loss: 0.9126 - learning_rate: 0.0010 Epoch 30/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6866 - loss: 0.8767 - val_accuracy: 0.6725 - val_loss: 0.9164 - learning_rate: 0.0010 Epoch 31/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6913 - loss: 0.8680 - val_accuracy: 0.6801 - val_loss: 0.8905 - learning_rate: 0.0010 Epoch 32/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6904 - loss: 0.8632 - val_accuracy: 0.6775 - val_loss: 0.9135 - learning_rate: 0.0010 Epoch 33/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6940 - loss: 0.8535 - val_accuracy: 0.6802 - val_loss: 0.8900 - learning_rate: 0.0010 Epoch 34/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6999 - loss: 0.8420 - val_accuracy: 0.6781 - val_loss: 0.8958 - learning_rate: 0.0010 Epoch 35/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7019 - loss: 0.8327 - val_accuracy: 0.6894 - val_loss: 0.8737 - learning_rate: 0.0010 Epoch 36/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7071 - loss: 0.8264 - val_accuracy: 0.6888 - val_loss: 0.8721 - learning_rate: 0.0010 Epoch 37/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7111 - loss: 0.8117 - val_accuracy: 0.6941 - val_loss: 0.8575 - learning_rate: 0.0010 Epoch 38/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7130 - loss: 0.8052 - val_accuracy: 0.6910 - val_loss: 0.8660 - learning_rate: 0.0010 Epoch 39/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.7147 - loss: 0.7974 - val_accuracy: 0.6897 - val_loss: 0.8703 - learning_rate: 0.0010 Epoch 40/50 621/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7173 - loss: 0.7900 Epoch 40: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7178 - loss: 0.7882 - val_accuracy: 0.6924 - val_loss: 0.8698 - learning_rate: 0.0010 Epoch 41/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7289 - loss: 0.7583 - val_accuracy: 0.7020 - val_loss: 0.8366 - learning_rate: 5.0000e-04 Epoch 42/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7321 - loss: 0.7479 - val_accuracy: 0.7045 - val_loss: 0.8300 - learning_rate: 5.0000e-04 Epoch 43/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7338 - loss: 0.7446 - val_accuracy: 0.7068 - val_loss: 0.8207 - learning_rate: 5.0000e-04 Epoch 44/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7378 - loss: 0.7348 - val_accuracy: 0.7090 - val_loss: 0.8182 - learning_rate: 5.0000e-04 Epoch 45/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7383 - loss: 0.7310 - val_accuracy: 0.7070 - val_loss: 0.8183 - learning_rate: 5.0000e-04 Epoch 46/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7414 - loss: 0.7260 - val_accuracy: 0.7085 - val_loss: 0.8244 - learning_rate: 5.0000e-04 Epoch 47/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 0s 6ms/step - accuracy: 0.7404 - loss: 0.7210 Epoch 47: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7420 - loss: 0.7218 - val_accuracy: 0.7091 - val_loss: 0.8183 - learning_rate: 5.0000e-04 Epoch 48/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7498 - loss: 0.7010 - val_accuracy: 0.7141 - val_loss: 0.8020 - learning_rate: 2.5000e-04 Epoch 49/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7521 - loss: 0.6972 - val_accuracy: 0.7136 - val_loss: 0.8068 - learning_rate: 2.5000e-04 Epoch 50/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7545 - loss: 0.6904 - val_accuracy: 0.7164 - val_loss: 0.8011 - learning_rate: 2.5000e-04 停止epoch:50 最終lr:0.000250 学習時間:209.5秒 === C_MC_ES_RLR(順番:['MC', 'ES', 'RLR']) === Epoch 1/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2595 - loss: 1.9305 - val_accuracy: 0.3688 - val_loss: 1.7088 - learning_rate: 0.0010 Epoch 2/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.3677 - loss: 1.6837 - val_accuracy: 0.4200 - val_loss: 1.5845 - learning_rate: 0.0010 Epoch 3/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4227 - loss: 1.5682 - val_accuracy: 0.4705 - val_loss: 1.4754 - learning_rate: 0.0010 Epoch 4/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4636 - loss: 1.4742 - val_accuracy: 0.4941 - val_loss: 1.3948 - learning_rate: 0.0010 Epoch 5/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4883 - loss: 1.3993 - val_accuracy: 0.5107 - val_loss: 1.3454 - learning_rate: 0.0010 Epoch 6/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5051 - loss: 1.3535 - val_accuracy: 0.5222 - val_loss: 1.3125 - learning_rate: 0.0010 Epoch 7/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5189 - loss: 1.3133 - val_accuracy: 0.5381 - val_loss: 1.2678 - learning_rate: 0.0010 Epoch 8/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5350 - loss: 1.2815 - val_accuracy: 0.5421 - val_loss: 1.2498 - learning_rate: 0.0010 Epoch 9/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5456 - loss: 1.2494 - val_accuracy: 0.5555 - val_loss: 1.2134 - learning_rate: 0.0010 Epoch 10/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5569 - loss: 1.2219 - val_accuracy: 0.5713 - val_loss: 1.1840 - learning_rate: 0.0010 Epoch 11/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5664 - loss: 1.1920 - val_accuracy: 0.5807 - val_loss: 1.1486 - learning_rate: 0.0010 Epoch 12/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5764 - loss: 1.1692 - val_accuracy: 0.5808 - val_loss: 1.1522 - learning_rate: 0.0010 Epoch 13/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5866 - loss: 1.1480 - val_accuracy: 0.5899 - val_loss: 1.1242 - learning_rate: 0.0010 Epoch 14/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5932 - loss: 1.1245 - val_accuracy: 0.6072 - val_loss: 1.0882 - learning_rate: 0.0010 Epoch 15/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6012 - loss: 1.1041 - val_accuracy: 0.6071 - val_loss: 1.0913 - learning_rate: 0.0010 Epoch 16/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6087 - loss: 1.0868 - val_accuracy: 0.6160 - val_loss: 1.0656 - learning_rate: 0.0010 Epoch 17/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6157 - loss: 1.0692 - val_accuracy: 0.6218 - val_loss: 1.0458 - learning_rate: 0.0010 Epoch 18/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6220 - loss: 1.0527 - val_accuracy: 0.6236 - val_loss: 1.0377 - learning_rate: 0.0010 Epoch 19/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6287 - loss: 1.0364 - val_accuracy: 0.6415 - val_loss: 1.0017 - learning_rate: 0.0010 Epoch 20/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6343 - loss: 1.0195 - val_accuracy: 0.6387 - val_loss: 1.0043 - learning_rate: 0.0010 Epoch 21/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.6405 - loss: 1.0013 - val_accuracy: 0.6475 - val_loss: 0.9862 - learning_rate: 0.0010 Epoch 22/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6449 - loss: 0.9923 - val_accuracy: 0.6483 - val_loss: 0.9757 - learning_rate: 0.0010 Epoch 23/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6500 - loss: 0.9767 - val_accuracy: 0.6547 - val_loss: 0.9644 - learning_rate: 0.0010 Epoch 24/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6578 - loss: 0.9586 - val_accuracy: 0.6597 - val_loss: 0.9468 - learning_rate: 0.0010 Epoch 25/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6582 - loss: 0.9488 - val_accuracy: 0.6604 - val_loss: 0.9495 - learning_rate: 0.0010 Epoch 26/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6624 - loss: 0.9377 - val_accuracy: 0.6633 - val_loss: 0.9474 - learning_rate: 0.0010 Epoch 27/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6675 - loss: 0.9246 - val_accuracy: 0.6690 - val_loss: 0.9271 - learning_rate: 0.0010 Epoch 28/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6758 - loss: 0.9083 - val_accuracy: 0.6725 - val_loss: 0.9192 - learning_rate: 0.0010 Epoch 29/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6762 - loss: 0.8969 - val_accuracy: 0.6741 - val_loss: 0.9162 - learning_rate: 0.0010 Epoch 30/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6828 - loss: 0.8866 - val_accuracy: 0.6740 - val_loss: 0.9156 - learning_rate: 0.0010 Epoch 31/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6865 - loss: 0.8753 - val_accuracy: 0.6777 - val_loss: 0.9004 - learning_rate: 0.0010 Epoch 32/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6880 - loss: 0.8697 - val_accuracy: 0.6718 - val_loss: 0.9253 - learning_rate: 0.0010 Epoch 33/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6924 - loss: 0.8605 - val_accuracy: 0.6829 - val_loss: 0.8930 - learning_rate: 0.0010 Epoch 34/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6965 - loss: 0.8455 - val_accuracy: 0.6773 - val_loss: 0.9076 - learning_rate: 0.0010 Epoch 35/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7020 - loss: 0.8369 - val_accuracy: 0.6899 - val_loss: 0.8807 - learning_rate: 0.0010 Epoch 36/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7032 - loss: 0.8306 - val_accuracy: 0.6889 - val_loss: 0.8663 - learning_rate: 0.0010 Epoch 37/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7054 - loss: 0.8219 - val_accuracy: 0.6935 - val_loss: 0.8708 - learning_rate: 0.0010 Epoch 38/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7084 - loss: 0.8159 - val_accuracy: 0.6956 - val_loss: 0.8699 - learning_rate: 0.0010 Epoch 39/50 623/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7124 - loss: 0.8068 Epoch 39: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7125 - loss: 0.8054 - val_accuracy: 0.6919 - val_loss: 0.8770 - learning_rate: 0.0010 Epoch 40/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7233 - loss: 0.7705 - val_accuracy: 0.7010 - val_loss: 0.8464 - learning_rate: 5.0000e-04 Epoch 41/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7248 - loss: 0.7627 - val_accuracy: 0.7012 - val_loss: 0.8506 - learning_rate: 5.0000e-04 Epoch 42/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7295 - loss: 0.7577 - val_accuracy: 0.7019 - val_loss: 0.8532 - learning_rate: 5.0000e-04 Epoch 43/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7322 - loss: 0.7522 - val_accuracy: 0.7032 - val_loss: 0.8417 - learning_rate: 5.0000e-04 Epoch 44/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7324 - loss: 0.7441 - val_accuracy: 0.7022 - val_loss: 0.8400 - learning_rate: 5.0000e-04 Epoch 45/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7357 - loss: 0.7399 - val_accuracy: 0.7041 - val_loss: 0.8402 - learning_rate: 5.0000e-04 Epoch 46/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7374 - loss: 0.7351 - val_accuracy: 0.7051 - val_loss: 0.8400 - learning_rate: 5.0000e-04 Epoch 47/50 622/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7378 - loss: 0.7299 Epoch 47: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7392 - loss: 0.7295 - val_accuracy: 0.7066 - val_loss: 0.8419 - learning_rate: 5.0000e-04 Epoch 48/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7453 - loss: 0.7150 - val_accuracy: 0.7095 - val_loss: 0.8249 - learning_rate: 2.5000e-04 Epoch 49/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7469 - loss: 0.7102 - val_accuracy: 0.7133 - val_loss: 0.8168 - learning_rate: 2.5000e-04 Epoch 50/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7491 - loss: 0.7040 - val_accuracy: 0.7133 - val_loss: 0.8193 - learning_rate: 2.5000e-04 停止epoch:50 最終lr:0.000250 学習時間:208.6秒
実験①:結果サマリー
print("\n===== 実験① 結果サマリー =====")
print(f"{'Pattern':>14} | {'停止epoch':>9} | {'最終val_acc':>11} | {'最終val_loss':>12} | {'最終lr':>10} | {'時間(s)':>8}")
print("-" * 78)
for label, _ in patterns_exp1:
h = histories1[label]
print(f"{label:>14} | {stopped_epoch1[label]:>9} | "
f"{h.history['val_accuracy'][-1]:>11.4f} | {h.history['val_loss'][-1]:>12.4f} | "
f"{final_lr1[label]:>10.6f} | {times1[label]:>8.1f}")
print("-" * 78)
実行結果をクリックして内容を開く
===== 実験① 結果サマリー =====
Pattern | 停止epoch | 最終val_acc | 最終val_loss | 最終lr | 時間(s)
------------------------------------------------------------------------------
A_ES_RLR_MC | 50 | 0.7102 | 0.8235 | 0.000250 | 220.9
B_RLR_ES_MC | 50 | 0.7164 | 0.8011 | 0.000250 | 209.5
C_MC_ES_RLR | 50 | 0.7133 | 0.8193 | 0.000250 | 208.6
------------------------------------------------------------------------------
この時点でA・B・Cのval_accuracy・最終学習率にばらつきが出ました。callbacksの順番が結果に影響したと結論づける前に、疑うべき点が2つあります。
1つ目は、同じシードを設定していてもGPU上の演算が完全に決定的とは限らないことです。
2つ目は、3つのパターンを別々のfit()として実行しているため、学習軌道そのものを完全に同一条件で比較できていないことです。
実験コード・実験②(1回目:D/Eを別々に実行)
class LRLogger(keras.callbacks.Callback):
"""各epoch終了時点のoptimizer.learning_rateを記録するだけのcallback"""
def __init__(self):
super().__init__()
self.recorded_lr = []
def on_epoch_end(self, epoch, logs=None):
current_lr = float(self.model.optimizer.learning_rate.numpy())
self.recorded_lr.append(current_lr)
patterns_exp2 = [
('D_Logger_before_RLR', 'before'),
('E_Logger_after_RLR', 'after'),
]
histories2, logger_records = {}, {}
for label, position in patterns_exp2:
print(f"\n=== {label}(LRLoggerの位置:{position}) ===")
keras.utils.set_random_seed(SEED)
model = compile_model(build_model(label))
logger = LRLogger()
es = keras.callbacks.EarlyStopping(monitor='val_loss', patience=7, restore_best_weights=True)
rlr = keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6, verbose=1)
if position == 'before':
cbs = [logger, rlr, es]
else:
cbs = [rlr, logger, es]
history = model.fit(
x_train, y_train, epochs=50, batch_size=64,
validation_split=0.2, callbacks=cbs, verbose=1)
histories2[label] = history
logger_records[label] = logger.recorded_lr
print(f"記録された学習率の推移:{logger.recorded_lr}")
実行結果をクリックして内容を開く
=== D_Logger_before_RLR(LRLoggerの位置:before) === Epoch 1/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.2574 - loss: 1.9321 - val_accuracy: 0.3582 - val_loss: 1.7182 - learning_rate: 0.0010 Epoch 2/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3587 - loss: 1.6927 - val_accuracy: 0.4220 - val_loss: 1.5818 - learning_rate: 0.0010 Epoch 3/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4220 - loss: 1.5697 - val_accuracy: 0.4649 - val_loss: 1.4743 - learning_rate: 0.0010 Epoch 4/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4615 - loss: 1.4738 - val_accuracy: 0.4931 - val_loss: 1.3923 - learning_rate: 0.0010 Epoch 5/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4866 - loss: 1.3989 - val_accuracy: 0.5059 - val_loss: 1.3483 - learning_rate: 0.0010 Epoch 6/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5068 - loss: 1.3527 - val_accuracy: 0.5235 - val_loss: 1.3042 - learning_rate: 0.0010 Epoch 7/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5238 - loss: 1.3088 - val_accuracy: 0.5442 - val_loss: 1.2561 - learning_rate: 0.0010 Epoch 8/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5378 - loss: 1.2719 - val_accuracy: 0.5490 - val_loss: 1.2354 - learning_rate: 0.0010 Epoch 9/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5485 - loss: 1.2401 - val_accuracy: 0.5588 - val_loss: 1.2154 - learning_rate: 0.0010 Epoch 10/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5592 - loss: 1.2118 - val_accuracy: 0.5699 - val_loss: 1.1830 - learning_rate: 0.0010 Epoch 11/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5724 - loss: 1.1814 - val_accuracy: 0.5810 - val_loss: 1.1641 - learning_rate: 0.0010 Epoch 12/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5794 - loss: 1.1613 - val_accuracy: 0.5865 - val_loss: 1.1471 - learning_rate: 0.0010 Epoch 13/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5904 - loss: 1.1404 - val_accuracy: 0.5990 - val_loss: 1.1116 - learning_rate: 0.0010 Epoch 14/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5992 - loss: 1.1158 - val_accuracy: 0.6044 - val_loss: 1.0987 - learning_rate: 0.0010 Epoch 15/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6054 - loss: 1.0989 - val_accuracy: 0.6133 - val_loss: 1.0824 - learning_rate: 0.0010 Epoch 16/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6131 - loss: 1.0790 - val_accuracy: 0.6251 - val_loss: 1.0477 - learning_rate: 0.0010 Epoch 17/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6180 - loss: 1.0604 - val_accuracy: 0.6233 - val_loss: 1.0443 - learning_rate: 0.0010 Epoch 18/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6266 - loss: 1.0426 - val_accuracy: 0.6326 - val_loss: 1.0220 - learning_rate: 0.0010 Epoch 19/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6318 - loss: 1.0277 - val_accuracy: 0.6390 - val_loss: 0.9964 - learning_rate: 0.0010 Epoch 20/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6398 - loss: 1.0093 - val_accuracy: 0.6445 - val_loss: 0.9977 - learning_rate: 0.0010 Epoch 21/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6438 - loss: 0.9956 - val_accuracy: 0.6475 - val_loss: 0.9741 - learning_rate: 0.0010 Epoch 22/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6482 - loss: 0.9831 - val_accuracy: 0.6509 - val_loss: 0.9628 - learning_rate: 0.0010 Epoch 23/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6559 - loss: 0.9690 - val_accuracy: 0.6542 - val_loss: 0.9632 - learning_rate: 0.0010 Epoch 24/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6580 - loss: 0.9555 - val_accuracy: 0.6547 - val_loss: 0.9508 - learning_rate: 0.0010 Epoch 25/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6633 - loss: 0.9433 - val_accuracy: 0.6623 - val_loss: 0.9408 - learning_rate: 0.0010 Epoch 26/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6681 - loss: 0.9304 - val_accuracy: 0.6618 - val_loss: 0.9332 - learning_rate: 0.0010 Epoch 27/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6729 - loss: 0.9166 - val_accuracy: 0.6678 - val_loss: 0.9216 - learning_rate: 0.0010 Epoch 28/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6738 - loss: 0.9070 - val_accuracy: 0.6730 - val_loss: 0.9167 - learning_rate: 0.0010 Epoch 29/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6777 - loss: 0.8964 - val_accuracy: 0.6708 - val_loss: 0.9171 - learning_rate: 0.0010 Epoch 30/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6822 - loss: 0.8880 - val_accuracy: 0.6728 - val_loss: 0.9107 - learning_rate: 0.0010 Epoch 31/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6867 - loss: 0.8768 - val_accuracy: 0.6740 - val_loss: 0.9125 - learning_rate: 0.0010 Epoch 32/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6892 - loss: 0.8733 - val_accuracy: 0.6685 - val_loss: 0.9297 - learning_rate: 0.0010 Epoch 33/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6969 - loss: 0.8552 - val_accuracy: 0.6793 - val_loss: 0.8992 - learning_rate: 0.0010 Epoch 34/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6977 - loss: 0.8468 - val_accuracy: 0.6794 - val_loss: 0.9072 - learning_rate: 0.0010 Epoch 35/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7013 - loss: 0.8380 - val_accuracy: 0.6842 - val_loss: 0.8950 - learning_rate: 0.0010 Epoch 36/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7046 - loss: 0.8297 - val_accuracy: 0.6905 - val_loss: 0.8732 - learning_rate: 0.0010 Epoch 37/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.7070 - loss: 0.8214 - val_accuracy: 0.6874 - val_loss: 0.8813 - learning_rate: 0.0010 Epoch 38/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7104 - loss: 0.8118 - val_accuracy: 0.6936 - val_loss: 0.8737 - learning_rate: 0.0010 Epoch 39/50 624/625 ━━━━━━━━━━━━━━━━━━━━ 0s 6ms/step - accuracy: 0.7086 - loss: 0.8140 Epoch 39: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7128 - loss: 0.8041 - val_accuracy: 0.6904 - val_loss: 0.8813 - learning_rate: 0.0010 Epoch 40/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7262 - loss: 0.7673 - val_accuracy: 0.6987 - val_loss: 0.8524 - learning_rate: 5.0000e-04 Epoch 41/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7308 - loss: 0.7611 - val_accuracy: 0.7031 - val_loss: 0.8455 - learning_rate: 5.0000e-04 Epoch 42/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7302 - loss: 0.7590 - val_accuracy: 0.7005 - val_loss: 0.8474 - learning_rate: 5.0000e-04 Epoch 43/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7318 - loss: 0.7526 - val_accuracy: 0.7024 - val_loss: 0.8469 - learning_rate: 5.0000e-04 Epoch 44/50 616/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7296 - loss: 0.7513 Epoch 44: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7333 - loss: 0.7446 - val_accuracy: 0.7040 - val_loss: 0.8463 - learning_rate: 5.0000e-04 Epoch 45/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7415 - loss: 0.7247 - val_accuracy: 0.7013 - val_loss: 0.8471 - learning_rate: 2.5000e-04 Epoch 46/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7440 - loss: 0.7217 - val_accuracy: 0.7092 - val_loss: 0.8332 - learning_rate: 2.5000e-04 Epoch 47/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7467 - loss: 0.7150 - val_accuracy: 0.7085 - val_loss: 0.8308 - learning_rate: 2.5000e-04 Epoch 48/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7483 - loss: 0.7132 - val_accuracy: 0.7041 - val_loss: 0.8409 - learning_rate: 2.5000e-04 Epoch 49/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7481 - loss: 0.7118 - val_accuracy: 0.7059 - val_loss: 0.8366 - learning_rate: 2.5000e-04 Epoch 50/50 621/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7462 - loss: 0.7092 Epoch 50: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7485 - loss: 0.7046 - val_accuracy: 0.7078 - val_loss: 0.8386 - learning_rate: 2.5000e-04 記録された学習率の推移:[0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628] === E_Logger_after_RLR(LRLoggerの位置:after) === Epoch 1/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2568 - loss: 1.9324 - val_accuracy: 0.3557 - val_loss: 1.7189 - learning_rate: 0.0010 Epoch 2/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3542 - loss: 1.6981 - val_accuracy: 0.4245 - val_loss: 1.5866 - learning_rate: 0.0010 Epoch 3/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4203 - loss: 1.5727 - val_accuracy: 0.4660 - val_loss: 1.4733 - learning_rate: 0.0010 Epoch 4/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4599 - loss: 1.4733 - val_accuracy: 0.4875 - val_loss: 1.4010 - learning_rate: 0.0010 Epoch 5/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.4879 - loss: 1.3971 - val_accuracy: 0.5097 - val_loss: 1.3488 - learning_rate: 0.0010 Epoch 6/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5056 - loss: 1.3492 - val_accuracy: 0.5223 - val_loss: 1.3065 - learning_rate: 0.0010 Epoch 7/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5228 - loss: 1.3059 - val_accuracy: 0.5354 - val_loss: 1.2671 - learning_rate: 0.0010 Epoch 8/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5365 - loss: 1.2714 - val_accuracy: 0.5392 - val_loss: 1.2500 - learning_rate: 0.0010 Epoch 9/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5516 - loss: 1.2392 - val_accuracy: 0.5532 - val_loss: 1.2173 - learning_rate: 0.0010 Epoch 10/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5608 - loss: 1.2107 - val_accuracy: 0.5731 - val_loss: 1.1812 - learning_rate: 0.0010 Epoch 11/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5708 - loss: 1.1810 - val_accuracy: 0.5702 - val_loss: 1.1693 - learning_rate: 0.0010 Epoch 12/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5795 - loss: 1.1594 - val_accuracy: 0.5828 - val_loss: 1.1509 - learning_rate: 0.0010 Epoch 13/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5894 - loss: 1.1384 - val_accuracy: 0.5914 - val_loss: 1.1170 - learning_rate: 0.0010 Epoch 14/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5996 - loss: 1.1129 - val_accuracy: 0.6082 - val_loss: 1.0830 - learning_rate: 0.0010 Epoch 15/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6047 - loss: 1.0974 - val_accuracy: 0.6090 - val_loss: 1.0723 - learning_rate: 0.0010 Epoch 16/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6108 - loss: 1.0796 - val_accuracy: 0.6106 - val_loss: 1.0667 - learning_rate: 0.0010 Epoch 17/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6172 - loss: 1.0617 - val_accuracy: 0.6223 - val_loss: 1.0451 - learning_rate: 0.0010 Epoch 18/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6248 - loss: 1.0456 - val_accuracy: 0.6279 - val_loss: 1.0301 - learning_rate: 0.0010 Epoch 19/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6321 - loss: 1.0281 - val_accuracy: 0.6376 - val_loss: 1.0072 - learning_rate: 0.0010 Epoch 20/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6361 - loss: 1.0131 - val_accuracy: 0.6413 - val_loss: 0.9996 - learning_rate: 0.0010 Epoch 21/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6407 - loss: 1.0009 - val_accuracy: 0.6437 - val_loss: 0.9872 - learning_rate: 0.0010 Epoch 22/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6470 - loss: 0.9851 - val_accuracy: 0.6505 - val_loss: 0.9715 - learning_rate: 0.0010 Epoch 23/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6514 - loss: 0.9705 - val_accuracy: 0.6530 - val_loss: 0.9652 - learning_rate: 0.0010 Epoch 24/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6541 - loss: 0.9589 - val_accuracy: 0.6548 - val_loss: 0.9546 - learning_rate: 0.0010 Epoch 25/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6600 - loss: 0.9472 - val_accuracy: 0.6578 - val_loss: 0.9533 - learning_rate: 0.0010 Epoch 26/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6673 - loss: 0.9327 - val_accuracy: 0.6626 - val_loss: 0.9434 - learning_rate: 0.0010 Epoch 27/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6678 - loss: 0.9228 - val_accuracy: 0.6632 - val_loss: 0.9416 - learning_rate: 0.0010 Epoch 28/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6743 - loss: 0.9105 - val_accuracy: 0.6701 - val_loss: 0.9210 - learning_rate: 0.0010 Epoch 29/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6759 - loss: 0.9000 - val_accuracy: 0.6696 - val_loss: 0.9209 - learning_rate: 0.0010 Epoch 30/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6831 - loss: 0.8866 - val_accuracy: 0.6633 - val_loss: 0.9393 - learning_rate: 0.0010 Epoch 31/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6844 - loss: 0.8800 - val_accuracy: 0.6781 - val_loss: 0.9051 - learning_rate: 0.0010 Epoch 32/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6897 - loss: 0.8718 - val_accuracy: 0.6798 - val_loss: 0.8998 - learning_rate: 0.0010 Epoch 33/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6913 - loss: 0.8599 - val_accuracy: 0.6818 - val_loss: 0.8971 - learning_rate: 0.0010 Epoch 34/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6964 - loss: 0.8507 - val_accuracy: 0.6847 - val_loss: 0.8858 - learning_rate: 0.0010 Epoch 35/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7010 - loss: 0.8412 - val_accuracy: 0.6874 - val_loss: 0.8858 - learning_rate: 0.0010 Epoch 36/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7035 - loss: 0.8326 - val_accuracy: 0.6857 - val_loss: 0.8828 - learning_rate: 0.0010 Epoch 37/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7080 - loss: 0.8217 - val_accuracy: 0.6896 - val_loss: 0.8662 - learning_rate: 0.0010 Epoch 38/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7107 - loss: 0.8119 - val_accuracy: 0.6970 - val_loss: 0.8581 - learning_rate: 0.0010 Epoch 39/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7128 - loss: 0.8086 - val_accuracy: 0.6907 - val_loss: 0.8720 - learning_rate: 0.0010 Epoch 40/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7139 - loss: 0.8006 - val_accuracy: 0.6888 - val_loss: 0.8791 - learning_rate: 0.0010 Epoch 41/50 616/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7166 - loss: 0.7912 Epoch 41: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7178 - loss: 0.7921 - val_accuracy: 0.6912 - val_loss: 0.8740 - learning_rate: 0.0010 Epoch 42/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7290 - loss: 0.7599 - val_accuracy: 0.6974 - val_loss: 0.8493 - learning_rate: 5.0000e-04 Epoch 43/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7325 - loss: 0.7509 - val_accuracy: 0.7033 - val_loss: 0.8364 - learning_rate: 5.0000e-04 Epoch 44/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7351 - loss: 0.7455 - val_accuracy: 0.7024 - val_loss: 0.8398 - learning_rate: 5.0000e-04 Epoch 45/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7368 - loss: 0.7392 - val_accuracy: 0.7042 - val_loss: 0.8374 - learning_rate: 5.0000e-04 Epoch 46/50 618/625 ━━━━━━━━━━━━━━━━━━━━ 0s 6ms/step - accuracy: 0.7358 - loss: 0.7343 Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7376 - loss: 0.7328 - val_accuracy: 0.7022 - val_loss: 0.8419 - learning_rate: 5.0000e-04 Epoch 47/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7458 - loss: 0.7105 - val_accuracy: 0.7073 - val_loss: 0.8240 - learning_rate: 2.5000e-04 Epoch 48/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7473 - loss: 0.7073 - val_accuracy: 0.7015 - val_loss: 0.8299 - learning_rate: 2.5000e-04 Epoch 49/50 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.7472 - loss: 0.7073 - val_accuracy: 0.7063 - val_loss: 0.8241 - learning_rate: 2.5000e-04 Epoch 50/50 622/625 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.7489 - loss: 0.7010 Epoch 50: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814. 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7509 - loss: 0.6984 - val_accuracy: 0.7044 - val_loss: 0.8279 - learning_rate: 2.5000e-04 記録された学習率の推移:[0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0010000000474974513, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0005000000237487257, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628, 0.0002500000118743628, 0.0001250000059371814]
実験②(1回目):DとEの記録値を突き合わせ
print("\n===== 実験② LR記録の比較(epochごと)=====")
lr_d = logger_records['D_Logger_before_RLR']
lr_e = logger_records['E_Logger_after_RLR']
n = min(len(lr_d), len(lr_e))
print(f"{'epoch':>6} | {'D(前配置)':>12} | {'E(後配置)':>12} | {'一致':>6}")
print("-" * 46)
for i in range(n):
match = "○" if abs(lr_d[i] - lr_e[i]) < 1e-12 else "✕"
print(f"{i+1:>6} | {lr_d[i]:>12.6f} | {lr_e[i]:>12.6f} | {match:>6}")
実行結果をクリックして内容を開く
===== 実験② LR記録の比較(epochごと)=====
epoch | D(前配置) | E(後配置) | 一致
----------------------------------------------
1 | 0.001000 | 0.001000 | ○
2 | 0.001000 | 0.001000 | ○
3 | 0.001000 | 0.001000 | ○
4 | 0.001000 | 0.001000 | ○
5 | 0.001000 | 0.001000 | ○
6 | 0.001000 | 0.001000 | ○
7 | 0.001000 | 0.001000 | ○
8 | 0.001000 | 0.001000 | ○
9 | 0.001000 | 0.001000 | ○
10 | 0.001000 | 0.001000 | ○
11 | 0.001000 | 0.001000 | ○
12 | 0.001000 | 0.001000 | ○
13 | 0.001000 | 0.001000 | ○
14 | 0.001000 | 0.001000 | ○
15 | 0.001000 | 0.001000 | ○
16 | 0.001000 | 0.001000 | ○
17 | 0.001000 | 0.001000 | ○
18 | 0.001000 | 0.001000 | ○
19 | 0.001000 | 0.001000 | ○
20 | 0.001000 | 0.001000 | ○
21 | 0.001000 | 0.001000 | ○
22 | 0.001000 | 0.001000 | ○
23 | 0.001000 | 0.001000 | ○
24 | 0.001000 | 0.001000 | ○
25 | 0.001000 | 0.001000 | ○
26 | 0.001000 | 0.001000 | ○
27 | 0.001000 | 0.001000 | ○
28 | 0.001000 | 0.001000 | ○
29 | 0.001000 | 0.001000 | ○
30 | 0.001000 | 0.001000 | ○
31 | 0.001000 | 0.001000 | ○
32 | 0.001000 | 0.001000 | ○
33 | 0.001000 | 0.001000 | ○
34 | 0.001000 | 0.001000 | ○
35 | 0.001000 | 0.001000 | ○
36 | 0.001000 | 0.001000 | ○
37 | 0.001000 | 0.001000 | ○
38 | 0.001000 | 0.001000 | ○
39 | 0.001000 | 0.001000 | ○
40 | 0.000500 | 0.001000 | ✕
41 | 0.000500 | 0.000500 | ○
42 | 0.000500 | 0.000500 | ○
43 | 0.000500 | 0.000500 | ○
44 | 0.000500 | 0.000500 | ○
45 | 0.000250 | 0.000500 | ✕
46 | 0.000250 | 0.000250 | ○
47 | 0.000250 | 0.000250 | ○
48 | 0.000250 | 0.000250 | ○
49 | 0.000250 | 0.000250 | ○
50 | 0.000250 | 0.000125 | ✕
DとEの学習率低下タイミングがepoch34とepoch46で8〜12エポックもズレています。これではLRLoggerの配置位置(前/後)による違いなのか、単にDとEが別々の独立したfit()呼び出しで学習の軌道自体が変わってしまったのかを区別できません。実験①と同じ問題(比較したい変数以外の要因が混ざっている)を疑い、再検証が必要と判断しました。
再検証コード
再検証①:determinismを有効化してA/B/Cが一致するか確認
tf.config.experimental.enable_op_determinism()
for label, order in patterns_exp1:
keras.utils.set_random_seed(SEED)
model = compile_model(build_model(f'{label}_det'))
cbs, es, rlr, mc = build_callbacks(order, f'/content/{label}_det.keras')
history = model.fit(x_train, y_train, epochs=50, batch_size=64,
validation_split=0.2, callbacks=cbs, verbose=0)
print(f"{label}: val_acc={history.history['val_accuracy'][-1]:.4f}, "
f"val_loss={history.history['val_loss'][-1]:.4f}, "
f"lr={float(model.optimizer.learning_rate.numpy()):.6f}")
実行結果をクリックして内容を開く
Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. A_ES_RLR_MC: val_acc=0.7114, val_loss=0.8282, lr=0.000500 Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. B_RLR_ES_MC: val_acc=0.7114, val_loss=0.8282, lr=0.000500 Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257. C_MC_ES_RLR: val_acc=0.7114, val_loss=0.8282, lr=0.000500
enable_op_determinism()を有効化すると、A・B・Cの3パターンとも val_acc=0.7114、val_loss=0.8282、最終lr=0.000500、RLR発火epoch=46 で完全に一致しました。このことから、1回目に見られた差はcallbacksの順番ではなく、GPU上の非決定的な演算など、再現性に関わる要因によるものと考えられます。
再検証②:同じ学習軌道を共有した状態でLoggerをRLRの前後両方に置く
keras.utils.set_random_seed(SEED)
class LRLogger(keras.callbacks.Callback):
def __init__(self):
super().__init__()
self.recorded_lr = []
def on_epoch_end(self, epoch, logs=None):
self.recorded_lr.append(float(self.model.optimizer.learning_rate.numpy()))
logger_before = LRLogger()
logger_after = LRLogger()
rlr = keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6, verbose=1)
es = keras.callbacks.EarlyStopping(monitor='val_loss', patience=7, restore_best_weights=True)
model = compile_model(build_model('single_run_before_after'))
history = model.fit(
x_train, y_train, epochs=50, batch_size=64, validation_split=0.2,
callbacks=[logger_before, rlr, logger_after, es], verbose=1)
print(f"\n{'epoch':>6} | {'before':>10} | {'after':>10} | {'一致':>4}")
for i in range(len(logger_before.recorded_lr)):
b, a = logger_before.recorded_lr[i], logger_after.recorded_lr[i]
print(f"{i+1:>6} | {b:>10.6f} | {a:>10.6f} | {'○' if abs(b-a)<1e-12 else '✕':>4}")
実行結果をクリックして内容を開く
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 10ms/step - accuracy: 0.2602 - loss: 1.9340 - val_accuracy: 0.3506 - val_loss: 1.7334 - learning_rate: 0.0010
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.3555 - loss: 1.6999 - val_accuracy: 0.4186 - val_loss: 1.5906 - learning_rate: 0.0010
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.4169 - loss: 1.5807 - val_accuracy: 0.4572 - val_loss: 1.4831 - learning_rate: 0.0010
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.4556 - loss: 1.4858 - val_accuracy: 0.4856 - val_loss: 1.4077 - learning_rate: 0.0010
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.4823 - loss: 1.4214 - val_accuracy: 0.5032 - val_loss: 1.3594 - learning_rate: 0.0010
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.5013 - loss: 1.3675 - val_accuracy: 0.5201 - val_loss: 1.3132 - learning_rate: 0.0010
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5181 - loss: 1.3207 - val_accuracy: 0.5342 - val_loss: 1.2773 - learning_rate: 0.0010
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.5331 - loss: 1.2813 - val_accuracy: 0.5472 - val_loss: 1.2434 - learning_rate: 0.0010
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5486 - loss: 1.2449 - val_accuracy: 0.5583 - val_loss: 1.2094 - learning_rate: 0.0010
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5590 - loss: 1.2161 - val_accuracy: 0.5613 - val_loss: 1.1974 - learning_rate: 0.0010
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5695 - loss: 1.1877 - val_accuracy: 0.5709 - val_loss: 1.1710 - learning_rate: 0.0010
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.5778 - loss: 1.1626 - val_accuracy: 0.5820 - val_loss: 1.1483 - learning_rate: 0.0010
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.5897 - loss: 1.1353 - val_accuracy: 0.5914 - val_loss: 1.1223 - learning_rate: 0.0010
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.5959 - loss: 1.1150 - val_accuracy: 0.5999 - val_loss: 1.0992 - learning_rate: 0.0010
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6044 - loss: 1.0937 - val_accuracy: 0.6063 - val_loss: 1.0815 - learning_rate: 0.0010
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6113 - loss: 1.0741 - val_accuracy: 0.6166 - val_loss: 1.0633 - learning_rate: 0.0010
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6176 - loss: 1.0548 - val_accuracy: 0.6139 - val_loss: 1.0548 - learning_rate: 0.0010
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6261 - loss: 1.0371 - val_accuracy: 0.6273 - val_loss: 1.0349 - learning_rate: 0.0010
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.6314 - loss: 1.0191 - val_accuracy: 0.6271 - val_loss: 1.0348 - learning_rate: 0.0010
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6387 - loss: 1.0063 - val_accuracy: 0.6254 - val_loss: 1.0427 - learning_rate: 0.0010
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6435 - loss: 0.9915 - val_accuracy: 0.6347 - val_loss: 1.0066 - learning_rate: 0.0010
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6497 - loss: 0.9764 - val_accuracy: 0.6485 - val_loss: 0.9795 - learning_rate: 0.0010
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6531 - loss: 0.9647 - val_accuracy: 0.6445 - val_loss: 0.9844 - learning_rate: 0.0010
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6589 - loss: 0.9497 - val_accuracy: 0.6478 - val_loss: 0.9838 - learning_rate: 0.0010
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6637 - loss: 0.9355 - val_accuracy: 0.6550 - val_loss: 0.9664 - learning_rate: 0.0010
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6684 - loss: 0.9219 - val_accuracy: 0.6561 - val_loss: 0.9643 - learning_rate: 0.0010
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.6738 - loss: 0.9128 - val_accuracy: 0.6572 - val_loss: 0.9566 - learning_rate: 0.0010
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6771 - loss: 0.9015 - val_accuracy: 0.6656 - val_loss: 0.9354 - learning_rate: 0.0010
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6817 - loss: 0.8900 - val_accuracy: 0.6710 - val_loss: 0.9231 - learning_rate: 0.0010
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6867 - loss: 0.8781 - val_accuracy: 0.6709 - val_loss: 0.9267 - learning_rate: 0.0010
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6903 - loss: 0.8666 - val_accuracy: 0.6773 - val_loss: 0.9116 - learning_rate: 0.0010
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.6916 - loss: 0.8627 - val_accuracy: 0.6738 - val_loss: 0.9136 - learning_rate: 0.0010
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.6987 - loss: 0.8481 - val_accuracy: 0.6807 - val_loss: 0.8998 - learning_rate: 0.0010
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6994 - loss: 0.8388 - val_accuracy: 0.6804 - val_loss: 0.8958 - learning_rate: 0.0010
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7037 - loss: 0.8308 - val_accuracy: 0.6862 - val_loss: 0.8864 - learning_rate: 0.0010
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7069 - loss: 0.8196 - val_accuracy: 0.6782 - val_loss: 0.9054 - learning_rate: 0.0010
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 10s 8ms/step - accuracy: 0.7100 - loss: 0.8121 - val_accuracy: 0.6787 - val_loss: 0.9036 - learning_rate: 0.0010
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7121 - loss: 0.8062 - val_accuracy: 0.6849 - val_loss: 0.8848 - learning_rate: 0.0010
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7152 - loss: 0.7961 - val_accuracy: 0.6699 - val_loss: 0.9186 - learning_rate: 0.0010
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7176 - loss: 0.7903 - val_accuracy: 0.6913 - val_loss: 0.8734 - learning_rate: 0.0010
Epoch 41/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7203 - loss: 0.7804 - val_accuracy: 0.6888 - val_loss: 0.8837 - learning_rate: 0.0010
Epoch 42/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7243 - loss: 0.7750 - val_accuracy: 0.6917 - val_loss: 0.8777 - learning_rate: 0.0010
Epoch 43/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7276 - loss: 0.7621 - val_accuracy: 0.6948 - val_loss: 0.8688 - learning_rate: 0.0010
Epoch 44/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7300 - loss: 0.7562 - val_accuracy: 0.6928 - val_loss: 0.8766 - learning_rate: 0.0010
Epoch 45/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7328 - loss: 0.7499 - val_accuracy: 0.6928 - val_loss: 0.8836 - learning_rate: 0.0010
Epoch 46/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.7334 - loss: 0.7483
Epoch 46: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257.
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7356 - loss: 0.7452 - val_accuracy: 0.6877 - val_loss: 0.8814 - learning_rate: 0.0010
Epoch 47/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7458 - loss: 0.7139 - val_accuracy: 0.7107 - val_loss: 0.8340 - learning_rate: 5.0000e-04
Epoch 48/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 9ms/step - accuracy: 0.7483 - loss: 0.7048 - val_accuracy: 0.7061 - val_loss: 0.8418 - learning_rate: 5.0000e-04
Epoch 49/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 8ms/step - accuracy: 0.7485 - loss: 0.7049 - val_accuracy: 0.7121 - val_loss: 0.8261 - learning_rate: 5.0000e-04
Epoch 50/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7513 - loss: 0.6974 - val_accuracy: 0.7114 - val_loss: 0.8282 - learning_rate: 5.0000e-04
epoch | before | after | 一致
1 | 0.001000 | 0.001000 | ○
2 | 0.001000 | 0.001000 | ○
3 | 0.001000 | 0.001000 | ○
4 | 0.001000 | 0.001000 | ○
5 | 0.001000 | 0.001000 | ○
6 | 0.001000 | 0.001000 | ○
7 | 0.001000 | 0.001000 | ○
8 | 0.001000 | 0.001000 | ○
9 | 0.001000 | 0.001000 | ○
10 | 0.001000 | 0.001000 | ○
11 | 0.001000 | 0.001000 | ○
12 | 0.001000 | 0.001000 | ○
13 | 0.001000 | 0.001000 | ○
14 | 0.001000 | 0.001000 | ○
15 | 0.001000 | 0.001000 | ○
16 | 0.001000 | 0.001000 | ○
17 | 0.001000 | 0.001000 | ○
18 | 0.001000 | 0.001000 | ○
19 | 0.001000 | 0.001000 | ○
20 | 0.001000 | 0.001000 | ○
21 | 0.001000 | 0.001000 | ○
22 | 0.001000 | 0.001000 | ○
23 | 0.001000 | 0.001000 | ○
24 | 0.001000 | 0.001000 | ○
25 | 0.001000 | 0.001000 | ○
26 | 0.001000 | 0.001000 | ○
27 | 0.001000 | 0.001000 | ○
28 | 0.001000 | 0.001000 | ○
29 | 0.001000 | 0.001000 | ○
30 | 0.001000 | 0.001000 | ○
31 | 0.001000 | 0.001000 | ○
32 | 0.001000 | 0.001000 | ○
33 | 0.001000 | 0.001000 | ○
34 | 0.001000 | 0.001000 | ○
35 | 0.001000 | 0.001000 | ○
36 | 0.001000 | 0.001000 | ○
37 | 0.001000 | 0.001000 | ○
38 | 0.001000 | 0.001000 | ○
39 | 0.001000 | 0.001000 | ○
40 | 0.001000 | 0.001000 | ○
41 | 0.001000 | 0.001000 | ○
42 | 0.001000 | 0.001000 | ○
43 | 0.001000 | 0.001000 | ○
44 | 0.001000 | 0.001000 | ○
45 | 0.001000 | 0.001000 | ○
46 | 0.001000 | 0.000500 | ✕
47 | 0.000500 | 0.000500 | ○
48 | 0.000500 | 0.000500 | ○
49 | 0.000500 | 0.000500 | ○
50 | 0.000500 | 0.000500 | ○
実験結果まとめ
実験①:1回目(非決定的・別実行)vs 再検証(determinism有効化)
| パターン | 1回目 val_acc | 1回目 最終lr | 再検証 val_acc | 再検証 最終lr |
|---|---|---|---|---|
| A:[ES, RLR, MC] | 0.7102 | 0.000250 | 0.7114 | 0.000500 |
| B:[RLR, ES, MC] | 0.7164 | 0.000250 | 0.7114 | 0.000500 |
| C:[MC, ES, RLR] | 0.7133 | 0.000250 | 0.7114 | 0.000500 |
実験②:1回目(D/E別実行)vs 再検証(同一fit内でbefore/after比較)
| RLR発火epoch | 不一致だったepoch数 | |
|---|---|---|
| 1回目(D vs E、別々のfit()) | D:46 E:34 | 17/50 epoch(発火タイミングそのものがズレた) |
| 再検証(同一fit内でbefore/after) | 共通46 | 1/50 epoch(RLR発火epochのみ) |
考察
① 標準3callbacksでは、順番による差は「見せかけ」だった
1回目の素朴な実験では、A・B・Cのval_accuracyや最終学習率に差が出て、一見「callbacksの順番が結果を左右する」ように見えました。しかしtf.config.experimental.enable_op_determinism()を有効化して再実行したところ、3パターンとも完全に一致(val_acc=0.7114、val_loss=0.8282、最終lr=0.000500、RLR発火epoch=46)しました。1回目の差はcallbacksの順番によるものではなく、determinismを有効にすると一致したことから、GPU上の非決定的な演算など、再現性に関わる要因によるものと考えられます。
EarlyStoppingとReduceLROnPlateauはどちらもlogsという「そのepochで確定した値」だけを参照して判断するため、呼び出し順が変わっても判断ロジックは変わりません。比較実験でA/Bパターン間に小さな差が出た場合、それが本当に検証したい変数(今回なら順番)によるものか、GPUの非決定性によるものかを切り分ける手順として、enable_op_determinism()での再実行は有効です。
② 実験②も、最初は比較設計自体に問題があった
1回目のD/E比較(別々のfit()呼び出し)では、RLRの発火epochがD(46epoch目)とE(34epoch目)で8〜12epochもズレ、それ以降の全epochが「不一致」になってしまいました。これはLRLoggerの配置位置による違いではなく、DとEがそもそも別々の独立した学習であり、学習の軌道自体が変わってしまったことが原因です(実験①と同根の問題)。この設計では「配置位置が読み取り値に与える純粋な影響」を検証できていませんでした。
そこで、同じ学習軌道を共有した状態でlogger_beforeとlogger_afterをReduceLROnPlateauの前後に配置し、同じ学習の同じepochを2つのLoggerが同時に観測する設計に変更しました。結果は非常にクリアで、RLRが実際に学習率を書き換えたepoch46だけ、before(0.001000=更新前の値)とafter(0.000500=更新後の値)で食い違い、それ以外の49epochは完全一致しました。
これは、①の「logsだけを参照するcallback同士なら順番は無関係」という結論とは対照的に、model.optimizer.learning_rateのようなミュータブルな共有状態を読み書きするcallbackが混在すると、その順番が読み取り値に直接影響することを示しています。RLRが学習率を書き換えるのはon_epoch_endの内部処理なので、リスト内でRLRより後ろに置かれたcallbackは「更新後」の値を、前に置かれたcallbackは「更新前」の値を見ることになります。
③ ModelCheckpointの位置は影響したか
実験①でCパターン(MCを先頭に配置)もA・Bと完全に一致したことから、save_best_only=TrueのModelCheckpointも、monitor='val_loss'で指定した指標を基準に保存するかどうかを判断します。今回の実験では、リスト内の位置を変えても学習結果に差は見られませんでした。
⚠ ハマりポイント
- callbacksの比較実験でA/Bパターンに小さな数値差が出ても、それだけで「この変数が結果に影響した」と結論づけるのは危険。GPU上のcuDNN演算は同じseedでも完全には決定的でないため、
keras.utils.set_random_seed()に加えてtf.config.experimental.enable_op_determinism()を有効化した上で再検証するのが安全(ただし決定的モードは学習速度がやや低下する点に注意)。 - 「A vs B」を比較したいとき、AとBを別々のfit()呼び出しで回すと、シードを固定していても学習の軌道自体がズレてしまい、比較したい変数以外の要因が混ざる。今回のように同じ学習軌道を共有した状態で両方を同時に観測できる設計に変更できないか、まず検討する価値がある。
- 学習率を記録・利用する自作callback(LR loggerや独自スケジューラなど)を書く場合は、ReduceLROnPlateauより前に置くか後に置くかで観測される値が変わる。CSVLoggerで学習率を記録している場合も、同様の観点で「更新前後どちらを記録したいか」を意識して配置する必要がある。
EarlyStopping(restore_best_weights=True)による重みの復元はfit()の最後に一度だけ行われる。ModelCheckpointが保存するのは各epoch終了時点の重みであり、EarlyStoppingの復元処理より先に走るため、両者の間に矛盾はない。
実務での推奨
| ケース | 推奨 |
|---|---|
| ES・RLR・MCのみを使う標準構成 | 今回の実験条件では、順番を意識する必要はなかった(3パターンで学習結果が完全一致) |
| 学習率を記録・参照する自作callbackを併用する | ReduceLROnPlateauより後に置き、「更新後の学習率」を記録する運用に統一するのが分かりやすい |
| A/Bパターンで小さな数値差が出た比較実験全般 | ①結論を出す前にenable_op_determinism()で再現性を確認する ②可能なら同じ学習軌道を共有した状態で両方を観測できないか設計を見直す |
✅ まとめ
- EarlyStopping・ReduceLROnPlateau・ModelCheckpointだけの標準構成では、callbacksの並び順を変えても学習結果(val_accuracy・val_loss・最終学習率・RLR発火epoch)は完全に一致した。1回目の実験で見えた差はGPUの非決定性によるものであり、
enable_op_determinism()で再検証することで切り分けられた。 - 学習率を記録するLRLoggerの検証でも、最初はD/Eを別々のfit()で実行したため学習軌道自体がズレて正しく比較できず、
同一fit()
内での比較に設計を改めて初めて、RLR発火epochだけに明確な差があるという結果を確認できた。 - 「callbacksの順番は関係ない」という通説は、logsだけを参照する標準callback同士に限れば正しいが、model.optimizer.learning_rateのような共有状態を読み書きする自作callbackを含めると成り立たなくなる——という条件付きの結論が、2段階の再検証を経て得られた。
関連記事もあわせてどうぞ:
- EarlyStoppingの基本 → 【Keras】EarlyStoppingで過学習防止:精度低下の原因と対策
- ReduceLROnPlateauの効果検証 → 【Keras】ReduceLROnPlateau の使い方と効果|patience・factor設定と実験で解説
- ModelCheckpointの使い方 → 【Keras入門】ModelCheckpointとは?ベストモデルを自動保存する方法 | Keras ModelCheckpoint: How to Automatically Save the Best Model
- CSVLoggerで学習ログを保存 → 【Keras】CSVLoggerの使い方|学習ログを簡単に保存する方法

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