Я установил модель Returnn Transformer для NMT, которую я хочу тренировать с дополнительной потерей для каждой точки внимания кодера / декодера h
на каждом слое декодера l
(в дополнение к ванильной потере перекрестной энтропии), т.е.:
loss = CrossEntropyLoss + sum_{Layer l=1,...,6} sum_{Head h=1,...,8} (lambda * AttentionLoss(l, h))
для некоторого скаляра lambda
. Я реализовал саму потерю внимания как eval
-уровень, используя опцию loss=as_is
, которая возвращает одно число для каждой партии (это значение lambda * AttentionLoss(l, h)
.
В качестве теста я также реализовал версию, в которой у меня есть одна потеря для каждого слоя l
, эквивалентная lambda * sum_{Head h=1,...,8} AttentionLoss(l, h)
, чтобы уменьшить количество потерь, поскольку я заметил снижение производительности и поскольку файлы журналов становились очень большими, поскольку Returnn печатает каждую потерю для каждой партии .
Однако я получил очень разные результаты для обеих реализаций: модель, обученная с одной потерей на слой И голова, работает стабильно лучше. Я пробовал это с несколькими запусками обучения.
Чтобы исследовать это, Я пробовал тренировочный прогон, в котором я установил параметр lambda=0.0
, то есть эффективно отключил потерю внимания. И даже здесь, по сравнению с базовой линией без каких-либо дополнительных потерь, модель, обученная с этими дополнительными 6 потерями, каждая из которых выводит константу 0, работает заметно. хуже, см. эту таблицу:
+--------------------------------------------+-------------+-------------+
| | Dev Set | Test Set |
+--------------------------------------------+------+------+------+------+
| | BLEU | TER | BLEU | TER |
+--------------------------------------------+------+------+------+------+
| Only Cross Entropy Loss | 35.7 | 51.4 | 34.2 | 53.5 |
+--------------------------------------------+------+------+------+------+
| + One loss per layer and head (lambda 0) | 35.5 | 51.5 | 33.9 | 53.7 |
+--------------------------------------------+------+------+------+------+
| + One loss per layer (lambda 0) | 35.4 | 51.8 | 33.5 | 54.2 |
+--------------------------------------------+------+------+------+------+
| + Simplified One loss per layer (lambda 0) | 35.1 | 52.0 | 33.5 | 54.3 |
+--------------------------------------------+------+------+------+------+
Здесь "упрощенное" ve rsion реализован именно так:
'dec_01_weight_loss': {
'class': 'eval', 'eval': '0.0 * tf.reduce_sum(source(0, auto_convert=False))',
'from': ['dec_01_att_weights'], 'loss': 'as_is',
'out_type': { 'batch_dim_axis': None, 'dim': None, 'dtype': 'float32', 'feature_dim_axis': None,
'shape': (), 'time_dim_axis': None}}
, хотя фактические потери, которые я использую, немного сложнее, я загрузил сюда свои полные файлы конфигурации. (Здесь уровень потерь называется dec_01_att_weight_variance
et c.)
И все lambda=0.0
упомянутые выше реализации выводят значение 0.0
для всех дополнительных потерь на каждом шаге обучения:
train epoch 1, step 0, cost:output/dec_01_weight_loss 0.0, cost:output/dec_02_weight_loss 0.0, cost:output/dec_03_weight_loss 0.0, [....], cost:output/output_prob 8.541749455164052, error:decision 0.0, error:output/output_prob 0.9999999680730979, loss 8.5417 49, max_mem_usage:GPU:0 1.2GB, mem_usage:GPU:0 1.2GB, 3.999 sec/step, elapsed 0:00:38, exp. remaining 1:30:00, complete 0.71%
Что происходит Вот? Есть ли какое-либо объяснение, почему модели ведут себя по-разному, почему дополнительная потеря с постоянным значением 0.0
меняет поведение модели?
Я использую TF 1.15.0 (v1.15.0-0-g590d6eef7e), Returnn 20200613.152716 - git -23332ca, используя Python 3.8.0 с CUDA 10.1.
Последующее обновление : я протестировал ту же конфигурацию, используя предварительное обучение, где я полностью отключил бы свою потерю для первых n-1
(здесь, например, n=50
) контрольных точек, используя следующий код:
def custom_construction_algo(idx, net_dict):
if idx == 0:
for lay in range(1, 7):
del net_dict["output"]["unit"]["dec_%02i_att_loss" % lay]
return net_dict
else:
return None
pretrain = {"repetitions": 49, "construction_algo": custom_construction_algo}
В файле журнала для первых n-1
контрольных точек я (правильно) вижу только отчет о потере CE.
Здесь я показываю свой Dev BLEU на последней контрольной точке, обученной без дополнительная потеря (например, n-1
, здесь 49
), каждый эксперимент запускается несколько раз:
- Базовый уровень (без дополнительных потерь): 31,8, 31,7, 31,7 BLEU
- Один потери на слой, отключенные с предварительным обучением: 29,2, 29,0, 28,5 BLEU
- Одна потеря на слой с
lambda=0.0
(как в исходном вопросе): 28,8, 28,7 BLEU - Одна потеря на слой И голова с
lambda=0.0
(как в исходном вопросе): 31,8 BLEU
Насколько я понимаю, график TF для конфигурации перед обучением и базовый уровень должны быть идентичны до контрольной точки n=50
. Однако они действуют по-разному. Что происходит?
Полную конфигурацию, которую я использовал для такого рода предварительной тренировки, можно найти здесь . Заголовки соответствующих файлов журнала находятся здесь . Я использую NewbobMultiEpoch с Адамом:
learning rate control: NewbobMultiEpoch(num_epochs=9, update_interval=1, relative_error_threshold=0, learning_rate_decay_factor=0.7, learning_rate_growth_factor=1.0), epoch data: , error key: None
Create optimizer <class 'tensorflow.python.training.adam.AdamOptimizer'> with options {'beta1': 0.9, 'beta2': 0.999, 'epsilon': 1e-08, 'learning_rate': <tf.Variable 'learning_rate:0' shape=() dtype=float32_ref>}.
Для всех описанных экспериментов скорость обучения не снижается до тех пор, пока контрольные точки не превышают 100, оставаясь неизменной на начальном уровне 10^-4
.
РЕДАКТИРОВАТЬ: Я сделал ошибку и случайно использовал другую версию Returnn в своих экспериментах . Returnn, который я использовал для своих экспериментов с дополнительными потерями, похоже, содержал некоторые локальные изменения, которые я сделал. При повторном запуске базовой линии с новой версией он работал значительно хуже - очень похож на другие значения BLEU, описанные здесь. Небольшая ошибка в одной из моих версий Returnn - вот и все, что касалось этой проблемы.