def train(self,
            *,
            epochs = None,
            steps_per_epoch = None,
            validation_steps = None):
    """Prepare the dataset, callbacks, and model, then train/save it.

    Args:
      epochs: The number of epochs to train for, if None then default to
        early stopping (useful for debugging)
      steps_per_epoch: How many training steps to take, if None default to
        normal training (useful for debugging)
      validation_steps: How many validation steps to take, if None defualt to
        normal training (useful for debugging)
    """
    logging.info('Preparing model with config:\n%s', self._model_config)
    with util.log_time('Initial dataset read'):
      builder = fever_tfds.FeverEvidence(
          data_dir=self._model_config.dataset,
          n_similar_negatives=self._model_config.n_similar_negatives,
          n_background_negatives=self._model_config.n_background_negatives,
          train_scrape_type=self._model_config.scrape_type,
          include_not_enough_info=self._model_config.include_not_enough_info,
          title_in_scoring=self._model_config.title_in_scoring,
      )
      # Cache here to prevent hitting remote fs again
      train_dataset = (builder.as_dataset(split='train')).cache()
    val_dataset = builder.as_dataset(split='validation').cache()
    if self._debug:
      train_dataset = train_dataset.take(1000)
    if self._debug:
      val_dataset = val_dataset.take(200)

    self._tokenizer = self._build_tokenizer()
    self._vocab = list(self._build_vocab(train_dataset))
    self._encoder = self._build_encoder(self._vocab, self._tokenizer)

    train_batched = self._encode_and_batch(train_dataset, train=True)
    val_batched = self._encode_and_batch(val_dataset, train=False)
    # Cache the batch creation, but not the batchwise shuffle.
    train_batched = train_batched.cache().shuffle(
        100,
        reshuffle_each_iteration=True).prefetch(tf.data.experimental.AUTOTUNE)
    # Cache the batched validation data.
    val_batched = val_batched.cache().prefetch(tf.data.experimental.AUTOTUNE)
    self._compile()
    model_callbacks = self._build_callbacks(val_batched)
    # Save enough to reconstruct anything except for the model.
    # The model itself is saved with the ModelCheckpoint callback.
    self._save_model_config()
    self._save_encoder()
    if epochs is None:
      epochs = self._model_config.max_epochs

    if self._model is None:
      raise ValueError('Model is not initialized.')
    self._model.fit(
        train_batched,
        validation_data=val_batched,
        callbacks=model_callbacks,
        epochs=epochs,
        steps_per_epoch=steps_per_epoch,
        validation_steps=validation_steps)
    logging.info('Model Summary:\n%s', self._model.summary())
    # First load the best model.
    logging.info('Loading best model weights')
    self._model.load_weights(self.model_weight_path)
    logging.info('Saving dev predictions from best model')
    self._save_dev_predictions(val_batched)
Prepare the dataset, callbacks, and model, then train/save it.

    Args:
      epochs: The number of epochs to train for, if None then default to
        early stopping (useful for debugging)
      steps_per_epoch: How many training steps to take, if None default to
        normal training (useful for debugging)
      validation_steps: How many validation steps to take, if None defualt to
        normal training (useful for debugging)
    
language/serene/training.py