FlashAttention Implementation › FlashAttention-2 Improvements

Michael BrenndoerferUpdated June 30, 20257 min read
Language AI HandbookAll chapters
Part 17 of 67Efficient Attention
Chapter 125FlashAttention Implementation › FlashAttention-2 Improvements
Reading section 5 of 10 · FlashAttention-2 Improvements · 7 minSection 5 of 10 · 7 min

Book contents

Section 5 of 10 · 7 min read

FlashAttention Implementation › FlashAttention-2 ImprovementsOne section · Sections in this chapter5 / 10 ↓
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

FlashAttention-2, released in 2023, builds on the original algorithm with several key optimizations that improve hardware utilization from ~50-70% to ~70-90% of theoretical peak performance.

Reduced Non-Matrix-Multiply FLOPs

The original FlashAttention spent significant time on non-matrix-multiply operations: rescaling outputs, updating statistics, and coordinating between iterations. FlashAttention-2 restructures the algorithm to minimize these overheads.

The key change is delaying the rescaling of output blocks. Instead of rescaling after each K-V block, FlashAttention-2 accumulates unnormalized outputs and applies a single rescaling at the end. This requires careful bookkeeping but reduces the number of scalar operations significantly.

In[23]:
Code
def compare_non_matmul_ops(n, B_r, B_c):
    """
    Compare non-matrix-multiply operations between FlashAttention versions.
    """
    num_blocks = n // B_c  # Number of K-V blocks per query block

    # FlashAttention-1: rescale after each block
    # For each K-V block: update m, l, rescale output
    flash1_rescales = num_blocks * B_r  # One rescale per query per block
    flash1_stats_updates = num_blocks * B_r * 2  # m and l updates

    # FlashAttention-2: single rescale at the end
    flash2_rescales = B_r  # One rescale per query at the end
    flash2_stats_updates = num_blocks * B_r * 2  # Same stats tracking

    return {
        "flash1_rescales": flash1_rescales,
        "flash2_rescales": flash2_rescales,
        "rescale_reduction": flash1_rescales / flash2_rescales,
        "num_kv_blocks": num_blocks,
    }


# Example calculation
ops = compare_non_matmul_ops(n=4096, B_r=64, B_c=64)
Out[24]:
Console
Non-MatMul Operations Comparison (n=4096, block=64):

  K-V blocks processed: 64
  FlashAttention-1 rescales: 4,096
  FlashAttention-2 rescales: 64
  Reduction: 64x fewer rescale operations

With 64 K-V blocks to process, FlashAttention-1 performs 4,096 rescale operations (one per query per block), while FlashAttention-2 performs only 64 (one per query at the end). This 64x reduction in rescaling operations translates directly to improved throughput, particularly when matrix multiplies are already saturating the GPU's compute units.

Better Work Partitioning

FlashAttention-2 improves how work is distributed across thread blocks and warps:

  • Parallelism over batch and heads: Each thread block handles one (batch, head) pair, maximizing parallelism across the GPU
  • Within-block parallelism: Different warps handle different parts of the Q block, with careful synchronization
  • Sequence parallelism: For very long sequences, work can be split across multiple blocks even for a single head
Out[25]:
Visualization
Hierarchical diagram showing work distribution from batch to heads to warps to threads.
FlashAttention-2 work partitioning. Thread blocks are assigned to (batch, head) pairs. Within each block, warps process different query rows in parallel. This maximizes GPU utilization across all levels of the thread hierarchy.

Improved Memory Access

FlashAttention-2 optimizes memory access patterns in several ways:

  • Swapping loops: The inner and outer loops are reordered so that the outer loop iterates over Q blocks and the inner loop over K-V blocks. This reduces the number of times Q blocks are loaded from HBM.
  • Pipelining: Memory loads are overlapped with computation. While computing attention for the current K-V block, the next block is being loaded from HBM.
  • Warp-level primitives: Instead of synchronizing entire thread blocks, FlashAttention-2 uses warp-level operations that are faster and more efficient.
