187 lines
5.9 KiB
Markdown
187 lines
5.9 KiB
Markdown
# attention
|
|
|
|
CPU attention: scaled dot-product, multi-head, KV cache, RoPE. No fused flash-attention kernel yet.
|
|
|
|
**Header:** `attention/attention.h`
|
|
**Source:** `attention/attention.c`
|
|
**Status:** API Complete - Pending Verification
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The attention module provides:
|
|
- Scaled dot-product attention
|
|
- Multi-head attention with projections
|
|
- KV cache for efficient inference
|
|
- Rotary Position Embedding (RoPE)
|
|
- Causal masking
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
```c
|
|
#include "attention/attention.h"
|
|
|
|
// Configure attention
|
|
fa_config cfg = fa_config_default(8, 64); // 8 heads, 64 dim per head
|
|
cfg.causal = true;
|
|
|
|
// Attention: Q, K, V are [batch, seq, heads, head_dim]
|
|
tm_tensor* output = fa_attention(Q, K, V, &cfg);
|
|
|
|
// With KV cache for generation
|
|
fa_context* ctx = fa_context_new(batch, max_seq, 8, 64, num_layers);
|
|
for (int pos = 0; pos < seq_len; pos++) {
|
|
tm_tensor* out = fa_attention_cached(Q, K, V, ctx, layer, pos, &cfg);
|
|
// ... use output ...
|
|
}
|
|
fa_context_free(ctx);
|
|
```
|
|
|
|
---
|
|
|
|
## API Reference
|
|
|
|
### Configuration
|
|
|
|
```c
|
|
typedef struct {
|
|
int num_heads;
|
|
int head_dim;
|
|
float dropout;
|
|
bool causal; // Causal masking for autoregressive
|
|
float scale; // Attention scale (default: 1/sqrt(head_dim))
|
|
} fa_config;
|
|
|
|
fa_config fa_config_default(int num_heads, int head_dim);
|
|
```
|
|
|
|
### Standard Attention
|
|
|
|
```c
|
|
// Scaled dot-product attention
|
|
// Q, K, V: (batch, seq_len, num_heads, head_dim)
|
|
// Returns: (batch, seq_len, num_heads, head_dim)
|
|
tm_tensor* fa_attention(tm_tensor* Q, tm_tensor* K, tm_tensor* V, fa_config* config);
|
|
|
|
// With explicit mask
|
|
// mask: (batch, 1, seq_len, seq_len) - use -inf for masked positions
|
|
tm_tensor* fa_attention_mask(tm_tensor* Q, tm_tensor* K, tm_tensor* V,
|
|
tm_tensor* mask, fa_config* config);
|
|
```
|
|
|
|
### Multi-Head Attention
|
|
|
|
```c
|
|
// Multi-head attention with projections
|
|
// x: (batch, seq_len, embed_dim)
|
|
// Wq, Wk, Wv: (embed_dim, num_heads * head_dim)
|
|
// Wo: (num_heads * head_dim, embed_dim)
|
|
tm_tensor* fa_multi_head(tm_tensor* x, tm_tensor* Wq, tm_tensor* Wk, tm_tensor* Wv,
|
|
tm_tensor* Wo, fa_config* config);
|
|
|
|
// Self-attention (Q=K=V from same source)
|
|
// Wqkv: (embed_dim, 3 * num_heads * head_dim)
|
|
tm_tensor* fa_self_attention(tm_tensor* x, tm_tensor* Wqkv, tm_tensor* Wo,
|
|
fa_config* config);
|
|
```
|
|
|
|
### KV Cache
|
|
|
|
```c
|
|
fa_context* fa_context_new(int batch_size, int max_seq_len, int num_heads,
|
|
int head_dim, int num_layers);
|
|
void fa_context_free(fa_context* ctx);
|
|
|
|
tm_tensor* fa_attention_cached(tm_tensor* Q, tm_tensor* K, tm_tensor* V,
|
|
fa_context* ctx, int layer_idx, int pos,
|
|
fa_config* config);
|
|
|
|
void fa_context_clear(fa_context* ctx);
|
|
int fa_context_seq_len(fa_context* ctx);
|
|
```
|
|
|
|
### Rotary Position Embedding (RoPE)
|
|
|
|
```c
|
|
// Apply RoPE to Q and K in-place
|
|
void fa_rope(tm_tensor* Q, tm_tensor* K, int start_pos, int head_dim);
|
|
|
|
// Precompute frequencies
|
|
tm_tensor* fa_rope_freqs(int max_seq_len, int head_dim);
|
|
```
|
|
|
|
### Utility
|
|
|
|
```c
|
|
tm_tensor* fa_causal_mask(int seq_len);
|
|
void fa_print_config(fa_config* config);
|
|
```
|
|
|
|
---
|
|
|
|
## TurboQuant KV cache compression
|
|
|
|
`attention/turboquant.{h,c}` (prefix `fa_tq_`) compresses the KV cache from FP32
|
|
to 2-4 bits per channel, based on TurboQuant (Zandieh et al. 2025,
|
|
arXiv:2504.19874). Full design in [attention/spec.md](../attention/spec.md).
|
|
|
|
Per K or V vector the pipeline is: randomized Hadamard rotation
|
|
(`D * H * x / sqrt(d)`, `O(d log d)`) to spread information across coordinates,
|
|
a per-head range map, Lloyd-Max scalar quantization against precomputed
|
|
`Beta(d/2, d/2)` codebooks (shipped as a static table in `tq_codebooks.h`, with a
|
|
Lloyd's-algorithm fallback), then bit-packing to 2/3/4 bits. Dequant reverses
|
|
each step. The module is tensor-library-free: it operates on raw `float*` /
|
|
`uint8_t*` buffers so the foundry attention loops and external engines can call
|
|
it directly. Bit allocation is asymmetric because keys route attention while
|
|
values are averaged. The default is K4/V2 (4-bit keys, 2-bit values), which is
|
|
9.14x smaller than FP32 including range metadata.
|
|
|
|
```c
|
|
#include "attention/turboquant.h"
|
|
|
|
fa_tq_config cfg = fa_tq_config_default(); // K4 / V2
|
|
fa_tq_state* tq = fa_tq_init(head_dim, cfg, seed); // seed drives the rotation
|
|
|
|
fa_tq_cache* cache = fa_tq_cache_new(tq, num_layers, num_heads, max_seq_len);
|
|
|
|
// Per token: quantize K and V into the cache, dequantize a range back out.
|
|
fa_tq_quantize(tq, cache, layer, pos, k_vec, /*is_key=*/true);
|
|
fa_tq_quantize(tq, cache, layer, pos, v_vec, /*is_key=*/false);
|
|
fa_tq_dequantize(tq, cache, layer, /*start=*/0, count, /*is_key=*/true, out);
|
|
|
|
fa_tq_cache_free(cache);
|
|
fa_tq_free(tq);
|
|
```
|
|
|
|
Low-level single-head `fa_tq_quantize_head` / `fa_tq_dequantize_head`,
|
|
`fa_tq_rotate` / `fa_tq_rotate_inverse`, and the codebook/introspection helpers
|
|
are also public (see `turboquant.h`).
|
|
|
|
### Quality: K4/V2 is lossy, validate the value bit width per model
|
|
|
|
4-bit keys are near-lossless, but 2-bit values are the error driver. Measured
|
|
attention-output cosine similarity (FP vs compressed):
|
|
|
|
| Config | Synthetic (Gaussian) | Realistic (correlated) |
|
|
|--------|----------------------|------------------------|
|
|
| K4/V2 | ~0.94 | ~0.975 |
|
|
| K4/V3 | ~0.98 | - |
|
|
| K4/V4 | ~0.99 | ~0.99 |
|
|
|
|
The default K4/V2 is a real quality hit, not lossless. Pick the value bit width
|
|
per model on real activations before relying on K4/V2; raise it to V3 or V4 where
|
|
output fidelity matters. `make test-turboquant` runs the 11 unit tests (all
|
|
pass); `make validate-turboquant` prints the attention-output quality report
|
|
(informational, not a build gate).
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [tensor](tensor.md) - Tensor operations
|
|
- [lora](lora.md) - LoRA for attention layers
|
|
- [attention/spec.md](../attention/spec.md) - TurboQuant design spec
|