<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fa3 on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/fa3/</link><description>Recent content in Fa3 on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Fri, 29 May 2026 17:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/fa3/index.xml" rel="self" type="application/rss+xml"/><item><title>FlashAttention v1/v2/v3/v4: el bibliotecario que nunca despeja la mesa — IO-awareness, async y la asimetría de Blackwell</title><link>https://blog.lo0.es/posts/flashattention-fundamentos/</link><pubDate>Fri, 29 May 2026 17:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/flashattention-fundamentos/</guid><description>&lt;blockquote>
&lt;p>Este post complementa los de &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache: la memoria de trabajo&lt;/a> y &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention deep dive&lt;/a>. KV cache explica &lt;strong>qué se almacena&lt;/strong>; PagedAttention, &lt;strong>cómo se gestiona en memoria&lt;/strong>; FlashAttention, &lt;strong>cómo se ejecuta el cálculo&lt;/strong>. Son tres capas distintas del mismo problema y se acumulan multiplicativamente.&lt;/p>
&lt;/blockquote>
&lt;h2 id="estás-aquí-deploy">Estás aquí: DEPLOY&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Deploy">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#7ad88f;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#fam)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#fam)}&lt;/style>
&lt;defs>&lt;marker id="fam" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: DEPLOY · kernel de attention, capa por debajo de PagedAttention y KV cache&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box active"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>El attention estándar de un transformer tiene un problema estructural en GPUs modernas: cuando se mira con un profiler, no está limitado por compute, está limitado por &lt;strong>memoria&lt;/strong>. La matriz &lt;code>S = QK^T&lt;/code> de tamaño &lt;code>N × N&lt;/code> —con N la longitud de la secuencia— no cabe en la SRAM rápida del chip y obliga a hacer round trips a HBM que dominan el tiempo total. &lt;strong>FlashAttention&lt;/strong> es la familia de kernels que evita materializar esa matriz haciendo &lt;em>tiling&lt;/em> sobre Q, K y V, calculando el softmax bloque a bloque con la versión &lt;em>online&lt;/em> y manteniendo todo dentro de SRAM. Cada versión sube el techo de utilización: &lt;strong>FA1&lt;/strong> (Dao et al. 2022) abolió la matriz N×N y bajó complejidad de memoria a O(N); &lt;strong>FA2&lt;/strong> (Dao 2023) paralelizó a lo largo de la dimensión de secuencia y redujo los non-matmul FLOPs hasta acercarse al 70 % de utilización en A100; &lt;strong>FA3&lt;/strong> (Shah, Bikshandi, Zhang, Thakkar, Ramani, Dao 2024) explotó tres mecanismos específicos de Hopper —WGMMA async, TMA y FP8— para llegar a &lt;strong>740 TFLOPS BF16 (75 % del peak) y 1.2 PFLOPS FP8 en H100&lt;/strong>; &lt;strong>FA4&lt;/strong> (marzo 2026) rescribió el kernel desde cero para Blackwell, donde el tensor core escala 2.25× pero la SFU (donde corre el &lt;code>exp&lt;/code> del softmax) y la SMEM bandwidth no escalan nada — la solución es &lt;strong>software-emulated exponential&lt;/strong> que corre en tensor cores. El resultado en B200: &lt;strong>1605 TFLOPS BF16, 1.3× más rápido que cuDNN 9.13 y 2× más rápido que FA3 en la misma GPU&lt;/strong>. Este post desmonta el porqué (memory roofline, IO complexity), la analogía maestra del bibliotecario, las matemáticas mínimas y los números reales en H100 y B200.&lt;/p>
&lt;h2 id="la-analogía-el-bibliotecario-que-nunca-despeja-la-mesa">La analogía: el bibliotecario que nunca despeja la mesa&lt;/h2>
&lt;p>Una biblioteca grande con dos zonas: una &lt;strong>mesa de trabajo&lt;/strong> muy rápida pero pequeña (el escritorio del bibliotecario, 200 libros caben encima), y una &lt;strong>estantería gigantesca&lt;/strong> que recorre tres pisos donde está todo (50 millones de libros). El bibliotecario tiene que cruzar referencias entre todos los libros de una sala temática y producir un resumen.&lt;/p>
&lt;p>Un &lt;strong>bibliotecario ingenuo&lt;/strong> lo hace de la forma directa: trae todos los libros relevantes de la estantería, los apila sobre la mesa de trabajo, y como no caben, deja la mitad en el suelo, en la silla, sobre cajas. Pasa el día corriendo entre el suelo y la mesa, abriendo y cerrando libros, sin poder concentrarse. La mesa de trabajo es rapidísima pero está infrautilizada porque la mayoría del tiempo el bibliotecario está moviendo libros entre el suelo y la mesa. Es lo que hace &lt;strong>standard attention&lt;/strong>: materializa la matriz &lt;code>S = QK^T&lt;/code> en HBM y vuelve una y otra vez por trozos.&lt;/p>
&lt;p>Un &lt;strong>bibliotecario FlashAttention v1&lt;/strong> cambia de estrategia: pide un estante a la vez, lo trae a la mesa, lee lo que necesita, anota notas en una libreta compacta —&amp;ldquo;de este estante me interesa esto, esto y esto, con estos pesos relativos&amp;rdquo;—, devuelve el estante a su sitio y trae el siguiente. La libreta es lo único que se conserva entre estantes. Nunca apila más de lo que cabe en la mesa. El truco que hace esto posible es la &lt;em>online softmax&lt;/em>: en lugar de necesitar todo el contenido a la vez para normalizar, mantiene un running max y un running sum que se actualizan estante a estante.&lt;/p>
&lt;p>Un &lt;strong>bibliotecario FlashAttention v2&lt;/strong> se da cuenta de que puede trabajar &lt;strong>varios temas en paralelo&lt;/strong> porque la mesa es grande y los estantes son independientes en algunos ejes. Pone tres ayudantes con sus libretas, cada uno cubriendo un bloque distinto de la sala, y combinan resultados al final.&lt;/p>
&lt;p>Un &lt;strong>bibliotecario FlashAttention v3&lt;/strong> consigue mecanizar el flujo: instala una cinta transportadora con dos estaciones. Mientras la &lt;strong>estación A&lt;/strong> lee el estante actual y toma notas, la &lt;strong>estación B&lt;/strong> ya tiene el siguiente estante en tránsito desde la estantería. Cuando A termina, B le pasa el estante nuevo sin esperar. Es el &lt;strong>ping-pong producer/consumer&lt;/strong>: la TMA descarga el data loading y los warps consumidores hacen el trabajo en paralelo con las cargas. Encima, las notas se escriben en taquigrafía de menor precisión (FP8) porque las páginas que importan llevan ya un pre-tratamiento ortogonal que no las hace perder precisión donde duele.&lt;/p>
&lt;p>Un &lt;strong>bibliotecario FlashAttention v4&lt;/strong> descubre algo nuevo de su biblioteca remodelada (Blackwell): le han instalado dos cintas transportadoras mucho más rápidas (tensor cores 2.25×), pero &lt;strong>la máquina de escribir taquigráfica no la han actualizado&lt;/strong> (la SFU sigue igual). Ahora el cuello de botella es escribir las notas, no traer los estantes. La solución es elegante: en lugar de usar la máquina taquigráfica, escribe las anotaciones con fórmulas polinómicas que &lt;strong>el propio tensor core puede evaluar&lt;/strong> (software-emulated exponential). La cinta no se queda parada esperando a la máquina.&lt;/p>
&lt;p>La analogía se sostiene con cuatro mapeos:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Mesa de trabajo&lt;/strong> = SRAM por SM (228 KB en H100, 256 KB en B200).&lt;/li>
&lt;li>&lt;strong>Estantería gigante&lt;/strong> = HBM (3.35 TB/s en H100, 8 TB/s en B200).&lt;/li>
&lt;li>&lt;strong>Libreta con max y sum running&lt;/strong> = stats de la online softmax (&lt;code>m&lt;/code>, &lt;code>ℓ&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Cinta transportadora con dos estaciones&lt;/strong> = pipeline TMA + WGMMA producer/consumer.&lt;/li>
&lt;/ul>
&lt;h2 id="por-qué-standard-attention-era-el-cuello-de-botella">Por qué standard attention era el cuello de botella&lt;/h2>
&lt;p>La intuición ingenua —&amp;ldquo;attention son matmuls, las GPUs son buenas con matmuls&amp;rdquo;— es correcta pero incompleta. Hay dos matmuls (&lt;code>QK^T&lt;/code> y luego &lt;code>softmax(S) V&lt;/code>), y en medio una operación no-matmul (softmax) que requiere materializar la matriz intermedia &lt;code>S&lt;/code> de tamaño &lt;code>N × N&lt;/code>.&lt;/p>
&lt;p>Las GPUs modernas tienen un &lt;strong>roofline&lt;/strong> muy concreto. Para H100 SXM5:&lt;/p>
&lt;ul>
&lt;li>Compute peak: &lt;strong>989 TFLOPS BF16&lt;/strong> (tensor core, dense, sin sparsity).&lt;/li>
&lt;li>Memory bandwidth: &lt;strong>3.35 TB/s&lt;/strong> HBM3.&lt;/li>
&lt;li>Punto de cruce (arithmetic intensity break-even): &lt;code>989 × 10¹² / (3.35 × 10¹²) ≈ 295 FLOP/byte&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Cualquier operación que no consiga ejecutar &lt;strong>295 operaciones por cada byte que mueve desde HBM&lt;/strong> está memory-bound: el tensor core se queda esperando datos. Para B200 el ratio es similar (~281 FLOP/byte) porque tanto compute como bandwidth subieron.&lt;/p>
&lt;p>Standard attention materializando &lt;code>S&lt;/code> lee la matriz dos veces (una para softmax, otra para multiplicar por V) y la escribe una vez. Para Llama 3 70B con head dim &lt;code>d = 128&lt;/code> y contexto &lt;code>N = 128K&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>Matriz &lt;code>S&lt;/code> por head por capa: &lt;code>N × N × 2 bytes = 128K × 128K × 2 = 34.36 GB&lt;/code>.&lt;/li>
&lt;li>80 capas × 64 Q-heads → tráfico HBM agregado (si se materializara serialmente) del orden de &lt;strong>TBs&lt;/strong>, prohibitivo en transient.&lt;/li>
&lt;li>Aunque no se materialice todo a la vez, los round trips dominan el tiempo: arithmetic intensity efectiva muy por debajo de 295 → operación memory-bound → tensor core infrautilizado a ~25 %.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>FlashAttention no cambia las matemáticas del attention, cambia el orden de las operaciones para no materializar S en HBM&lt;/strong>. Su IO complexity es &lt;code>Θ(N²·d²/M)&lt;/code> con M = tamaño SRAM por SM, frente a &lt;code>Θ(N·d + N²)&lt;/code> de standard attention. Con d = 128 y M = 228 KB: factor de reducción aproximado &lt;strong>M/d² ≈ 14×&lt;/strong> menos tráfico HBM. Eso es lo que mueve la operación de memory-bound a casi compute-bound.&lt;/p>
&lt;h2 id="el-truco-que-hizo-posible-todo-online-softmax">El truco que hizo posible todo: online softmax&lt;/h2>
&lt;p>Sin online softmax no hay FlashAttention. La idea es de &lt;strong>Milakov y Gimelshein, 2018&lt;/strong> (paper &amp;ldquo;Online normalizer calculation for softmax&amp;rdquo;, arXiv:1805.02867), y permite calcular &lt;code>softmax([x_1, ..., x_N])&lt;/code> en un pase incremental sin necesitar conocer el máximo global antes de empezar.&lt;/p>
&lt;p>El softmax estándar es:&lt;/p>
&lt;p>$$\text{softmax}(x_i) = \frac{e^{x_i - m}}{\sum_{j} e^{x_j - m}}, \quad m = \max_j x_j$$&lt;/p>
&lt;p>El truco &lt;em>online&lt;/em>: mantén un máximo running &lt;code>m^{(t)}&lt;/code> y una suma running &lt;code>ℓ^{(t)}&lt;/code>. Cuando llega un bloque nuevo de valores con máximo local &lt;code>m_{\text{new}}&lt;/code>:&lt;/p>
&lt;p>$$m^{(t+1)} = \max(m^{(t)}, m_{\text{new}})$$&lt;/p>
&lt;p>$$\ell^{(t+1)} = e^{m^{(t)} - m^{(t+1)}} \cdot \ell^{(t)} + \sum_{j \in \text{nuevo}} e^{x_j - m^{(t+1)}}$$&lt;/p>
&lt;p>Y los outputs parciales acumulados también se reescalan por el mismo factor &lt;code>e^{m^{(t)} - m^{(t+1)}}&lt;/code>. Al final, dividir por &lt;code>ℓ&lt;/code> final da exactamente lo mismo que el softmax estándar. &lt;strong>Es matemáticamente exacto&lt;/strong>, no es una aproximación.&lt;/p>
&lt;p>Esto es lo que permite recorrer K bloque a bloque sin materializar la matriz &lt;code>S&lt;/code> entera. Cada bloque actualiza los stats y los outputs acumulados, y se descarta. La mesa nunca se llena.&lt;/p>
&lt;h2 id="las-cuatro-versiones-mayo-2026">Las cuatro versiones (mayo 2026)&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;th>&lt;strong>FA1&lt;/strong> (2022)&lt;/th>
&lt;th>&lt;strong>FA2&lt;/strong> (2023)&lt;/th>
&lt;th>&lt;strong>FA3&lt;/strong> (2024)&lt;/th>
&lt;th>&lt;strong>FA4&lt;/strong> (2026)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>GPU target&lt;/td>
&lt;td>A100 / Ampere&lt;/td>
&lt;td>A100 / H100&lt;/td>
&lt;td>H100 / Hopper&lt;/td>
&lt;td>B200 / Blackwell&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Idea central&lt;/td>
&lt;td>Tiling + online softmax&lt;/td>
&lt;td>Sequence parallelism + work partitioning&lt;/td>
&lt;td>Async WGMMA + TMA + FP8&lt;/td>
&lt;td>Polynomial exp + 2-CTA tensor cores&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Memoria&lt;/td>
&lt;td>O(N) (vs O(N²))&lt;/td>
&lt;td>igual&lt;/td>
&lt;td>igual&lt;/td>
&lt;td>igual&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Peak util típica&lt;/td>
&lt;td>~25 % A100&lt;/td>
&lt;td>~70 % A100, ~35 % H100&lt;/td>
&lt;td>&lt;strong>75 % H100 BF16, 60 % H100 FP8&lt;/strong>&lt;/td>
&lt;td>&lt;strong>71 % B200 BF16&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>TFLOPS efectivos&lt;/td>
&lt;td>—&lt;/td>
&lt;td>225 TFLOPS A100 BF16&lt;/td>
&lt;td>740 H100 BF16, 1200 H100 FP8&lt;/td>
&lt;td>&lt;strong>1605 B200 BF16&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Speedup vs anterior&lt;/td>
&lt;td>2-4× standard&lt;/td>
&lt;td>2× FA1&lt;/td>
&lt;td>1.5-2× FA2 (BF16), 2.6× (FP8)&lt;/td>
&lt;td>2× FA3 en B200&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Paper&lt;/td>
&lt;td>arXiv:2205.14135&lt;/td>
&lt;td>arXiv:2307.08691&lt;/td>
&lt;td>arXiv:2407.08608&lt;/td>
&lt;td>arXiv:2603.05451&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="fa1--el-cambio-de-orden-de-las-operaciones">FA1 — el cambio de orden de las operaciones&lt;/h3>
&lt;p>Tres ideas combinadas: tiling de Q/K/V en bloques que caben en SRAM, online softmax sobre esos bloques, y &lt;strong>recomputation en backward&lt;/strong> —no se guarda la matriz S de tamaño N×N, solo los stats &lt;code>(m, ℓ)&lt;/code>, y en backward se recomputa S bloque a bloque a partir de Q, K y los stats—. Resultado: 7.6× speedup en GPT-2 vs PyTorch standard attention, memoria O(N).&lt;/p>
&lt;h3 id="fa2--paralelizar-en-serie">FA2 — paralelizar en serie&lt;/h3>
&lt;p>FA1 paralelizaba solo en batch × heads. Con batch pequeño (1-4) y modelos con pocos heads o GQA agresivo, la GPU se quedaba con SMs ociosos. FA2 paraleliza también &lt;strong>en la dimensión de secuencia&lt;/strong>: distintos SMs procesan distintos tramos de Q al mismo tiempo. Además reescribe el algoritmo para minimizar las operaciones no-matmul (rescaling del softmax) porque esas no pasan por tensor cores. Y mejora el work partitioning entre warps (split-Q en lugar de split-K reduce tráfico de shared memory). Resultado: ~2× sobre FA1 en H100 y A100, 225 TFLOPS en A100 (72 % MFU). En H100 se queda en torno al 30-35 % del peak BF16 porque no aprovecha WGMMA async.&lt;/p>
&lt;h3 id="fa3--el-momento-hopper">FA3 — el momento Hopper&lt;/h3>
&lt;p>Aquí FlashAttention deja de ser un algoritmo y se convierte en una pieza específica de Hopper. Tres pilares:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WGMMA async&lt;/strong>: las instrucciones nuevas de tensor core de Hopper permiten que un warpgroup dispare un GEMM y el resto del warpgroup haga otra cosa (la softmax, por ejemplo) mientras el tensor core sigue trabajando. Es el truco que destraba el solapamiento matmul/softmax.&lt;/li>
&lt;li>&lt;strong>TMA (Tensor Memory Accelerator)&lt;/strong>: hardware dedicado a copiar tiles entre HBM y SRAM. Libera al SM del trabajo de calcular índices y predicar out-of-bounds, que antes ocupaba ciclos del propio SM. Es el equivalente a contratar mozos de almacén: el bibliotecario deja de tener que cargar libros él mismo.&lt;/li>
&lt;li>&lt;strong>FP8 con block quantization + incoherent processing&lt;/strong>: cuantizar Q y K a FP8 dobla el throughput del tensor core. La pérdida de precisión se mitiga con dos trucos: una escala por tile (64×d) en lugar de por tensor entero, y una pre-multiplicación por una matriz ortogonal aleatoria basada en Hadamard que &amp;ldquo;esparce&amp;rdquo; los outliers antes de cuantizar. Resultado documentado: error numérico &lt;strong>2.6× menor&lt;/strong> que FP8 baseline.&lt;/li>
&lt;/ol>
&lt;p>Estos tres pilares se combinan con &lt;strong>warp specialization producer/consumer&lt;/strong> (warps productores hacen TMA loads; warps consumidores hacen WGMMA + softmax) y un &lt;strong>ping-pong scheduling&lt;/strong> con dos warpgroups que se turnan para que nunca haya pipeline bubbles. Cuando WG1 hace softmax, WG2 hace GEMM; luego se intercambian.&lt;/p>
&lt;p>Números: 740 TFLOPS BF16 en H100 (75 % del peak 989), 1.2 PFLOPS FP8 (60 % del peak 1978 FP8 dense). Para secuencias ≥ 1K supera a cuDNN. Speedup sobre FA2: 1.5-2× BF16, &lt;strong>2.6× FP8&lt;/strong>.&lt;/p>
&lt;h3 id="fa4--la-asimetría-de-blackwell">FA4 — la asimetría de Blackwell&lt;/h3>
&lt;p>Blackwell escaló todo de forma desigual:&lt;/p>
&lt;ul>
&lt;li>Tensor core BF16 throughput: 1 PFLOP H100 → &lt;strong>2.25 PFLOPS B200 (2.25×)&lt;/strong>.&lt;/li>
&lt;li>SFU count (donde corre &lt;code>exp&lt;/code> del softmax): &lt;strong>sin cambios&lt;/strong>.&lt;/li>
&lt;li>Shared memory bandwidth: &lt;strong>sin cambios&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>Es decir, si FA3 corre tal cual en B200 sin tocarlo, el matmul va el doble de rápido pero el softmax queda exactamente igual, y eso &lt;strong>bloquea el pipeline&lt;/strong>. Era cuestión de tiempo que alguien resolviera el desequilibrio.&lt;/p>
&lt;p>FA4 (marzo 2026, mismo equipo Dao + Princeton + Together AI + Meta + NVIDIA + Colfax) hace un rewrite ground-up con tres ideas:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Software-emulated exponential&lt;/strong>: aproximación polinómica del &lt;code>exp&lt;/code> que se ejecuta en el tensor core en lugar de en la SFU. Pierde un poquito de precisión (cuidadosamente acotada y compensada por el resto del kernel) pero deja la cinta transportadora moviéndose.&lt;/li>
&lt;li>&lt;strong>Conditional softmax rescaling&lt;/strong>: evita rescalar acumuladores cuando el running max no cambia significativamente. Optimización de tipo &amp;ldquo;lazy&amp;rdquo;: solo paga el coste cuando hace falta.&lt;/li>
&lt;li>&lt;strong>2-CTA tensor core&lt;/strong>: dos CTAs (Cooperative Thread Arrays) colaboran para alimentar los tensor cores con tiles más grandes. Saca más juego de las capacidades nuevas de Blackwell.&lt;/li>
&lt;/ol>
&lt;p>Escrito en &lt;strong>CuTeDSL&lt;/strong> (Python DSL de NVIDIA CUTLASS, no CUDA C++ directo). Resultado en B200 BF16: &lt;strong>1605 TFLOPS&lt;/strong> (71 % del peak 2250). &lt;strong>1.3×&lt;/strong> sobre cuDNN 9.13. &lt;strong>2.7×&lt;/strong> sobre Triton. &lt;strong>2×&lt;/strong> sobre FA3 ejecutado tal cual en B200 (que era el baseline anterior). Es el primer kernel de attention que pasa de 1 PFLOPS.&lt;/p>
&lt;blockquote>
&lt;p>Nota: hay confusión recurrente con &amp;ldquo;FP4 attention&amp;rdquo;. Las extensiones NVFP4/MXFP4 de Blackwell &lt;strong>se aplican a pesos&lt;/strong>, no a attention. FA4 puede combinarse con weights NVFP4, pero el cómputo de attention en sí sigue siendo BF16 o FP8 según configuración. La cuantización a FP4 de QK^T existe en algunos kernels propietarios (FireAttention V4 de Fireworks AI lo combina) pero no es la práctica estándar.&lt;/p>
&lt;/blockquote>
&lt;h2 id="implementaciones-y-librerías-en-2026">Implementaciones y librerías en 2026&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Dao-AILab/flash-attention&lt;/strong> (repo canónico): soporta SM 8.0 (Ampere) con FA2, SM 9.0 (Hopper) con FA3, SM 10.0 (Blackwell datacenter B100/B200/B300) con FA4. La versión consumer Blackwell (5090, SM 12.0) tiene soporte parcial al cierre de este post.&lt;/li>
&lt;li>&lt;strong>FlashInfer&lt;/strong> (flashinfer-ai/flashinfer, arXiv:2501.01005): engine de attention orientado a &lt;em>serving&lt;/em> (no a training). Su contribución conceptual es el &lt;strong>Block-Sparse Row (BSR)&lt;/strong>, una abstracción unificada que cubre paged KV cache, radix tree de prefix caching y máscaras de árbol de speculative decoding. Internamente puede llamar a kernels FA2/FA3, cuDNN, CUTLASS, o trtllm-gen FMHA según el caso. JIT compila variantes específicas en runtime. Integrado en vLLM, SGLang, TensorRT-LLM.&lt;/li>
&lt;li>&lt;strong>vLLM (mayo 2026)&lt;/strong>: selección automática del backend según GPU. Default &lt;strong>FA4 en SM 10.0+, FA3 en SM 9.0, FA2 en resto&lt;/strong>. Fallbacks en Blackwell: TRT-LLM Ragged → FlashInfer → TokenSpeed MLA. Para FP8 KV cache en B200, FlashInfer es competitivo.&lt;/li>
&lt;li>&lt;strong>SGLang&lt;/strong>: usa FlashInfer como backend de attention; RadixAttention es la capa de prefix caching encima (un radix tree del KV cache).&lt;/li>
&lt;li>&lt;strong>TensorRT-LLM&lt;/strong>: kernels fused propios (trtllm-gen FMHA). XQA es la optimización propia de NVIDIA para GQA en decode.&lt;/li>
&lt;li>&lt;strong>PyTorch SDPA y FlexAttention&lt;/strong>: &lt;code>torch.nn.functional.scaled_dot_product_attention&lt;/code> selecciona backend automático. &lt;strong>FlexAttention&lt;/strong> (nuevo) permite definir custom masks declarativamente y compila a kernels que pueden usar FA4 como backend.&lt;/li>
&lt;li>&lt;strong>xFormers&lt;/strong>: sigue vivo pero residual. PyTorch SDPA built-in cubre la mayoría de casos.&lt;/li>
&lt;/ul>
&lt;h2 id="casos-donde-flashattention-no-ayuda">Casos donde FlashAttention no ayuda&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Contextos muy cortos (N &amp;lt; 512)&lt;/strong>: el overhead de tiling y kernel launch no compensa; cuDNN puede ganar.&lt;/li>
&lt;li>&lt;strong>Custom masks no estándar&lt;/strong>: FA solo trae causal, sliding window y ALiBi de serie. Para máscaras arbitrarias hace falta FlexAttention o variantes JIT de FlashInfer.&lt;/li>
&lt;li>&lt;strong>Head dim no estándar&lt;/strong>: FA optimiza para d = 64, 128, 256. Dimensiones extrañas (d = 96, d = 192) caen en paths lentos.&lt;/li>
&lt;li>&lt;strong>GQA/MQA con ratios extremos&lt;/strong>: soportado nativo, pero el speedup vs MHA puro depende del ratio Q-heads : KV-heads.&lt;/li>
&lt;li>&lt;strong>Cross-attention&lt;/strong>: soportado pero menos optimizado; el caso self-attention es donde más ganancia hay.&lt;/li>
&lt;li>&lt;strong>FP8 sin block quantization ni incoherent processing&lt;/strong>: pierde varios puntos en benchmarks. Si tu serving framework no implementa los dos trucos del FA3 paper, FP8 attention puede ser una mala idea.&lt;/li>
&lt;/ul>
&lt;h2 id="implicaciones-en-hardware-on-premise">Implicaciones en hardware on-premise&lt;/h2>
&lt;h3 id="en-una-rtx-4090-24-gb-ada-lovelace-sm-89">En una RTX 4090 (24 GB, Ada Lovelace, SM 8.9)&lt;/h3>
&lt;p>La 4090 es Ada Lovelace, no Hopper. &lt;strong>No corre FA3 ni FA4&lt;/strong>; corre FA2. Eso significa: ~70 % de utilización en attention BF16 (~250 TFLOPS efectivos sobre el peak de 330 TFLOPS BF16 de la 4090). No es trágico —FA2 ya es muy bueno comparado con standard attention— pero el techo está claramente por debajo del de un H100. Para deploys consumer en 4090 con Llama 3 8B BF16 o cualquier 14B-32B INT4 AWQ, FA2 es lo que vas a estar usando, y es perfectamente razonable.&lt;/p>
&lt;h3 id="en-un-cluster-genérico-4h100-sxm-320-gb-nvlink-fp8-nativo">En un cluster genérico 4×H100 SXM (320 GB, NVLink, FP8 nativo)&lt;/h3>
&lt;p>Aquí FA3 brilla y es lo que vLLM/SGLang/TRT-LLM van a seleccionar por defecto. Dos configuraciones comunes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Llama 3 70B FP8 con FA3 FP8 attention&lt;/strong>: 1.2 PFLOPS pico en la GPU, throughput agregado del cluster en el orden de 8000-12000 tokens/s en batch medio dependiendo de TP y contexto. Para que el FP8 attention dé su pleno rendimiento es crucial usar las técnicas de block quantization + incoherent processing del paper FA3 (vienen activadas en vLLM por defecto).&lt;/li>
&lt;li>&lt;strong>DeepSeek-V3 671B FP8 + MLA con FlashInfer&lt;/strong>: DeepSeek usa &lt;strong>Multi-head Latent Attention&lt;/strong> (MLA), una variante distinta del attention estándar. FlashInfer tiene kernels específicos (FlashMLA). El stack típico es vLLM/SGLang + FlashInfer + FlashMLA + FA3 fallback para las capas no-MLA.&lt;/li>
&lt;/ul>
&lt;p>Si la infraestructura es Blackwell (B200/B300, que algunos clusters empiezan a recibir en 2026), &lt;strong>FA4 es la opción correcta&lt;/strong> y debería estar habilitado por defecto en vLLM 0.16+ y SGLang 0.5.11+.&lt;/p>
&lt;h2 id="lo-que-no-hemos-cubierto">Lo que no hemos cubierto&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>MLA (Multi-head Latent Attention)&lt;/strong> de DeepSeek y los kernels FlashMLA específicos: optimizan compresión de KV cache pero requieren kernels distintos.&lt;/li>
&lt;li>&lt;strong>Flexible masking y los casos de uso de FlexAttention&lt;/strong> (PyTorch 2.5+): cómo declarar máscaras arbitrarias sin pagar el coste de un kernel custom.&lt;/li>
&lt;li>&lt;strong>Asistencia de hardware para sparse attention&lt;/strong> (NVIDIA sparse tensor cores 2:4) y por qué attention sparse no ha consolidado como techo más alto que FA dense.&lt;/li>
&lt;li>&lt;strong>FA en backward de fine-tuning&lt;/strong>: el post se centra en inferencia, pero FA3/FA4 también pasan por backward y son lo que hace viable entrenar modelos con contextos largos en H100/B200.&lt;/li>
&lt;/ul>
&lt;h2 id="ver-también">Ver también&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache: la memoria de trabajo que sostiene la inferencia LLM&lt;/a> — el KV cache es lo que FlashAttention recorre y multiplica contra Q en cada iteración; entender uno requiere entender el otro.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention deep dive&lt;/a> — PagedAttention organiza el KV cache en bloques físicos no contiguos; FlashAttention es el kernel que itera sobre esos bloques. Capas distintas del mismo problema.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/quantization-fundamentos-inferencia/">Quantization para inferencia LLM&lt;/a> — FP8 attention de FA3 con block quantization y FP4 weights de Blackwell se acumulan; este post da el marco de cuantización general.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/disaggregated-serving-prefill-decode/">Disaggregated serving: prefill y decode en pods especializados&lt;/a> — prefill es compute-bound y se beneficia mucho de FA3/FA4 FP8; decode es memory-bound y se beneficia menos pero igualmente. La separación deja optimizar el kernel por fase.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/speculative-decoding-fundamentos/">Speculative decoding: el secretario que adelanta lo que va a decir el jefe&lt;/a> — speculative produce más tokens por forward pass; FlashAttention hace cada forward pass más barato. Palancas multiplicativas.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/pipeline-llmops-seis-etapas/">El pipeline LLMOps de seis etapas&lt;/a> — el mapa maestro donde Deploy es la etapa 4.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;ul>
&lt;li>Dao, T., Fu, D., Ermon, S., Rudra, A., Ré, C. &lt;em>FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness&lt;/em>. NeurIPS 2022. &lt;a href="https://arxiv.org/abs/2205.14135">https://arxiv.org/abs/2205.14135&lt;/a>&lt;/li>
&lt;li>Dao, T. &lt;em>FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning&lt;/em>. 2023. &lt;a href="https://arxiv.org/abs/2307.08691">https://arxiv.org/abs/2307.08691&lt;/a>&lt;/li>
&lt;li>Shah, J., Bikshandi, G., Zhang, Y., Thakkar, V., Ramani, P., Dao, T. &lt;em>FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision&lt;/em>. NeurIPS 2024. &lt;a href="https://arxiv.org/abs/2407.08608">https://arxiv.org/abs/2407.08608&lt;/a>&lt;/li>
&lt;li>Dao, T. et al. &lt;em>FlashAttention-4: Algorithm and Kernel Pipelining Co-Design for Asymmetric Hardware Scaling&lt;/em>. 2026. &lt;a href="https://arxiv.org/abs/2603.05451">https://arxiv.org/abs/2603.05451&lt;/a>&lt;/li>
&lt;li>Milakov, M., Gimelshein, N. &lt;em>Online normalizer calculation for softmax&lt;/em>. 2018. &lt;a href="https://arxiv.org/abs/1805.02867">https://arxiv.org/abs/1805.02867&lt;/a>&lt;/li>
&lt;li>Ye, Z. et al. &lt;em>FlashInfer: Efficient and Customizable Attention Engine for LLM Inference Serving&lt;/em>. MLSys 2025. &lt;a href="https://arxiv.org/abs/2501.01005">https://arxiv.org/abs/2501.01005&lt;/a>&lt;/li>
&lt;li>Tri Dao FA3 blog: &lt;a href="https://tridao.me/blog/2024/flash3/">https://tridao.me/blog/2024/flash3/&lt;/a>&lt;/li>
&lt;li>Tri Dao FA4 blog: &lt;a href="https://tridao.me/blog/2026/flash4/">https://tridao.me/blog/2026/flash4/&lt;/a>&lt;/li>
&lt;li>PyTorch FlashAttention-3 announcement: &lt;a href="https://pytorch.org/blog/flashattention-3/">https://pytorch.org/blog/flashattention-3/&lt;/a>&lt;/li>
&lt;li>PyTorch FlexAttention + FA4: &lt;a href="https://pytorch.org/blog/flexattention-flashattention-4-fast-and-flexible/">https://pytorch.org/blog/flexattention-flashattention-4-fast-and-flexible/&lt;/a>&lt;/li>
&lt;li>Together AI FA4 blog: &lt;a href="https://www.together.ai/blog/flashattention-4">https://www.together.ai/blog/flashattention-4&lt;/a>&lt;/li>
&lt;li>Colfax Research FA3: &lt;a href="https://research.colfax-intl.com/flashattention-3-fast-and-accurate-attention-with-asynchrony-and-low-precision/">https://research.colfax-intl.com/flashattention-3-fast-and-accurate-attention-with-asynchrony-and-low-precision/&lt;/a>&lt;/li>
&lt;li>Colfax Research FA4: &lt;a href="https://research.colfax-intl.com/flashattention-4-algorithm-and-kernel-pipelining-co-design-for-asymmetric-hardware-scaling/">https://research.colfax-intl.com/flashattention-4-algorithm-and-kernel-pipelining-co-design-for-asymmetric-hardware-scaling/&lt;/a>&lt;/li>
&lt;li>Repo Dao-AILab/flash-attention: &lt;a href="https://github.com/Dao-AILab/flash-attention">https://github.com/Dao-AILab/flash-attention&lt;/a>&lt;/li>
&lt;li>Repo flashinfer-ai/flashinfer: &lt;a href="https://github.com/flashinfer-ai/flashinfer">https://github.com/flashinfer-ai/flashinfer&lt;/a>&lt;/li>
&lt;li>vLLM attention backends: &lt;a href="https://docs.vllm.ai/en/latest/design/attention_backends/">https://docs.vllm.ai/en/latest/design/attention_backends/&lt;/a>&lt;/li>
&lt;li>NVIDIA Hopper Architecture in Depth: &lt;a href="https://developer.nvidia.com/blog/nvidia-hopper-architecture-in-depth/">https://developer.nvidia.com/blog/nvidia-hopper-architecture-in-depth/&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>