Значительная разница в производительности для model.fit () при использовании одного и того же набора обучающих данных в данных проверки. - PullRequest
0 голосов
/ 19 июня 2020

В настоящее время я работаю над простой проблемой классификации, используя средство извлечения признаков и классификатор. Для экстрактора функций я использую предварительно обученную модель ResNet50, найденную в tf.keras.application в TF 1.15.2 . Я провожу двухэтапное обучение, на котором я обучаю экстрактор признаков на первом этапе (здесь нет проблем) и обучаю классификатор на втором этапе, где я замораживаю обученный экстрактор признаков (проблемы здесь). Я использую размер пакета 128 и скорость обучения 0,3 для обучения классификатора. У меня возникли проблемы с производительностью фактического набора для проверки, поэтому я проверяю производительность обучающего набора, чтобы лучше понять, в чем проблема с моим кодом.

Вот мой код для загрузки набора данных

def make_generator(images, labels):
    def _generator():
        for image, label in zip(images, labels):
            yield image, np.array(label)
    return _generator

def create_dataset(dataset_dict, shuffle=False):
    images = []
    labels = []
    buffer_size = 0
    for k,v in dataset_dict.items():
        images += v
        labels += [k for _ in v]
        buffer_size += len(v)   
    dataset = tf.data.Dataset.from_generator(make_generator(images, labels),
              (tf.float32, tf.uint8), output_shapes=(tf.TensorShape([HEIGHT,WIDTH,DEPTH]), tf.TensorShape([])))
    if shuffle:
        dataset = dataset.shuffle(buffer_size, reshuffle_each_iteration=True)
    dataset = dataset.batch(batch_size, drop_remainder=True) \
                        .prefetch(10)

    return dataset

где dataset_dict - это словарь, содержащий {label: <preprocessed images from class>}

train_dataset = create_dataset(base_train_dict, shuffle=True)

Создать модель

def get_feature_extractor(pretrained=True):
    if pretrained:
        weights = 'imagenet'
    feat_extractor = tf.keras.applications.ResNet50(
            input_shape=(HEIGHT, WIDTH, DEPTH),
            include_top=False,
            layers=tf.keras.layers,
            pooling='avg',
            weights=weights)
    for layer in feat_extractor.layers[:25]:
        layer.trainable = False

    return feat_extractor

model_input = tf.keras.Input(shape=(HEIGHT, WIDTH, DEPTH), name='input')
feat_extractor = get_feature_extractor()
.
.
.
# feat_extractor is trained in first stage
output = feat_extractor(model.inputs)
output = Dense(num_classes, 'softmax')(output)
model = tf.keras.Model(model.inputs, output)

# freeze layers before classification layer
for layer in model.layers[:-1]:
    layer.trainable = False

Определить метрики

loss = 'sparse_categorical_crossentropy'

if optimizer == 'SGD':
    opt = SGD(lr=learning_rate, momentum=momentum, clipnorm=5)
else:
    opt = Adam(lr=learning_rate, decay=weight_decay, clipnorm=5)

def sparse_top_3_categorical_accuracy(y_true, y_pred):
    return sparse_top_k_categorical_accuracy(y_true, y_pred, k=3)

metrics = ['sparse_categorical_accuracy', sparse_top_3_categorical_accuracy]

model.compile(loss=loss, optimizer=opt, metrics=metrics)
def scheduler(epoch, restart=50):
    if epoch % restart == 0:
        return learning_rate
    else:
        return learning_rate * (0.999 ** (epoch % restart))

monitor = 'val_sparse_categorical_accuracy'
callbacks = []
callbacks.append(
    ModelCheckpoint('output/local_base_class.h5', monitor=monitor,
                    save_best_only=True,
                    mode='max'))
# callbacks.append(CustomTensorBoardCallback(log_dir=tensorboard_dir))
#     callbacks.append(ReduceLROnPlateau(monitor='sparse_categorical_accuracy', patience=8, verbose=1))
callbacks.append(TerminateOnNaN())
callbacks.append(CSVLogger(f'classifier_base_{datetime.now()}.log'))
callbacks.append(LearningRateScheduler(scheduler))
epochs = 10
logging.info("Starting classifier training")
history = model.fit(train_dataset,
                    epochs=epochs,
                    validation_data=train_dataset,
                    callbacks=callbacks,
                    verbose=2)

Я столкнулся со специфической проблемой получения совершенно разных результатов для моего вызова model.fit(), и я подозреваю, что это связано с уровнем BatchNormalization Layer, найденным в ResNet50.

Epoch 10/10
82/82 - 22s - loss: 5.5539 - sparse_categorical_accuracy: 0.5319 - sparse_top_3_categorical_accuracy: 0.6624 - val_loss: 74.7229 - val_sparse_categorical_accuracy: 0.0033 - val_sparse_top_3_categorical_accuracy: 0.0109

Затем я сделал оценку

model.evaluate(train_dataset)
82/82 [==============================] - 10s 125ms/step - loss: 74.7229 - sparse_categorical_accuracy: 0.0033 - sparse_top_3_categorical_accuracy: 0.0109

Итак, я попытался исправить, выполнив

from tensorflow.keras import backend as K
from tensorflow.keras.models import load_model
dependencies = {
    'sparse_top_3_categorical_accuracy': sparse_top_3_categorical_accuracy
}
K.clear_session()
K.set_learning_phase(1)
model = load_model('tmp.h5', custom_objects=dependencies)

Но я получил тот же результат

model.evaluate(train_dataset)
82/82 [==============================] - 11s 135ms/step - loss: 74.7229 - sparse_categorical_accuracy: 0.0033 - sparse_top_3_categorical_accuracy: 0.0109

Как исправить эту проблему, чтобы получить почти такой же уровень производительности для model.fit() для того же набора данных или такую ​​же производительность для model.evaluate?

...