In[26]:
Code
def memory_access_comparison(n, d, B_r, B_c, dtype_bytes=2):
    """
    Compare HBM access patterns between FlashAttention versions.
    """
    num_q_blocks = n // B_r
    num_kv_blocks = n // B_c

    # FlashAttention-1: outer loop over K-V, inner over Q
    # Q loaded num_kv_blocks times
    flash1_q_loads = num_kv_blocks * n * d * dtype_bytes
    flash1_kv_loads = (
        n * d * 2 * dtype_bytes
    )  # K and V each once per Q block pass

    # FlashAttention-2: outer loop over Q, inner over K-V
    # Q loaded once per Q block
    flash2_q_loads = n * d * dtype_bytes  # Just once total
    flash2_kv_loads = (
        num_q_blocks * n * d * 2 * dtype_bytes
    )  # K, V for each Q block

    return {
        "flash1_total_mb": (flash1_q_loads + flash1_kv_loads) / 1e6,
        "flash2_total_mb": (flash2_q_loads + flash2_kv_loads) / 1e6,
        "flash2_q_reduction": flash1_q_loads / flash2_q_loads,
    }


access = memory_access_comparison(n=4096, d=64, B_r=64, B_c=64)
Out[27]:
Console
Memory Access Patterns (n=4096, d=64, block=64):

  FlashAttention-1 total HBM reads: 34.6 MB
  FlashAttention-2 total HBM reads: 67.6 MB
  Q matrix read reduction: 64x fewer Q loads

By swapping the loop order, FlashAttention-2 reads the Q matrix 64x fewer times from HBM. This is the dominant source of the memory access reduction. Since memory bandwidth is the bottleneck, reducing redundant reads directly improves throughput.

Performance Gains

These optimizations combine to give FlashAttention-2 a 2x speedup over FlashAttention on many workloads:

In[28]:
Code
def theoretical_speedup():
    """
    Approximate speedups from FlashAttention to FlashAttention-2.
    Based on published benchmarks.
    """
    # Speedups vary by sequence length and head dimension
    benchmarks = [
        {
            "config": "n=1K, d=64",
            "flash1_tflops": 124,
            "flash2_tflops": 185,
            "speedup": 1.49,
        },
        {
            "config": "n=2K, d=64",
            "flash1_tflops": 128,
            "flash2_tflops": 210,
            "speedup": 1.64,
        },
        {
            "config": "n=4K, d=64",
            "flash1_tflops": 115,
            "flash2_tflops": 220,
            "speedup": 1.91,
        },
        {
            "config": "n=8K, d=64",
            "flash1_tflops": 109,
            "flash2_tflops": 230,
            "speedup": 2.11,
        },
        {
            "config": "n=16K, d=64",
            "flash1_tflops": 102,
            "flash2_tflops": 235,
            "speedup": 2.30,
        },
    ]
    return benchmarks


benchmarks = theoretical_speedup()
Out[29]:
Console
FlashAttention-2 vs FlashAttention-1 Performance (A100):

Configuration        FA-1 (TFLOPS)   FA-2 (TFLOPS)    Speedup
------------------------------------------------------------
n=1K, d=64                     124             185      1.49x
n=2K, d=64                     128             210      1.64x
n=4K, d=64                     115             220      1.91x
n=8K, d=64                     109             230      2.11x
n=16K, d=64                    102             235      2.30x

The benchmarks show a clear trend: FlashAttention-2's advantage grows with sequence length. At 1K tokens, the speedup is a modest 1.49x. At 16K tokens, it reaches 2.30x. This pattern occurs because longer sequences have more K-V blocks, amplifying the benefits of reduced rescaling operations and optimized memory access. FlashAttention-2 also achieves higher absolute TFLOPS, indicating better GPU utilization.

Out[30]:
Visualization
Bar chart showing increasing speedup of FlashAttention-2 over FlashAttention-1 as sequence length increases.
FlashAttention-2 speedup over FlashAttention-1 increases with sequence length. At 16K tokens, FlashAttention-2 is over 2x faster, achieving higher hardware utilization through optimized memory access and work partitioning.