Span Corruption › T5-Style Training

Michael BrenndoerferUpdated July 11, 20257 min read
Language AI HandbookAll chapters
Part 22 of 67Pre-training Objectives
Chapter 158Span Corruption › T5-Style Training
Reading section 7 of 14 · T5-Style Training · 7 minSection 7 of 14 · 7 min

Book contents

Section 7 of 14 · 7 min read

Span Corruption › T5-Style TrainingOne section · Sections in this chapter7 / 14 ↓
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

T5 uses span corruption within an encoder-decoder framework. The corrupted input feeds into the encoder, while the decoder autoregressively generates the target sequence. This setup naturally handles variable-length span reconstruction.

Encoder-Decoder Architecture

The encoder processes the corrupted input sequence, producing hidden representations that capture the context around each sentinel:

Henc=Encoder(x1,…,<extra_id_0>,…,xn)H_{\text{enc}} = \text{Encoder}(x_1, \ldots, \text{<extra\_id\_0>}, \ldots, x_n)

where:

  • HencH_{\text{enc}}: the encoder's output hidden states, a matrix of shape (sequence length ×\times hidden dimension)
  • x1,…,xnx_1, \ldots, x_n: the corrupted input tokens, including uncorrupted tokens and sentinel placeholders
  • <extra_id_0>\text{<extra\_id\_0>}: a sentinel token marking where a span was removed

The encoder uses full bidirectional self-attention: every token can attend to every other token. This means the representation at the <extra_id_0> position has access to all the surrounding context, both the tokens that appear before the sentinel and those that appear after. This bidirectional view is a significant advantage over causal decoder-only models, which can only see leftward context. When predicting what phrase fills a gap, the context to the right of the gap is often just as informative as the context to the left, and the encoder captures both.

The decoder then generates the target sequence autoregressively, conditioned on the encoder's hidden states:

P(yt∣y<t,Henc)=Decoder(y<t,Henc)P(y_t \mid y_{<t}, H_{\text{enc}}) = \text{Decoder}(y_{<t}, H_{\text{enc}})

where:

  • yty_t: the token being predicted at position tt in the target sequence
  • y<ty_{<t}: all previously generated target tokens (y1,y2,…,yt−1)(y_1, y_2, \ldots, y_{t-1})
  • P(yt∣y<t,Henc)P(y_t \mid y_{<t}, H_{\text{enc}}): the probability distribution over the vocabulary for the next token

During training, we use teacher forcing: the decoder receives the true previous tokens rather than its own predictions. Teacher forcing is important for span corruption because the target sequence can be quite long (dozens of tokens across multiple spans), and sampling from the model's own distributions during training would introduce compounding errors that would destabilize learning. By feeding the ground-truth tokens at each decoder step, the model receives clean, unambiguous gradient signal throughout the target sequence.

The training objective is standard cross-entropy loss over the target sequence:

L=−∑t=1Tlog⁡P(yt∣y<t,Henc)\mathcal{L} = -\sum_{t=1}^{T} \log P(y_t \mid y_{<t}, H_{\text{enc}})

where:

  • L\mathcal{L}: the total loss for this training example
  • TT: the length of the target sequence
  • log⁡P(yt∣⋅)\log P(y_t \mid \cdot): the log probability assigned to the correct token at each position

This loss encourages the model to assign high probability to the actual tokens that were corrupted, learning to reconstruct spans from context. Because the target includes both sentinel tokens and the actual span content, the model learns two things simultaneously: when to begin generating a new span (at sentinel boundaries) and what content to generate within each span.

Why Encoder-Decoder?

Span corruption works well with encoder-decoder models for several interconnected reasons.

Bidirectional encoding is perhaps the most important. The encoder sees all uncorrupted context simultaneously, enabling rich representations of what surrounds each sentinel. Unlike a causal language model that can only look left, the encoder integrates both left and right context at every position, producing representations that carry far more information about the missing span. For named entity recognition, for instance, the context to the right of a person's name can be just as disambiguating as the context to the left.

Autoregressive decoding complements this by enabling the model to generate spans of variable length coherently. The decoder generates spans token by token, learning proper phrase structure and coherence within each span. Because each generated token conditions on all previous tokens in the target, the decoder naturally models intra-span dependencies: the second word of a phrase is influenced by the first, the third by both, and so on.

