Где именно потери KL используются после прямого прохода? - PullRequest
1 голос
/ 20 апреля 2020

Я заметил, что KL часть потери добавляется в список self._losses Layer класса , когда self.add_loss вызывается из call метода из DenseVariational (т.е. во время прямого прохода).

Но как этот список self._losses (или метод losses из того же Layer класса) обрабатывается во время тренировки? Откуда это вызывается во время тренировки? Например, они суммируются или усредняются перед добавлением их к окончательному проигрышу? Я хотел бы ВИДЕТЬ ФАКТИЧЕСКИЙ КОД.

Я хотел бы знать, как именно эти потери сочетаются с потерями, указанными в методе fit. Можете ли вы предоставить мне код, который объединяет их? Обратите внимание, что меня интересует Keras, поставляемый с TensorFlow (потому что я использую его).

1 Ответ

1 голос
/ 22 апреля 2020

На самом деле, часть, где вычисляется общий убыток, находится в методе compile класса Model, в частности, в этой строке :

    # Compute total loss.
    # Used to keep track of the total loss value (stateless).
    # eg., total_loss = loss_weight_1 * output_1_loss_fn(...) +
    #                   loss_weight_2 * output_2_loss_fn(...) +
    #                   layer losses.
    self.total_loss = self._prepare_total_loss(masks)

Метод _prepare_total_loss добавляет регуляризацию и потери слоя к общим потерям (т. е. все потери суммируются вместе), а затем усредняет их по оси пакета в эти строки :

        # Add regularization penalties and other layer-specific losses.
        for loss_tensor in self.losses:
            total_loss += loss_tensor

    return K.mean(total_loss)

На самом деле, self.losses не является атрибутом класса Model; скорее это атрибут родительского класса , то есть Network, который возвращает все потери уровня c в виде списка. Кроме того, чтобы устранить любую путаницу, total_loss в приведенном выше коде - это единственный тензор, который равен суммированию всех потерь в модели (т. Е. Значений функции потерь и потерь, определяемых уровнем c) ). Обратите внимание, что функции потерь по определению должны возвращать одно значение потерь для каждой входной выборки (а не всей партии). Следовательно, K.mean(total_loss) будет усреднять все эти значения по оси пакета до одного конечного значения потерь, которое должно быть минимизировано оптимизатором.


Что касается tf.keras, то оно более или менее совпадает с собственным. keras; однако структуры и поток вещей немного отличаются, что объясняется ниже.

Во-первых, в compile методе Model класса создается контейнер потерь , который содержит и вычисляет значение функций потерь:

  self.compiled_loss = compile_utils.LossesContainer(
      loss, loss_weights, output_names=self.output_names)

Далее, в train_step методе класса Model этот контейнер вызывается для вычисления значения потери партии:

  loss = self.compiled_loss(
      y, y_pred, sample_weight, regularization_losses=self.losses)

Как вы можете видеть выше, self.losses передается в этот контейнер. self.losses, как и в собственной реализации Keras, содержит все значения потерь, определяемые слоем c, с той лишь разницей, что в tf.keras он реализован в Layer классе (вместо Network класс как у родного кераса). Обратите внимание, что Model является подклассом Network, который сам является подклассом Layer. Теперь давайте посмотрим, как будет обрабатываться regularization_losses в методе __call__ LossesContainer ( эти строки ):

  if (loss_obj.reduction == losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE or
      loss_obj.reduction == losses_utils.ReductionV2.AUTO):
    loss_value = losses_utils.scale_loss_for_distribution(loss_value)


  loss_values.append(loss_value)
  loss_metric_values.append(loss_metric_value)


if regularization_losses:
  regularization_losses = losses_utils.cast_losses_to_common_dtype(
      regularization_losses)
  reg_loss = math_ops.add_n(regularization_losses)
  loss_metric_values.append(reg_loss)
  loss_values.append(losses_utils.scale_loss_for_distribution(reg_loss))


if loss_values:
  loss_metric_values = losses_utils.cast_losses_to_common_dtype(
      loss_metric_values)
  total_loss_metric_value = math_ops.add_n(loss_metric_values)
  self._loss_metric.update_state(
      total_loss_metric_value, sample_weight=batch_dim)


  loss_values = losses_utils.cast_losses_to_common_dtype(loss_values)
  total_loss = math_ops.add_n(loss_values)
  return total_loss

Как вы можете видеть, regularization_losses будет быть добавлен к total_loss, который будет содержать сумму специфичных для слоя c потерь и сумму среднего значения всех функций потерь по оси пакета (следовательно, это будет одно значение).

...