BART Pre-training › Text Infilling
Language AI HandbookAll chapters BART Pre-training › Text InfillingOne section · Sections in this chapter5 / 16 ↓
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
Text infilling is BART's most important corruption scheme and the one that proved most effective in experiments. Instead of corrupting individual tokens, we corrupt contiguous spans of varying lengths. Critically, each span is replaced with a single mask token regardless of how many tokens it originally contained. This creates a challenging reconstruction task that teaches the model key skills for generation: predicting what content is missing and how much content is missing.
How It Works
The infilling process has two steps that together create spans of varying lengths positioned throughout the document:
-
Sample span lengths: Draw span lengths from a Poisson distribution with parameter (typically ). This creates spans of varying sizes: many single-token spans, some two-token spans, fewer three-token spans, and so on. The Poisson distribution provides a natural way to generate this variety with a single parameter controlling the expected length.
-
Sample span positions: Randomly select starting positions for spans until approximately of the total tokens are covered by spans. The sampling continues until the target corruption level is reached. This keeps consistent corruption intensity across documents of different lengths.
Each span, regardless of length, is replaced with exactly one [MASK] token:
where:
- : a contiguous span of tokens starting at position
- : a single mask token that replaces the entire span
- : indicates the replacement operation
This many-to-one mapping is the important innovation. A single [MASK] in the input might correspond to zero tokens, one token, three tokens, or even more in the output. The model cannot simply count masks and produce the same number of tokens. It must learn to judge, from context alone, how extensive each gap is.
For example, "The quick brown fox jumps over the lazy dog" might become "The [MASK] fox [MASK] the [MASK] dog" where:
- "[MASK]₁" replaces "quick brown" (2 tokens)
- "[MASK]₂" replaces "jumps over" (2 tokens)
- "[MASK]₃" replaces "lazy" (1 token)
The decoder must figure out that the first mask needs two tokens (an adjective pair), the second needs two (a verb phrase), and the third needs one (a single adjective), all from the contextual clues in "The ... fox ... the ... dog."
The Poisson Distribution for Span Lengths
Why use Poisson? We want span lengths that vary naturally, mostly short spans with occasional longer ones, without needing to set a maximum length. The Poisson distribution is ideal because it models counts of independent events and has a single parameter controlling the average. This is convenient: rather than specifying an entire distribution over possible lengths, we tune one number and get a reasonable distribution automatically.
The Poisson distribution gives the probability of observing exactly events:
where:
- : the probability of observing exactly events (here, a span of tokens)
- : the span length (number of tokens, can be 0, 1, 2, ...)
- : the expected (average) span length, set to 3 in BART
- : the exponential decay factor so probabilities sum to 1
- : factorial of , which appears because ordering doesn't matter within the span count
The formula works as follows: makes longer spans increasingly likely as grows.if the average is higher, we should see more long spans. Meanwhile, in the denominator penalizes very long spans (since factorial grows faster than exponential), preventing the distribution from placing too much mass on extremely long spans that would destroy too much context. The term normalizes everything to sum to 1. This keeps we have a valid probability distribution. Together, these three components create a distribution peaked near with a long tail toward higher values.
With :
- : 5% of spans have length 0 (insertions!)
- : 15% single-token spans
- : 22% two-token spans
- : 22% three-token spans
- : 36% longer spans


The inclusion of zero-length spans is particularly clever and deserves special attention. A zero-length span means inserting a [MASK] token between two existing tokens without removing anything. The decoder must learn to generate empty content for this mask.to recognize that sometimes a mask is a false alarm requiring no output. This teaches the model that not every mask needs to expand into content, a nuance absent from standard masking approaches where every mask always corresponds to exactly one token.
What the Model Learns
Text infilling develops generation capabilities that transfer directly to downstream tasks:
-
Length prediction: The model must infer how many tokens each mask represents. A single mask might expand to zero, one, five, or more tokens. This requires understanding semantic and syntactic constraints.
-
Coherent multi-token generation: Generating "quick brown" as a unit requires understanding that these words form a coherent phrase modifying "fox." The model cannot generate each token independently.
-
Span boundary detection: The model must determine where masked content ends and original content resumes. When generating tokens for a mask, the model must decide when to stop generating.
This directly addresses a limitation of T5's span corruption. T5 uses sentinel tokens that indicate span boundaries and generates only the corrupted spans with their sentinels. BART must reconstruct the full original text, interleaving generated and copied content smoothly. This trains the model for generation tasks where the output blends novel phrases with material from the input. This is exactly what happens in summarization and paraphrasing, among other applications.
import numpy as np
def text_infilling(
tokens: List[str],
mask_ratio: float = 0.15,
poisson_lambda: float = 3.0,
mask_token: str = "[MASK]",
) -> Tuple[List[str], List[str]]:
"""Apply text infilling corruption.
Replaces spans of varying lengths (Poisson-distributed) with single mask tokens.
Returns:
Tuple of (corrupted_tokens, original_tokens)
"""
n = len(tokens)
if n == 0:
return [], tokens
# Calculate target number of tokens to mask
target_masked = int(n * mask_ratio)
# Sample spans until we've masked enough tokens
spans = [] # List of (start, end) tuples
total_masked = 0
while total_masked < target_masked:
# Sample span length from Poisson
span_length = np.random.poisson(poisson_lambda)
# Sample random start position
start = random.randint(0, n - 1)
end = min(start + span_length, n)
# Check for overlap with existing spans
overlaps = False
for existing_start, existing_end in spans:
if not (end <= existing_start or start >= existing_end):
overlaps = True
break
if not overlaps:
spans.append((start, end))
total_masked += end - start
# Sort spans by start position
spans.sort()
# Build corrupted sequence
corrupted = []
prev_end = 0
for start, end in spans:
# Add tokens before this span
corrupted.extend(tokens[prev_end:start])
# Add single mask for entire span (even if span has 0 length)
corrupted.append(mask_token)
prev_end = end
# Add remaining tokens
corrupted.extend(tokens[prev_end:])
return corrupted, tokens# Demonstrate infilling with visible span corruption
np.random.seed(42)
random.seed(42)
original = "The quick brown fox jumps over the lazy dog".split()
corrupted, _ = text_infilling(original, mask_ratio=0.4, poisson_lambda=2.0)Original (9 tokens): The quick brown fox jumps over the lazy dog Corrupted (6 tokens): The [MASK] over the lazy dog Length reduction: 3 tokens
The corrupted sequence is shorter than the original. Each [MASK] might represent multiple tokens, so the decoder must learn to expand these placeholders appropriately. This many-to-one corruption followed by one-to-many generation is central to BART's effectiveness on generative tasks.