docs: def _training(self):
      """Perform multiple training iterations of both policy and value baseline.
  
      Training on the episodes collected in the memory. Reset the memory
      afterwards. Always returns a summary string.
  
      Returns:
        Summary tensor.
      """
      with tf.device('/gpu:0' if self._use_gpu else '/cpu:0'):
        with tf.name_scope('training'):
          assert_full = tf.assert_equal(
              self._num_finished_episodes, self._config.update_every)
          with tf.control_dependencies([assert_full]):
            data = self._finished_episodes.data()
          (observ, action, old_policy_params, reward), length = data
          # We set padding frames of the parameters to ones to prevent Gaussians
          # with zero variance. This would result in an infinite KL divergence,
          # which, even if masked out, would result in NaN gradients.
          old_policy_params = tools.nested.map(
              lambda param: self._mask(param, length, 1), old_policy_params)
          with tf.control_dependencies([tf.assert_greater(length, 0)]):
            length = tf.identity(length)
          observ = self._observ_filter.transform(observ)
          reward = self._reward_filter.transform(reward)
          update_summary = self._perform_update_steps(
              observ, action, old_policy_params, reward, length)
          with tf.control_dependencies([update_summary]):
            penalty_summary = self._adjust_penalty(
                observ, old_policy_params, length)
          with tf.control_dependencies([penalty_summary]):
            clear_memory = tf.group(
                self._finished_episodes.clear(),
                self._num_finished_episodes.assign(0))
          with tf.control_dependencies([clear_memory]):
            weight_summary = utility.variable_summaries(
                tf.trainable_variables(), self._config.weight_summaries)
            return tf.summary.merge([
                update_summary, penalty_summary, weight_summary])