Sparse Attention Patterns › Local Attention Windows

Michael BrenndoerferUpdated June 25, 202510 min read
Language AI HandbookAll chapters
Part 17 of 67Efficient Attention
Chapter 118Sparse Attention Patterns › Local Attention Windows
Reading section 3 of 13 · Local Attention Windows · 10 minSection 3 of 13 · 10 min

Book contents

Section 3 of 13 · 10 min read

Sparse Attention Patterns › Local Attention WindowsOne section · Sections in this chapter3 / 13 ↓
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

The most intuitive sparse pattern is local attention, where each token attends only to tokens within a fixed window around it. This pattern exploits the locality of language: consecutive words form phrases, sentences have local structure, and most grammatical dependencies span short distances.

Local attention is the simplest possible restriction you can impose on the attention matrix. Rather than building an elaborate sparse structure, you just draw a band along the diagonal and say: tokens can see their neighbors, but nothing beyond. Despite its simplicity, this approach works remarkably well for many tasks. Linguistic research has consistently found that the majority of syntactic dependencies, the head-dependent relationships that determine grammatical structure, span fewer than five words. Named entity recognition, part-of-speech tagging, and many types of sentiment analysis can be solved almost entirely with local context. Even for tasks that seem to require global reasoning, local attention in lower layers combined with full or near-full attention in upper layers often achieves excellent results, because early layers aggregate local evidence that later layers then reason about globally.

The hardware story for local attention is also appealing. Because each query attends to a contiguous segment of the key sequence, memory accesses are sequential and cache-friendly. This is in contrast to patterns like random sparse attention, where the irregular access pattern thrashes the cache and reduces effective throughput. Local attention can be implemented as a series of small, dense matrix multiplications on sliding windows, each of which maps cleanly to optimized GPU kernels.

Window Formulation

To formalize local attention, we need to answer a simple question: which positions should a token be allowed to attend to? The intuition is straightforward. Imagine you're reading position 10 in a sequence. Local attention says you can "look" at positions 8, 9, 10, 11, and 12 if the window size is 2, but nothing beyond that range. The window creates a neighborhood around each position.

Let's define this precisely. For a window size ww, each query at position ii attends to positions in the range [i−w,i+w][i - w, i + w]. This range includes:

  • ww positions to the left (earlier in the sequence)
  • The current position ii itself
  • ww positions to the right (later in the sequence)

The total number of attended positions is 2w+12w + 1. Notice that this count is independent of sequence length nn. Whether your sequence has 100 tokens or 100,000 tokens, each position still attends to exactly 2w+12w + 1 neighbors. This independence is what gives local attention its O(n)O(n) complexity: nn positions, each computing 2w+12w + 1 attention scores, yields n⋅(2w+1)n \cdot (2w + 1) total operations.

Now we need a mechanism to enforce this pattern. In transformer attention, we use an attention mask MM that modifies the attention scores before the softmax. The mask for local attention is:

Mij={0if ∣i−j∣≤w−∞otherwiseM_{ij} = \begin{cases} 0 & \text{if } |i - j| \leq w \\ -\infty & \text{otherwise} \end{cases}

where:

  • MijM_{ij}: the mask value applied when query position ii attends to key position jj
  • ii: the query position (which token is asking "what should I attend to?")
  • jj: the key position (a candidate token that might be attended to)
  • ww: the window size (the radius of the local neighborhood)
  • ∣i−j∣|i - j|: the absolute distance between positions (how far apart are they?)

The mask works through the attention computation. Recall that standard attention computes:

Attention(Q,K,V)=softmax(QKTdk+M)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + M\right) V

When Mij=0M_{ij} = 0, the attention score passes through unchanged. When Mij=−∞M_{ij} = -\infty, adding negative infinity to any finite score produces negative infinity. The softmax function then converts e−∞=0e^{-\infty} = 0, effectively blocking query ii from attending to key jj. This elegant mechanism lets us selectively disable attention connections without changing the core attention computation.

In[7]:
Code
def create_local_attention_mask(seq_len, window_size):
    """
    Create a local attention mask where each position attends
    to window_size positions on each side.

    Args:
        seq_len: Length of the sequence
        window_size: Number of positions to attend on each side

    Returns:
        mask: (seq_len, seq_len) boolean mask (True = attend, False = block)
    """
    mask = np.zeros((seq_len, seq_len), dtype=bool)

    for i in range(seq_len):
        start = max(0, i - window_size)
        end = min(seq_len, i + window_size + 1)
        mask[i, start:end] = True

    return mask


