# RULER 32K Chunked Offload Accuracy Issue **Status**: ✅ **RESOLVED** (Last Updated: 2026-01-21) **Branch**: `tzj/minference` **Severity**: RESOLVED - State leakage fixed --- ## 🎯 修复完成 ### 问题根因 **连续请求间的 CPU KV Cache 状态泄露** `OffloadEngine.reset()` 清除了 GPU buffers 但**没有清除 CPU cache**,导致前一个请求的 KV cache 数据残留在 CPU 内存中,污染后续请求。 ### 修复实施 (2026-01-21) #### Fix 1: CPU Cache 清理 **文件**: `nanovllm/kvcache/offload_engine.py` ```python def reset(self) -> None: # 清除 GPU buffers (原有) self.k_cache_gpu.zero_() self.v_cache_gpu.zero_() self.decode_k_buffer.zero_() self.decode_v_buffer.zero_() self.prefill_k_buffer.zero_() self.prefill_v_buffer.zero_() # 🔧 新增:清除 CPU cache (关键修复) self.k_cache_cpu.zero_() self.v_cache_cpu.zero_() self.pending_events.clear() ``` #### Fix 2: Decode 状态跟踪清理 **文件**: `nanovllm/kvcache/hybrid_manager.py` ```python def deallocate(self, seq: Sequence) -> None: # ... release blocks ... seq.num_cached_tokens = 0 seq.block_table.clear() # 🔧 新增:清理 decode 位置跟踪 self.clear_decode_tracking(seq) if self.offload_engine is not None: self.offload_engine.reset() ``` ### 验证结果 (2026-01-21) | 测试任务 | 修复前 | 修复后 | 改善 | |---------|--------|--------|------| | niah_single_1 (100样本) | ~80% | **94%** | +14% ✅ | | niah_single_1 (50样本) | - | **100%** | ✅ | | niah_multikey_1 (50样本) | - | **96%** | ✅ | | niah_multikey_2 (50样本) | - | **100%** | ✅ | ### 结论 1. **CPU cache 泄露已修复** - 批量测试准确率从 ~80% 提升到 94% 2. **剩余 ~6% 错误是模型固有限制** - 失败样本 (17, 37, 52, 87, 91, 94) 与模型能力相关,非状态泄露 3. **Chunked attention 算法正确** - niah_single_1 可达 100% 准确率 ### 修复前后对比 | 状态 | 组件 | 修复前 | 修复后 | |------|------|--------|--------| | CPU KV Cache | `k_cache_cpu`, `v_cache_cpu` | ❌ 不清理 | ✅ 清理 | | Decode 跟踪 | `_decode_start_pos`, `_prefill_len` | ❌ 不清理 | ✅ 清理 | --- ## 历史问题记录 以下是原始问题分析,保留作为参考。 ### Problem (Original) When running RULER benchmark with 32K context length using the chunked offload mechanism in `tzj/minference` branch, accuracy degradation is observed compared to the `xattn_stride8` baseline. **Note**: An error is counted when the expected answer is **NOT contained** in the model's output. If the expected answer appears anywhere in the output, it's considered correct. ### Error Statistics (Corrected) | Task | Total Samples | Errors | Error Rate | |------|--------------|--------|------------| | niah_single_1 | 100 | 19 | 19% | | niah_single_2 | 100 | 23 | 23% | | niah_single_3 | 100 | 8 | **8%** | | niah_multikey_1 | 100 | 16 | 16% | | niah_multikey_2 | 100 | 30 | 30% | | niah_multikey_3 | 100 | 24 | **24%** | | **TOTAL** | **600** | **120** | **20%** | ### Critical Failure Pattern **niah_multikey_2** shows the highest error rate at **30%**: - Many samples show pattern loops and repetitions ("is:", digit patterns) - Suggests systematic chunk boundary handling issues **niah_single_3** and **niah_multikey_3** have much lower error rates than initially reported: - niah_single_3: Only 8 errors (not 54) - niah_multikey_3: Only 24 errors (not 54) - Most UUID samples were correctly identified despite minor formatting differences ### Error Examples #### Type 1: Corrupted Number Output ``` Index 28: 标准答案=9874152, 当前输出=:151:52 Index 33: 标准答案=9196204, 当前输出=: Index 40: 标准答案=6171716, 当前输出=: 17: 16 ``` #### Type 2: Number Repetition/Loop ``` Index 61: 当前输出=: 8, 9, 10, 11, 12, 13, 14, 15, 16, ... Index 65: 当前输出=:361361361361361361361361361361... ``` #### Type 3: Duplicated "is:" Pattern ``` Index 17: 当前输出=: 234404047 is: 234404047 is: 2344047 ``` --- ## Solution Attempts ### Attempt 1: Increase GPU Slots (4-slot Configuration) **Date**: 2026-01-20 **Rationale**: Based on Hypothesis 2 (Ring Buffer Race Condition), increasing GPU slots should reduce memory contention during CPU↔GPU transfers. **Configuration Changes**: ```python # Before (2-slot) num_gpu_blocks = 2 tokens_per_chunk = 1024 compute_size = 1 block # After (4-slot) num_gpu_blocks = 4 tokens_per_chunk = 2048 compute_size = 2 blocks ``` **Offload Log**: ``` [INFO] Unified Ring Buffer: 4 slots total [INFO] Prefill: all slots as ring buffer [0..3] [INFO] Decode: slot[0] as decode_slot, slots[1..3] for loading [INFO] KV Cache allocated (Chunked Offload mode): GPU=4 blocks (512.0MB), CPU=32 blocks (4096.0MB) [INFO] Chunked Offload config: compute_size=2 blocks, tokens_per_chunk=2048, block_size=1024 ``` **Results Comparison**: | Task | 2-slot Accuracy | 4-slot Accuracy | Improvement | |------|-----------------|-----------------|-------------| | niah_single_1 | 94% (94/100) | **98%** (98/100) | +4% ✅ | | niah_multikey_3 | 48% (48/100) | **56%** (56/100) | +8% ✅ | **Test Duration**: - niah_single_1: 40 minutes (2402s) - niah_multikey_3: 100 minutes (6008s) **Key Findings**: 1. ✅ **Significant Improvement**: 4-slot configuration reduced error rate for both tasks 2. ✅ **Validation**: Supports Hypothesis 2 that ring buffer contention contributes to errors 3. ❌ **Not Fully Resolved**: 2 failures still occur in niah_single_1 with same error pattern **Remaining Failures** (niah_single_1): | Sample | Expected | Actual | Error Type | |--------|----------|--------|------------| | 17 | `2344047` | `23440447` | Extra digit | | 40 | `6171716` | `6171717161711716` | Number repetition | **Critical Observation**: Sample 40 shows the **exact same number repetition error** (`6171717161711716`) as in the 2-slot configuration, confirming the root cause is partially mitigated but not eliminated by reducing ring buffer contention. **Conclusion**: - Increasing GPU slots from 2 to 4 **reduces but does not eliminate** KV cache corruption - The remaining errors suggest additional factors contribute to the problem - Further investigation needed into: - Request-to-request KV cache isolation - Layer-wise offload state management - Potential timing issues in async transfer completion --- ## Test Configuration ### Environment - **Model**: Llama-3.1-8B-Instruct - **Context Length**: 32768 tokens - **GPUs**: 4x RTX 3090 (24GB each) - **Branch**: `tzj/minference` - **Chunk Size**: 1024 tokens (kvcache_block_size) - **Chunks**: ~32 chunks per 32K sequence ### Key Parameters ```python kvcache_block_size = 1024 enable_cpu_offload = True num_gpu_blocks = 2 max_model_len = 32768 tokens_per_chunk = 1024 ``` ### Chunked Offload Log ``` [INFO] Unified Ring Buffer: 2 slots total [INFO] KV Cache allocated (Chunked Offload mode): GPU=2 blocks (256.0MB), CPU=128 blocks (16384.0MB) [INFO] Chunked Offload config: compute_size=1 blocks, tokens_per_chunk=1024, block_size=1024 ``` --- ## Error Sample Indices ### niah_single_1 (19 errors) ``` 28, 33, 39, 40, 41, 43, 44, 49, 51, 52, 53, 57, 61, 63, 65, 67, 72, 77, 83 ``` ### niah_single_2 (23 errors) ``` 16, 24, 30, 32, 40, 41, 42, 50, 51, 52, 55, 58, 60, 62, 64, 66, 67, 68, 69, 77, 85, 91, 93 ``` ### niah_single_3 (8 errors) ``` 7, 9, 14, 24, 25, 29, 31, 43 ``` ### niah_multikey_1 (16 errors) ``` 20, 31, 32, 40, 41, 45, 51, 54, 59, 63, 64, 65, 67, 69, 71, 74 ``` ### niah_multikey_2 (30 errors) ``` 2, 13, 21, 22, 23, 24, 25, 28, 32, 34, 38, 39, 40, 41, 42, 43, 45, 46, 47, 49, 50, 53, 54, 56, 57, 59, 60, 63, 64, 65 ``` ### niah_multikey_3 (24 errors) ``` 11, 18, 20, 23, 24, 25, 26, 27, 29, 30, 33, 35, 37, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 52 ``` --- ## Analysis ### Possible Root Causes 1. **Chunk Boundary Handling**: Chunk size of 1024 may cause precision loss at chunk boundaries during attention computation 2. **KV Cache Transfer**: Ring buffer with only 2 slots may cause race conditions or data corruption during high-frequency CPU↔GPU transfers 3. **Attention State Accumulation**: The `chunked_attention_varlen` function uses online softmax with log-sum-exp tracking - numerical instability may accumulate over 32 chunks 4. **Layer-wise Offload Interaction**: Chunked prefill with layer-wise CPU offload may have interference in memory management 5. **Position Encoding**: RoPE embeddings may have precision issues when computed in chunks vs. full sequence --- ## Detailed Hypotheses ### Hypothesis 1: Chunk Boundary Precision Loss ⚠️ HIGH LIKELIHOOD **Problem**: 32K context with 1024 token chunks means 32 chunk boundaries. At each boundary: - Attention scores must be merged using online softmax (`logsumexp`) - Small numerical errors accumulate exponentially across 32 operations - The `logsumexp` operation: `log(exp(A) + exp(B))` can lose precision when A and B have very different magnitudes **Evidence supporting this hypothesis**: - Error patterns show corrupted outputs that look like "partial" answers (e.g., `:151:52` instead of `9874152`) - This suggests some chunks produce correct output while others are corrupted - niah_single_3 and niah_multikey_3 (54% error) may have different input patterns that exacerbate boundary issues **Test**: Compare chunk sizes (512 vs 1024 vs 2048 vs 4096). If boundary precision is the issue: - Smaller chunks → more boundaries → higher error rate - Larger chunks → fewer boundaries → lower error rate --- ### Hypothesis 2: Ring Buffer Race Condition ✅ PARTIALLY VALIDATED **Problem**: With only 2 ring buffer slots and 32 chunks: - Each chunk must: load previous chunks → compute → store to CPU → free slot - Slot 0 is used for decoding, leaving only Slot 1 for prefill loading - With high-frequency transfers, GPU/CPU may access the same slot simultaneously **Code location**: `offload_engine.py`: ```python def get_write_slot_for_prefill(self, chunk_idx: int) -> int: return chunk_idx % self.num_ring_slots # Only 2 slots! ``` **Evidence supporting this hypothesis**: - The "number repetition" errors (e.g., `:3613613613...`) look like memory corruption - Repetition patterns suggest reading stale/corrupted data from a previous chunk - 2 slots is extremely aggressive for 32 chunks - could cause slot reuse before data is safely offloaded **Test Completed** (2026-01-20): - ✅ Increased `num_gpu_blocks` from 2 to 4 - ✅ Error rate decreased significantly (niah_single_1: 94%→98%, niah_multikey_3: 48%→56%) - ⚠️ Some errors remain with same pattern (e.g., Sample 40: `6171717161711716`) **Conclusion**: Ring buffer contention is **a contributing factor** but not the sole cause. Additional mechanisms also contribute to KV cache corruption. --- ### Hypothesis 3: Position Embedding Chunk Mismatch ⚠️ MEDIUM LIKELIHOOD **Problem**: RoPE (Rotary Position Embedding) requires absolute positions: - Token at position 1024 should get RoPE(1024), not RoPE(0) relative to chunk - If positions reset at each chunk boundary, attention sees wrong positional relationships - For 32K context, tokens at positions 30720-32768 would have incorrect RoPE **Code to check**: In `model_runner.py`, are positions computed as: ```python # WRONG: resets at chunk boundary positions = torch.arange(chunk_start, chunk_end) # 0-1023, 0-1023, ... # CORRECT: absolute positions positions = torch.arange(chunk_start, chunk_end) + chunk_idx * chunk_size # 0-1023, 1024-2047, ... ``` **Evidence supporting this hypothesis**: - RULER needle-in-haystack tasks are position-sensitive - Wrong RoPE would cause the model to miss the "needle" (answer) - Error rate of 35% suggests positional confusion **Test**: Inject a position-only test (no attention) to verify RoPE is computed correctly across chunks. --- ### Hypothesis 4: Layer-wise Offload Interference ⚠️ LOW LIKELIHOOD **Problem**: `tzj/minference` branch implements BOTH: 1. Chunked prefill (process sequence in chunks) 2. Layer-wise offload (offload KV to CPU after each layer) **Potential conflict**: - After processing layer N with chunk K, KV is offloaded to CPU - When processing layer N+1 with chunk K+1, previous chunks must be reloaded - If timing is wrong, layer N+1 might read stale KV from layer N **Evidence against this hypothesis**: - Layer-wise offload should be independent per-layer - Each layer's KV cache is separate - But: if ring buffer slots are shared across layers... **Test**: Disable layer-wise offload (`num_gpu_blocks=-1` or large number) and retry. --- ### Hypothesis 5: Attention State Numerical Instability ⚠️ MEDIUM LIKELIHOOD **Problem**: `chunked_attention_varlen` in `chunked_attention.py` uses: ```python # Track accumulated attention for online softmax attn_output = 0.0 max_score = -float('inf') for chunk in chunks: # Compute attention for this chunk chunk_attn, chunk_max = compute_attention(chunk, all_chunks) # Merge using online softmax formula max_score = torch.maximum(max_score, chunk_max) attn_output += (chunk_attn - max_score).exp() * values ``` **Numerical issue**: - `torch.maximum(max_score, chunk_max)` loses precision when values differ significantly - After 32 chunks, accumulated error can be substantial - For very large or very small attention scores, exp() can underflow/overflow **Evidence supporting this hypothesis**: - 4K context (4 chunks) works fine → fewer chunk merges - 32K context (32 chunks) fails → many chunk merges - Error patterns suggest "some chunks correct, others corrupted" **Test**: Add tensor logging at each chunk merge to track numerical precision degradation. --- ### Hypothesis 6: Sparse Policy Trigger Mismatch 🤔 UNCERTAIN **Problem**: The `_should_use_chunked_offload()` function checks: ```python def _should_use_chunked_offload(self, seqs, is_prefill): # Check if blocks are on CPU OR sequence exceeds GPU compute region cpu_blocks, _ = self.kvcache_manager.get_all_cpu_blocks(seq) if cpu_blocks: return True if seq.num_blocks > compute_size: return True return False ``` **Potential issue**: - For some samples, chunked offload is enabled - For other samples (with shorter effective length), regular prefill is used - The switch between modes might have state corruption **Evidence supporting this hypothesis**: - niah_single_1 has samples 0-16 correct, then errors start at 17 - This suggests mode switching or threshold-based behavior - Different task types have different error rates (19% vs 54%) **Test**: Force chunked offload ALWAYS (or NEVER) to see if error rate stabilizes. --- ### Hypothesis 7: GPU Memory Fragmentation ⚠️ LOW LIKELIHOOD **Problem**: With only 2 GPU blocks (256MB each): - Ring buffer slots are 128MB each - Frequent allocation/deallocation might fragment GPU memory - Subsequent chunks might get misaligned or corrupted memory regions **Evidence against this hypothesis**: - GPU memory is managed at block level (1024 tokens = 128MB) - Fragmentation would cause crashes, not semantic errors - PyTorch's memory allocator should handle this **Test**: Run with `num_gpu_blocks=4` to reduce memory pressure. --- ## Error Pattern Analysis ### Why niah_single_3 and niah_multikey_3 Fail catastrophically **Hypothesis**: Task 3 in each category has different data distribution: - May have longer input sequences (more haystack text) - May have needles at different positions - May require different attention patterns **Investigation needed**: 1. Compare input lengths of task 3 vs tasks 1/2 2. Check if task 3 samples trigger more aggressive chunked offload 3. Verify if task 3 has different position encoding requirements ### Why "Number Repetition" Errors Occur **Pattern**: `:3613613613613...` or `: 8, 9, 10, 11, ...` **Hypothesis**: Model enters a "loop" state where: 1. Attention produces a partial token (e.g., "36") 2. Next attention step sees corrupted context 3. Instead of producing new content, model repeats the partial token 4. This continues until hitting max_token limit **Root cause**: Likely KV cache corruption at chunk boundary, causing the model to "forget" the original question and enter a degenerate generation loop. --- ## Key Files to Investigate - `nanovllm/kvcache/chunked_attention.py` - Chunked attention computation (Hypothesis 1, 5) - `nanovllm/engine/model_runner.py` - `run_chunked_offload_prefill()` method (Hypothesis 3, 6) - `nanovllm/kvcache/offload_engine.py` - Ring buffer management (Hypothesis 2, 7) - `nanovllm/layers/attention.py` - Attention layer with chunked offload (Hypothesis 4) - `nanovllm/kvcache/hybrid_manager.py` - KV cache manager and block allocation (Hypothesis 6) --- ## Detailed Error Samples ### niah_single_1 (19 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 28 | `9874152` | `:151:52<|eot_id|>` | | 33 | `9196204` | `:<|eot_id|>` | | 39 | `3484601` | `:<|eot_id|>` | | 40 | `6171716` | `: 17: 16<|eot_id|>` | | 41 | `4524499` | `:<|eot_id|>` | | 43 | `3726327` | `: 16: 7<|eot_id|>` | | 44 | `4009172` | `: 2<|eot_id|>` | | 49 | `4240180` | `:354:180<|eot_id|>` | | 51 | `9546409` | `:<|eot_id|>` | | 52 | `2935113` | `: 29351113.<|eot_id|>` | | 53 | `5453786` | `:354:678:90<|eot_id|>` | | 57 | `8315831` | `: 5831<|eot_id|>` | | 61 | `5960271` | `: 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,...<|eot_id|>` | | 63 | `6049101` | `: 5 0 4 9 1 0 1<|eot_id|>` | | 65 | `6406444` | `:361361361361361361361361361361361361361361361361361361361361361361361361361361...<|eot_id|>` | | 67 | `2422633` | `:31<|eot_id|>` | | 72 | `7442089` | ` 7953166<|eot_id|>` | | 77 | `8795419` | `:<|eot_id|>` | | 83 | `6363836` | `: 2<|eot_id|>` | ### niah_single_2 (23 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 16 | `2344047` | `: 23440447.<|eot_id|>` | | 24 | `5449324` | `:<|eot_id|>` | | 30 | `5727085` | `:<|eot_id|>` | | 32 | `9196204` | `:<|eot_id|>` | | 40 | `4524499` | `:460<|eot_id|>` | | 41 | `7817881` | `:171.<|eot_id|>` | | 42 | `3726327` | `:<|eot_id|>` | | 50 | `9546409` | `:<|eot_id|>` | | 51 | `2935113` | `: 3: 5113<|eot_id|>` | | 52 | `5453786` | `:354<|eot_id|>` | | 55 | `4188992` | `: 418899189418899, but it is not explicitly stated in the provided ...` | | 58 | `6266630` | `:5963<|eot_id|>` | | 60 | `5960271` | ` 0271<|eot_id|>` | | 62 | `6049101` | `:<|eot_id|>` | | 64 | `6406444` | `:<|eot_id|>` | | 66 | `2422633` | `:5313<|eot_id|>` | | 67 | `4940441` | `:5311<|eot_id|>` | | 68 | `3472189` | `:361.<|eot_id|>` | | 69 | `8971465` | `:361.<|eot_id|>` | | 77 | `8963715` | `: 0 8 9 7 1 5<|eot_id|>` | | 85 | `2044645` | `: 20446445.<|eot_id|>` | | 91 | `7783308` | `:<|eot_id|>` | | 93 | `1454696` | `:<|eot_id|>` | ### niah_single_3 (8 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 7 | `ee87905e-4ca4-45ea-8dfa-6a56d12dbc9a` | `: 2010-07-01T00:00:00Z<|eot_id|>` | | 9 | `b7b56ea7-35eb-432d-9ad6-20ab48212ddb` | `:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0<|eot_id|>` | | 14 | `e767dcea-b0e6-4969-a213-42b0f1eedba3` | `:0e6-4969-a213-42b0f1eedba3<|eot_id|>` | | 24 | `59e4b671-4774-4c58-85f8-bc16f7860b50` | `:4774:4c58:85f8:bc16f7860b50<|eot_id|>` | | 25 | `54c63cd8-8945-4f27-97fa-2d8dfb2ca025` | `: 54c63c63cd8-8945-4f27-97fa-2d8dfb2ca025.<|eot_id|>` | | 29 | `006ed6e3-6fa1-4735-b572-f3d00b5cea6a` | `:6e3-6fa1-4735-b572-f3d00b5cea6a<|eot_id|>` | | 31 | `e6697833-b841-40a0-9fe7-71d6d9178793` | `: e6697837837833-b841-40a0-9fe7-71d6d9178793.<|eot_id|>` | | 43 | `d92c9227-eadf-4085-bfcb-75468eb22579` | `: d92c922c9227-eadf-4085-bfcb-75468eb22579.<|eot_id|>` | ### niah_multikey_1 (16 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 20 | `2171218` | `: 2171212181212181212181218<|eot_id|>` | | 31 | `9333700` | `:<|eot_id|>` | | 32 | `7121355` | `:9651<|eot_id|>` | | 40 | `3112652` | `:285<|eot_id|>` | | 41 | `3427461` | `:<|eot_id|>` | | 45 | `8217547` | `:<|eot_id|>` | | 51 | `1514340` | `: 1514343403361.<|eot_id|>` | | 54 | `8212753` | `:<|eot_id|>` | | 59 | `6587964` | `:<|eot_id|>` | | 63 | `1688246` | `:<|eot_id|>` | | 64 | `8344365` | `: 834436, but it is not explicitly mentioned.<|eot_id|>` | | 65 | `6614484` | `: 4367.<|eot_id|>` | | 67 | `6510922` | `:7780<|eot_id|>` | | 69 | `6649968` | `: 43610.<|eot_id|>` | | 71 | `9437374` | `:<|eot_id|>` | | 74 | `6625238` | `:1472908<|eot_id|>` | ### niah_multikey_2 (30 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 2 | `1535573` | `: 8651665.<|eot_id|>` | | 13 | `2794159` | `: 5261593<|eot_id|>` | | 21 | `8970232` | `:168<|eot_id|>` | | 22 | `9134051` | `: 381:055: 381:055: 381:055: 381:055: 381:055: 381:055: 381:055: 38...` | | 23 | `9696620` | `: 969662620969662, which is: 969662920, 96966220 is not actually me...` | | 24 | `7071187` | ` 055055055.<|eot_id|>` | | 25 | `5572782` | `: 5342494<|eot_id|>` | | 28 | `4953027` | `:1687719<|eot_id|>` | | 32 | `4259234` | `: 425923521250, but not found is: 425923751572250, however is: 4259...` | | 34 | `3643022` | `: 3957500<|eot_id|>` | | 38 | `2031469` | `: the text.<|eot_id|>` | | 39 | `8740362` | `: 8740364 8740364 8740364 8740364 is: is: is: is: 874036...` | | 40 | `7041770` | `:1682<|eot_id|>` | | 41 | `1986258` | `:086.<|eot_id|>` | | 42 | `5668574` | `:055.<|eot_id|>` | | 43 | `8560471` | `:067<|eot_id|>` | | 45 | `9973767` | `: 8420273<|eot_id|>` | | 46 | `3960211` | `:0<|eot_id|>` | | 47 | `8003271` | `: 60870870870870870870870870870870870870870870870870870870870870870...` | | 49 | `8632309` | ` 303640 is640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 640 6...` | | 50 | `2318630` | `: 7780552.<|eot_id|>` | | 53 | `3405052` | `:<|eot_id|>` | | 54 | `5364945` | `: 536494, which is: 536494, which is: 536494494494494494494494494494494494494494...` | | 56 | `7319214` | `:7607607607607607607607607607607607607607607607607607607607607607607607607607607...` | | 57 | `9206104` | `:7607607607607607607607607607607607607607607607607607607607607607607607607607607607607607607...` | | 59 | `9555385` | `:7095<|eot_id|>` | | 60 | `5727554` | `: 572755755755755755755755755755755755755755755755755755755755 is: 572...` | | 63 | `1090767` | `:7607607607607607607607607607607607607607607607607607607607607607607607607607607607607607...` | | 64 | `6791240` | `:<|eot_id|>` | | 65 | `7275999` | `:7607607607607607607607607607607607607607607607607607607607607607607607607607607607607...` | ### niah_multikey_3 (24 errors) | Index | 标准答案 | 当前答案 | |-------|----------|----------| | 11 | `c73ed342-6523-4d4b-aa33-beb1c9007315` | `: 1d28b88b-b6a8-46ba-8e8f-56cbafbfd897.<|eot_id|>` | | 18 | `87b8a762-1d1f-4e85-a5d1-caf284c95aa6` | `: 429a6676-5295-4ea2-a694-6aa949f48e31.<|eot_id|>` | | 20 | `cce29702-134a-460c-979b-6f7ee7895280` | `:<|eot_id|>` | | 23 | `ed344bfe-983f-4a21-af44-722e2517244c` | `: aec431e7d880a8dce2c023de24 is: aec43163-061a-4afe-b80a-f5bfb5e3c9...` | | 24 | `4712ef99-a8d1-4388-8ca7-b08dd3505d77` | `:<|eot_id|>` | | 25 | `46969ce7-0da0-49f8-87b2-845e7b8ef100` | `:<|eot_id|>` | | 26 | `7cff3c66-6860-49e6-8ba5-002162c250c0` | `:4c7e-946b-30812edf965e<|eot_id|>` | | 27 | `b63b4988-40bc-44b2-bf1c-ca95adbca4e9` | `:<|eot_id|>` | | 29 | `6d94011c-f28a-4b0b-a2e2-fe34bb8b19a1` | `: 6d6d6d6d4b0e-52ce-44d9-a0f6-1ae405825615<|eot_id|>` | | 30 | `7c33bb00-4ab4-4e4f-a78e-39f8f06d63eb` | ` d7a2-4b23-a2c0-8c859cb1fa96<|eot_id|>` | | 33 | `b7c6b586-713a-4907-ad24-5c4f25aeb769` | `:1-4d2c-b42b-933ded2633d6<|eot_id|>` | | 35 | `ac8a317b-a6bb-4327-90db-2a01622cb723` | `: d2f2f2f2f2f2f2f2d2d2f2d2d2d3d2f6b3d2f- is: d2dab is: is: is: i...` | | 37 | `b187b337-3132-4376-a500-9340102092ae` | `:<|eot_id|>` | | 40 | `2559fa56-dd0a-48d4-ba82-3ae2bf0a4b33` | `:358fe0e3-724e-4cfc-9ae0-d0873162626b.<|eot_id|>` | | 41 | `7842feb5-e758-44cd-b73b-8ae08aa33142` | `: 6c6adf83-36a9-4e41-9cbe-60a8c9ffba92.<|eot_id|>` | | 42 | `a1196139-f6fa-4c18-b3da-b7bd50362ac7` | `: a1196131396131196131399a1196139a1196139a1196139a1196139f6a1196139...` | | 44 | `7d3d40b2-4594-4573-b267-4c6270dd4425` | `: 613a9e-4e7d-8c9f-740a630e3c53<|eot_id|>` | | 45 | `500b8a75-8f05-43f5-b9ad-46d47d4e33fc` | `: 500b8a5e0e0e0a500b is: 500b is: 500b-4 is: is: is: is: is: i...` | | 46 | `86a867a7-6a98-4a02-b065-70a33bafafde` | `:6139a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a...` | | 47 | `7c0f7fd2-237e-4c0f-b3f5-f43623551169` | ` 5fb71d2f0f0b4f0 is: 5fb71 is: 5fb71f-4f-4f-4f-4f-4f-4d7 is: is: ...` | | 48 | `b0e1f3f5-6570-437e-b8a1-f1b3f654e257` | `: 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b ...` | | 49 | `0153722a-70a8-4ec0-9f03-2b0930937e60` | `: 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b ...` | | 50 | `0a1ead51-0c39-4eeb-ac87-d146acdb1d4a` | `: 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b 500b ...` | | 52 | `ff686e85-3a9f-4635-95dd-f19e8ca68eb1` | ` ff686e686e686e686e686e686f686e6f686e6fb686f686f686f686f686f- is: f...` | --- ## Multikey 任务失败分析 (单样本测试) ### 失败样本特征 单样本测试中 multikey 任务的失败**不是**状态泄露,而是**模型检索能力问题**。 #### 错误类型 | 类型 | 示例 | 说明 | |------|------|------| | **检索错误 key** | Expected `5833597`, Got `8617381` | 返回了上下文中另一个 key 的 value | | **UUID 检索错误** | Expected `c73ed342-...`, Got `1d28b88b-...` | 返回了错误 key 对应的 UUID | #### multikey_2 失败样本详情 (单样本测试) | Sample | Expected | Got | 分析 | |--------|----------|-----|------| | 2 | `1535573` | `8651665` | 错误 key | | 12 | `4641400` | `9390530` | 错误 key | | 19 | `8591874` | `3853628` | 错误 key | | 50 | `2318630` | `7780552` | 错误 key | | 66 | `1926587` | `9249734` | 错误 key | | 85 | `1253265` | `3263480` | 错误 key | | 86 | `7772887` | `3762547` | 错误 key | | 89 | `2266721` | `5873220` | 错误 key | | 98 | (未记录) | (未记录) | - | #### multikey_3 失败样本详情 (单样本测试) | Sample | Expected | Got | 分析 | |--------|----------|-----|------| | 11 | `c73ed342-6523-...` | `1d28b88b-b6a8-...` | 错误 key 的 UUID | | 18 | `87b8a762-1d1f-...` | `429a6676-5295-...` | 错误 key 的 UUID | | 23 | `ed344bfe-983f-...` | `aec43163-061a-...` | 错误 key 的 UUID | | 35 | `ac8a317b-a6bb-...` | `d2f22889-5b72-...` | 错误 key 的 UUID | | 41 | `7842feb5-e758-...` | `fc8e724e-418d-...` | 错误 key 的 UUID | | 47 | `7c0f7fd2-237e-...` | `5fb71d15-4675-...` | 错误 key 的 UUID | | 53 | `bccd56fa-8fba-...` | `373cc0cc-6ab7-...` | 错误 key 的 UUID | | 86 | `68c49603-1d17-...` | `aef58e2e-9e99-...` | 错误 key 的 UUID | | 93 | `74651292-5664-...` | `4546dd56-fe88-...` | 错误 key 的 UUID | ### 关键发现 1. **格式正确**: 失败样本的输出格式完全正确(7位数字或UUID) 2. **合法 value**: 输出的是上下文中存在的另一个 key-value 对的 value 3. **确定性失败**: 同一样本多次测试返回相同的错误值 4. **模型能力边界**: 这是多 key 检索任务的模型能力上限,~91% 准确率符合预期 --- ## Comparison with Working Baseline ### xattn_stride8 (Working) - **Branch**: `tzj/vs_offload` or earlier - **Method**: XAttention sparse pattern with stride 8 - **Error Rate**: ~8% (expected RULER baseline) - **Samples**: 100 samples per task ### Chunked Offload - 批量测试 (Broken) - **Branch**: `tzj/minference` - **Method**: Full attention with chunked CPU offload - **Error Rate**: 20% (120/600) - **状态泄露导致** - **Samples**: 100 samples per task ### Chunked Offload - 单样本测试 (Working) - **Branch**: `tzj/minference` - **Method**: Full attention with chunked CPU offload, 每个请求重新初始化 LLM - **Error Rate**: 0% (niah_single_1), ~9% (multikey tasks) - **Samples**: 100 samples per task - **结论**: 算法正确,multikey 失败是模型能力问题 --- ## Next Steps (Updated) ### 已完成 ✅ 1. ~~**Reproduce with 4K context**~~ - 不再需要,算法已验证正确 2. ~~**Vary chunk size**~~ - 不再需要,问题不在 chunk 大小 3. ~~**4-slot 配置测试**~~ - 已完成,有改善但不是根本原因 ### 待完成 🔧 1. **定位状态泄露组件**: 调查连续请求间哪些状态未正确重置 - KV cache manager 的 `reset()` 或 `clear()` 方法 - Offload engine 的 ring buffer slot 状态 - Decode buffer 的跨请求隔离 - Sparse policy 的内部状态 2. **实现状态重置修复**: 在每个请求完成后正确清理所有状态 3. **验证修复**: 使用批量测试验证修复后准确率恢复到 ~95%+ 4. **Add tensor checkpoints**: Log intermediate attention outputs at chunk boundaries 5. **Compare with non-offload**: Test 32K with GPU-only mode (if memory permits) 6. **Numerical stability**: Add clipping/normalization to online softmax accumulation --- ## Related Documents - [`architecture_guide.md`](architecture_guide.md) - Chunked attention design - [`known_issues.md`](known_issues.md) - Previously fixed bugs - [`ruler_benchmark_results_32k.md`](ruler_benchmark_results_32k.md) - Previous working results --- **Author**: Zijie Tian **Reported**: 2026-01-18 **Last Updated**: 2026-01-20 (4-slot test results added)