Denoising Objectives › Training with Denoising Objectives

Michael BrenndoerferUpdated July 14, 20255 min read
Language AI HandbookAll chapters
Part 22 of 67Pre-training Objectives
Chapter 161Denoising Objectives › Training with Denoising Objectives
Reading section 11 of 15 · Training with Denoising Objectives · 5 minSection 11 of 15 · 5 min

Book contents

Section 11 of 15 · 5 min read

Denoising Objectives › Training with Denoising ObjectivesOne section · Sections in this chapter11 / 15 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Training a denoising model requires carefully balancing the encoder and decoder. The encoder must build useful representations from corrupted input. The decoder must learn to generate coherent text conditioned on those representations.

The training setup is conceptually simple but hides important implementation details. On the encoder side, the corrupted sequence is padded to a fixed length and processed with full bidirectional attention, so every token can attend to every other token. The encoder produces a sequence of hidden states, one per input token, that capture contextual information about the corrupted document. On the decoder side, training uses teacher forcing: the decoder receives the ground-truth target tokens as input at each step and is trained to predict the next token. At inference time, teacher forcing is replaced by autoregressive generation, where each predicted token is fed back as input to predict the next one.

In[36]:
Code
class DenoisingTrainer:
    """
    Training loop for denoising language models.

    Handles batching, corruption, and loss computation.
    """

    def __init__(self, model, tokenizer, corruptor, learning_rate=1e-4):
        self.model = model
        self.tokenizer = tokenizer
        self.corruptor = corruptor
        self.optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate)

    def prepare_batch(self, texts):
        """
        Prepare a batch for training.

        Args:
            texts: List of text strings

        Returns:
            dict with encoder_input, decoder_input, labels tensors
        """
        batch_encoder = []
        batch_decoder = []
        batch_labels = []

        for text in texts:
            tokens = text.split()
            result = self.corruptor.corrupt(tokens)

            # Corrupted text goes to encoder
            encoder_tokens = result["input"]
            # Original text is the target for decoder
            target_tokens = result["target"]

            batch_encoder.append(" ".join(encoder_tokens))
            batch_decoder.append(" ".join(target_tokens))
            batch_labels.append(" ".join(target_tokens))

        return {
            "encoder_texts": batch_encoder,
            "decoder_texts": batch_decoder,
            "target_texts": batch_labels,
        }

    def compute_loss(self, encoder_input, decoder_input, labels):
        """
        Compute cross-entropy loss on target tokens.

        This is a placeholder showing the structure.
        Real implementation would use model forward pass.
        """
        # In practice:
        # outputs = self.model(encoder_input, decoder_input)
        # loss = F.cross_entropy(outputs.logits, labels)
        pass

The training loop follows a straightforward sequence-to-sequence pattern:

  1. Sample a batch of documents from the training corpus
  2. Apply corruption (text infilling and sentence permutation)
  3. Pass corrupted input through the encoder
  4. Generate the original text with the decoder using teacher forcing
  5. Compute cross-entropy loss on target tokens
  6. Backpropagate gradients and update parameters

The training objective is standard sequence-to-sequence cross-entropy. The difference from other seq2seq tasks lies entirely in how the training pairs are constructed: the corrupted input is the source, and the original text is the target. This means you can use any standard seq2seq training infrastructure (Hugging Face Seq2SeqTrainer, for instance) and simply provide corrupted-original pairs as your dataset. The denoising is entirely a data preprocessing concern, not an architectural one.

Hyperparameter Considerations

Key hyperparameters for denoising pretraining include:

  • Mask probability (default: 30% for BART): Higher than BERT's 15% because infilling is more efficient. Each mask token can represent multiple original tokens.

  • Mean span length (default: 3): Balances short spans (token-level learning) with longer spans (phrase-level learning). Span lengths follow a geometric distribution with parameter p=1/3p = 1/3, producing a mean of 3 tokens. Most spans are short (1-2 tokens), with occasional longer spans.

Out[37]:
Visualization
Dual-axis line plot showing training signal increasing and encoder context decreasing as mask probability increases from 10% to 50%.
Trade-off between mask probability and training dynamics for a 512-token sequence. Higher mask probabilities provide more training signal (more tokens to reconstruct) but also reduce encoder context. The 30% rate used by BART provides substantial signal while preserving 70% of context for the encoder, striking a balance between learning pressure and reconstruction feasibility.
  • Sentence permutation probability: BART applies permutation to all documents. Some variants skip permutation for single-sentence inputs.

  • Learning rate: Standard transformer learning rates (1e-4 to 5e-4) with warmup work well.

  • Batch size: Large batches (2048+ tokens per GPU) help with the noisy gradients from aggressive corruption.