Natural length handling emerges from this architecture without any special design. Spans of different lengths produce targets of different lengths, which encoder-decoder models handle gracefully through their sequence-to-sequence framing. A decoder-only model using span corruption as a fill-in-the-blank task would need to know in advance how many tokens to generate for each gap, which is not available during inference.

Decoder-only models can also use span corruption, treating the task as infilling. The corrupted input and target concatenate with appropriate separators, and the model learns to continue after each sentinel. Some newer models like FIM (Fill in the Middle) explore exactly this setting. The trade-off is that decoder-only models must still predict a fixed-length span or use special boundary tokens, whereas the encoder-decoder design handles this naturally through its two-part architecture.

Comparison to MLM

Let's compare the training signals from span corruption versus token-level MLM:

In[18]:
Code
def mlm_mask(tokens, mask_rate=0.15, mask_token="[MASK]"):
    """Apply standard MLM masking (token-level, not spans)."""
    mask = np.random.random(len(tokens)) < mask_rate
    masked_tokens = [mask_token if m else t for t, m in zip(tokens, mask)]
    targets = [(i, t) for i, (t, m) in enumerate(zip(tokens, mask)) if m]
    return masked_tokens, targets


def compare_corruption_methods(text, seed=42):
    """Compare span corruption vs MLM on the same text."""
    tokens = text.split()

    # MLM
    np.random.seed(seed)
    mlm_input, mlm_targets = mlm_mask(tokens)

    # Span corruption
    np.random.seed(seed)
    span_result = SpanCorruptor().corrupt(tokens)

    return {
        "original": tokens,
        "mlm_input": mlm_input,
        "mlm_targets": mlm_targets,
        "span_input": span_result["input"],
        "span_target": span_result["target"],
    }
In[19]:
Code
sample_text = """The transformer architecture revolutionized natural language
processing by enabling parallel computation and capturing long range dependencies
through self attention mechanisms"""

comparison = compare_corruption_methods(sample_text)
Out[20]:
Console
=== Original ===
The transformer architecture revolutionized natural language processing by enabling parallel computation and capturing long range dependencies through self attention mechanisms

=== MLM (2 masks) ===
The transformer architecture revolutionized natural language [MASK] by enabling parallel [MASK] and capturing long range dependencies through self attention mechanisms
Targets: [(6, 'processing'), (10, 'computation')]

=== Span Corruption (19 input tokens) ===
The transformer architecture revolutionized natural language processing by enabling parallel computation and capturing long <extra_id_0> through self attention mechanisms
Target: <extra_id_0> range dependencies

With MLM, each mask corresponds to exactly one token. With span corruption, each sentinel may require generating multiple tokens, forcing the model to learn phrase-level coherence.

The difference becomes clearer when we visualize the corruption patterns side by side. Let's create multiple samples and compare how MLM scatters masks across the sequence while span corruption creates contiguous blocks.

In[21]:
Code
def visualize_corruption_patterns(seq_length=60, num_samples=8, seed=42):
    """Generate corruption patterns for visualization."""
    np.random.seed(seed)

    mlm_patterns = []
    span_patterns = []

    for i in range(num_samples):
        # MLM: independent token masking
        mlm_mask = np.random.random(seq_length) < 0.15
        mlm_patterns.append(mlm_mask)

        # Span corruption
        span_mask = select_corruption_mask(
            seq_length, corruption_rate=0.15, mean_span_length=3
        )
        span_patterns.append(span_mask)

    return np.array(mlm_patterns), np.array(span_patterns)


mlm_patterns, span_patterns = visualize_corruption_patterns()
Out[22]:
Visualization
Heatmap showing scattered corruption patterns for MLM across 8 samples.
MLM produces scattered, isolated masks where each dark cell is an independent prediction task. The salt-and-pepper pattern reflects the independent per-token sampling that underlies BERT-style training.
Heatmap showing contiguous block corruption patterns for span corruption across 8 samples.
Span corruption creates contiguous blocks of corruption that must be reconstructed together. Each horizontal streak represents a multi-token span that the model must generate as a coherent phrase.

The visual contrast is clear. MLM produces a scattered, salt-and-pepper pattern where each dark cell is an isolated prediction task. Span corruption creates horizontal streaks, each representing a multi-token reconstruction challenge. This structural difference explains why span-corrupted models develop stronger phrase-level generation capabilities.