# Create masks with different window sizes
seq_len = 32
small_window = create_local_attention_mask(seq_len, window_size=2)
medium_window = create_local_attention_mask(seq_len, window_size=4)
large_window = create_local_attention_mask(seq_len, window_size=8)
Out[8]:
Visualization
Narrow diagonal band in attention mask with window size 2.
Window size 2: Each position attends to 5 positions (2 left, self, 2 right). Very efficient but limited context.
Medium diagonal band in attention mask with window size 4.
Window size 4: Each position attends to 9 positions. Better context coverage with moderate overhead.
Wide diagonal band in attention mask with window size 8.
Window size 8: Each position attends to 17 positions. Rich local context approaching the density of short sequences.
Out[9]:
Console
Window 2: 154 attention scores (85.0% sparse), 5 positions per query
Window 4: 268 attention scores (73.8% sparse), 9 positions per query
Window 8: 472 attention scores (53.9% sparse), 17 positions per query

Local attention achieves significant sparsity even with generous window sizes. A window of 8 positions (17 attended positions per query) reduces computation by over 45% for a 32-token sequence. The savings grow with sequence length: for a 4,096-token sequence with window 256, sparsity exceeds 93%.

Choosing Window Size

The optimal window size depends on the task and sequence characteristics. Here are key considerations:

  • Linguistic dependencies: Most grammatical dependencies span fewer than 10-15 tokens. A window of 256-512 tokens covers most syntactic structures.
  • Task requirements: Sentiment analysis might need only local context, while question answering may require longer-range connections.
  • Computational budget: Larger windows provide more context but increase memory and compute proportionally.
  • Layer depth: Some architectures use smaller windows in early layers and larger windows (or global attention) in later layers.

The relationship between window size and quality is not always monotonic, which can be counterintuitive. A very large window does not always outperform a smaller one, because forcing attention to consider many irrelevant positions can reduce the signal-to-noise ratio. The softmax normalization distributes probability mass across all attended positions, so attending to many low-relevance tokens necessarily dilutes the weight given to high-relevance ones. This means that for tasks with highly local structure, a tightly bounded window of 64 or 128 tokens can outperform a window of 1024 tokens on the same task.

In practice, window size is treated as a hyperparameter that you tune based on validation performance. A useful starting heuristic: set the window to roughly the length of the longest meaningful span in your data. For sentence-level tasks, 128 tokens is usually sufficient. For paragraph-level reasoning, 256 to 512 works well. For document-level understanding where cross-paragraph connections matter, you will need to supplement local windows with a global attention mechanism, which we cover later in this chapter when discussing combined patterns.

In[10]:
Code
def compute_local_attention_complexity(seq_len, window_size):
    """
    Compute the number of attention scores for local attention.

    Returns:
        attended_pairs: Number of (query, key) pairs computed
        full_pairs: Number of pairs in full attention
        speedup: Ratio of full to local complexity
    """
    # Each of n positions attends to min(2w+1, n) positions
    # Edge positions attend to fewer
    attended = 0
    for i in range(seq_len):
        start = max(0, i - window_size)
        end = min(seq_len, i + window_size + 1)
        attended += end - start

    full = seq_len * seq_len
    return attended, full, full / attended


# Analyze complexity for various sequence lengths
seq_lens = [128, 512, 2048, 8192, 32768]
window_size = 256
Out[11]:
Console
Local attention speedup (window_size=256):

  Seq Length      Full Pairs     Local Pairs    Speedup
-------------------------------------------------------
         128          16,384          16,384        1.0x
         512         262,144         196,864        1.3x
       2,048       4,194,304         984,832        4.3x
       8,192      67,108,864       4,136,704       16.2x
      32,768   1,073,741,824      16,744,192       64.1x

The speedup from local attention grows linearly with sequence length. At 32,768 tokens, local attention with a 256-token window provides over 60x speedup compared to full attention. This scaling is what makes local attention essential for processing long documents.

The log-log linear relationship in the plot reveals something deeper than just "local attention is faster." It shows that the complexity gap between full and local attention is structural, not incidental. Full attention is O(n2)O(n^2) while local attention is O(n⋅w)O(n \cdot w) where ww is fixed. The ratio between them is therefore n2/(n⋅w)=n/wn^2 / (n \cdot w) = n/w, which grows linearly with nn. No amount of engineering optimization can close this gap for very long sequences: it is a fundamental algorithmic property.

This has an important practical implication for system design. If you are building an application that needs to handle documents of varying length, the performance profile of full attention is unpredictable: doubling the document length quadruples the computation. Local attention has predictable, linear scaling: doubling the document length doubles the computation. For production systems where latency budgets matter, this predictability is often as valuable as the raw speedup.

Out[12]:
Visualization
Log-log line plot showing linearly increasing speedup as sequence length increases from 128 to 32768 tokens.
Speedup of local attention over full attention as sequence length increases. The speedup grows linearly because local attention complexity is O(n) while full attention is O(n squared). Longer sequences benefit dramatically from sparse patterns.

The log-log plot reveals the linear relationship between sequence length and speedup. Doubling the sequence length approximately doubles the speedup, regardless of window size. Smaller windows provide greater speedups but capture less context.