не может воспроизвести model.fit с GradientTape - PullRequest
1 голос
/ 07 марта 2020

Я пытался выяснить причину (например, путем проверки весов, градиентов и активаций во время обучения), почему SGD со скоростью обучения 0,001 работал на тренировке, в то время как Адам не смог этого сделать. (Пожалуйста, смотрите мой предыдущий пост [здесь] ( Почему моя потеря (двоичная перекрестная энтропия) сходится на ~ 0,6? (Задача: Вывод на естественном языке)"Почему моя потеря (двоичная перекрестная энтропия) сходится на ~ 0.6? (Задача: Вывод естественного языка) "))

Примечание: я также использую ту же модель из моего предыдущего поста.


с использованием tf. keras , я обучил нейронную сеть, используя model.fit():

model.compile(optimizer=SGD(learning_rate=0.001),
            loss='binary_crossentropy',
            metrics=['accuracy'])

model.fit(x=ds,
        epoch=80,
        validation_data=ds_val)

Это привело к тому, что потеря эпохи была представлена ​​ниже, в 1-й эпохе она достигла потери поезда на 0,46, а затем, в конечном итоге, привела к train_loss = 0,1241 и val_loss = 0,2849.

model.fit sgd(0.001) success

Я бы использовал tf.keras.callbacks.Tensorboard(histogram_freq=1) для обучения сети с SGD (0,001) и Адамом исследовать, но он выдает InvalidArgumentError в Variable: 0, что я не могу расшифровать. Поэтому я попытался написать собственный тренинг l oop, используя GradientTape и нанести на график значения.


, используя tf.GradientTape () , я попытался воспроизвести результаты, используя точное та же модель и набор данных, однако потери эпохи тренируются невероятно медленно, достигая потери поездов 0,676 после 15 эпох (см. график ниже), что-то не так с моей реализацией? (код ниже)

GradientTape sgd(0.001) fails

@tf.function
def compute_grads(train_batch: Dict[str,tf.Tensor], target_batch: tf.Tensor, 
                 loss_fn: Loss, model: tf.keras.Model):
    with tf.GradientTape(persistent=False) as tape:
        # forward pass
        outputs = model(train_batch)
        # calculate loss
        loss = loss_fn(y_true=target_batch, y_pred=outputs)

    # calculate gradients for each param
    grads = tape.gradient(loss, model.trainable_variables)
    return grads, loss

BATCH_SIZE = 8
EPOCHS = 15

bce = BinaryCrossentropy()
optimizer = SGD(learning_rate=0.001)

for epoch in tqdm(range(EPOCHS), desc='epoch'):
    # - accumulators
    epoch_loss = 0.0

    for (i, (train_batch, target_dict)) in tqdm(enumerate(ds_train.shuffle(1024).batch(BATCH_SIZE)), desc='step'):

        (grads, loss) = compute_grads(train_batch, target_dict['target'], bce, model)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))

        epoch_loss += loss

    avg_epoch_loss = epoch_loss/(i+1)
    tensorboard_scalar(writer, name='epoch_loss', data=avg_epoch_loss, step=epoch)  # custom helper function
    print("Epoch {}: epoch_loss = {}".format(epoch, avg_epoch_loss))

Заранее спасибо!

1 Ответ

0 голосов
/ 18 марта 2020

Проверьте, если вы перетасовали свой набор данных, то проблема может быть связана с перестановкой, используя метод tf.Dataset . Он только перетасовал через набор данных одно ведро за раз. Использование Keras.Model.fit дало лучшие результаты, потому что, вероятно, добавляет еще одну перемешивание. Добавление тасования с numpy.random.shuffle может улучшить тренировочные показатели. Из этой ссылки.

Пример применения этого в генерации набора данных:

numpy_data = np.hstack([index_rows.reshape(-1, 1), index_cols.reshape(-1, 1), index_data.reshape(-1, 1)])

np.random.shuffle(numpy_data)

indexes = np.array(numpy_data[:, :2], dtype=np.uint32)
labels = np.array(numpy_data[:, 2].reshape(-1, 1), dtype=np.float32)

train_ds = data.Dataset.from_tensor_slices(
    (indexes, labels)
).shuffle(100000).batch(batch_size, drop_remainder=True)

Если это не сработает, вам может понадобиться использовать Набор данных .repeat(epochs_number) and .shuffle(..., reshuffle_each_iteration=True):

train_ds = data.Dataset.from_tensor_slices(
    (np.hstack([index_rows.reshape(-1, 1), index_cols.reshape(-1, 1)]), index_data)
    ).shuffle(100000, reshuffle_each_iteration=True
    ).batch(batch_size, drop_remainder=True
    ).repeat(epochs_number)

for ix, (examples, labels) in train_ds.enumerate():
    train_step(examples, labels)
    current_epoch = ix // (len(index_data) // batch_size)

Этот обходной путь не красив и не естественен, на данный момент вы можете использовать его, чтобы перетасовать каждую эпоху. Это известная проблема, которая будет устранена, в будущем вы можете использовать for epoch in range(epochs_number) вместо .repeat()

Решение, предоставленное здесь , также может помочь. Вы можете проверить это.

Если это не так, вы можете ускорить TF2.0 GradientTape . Это может быть решением: TensorFlow 2.0 вводит концепцию функций , которые переводят нетерпеливый код в графовый код.

Использование довольно простое. Единственное необходимое изменение - все соответствующие функции (like compute_loss и apply_gradients) должны быть помечены @tf.function.

...