web-dev-qa-db-ja.com

検証精度は常にKerasのトレーニング精度よりも優れています

シンプルなニューラルネットワークをmnistデータセットでトレーニングしようとしています。何らかの理由で、履歴(model.fitから返されるパラメーター)を取得すると、検証精度はトレーニング精度よりも高くなりますが、これは本当に奇妙ですが、モデルを評価するときにスコアを確認すると、より高くなります。テスト精度よりトレーニング精度。

これは、モデルのパラメーターに関係なく、毎回発生します。また、カスタムコールバックを使用してパラメーター 'acc'および 'val_acc'にアクセスすると、同じ問題が発生します(数値は履歴で返されたものと同じです)。

私を助けてください!何が悪いのですか?検証精度がトレーニング精度よりも高いのはなぜですか(損失を見ると、同じ問題があることがわかります)。

これは私のコードです:

#!/usr/bin/env python3.5

from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
import numpy as np
from keras import backend
from keras.utils import np_utils
from keras import losses
from keras import optimizers
from keras.datasets import mnist
from keras.models import Sequential
from matplotlib import pyplot as plt

# get train and test data (minst) and reduce volume to speed up (for testing)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
data_reduction = 20
x_train = x_train[:x_train.shape[0] // data_reduction]
y_train = y_train[:y_train.shape[0] // data_reduction]
x_test = x_test[:x_test.shape[0] // data_reduction]
y_test = y_test[:y_test.shape[0] // data_reduction]
try:
    IMG_DEPTH = x_train.shape[3]
except IndexError:
    IMG_DEPTH = 1  # B/W
labels = np.unique(y_train)
N_LABELS = len(labels)
# reshape input data
if backend.image_data_format() == 'channels_first':
    X_train = x_train.reshape(x_train.shape[0], IMG_DEPTH, x_train.shape[1], x_train.shape[2])
    X_test = x_test.reshape(x_test.shape[0], IMG_DEPTH, x_train.shape[1], x_train.shape[2])
    input_shape = (IMG_DEPTH, x_train.shape[1], x_train.shape[2])
else:
    X_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], IMG_DEPTH)
    X_test = x_test.reshape(x_test.shape[0], x_train.shape[1], x_train.shape[2], IMG_DEPTH)
    input_shape = (x_train.shape[1], x_train.shape[2], IMG_DEPTH)
# convert data type to float32 and normalize data values to range [0, 1]
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
# reshape input labels
Y_train = np_utils.to_categorical(y_train, N_LABELS)
Y_test = np_utils.to_categorical(y_test, N_LABELS)

# create model
opt = optimizers.Adam()
loss = losses.categorical_crossentropy
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(len(labels), activation='softmax'))
model.compile(optimizer=optimizers.Adam(), loss=losses.categorical_crossentropy, metrics=['accuracy'])
# fit model
history = model.fit(X_train, Y_train, batch_size=64, epochs=50, verbose=True,
                    validation_data=(X_test, Y_test))
# evaluate model
train_score = model.evaluate(X_train, Y_train, verbose=True)
test_score = model.evaluate(X_test, Y_test, verbose=True)

print("Validation:", test_score[1])
print("Training:  ", train_score[1])
print("--------------------")
print("First 5 samples validation:", history.history["val_acc"][0:5])
print("First 5 samples training:", history.history["acc"][0:5])
print("--------------------")
print("Last 5 samples validation:", history.history["val_acc"][-5:])
print("Last 5 samples training:", history.history["acc"][-5:])

# plot history
plt.ion()
fig = plt.figure()
subfig = fig.add_subplot(122)
subfig.plot(history.history['acc'], label="training")
if history.history['val_acc'] is not None:
    subfig.plot(history.history['val_acc'], label="validation")
subfig.set_title('Model Accuracy')
subfig.set_xlabel('Epoch')
subfig.legend(loc='upper left')
subfig = fig.add_subplot(121)
subfig.plot(history.history['loss'], label="training")
if history.history['val_loss'] is not None:
    subfig.plot(history.history['val_loss'], label="validation")
subfig.set_title('Model Loss')
subfig.set_xlabel('Epoch')
subfig.legend(loc='upper left')
plt.ioff()

input("Press ENTER to close the plots...")

私が得る出力は次のとおりです:

Validation accuracy: 0.97599999999999998
Training accuracy:   1.0
--------------------
First 5 samples validation: [0.83400000286102294, 0.89200000095367427, 0.91599999904632567, 0.9279999976158142, 0.9399999990463257]
First 5 samples training: [0.47133333333333333, 0.70566666682561241, 0.76933333285649619, 0.81133333333333335, 0.82366666714350378]
--------------------
Last 5 samples validation: [0.9820000019073486, 0.9860000019073486, 0.97800000190734859, 0.98399999713897701, 0.975999997138977]
Last 5 samples training: [0.9540000001589457, 0.95766666698455816, 0.95600000031789145, 0.95100000031789145, 0.95033333381017049]

ここで私が得るプロットを見ることができます: トレーニングと検証の精度と損失のプロット

これが適切かどうかはわかりませんが、python 3.5およびkeras 2.0.4を使用しています。

11
danidc

Keras FAQ から:

トレーニングの損失がテストの損失よりもはるかに高いのはなぜですか?

Kerasモデルには、トレーニングとテストの2つのモードがあります。ドロップアウトやL1/L2重みの正規化などの正規化メカニズムは、テスト時にはオフになっています。

さらに、トレーニング損失は、トレーニングデータの各バッチでの損失の平均です。モデルは時間とともに変化するため、エポックの最初のバッチでの損失は通常、最後のバッチでの損失よりも大きくなります。一方、エポックのテスト損失は、エポックの終了時のモデルを使用して計算されるため、損失が低くなります。

そのため、ML理論を読んだ後に見える動作ほど、異常ではありません。これは、同じモデルでトレーニングセットとテストセットの両方を評価すると、予期した動作が突然得られることも説明しています(train acc> val acc)。あなたの場合、ドロップアウトの存在は特に、評価(テスト)中にそれを達成する一方で、トレーニング中に精度が1.0になることを妨げると思います。

すべてのエポックでモデルを保存するコールバックを追加することにより、さらに調査できます。次に、両方のセットで保存された各モデルを評価して、プロットを再作成できます。

11
5Ke