即使使用相同的培训和验证数据集,Keras验证准确性也远低于训练准确度

时间:2018-05-22 05:32:30

标签: tensorflow keras deep-learning

我们尝试使用Keras ResNet50应用程序(Tensorflow作为后端)进行传输学习,使用我们自己的2000个数据集,其中14000个图像作为训练集,5261个图像作为验证集。我们获得的培训结果在培训与验证的损失和准确性方面有很大差异。然后,我们尝试使用相同的图像进行训练和验证,即训练了14000张图像并使用相同的14000张图像进行验证,尝试的训练结果相似,即训练精度高,验证准确度低。

Keras版本:2.1.6

Tensorflow版本:1.8.0

代码(培训和验证的数据集相同),如下所示,

from __future__ import print_function

from keras.applications.resnet50 import ResNet50
from keras.applications.resnet50 import preprocess_input, decode_predictions
from keras.models import *
from keras.layers import *
from keras.callbacks import *
from keras.preprocessing.image import ImageDataGenerator
from datetime import datetime
from keras.optimizers import SGD

import numpy as np

batch_size = 28   # tweak to your GPUs capacity
img_height = 224   # ResNetInceptionv2 & Xception like 299, ResNet50 & VGG like 224
img_width = img_height 
channels = 3
input_shape = (img_height, img_width, channels)
best_model = 'best_model.h5'

train_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)

train_generator = train_datagen.flow_from_directory(
    'data/train',  # this is the target directory
    target_size=(img_height, img_width), 
    batch_size=batch_size,
    class_mode='categorical')

classes = len(train_generator.class_indices)
n_of_train_samples = train_generator.samples

callbacks = [ModelCheckpoint(filepath=best_model, verbose=0, save_best_only=True),
             EarlyStopping(monitor='val_acc', patience=3, verbose=0)]

base_model = ResNet50(input_shape=input_shape, weights='imagenet', include_top=False)

# first: train only the top layers (which were randomly initialized)
# i.e. freeze all convolutional ResNet50 layers
for layer in base_model.layers:
    layer.trainable = False

pool_layer = [layer for layer in base_model.layers if layer.name == 'avg_pool'][0]
base_model = Model(base_model.input, pool_layer.input)
base_model.layers.pop()

dropout=[.25,.25]
dense=1024
last = base_model.output
a = MaxPooling2D(pool_size=(7,7),name='maxpool')(last)
b = AveragePooling2D(pool_size=(7,7),name='avgpool')(last)
x = concatenate([a,b], axis = 1)
x = Flatten()(x)
x = Dense(dense, init='uniform', activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(dropout[0])(x)
x = Dense(classes, activation='softmax')(x)

model = Model(base_model.input, outputs=x)

print("Start time: %s" % str(datetime.now()))

# compile the model (should be done *after* setting layers to non-trainable)
model.compile(optimizer=SGD(lr=1e-2, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy'])

# train the model on the new data for a few epochs
model.fit_generator(
    train_generator,
    steps_per_epoch=n_of_train_samples//batch_size,
    epochs=3,
    validation_data=train_generator,
    validation_steps=n_of_train_samples//batch_size,
    callbacks=callbacks)

print("End time: %s" % str(datetime.now()))

培训结果如下

Found 14306 images belonging to 2000 classes.
Start time: 2018-05-21 10:51:34.459545
Epoch 1/3
510/510 [==============================] - 10459s 21s/step - loss: 5.6433 - acc: 0.1538 - val_loss: 9.8465 - val_acc: 0.0024
Epoch 2/3
510/510 [==============================] - 10258s 20s/step - loss: 1.3632 - acc: 0.8550 - val_loss: 10.3264 - val_acc: 0.0044
Epoch 3/3
510/510 [==============================] - 63640s 125s/step - loss: 0.2367 - acc: 0.9886 - val_loss: 10.4537 - val_acc: 0.0034
End time: 2018-05-22 10:17:42.028052

我们知道我们不应该使用相同的数据集进行训练和验证,但我们无法理解为什么当数据集对于两者都相同时,Keras在训练与验证的损失和准确性方面给出了很大差异培训和验证。

PS。我们尝试了相同的数据集,即2000个类,14000个图像作为训练集,5261个图像作为验证集,使用fast.ai库ResNet50,训练损失和验证损失差别不大。使用fast.ai库的代码和结果如下

from fastai.imports import *
from fastai.transforms import *
from fastai.conv_learner import *
from fastai.model import *
from fastai.dataset import *
from fastai.sgdr import *
from fastai.plots import *
from datetime import datetime

PATH = "data/"
sz=224
arch=resnet50
bs=28

tfms = tfms_from_model(arch, sz)
data = ImageClassifierData.from_paths(PATH, tfms=tfms, bs=bs)
learn = ConvLearner.pretrained(arch, data, precompute=False)

print("Start time: %s" % str(datetime.now()))
learn.fit(1e-2, 5)
print("End time: %s" % str(datetime.now()))

Start time: 2018-05-02 18:08:51.644750

  0%|          | 1/487 [00:14<2:00:00, 14.81s/it, loss=tensor(7.5704)]

[0.      6.13229 5.2504  0.26458]                                     
[1.      3.70098 2.74378 0.6752 ]                                     
[2.      1.80197 1.08414 0.88106]                                     
[3.      0.83221 0.50391 0.9424 ]                                     
[4.      0.45565 0.31056 0.95554]                                     

End time: 2018-05-03 00:27:13.147758

1 个答案:

答案 0 :(得分:2)

不是答案,而是建议查看每批不受影响的损失/指标:

def batchEnd(batch,logs):
    print("\nfinished batch " + str(batch) + ": " + str(logs) + "\n")

metricCallback = LambdaCallback(on_batch_end=batchEnd)

callbacks = [  metricCallback, 
               ModelCheckpoint(filepath=best_model, verbose=0, save_best_only=True),
               EarlyStopping(monitor='val_acc', patience=3, verbose=0)]

通过此操作,您将看到每个批次的指标,而不受其他批次的影响。 (假设Keras在显示纪元的指标时会进行某种平均/总计)。