Skip to content

[RFC]: Wavefront Chunked Prefill Batching (WCPB) implementation #65

Open

Description

@LyxWxj

Progress update — 2026-10-22

Baseline: main 4a350344027960a48384626aa646f1765fda6d4f.

Motivation.

Motivation

Issue #2 defines the primary optimization target as faster Ouro inference on one GPU with loop-level batching and last-exited KV semantics. The current runtime already supports chunked prefill, refill scheduling, asynchronous execution, multiple attention backends, CUDA Graphs, prefix caching, and preemption. The scheduler walkthrough documents the existing separation between admission, stage selection, and batch construction, while the module-boundary RFC calls for explicit scheduling tasks and separate ownership of logical request state, KV resources, and device execution.

The current chunked prefill path leaves parallelism inside a request's recurrent-depth dimension unused:

  1. The scheduler selects a token range for each request.
  2. The runner embeds those tokens.
  3. The runner executes all recurrent depths for the selected range before returning.
  4. The engine advances the prompt frontier and requeues the request.

With LAST_EXITED, the KV written for c0@d0 is sufficient for c1@d0; c1@d0 does not depend on c0@d1. These dependencies allow a scheduler to overlap work across chunks and depths when the required state is ready.

This is useful when active prompt work is sparse or uneven. A conventional chunk batch may contain only a few rows even though several depth/chunk tasks are ready. WCPB can use those tasks to fill the same recurrent invocation. Smaller prompt tasks also produce more scheduler boundaries, allowing refill policies to admit new prompt work or schedule decode work earlier.

Benefits and Chunk-Size Trade-offs

WCPB is motivated by a real trade-off in ordinary chunked prefill. The chunk size controls both execution occupancy and scheduling granularity:

Chunk size Ordinary chunked prefill Scheduling consequence
Large More prompt rows are selected per batch and recurrent kernels are easier to fill Fewer scheduler boundaries; a long prefill chunk can delay newly admitted prompt or decode work
Small More frequent boundaries and smaller units of prompt work Each ordinary recurrent invocation has fewer rows, so launch, metadata, and scheduling overhead can dominate and leave the GPU underfilled

The small-chunk benefit for decode is a scheduling property rather than a claim that every small-chunk workload has lower decode latency. A smaller chunk gives the policy more opportunities to select a decode batch between prompt batches, but the actual ITL/TPOT improvement depends on stage policy, active decode work, and device execution overlap. The static experiments in this RFC did not include a concurrent decode stream, so they measure the occupancy/throughput side of this trade-off rather than directly qualifying decode latency.

What the baseline measurements show

The controlled A100 experiments make the ordinary-chunk trade-off visible. For four 8064-token requests with max_num_batched_tokens=1024, baseline end-to-end throughput fell as the chunk size became smaller:

Chunk size Baseline end-to-end tok/s Baseline prefill rows/batch
128 443.55 512.00
64 417.87 256.00
32 367.98 128.00
16 275.82 64.00

The same pattern appears in the mixed workloads. For the 32-request workload, baseline throughput changed from 662.25 tok/s at chunk 128 to 337.51 tok/s at chunk 16, while baseline prefill rows per batch changed from 480.00 to 60.00. For the 128-request workload, baseline throughput changed from 758.72 tok/s to 471.95 tok/s, and rows per batch changed from 451.39 to 97.57. These are paired measurements within each workload; they are not a claim that one chunk size is universally optimal.

Large chunks therefore remain useful when prompt throughput is the primary objective and enough prompt rows are available to fill the recurrent kernels. Their cost is reduced scheduling flexibility: a scheduler sees fewer points at which it can admit work or give decode a turn. Small chunks preserve those boundaries, but ordinary chunking cannot use the recurrent-depth dimension to compensate for the smaller per-chunk batch.

What WCPB adds

WCPB keeps the small chunk as the scheduling unit while allowing ready tasks from different chunks and recurrent depths to share the recurrent-core batch. This directly addresses the underfill mechanism in ordinary small-chunk prefill:

  • It does not require increasing prefill_chunk_size to obtain more tokens in a recurrent invocation.
  • It can combine c0@d1 with c1@d0 and later combinations when their hidden-state and depth-specific KV dependencies are ready.
  • It retains more scheduler boundaries than a large ordinary chunk, while using independent ready tasks to improve the effective batch size.
  • It is most useful when only a few requests are active or prompt lengths are uneven; in those cases, request-level batching alone may not provide enough rows.

The measurements support this mechanism. In the four-request 8064-token workload, WCPB raised rows per batch from 64.00 to 254.49 at chunk 16 and improved measured throughput from 275.82 to 412.01 tok/s (+49.38%). In the 32-request mixed workload, it raised rows per batch from 60.00 to 238.60 and improved throughput from 337.51 to 628.45 tok/s (+86.20%). In the 128-request mixed workload, it raised rows per batch from 97.57 to 361.96 and improved throughput from 471.95 to 740.29 tok/s (+56.86%). These chunk-16 results used one warmup and one measured run per variant, so they are directional measurements rather than three-run medians.

WCPB does not guarantee that a small chunk reaches the same absolute throughput as a large chunk. In the four-request workload, WCPB measured 465.31 tok/s at chunk 128 and 412.01 tok/s at chunk 16. Task metadata, hidden-state retention, dependency checks, and additional scheduling work remain costs. The intended benefit is to recover part of the occupancy lost by choosing a small chunk, while retaining its scheduling granularity. The appropriate acceptance target is therefore an end-to-end trade-off: higher effective rows and useful throughput at a chosen chunk size, together with bounded TTFT, decode ITL/TPOT, memory, and scheduler overhead.

For the SHARED KV layout, c1@d0 depends on the final-depth KV of the preceding prompt positions. The LAST_EXITED WCPB schedule therefore cannot be directly applied without changing the dependency graph. The first implementation supports only LAST_EXITED and rejects SHARED.

Proposed Design

Scheduler-visible phases and execution boundaries

The implementation keeps the existing prompt-prefill path and adds staged phases for mixed scheduling and WCPB.

With wavefront_chunked_prefill=False, an ordinary PREFILL batch executes its selected prompt range through the model’s full recurrent depth. In mixed mode, the scheduler can stage prompt work at boundaries needed to schedule prompt and decode requests together.

With WCPB enabled, prompt work uses two scheduler-visible phases:

PREFILLING_PRELUDE
-> embed a scheduled prompt range and prepare its inputs

PREFILLING_RECURRENT
-> execute one ready recurrent depth for scheduled prompt ranges

The prelude is a separate submission; the current implementation does not fuse it with depth 0. A WCPB prelude batch has loop_count=0, while a WCPB recurrent batch has loop_count=1. The scheduler records the execution boundary in the batch plan rather than relying on a user-facing atomic-prefill switch.

The model still processes prompt tokens through the configured recurrent depth before the prompt can proceed to CODA. WCPB changes how ready work is grouped and scheduled, not the logical number of recurrent depths.

Request state and scheduled work

The implementation does not create a persistent PrefillTask table or a general ExecutionTask runtime. The request owns its logical prompt progress; ScheduledRequest snapshots ranges and execution metadata for each batch.

The main progress state is:

  • num_prefilled_tokens: prompt progress completed at the final recurrent depth, including progress within the current chunk.
  • num_preluded_tokens: end of the prompt range whose prelude has been staged.
  • prefill_depth_ranges: the ready token frontier for each recurrent depth.
  • prefill_reclaimable_tokens: the start of the oldest resident chunk. It advances only when that chunk completes its final depth and its ring slot can be reused.
  • prefill_window_origin: the origin used for ring-slot assignment, including a reused cached prefix.

Each scheduled range carries its token start and count, phase, depth, chunk start, and optional prefill_hidden_row_offset. It does not carry a persistent task ID or task-owned lifecycle state. One request may contribute multiple ranges at different depths to the same WCPB batch.

Readiness and wavefront batch construction

WCPB applies only to LAST_EXITED. Its depth-separated KV planes allow depth-0 work for a later chunk to proceed once the preceding depth-0 KV prefix is ready, even while an earlier chunk is doing deeper recurrent work.

The scheduler uses per-depth frontiers to select ready ranges:

  • Depth-0 work follows the contiguous depth-0 KV prefix.
  • Work at depth d + 1 follows the available hidden state from depth d.
  • A recurrent range is limited by its depth frontier, staged prelude frontier, prompt end, chunk boundary, and remaining token budget.

The scheduler round-robins eligible request owners and ready ranges under max_num_batched_tokens, max_num_seqs, and KV-capacity constraints. It can place work from different chunks, requests, and recurrence depths into one recurrent-core batch. These are snapshots of ready ranges, not independently persisted tasks.

In mixed mode, the scheduler can combine decode and staged-prefill work in a batch when their execution phases are compatible. In particular, decode recurrent work and prompt recurrent work can share a recurrent batch. This behavior is implemented; it is not a non-goal.

Hidden-state storage and runner execution

The runner allocates staged prompt hidden-state storage with prefill_chunk_size * total_ut_steps rows per request. WCPB assigns chunks to ring slots relative to prefill_window_origin:

slot = chunk_index % total_ut_steps
prefill_hidden_row_offset = slot * prefill_chunk_size + chunk_offset

The runner embeds prelude ranges, gathers retained hidden rows for recurrent work, and packs them into the recurrent input batch. It scatters intermediate outputs back to their request ring rows for successor depths. The explicit row offset addresses the full request buffer, including the ring-slot offset. When it is None, the runner derives the row from token_start - chunk_start.

The final-depth output is used for prompt completion and CODA as needed; the runner does not retain a chunk’s intermediate state after that chunk has completed its final depth. Asynchronous submissions retain buffers until dependent device work has finished.

Progress, completion, and recovery

Prelude completion advances num_preluded_tokens and makes recurrent work eligible; it does not advance the fully prefilled prompt frontier.

Recurrent completion updates the corresponding depth frontier. Final-depth progress updates num_prefilled_tokens, but prefill_reclaimable_tokens advances only when the oldest resident chunk reaches its chunk end at the final depth. This keeps partial progress within a chunk separate from ring-slot reuse.

Prefix publication and PD progress are tied to completed prompt chunks. Imported requests initialize their prompt frontiers from the imported prefix. On preemption, staged progress is rewound to the request’s completed prompt frontier; unfinished staged work is recomputed after resume.

Compatibility and scope

WCPB requires LAST_EXITED; the scheduler rejects the SHARED KV layout because its position-major dependencies do not support this wavefront schedule. Unsupported staged-prefill combinations are rejected by scheduling-policy validation.

The current implementation includes paths for mixed scheduling, preemption and recovery, PD chunk transfer, speculative execution under compatible policies, asynchronous execution, and CUDA graph capture/replay. Mixed scheduling with speculative work is rejected; speculative WCPB uses a compatible non-mixed policy.

A generic task table, task-owned hidden-state handles, and out-of-order final-depth completion tracking remain future design options, not part of this implementation. The implementation enforces readiness and completion through request-owned frontiers, scheduled range snapshots, and the bounded hidden-state ring.

Goals

  • Increase recurrent-core batch occupancy for chunked prompt prefill.
  • Preserve LAST_EXITED causal attention and depth-specific KV semantics.
  • Keep prompt prefill at full model depth so the first generated token has the same full-depth contract.
  • Work with synchronous and asynchronous execution paths.
  • Work with the existing Triton/FlashAttention execution and CUDA Graph infrastructure where a stable batch shape is available.
  • Keep scheduler, logical KV management, and device execution responsibilities explicit.
  • Make correctness and performance claims reproducible under controlled workloads.
  • Provide an incremental path from the current minimal implementation to a more general ready-task scheduler.
  • Introducing PD prefill/decode separation.

Non-goals

  • Fused prefilling and decoding in the same device batch.
  • Supporting WCPB with SHARED KV in the initial implementation.
  • Adding preemption or recomputation of partially completed WCPB tasks in the initial implementation.
  • Changing Ouro exit policies, gate thresholds, sampling semantics, or decode loop counts.
  • Reducing the model's logical recurrent work or claiming fewer FLOPs.
  • Replacing the scheduler with a generic task runtime or reproducing the full vLLM scheduler hierarchy.

Feedback Period.

No response

CC List.

No response

Anything else.

No response

Before submitting a new issue...

Activity

  1. LyxWxj commented on Sep 28, 2026

    @LyxWxj
    ContributorAuthor
  2. LyxWxj commented on Oct 23, 2026

    @LyxWxj
    ContributorAuthor

    Performance and Accuracy Validation of Split Prefill, WCPB, and Atomic Prefill

    cc @bjf-frz @Carlos779988
    The results come from the same code(implemented on ff05fe15d182af97a30be321c99e20d5d3b17b92, #144 ), the same model, each performance configuration was run for 3 rounds and I took the average.

    Conclusions

    We have a performance gaining but precision divergence.

    The request throughput, token throughput, and latency for fixed 512-token and variable-length 256/512/768-token requests are now shown side by side for the Split, WCPB, and Atomic paths. Under this A100 workload, WCPB generally had higher throughput than Split; Atomic throughput was close to the serial result of chunk128 Split, but under concurrent/arrival it was lower than Split/WCPB. Atomic used the refill scheduler, while Split/WCPB used the mixed scheduler, so the throughput differences also include scheduler-policy differences.

    In the workload, the outputs of the three paths were not always identical. Split/WCPB had 9% to 16% of request texts differing for fixed input and 15% to 20% for variable-length input; Atomic also differed from Split under concurrent/arrival, and the outputs of Atomic chunk32 and chunk128 were also not completely identical. In the single-request test with the fixed GSM8K-87 protocol and prefill_chunk_size=64, Split/Atomic were both 60/87, and WCPB was 63/87; WCPB and Split/Atomic had 24/87 token sequences different, so the accuracy increase cannot be interpreted as semantic equivalence or model-quality improvement.

    On GSM8K-87, Split and Atomic both scored 60/87, and the token IDs for all 87 questions were completely identical; WCPB scored 63/87, but had 24/87 sequences different from Split/Atomic. The Atomic test used mode=refill, atomic_prefill=True.

    Validation Environment

    Item Configuration
    Code b2ca1f5ac10f3f133c39e9df688521524c0530c1 #144
    Model ByteDance/Ouro-1.4B
    dtype BF16
    Attention backend Triton
    GPU 2 × NVIDIA A100 80GB PCIe
    python 3.10.20
    torch 2.14.0
    triton 3.8.0
    benchmark client vLLM 0.28.0, client in a separate environment
    num_blocks 512
    max_num_seqs 8
    max_num_batched_tokens 1024
    scheduler mode Split/WCPB: mixed; Atomic: refill
    max_prefill_batches_before_decode 1
    atomic/split Split/WCPB: --no-atomic-prefill; Atomic: atomic prefill enabled by default
    WCPB switch Split/Atomic: off; WCPB: --wavefront-chunked-prefill
    Output length Fixed 64 tokens, ignore-eos
    Sampling temperature=0, seed=0
    loop policy min_loops=2, max_loops=4, exit_threshold=1
    Number of requests 100 per configuration
    Repetitions 1 per configuration

    The paired Split/WCPB services rotated GPUs by chunk size; Atomic chunk32/128 used GPU 0/1 respectively in fixed-input tests and swapped the mapping in variable-length input tests. Each service group first completed a readiness check and a single-request warm-up; warm-up was not included in the client benchmark.

    Workload Matrix

    The client uses /v1/completions; --max-concurrency and --request-rate define three workload types:

    Workload max-concurrency request-rate Meaning
    serial 1 inf Serial requests
    concurrent 8 inf 8-way concurrency
    arrival 4 2 Up to 4-way concurrency, Poisson arrival rate 2 req/s

    Each workload type was tested with prefill_chunk_size=32 and 128, and Split, WCPB, and Atomic were measured separately. Split/WCPB used mode=mixed, and Atomic used mode=refill; the current configuration validation does not allow mode=mixed and atomic prefill to be enabled at the same time. For Atomic, chunk size controls the prompt span size, and each span runs the full recursion depth in one submission. The server-side max_num_seqs=8 is the scheduler's request-owner limit; the client concurrency parameter only controls arrival-side pressure, and the two have different meanings.

    Fixed Input 512

    Using the benchmark client's random dataset: random-input-len=512, random-output-len=64, random-range-ratio=0; all 100 requests had an input length of 512.

    In the table, latency is in ms and formatted as p50/p90/p99; throughput is request/s, output tok/s, and total tok/s, respectively.

    Chunk Workload Config Request/s Output tok/s Total tok/s TTFT TPOT ITL E2E
    32 serial Split 0.159 10.17 91.56 1306/1312/1325 79/79/80 79/80/80 6285/6312/6372
    32 serial WCPB 0.180 11.53 103.80 440/445/449 82/82/83 81/83/86 5582/5614/5644
    32 serial Atomic 0.160 10.22 92.02 1260/1263/1284 79/79/80 79/80/81 6254/6269/6309
    32 concurrent Split 0.441 28.22 253.97 14684/14795/14867 84/85/85 84/85/86 19974/20103/20214
    32 concurrent WCPB 0.494 31.61 284.52 12485/12581/12626 87/87/87 87/87/91 17704/18057/18118
    32 concurrent Atomic 0.429 27.44 246.93 14905/15150/15275 87/89/90 85/86/239 20385/20695/20743
    32 arrival Split 0.443 28.35 255.13 2879/6317/6340 84/84/85 83/85/90 8134/11599/11647
    32 arrival WCPB 0.494 31.62 284.54 1943/4465/4589 88/88/89 87/94/113 7480/10004/10215
    32 arrival Atomic 0.351 22.47 202.23 3420/8177/8349 108/110/116 86/97/410 10206/15076/15189
    128 serial Split 0.186 11.93 107.39 365/369/378 79/80/82 79/80/88 5361/5404/5511
    128 serial WCPB 0.192 12.32 110.85 195/199/213 79/80/81 79/80/87 5174/5258/5319
    128 serial Atomic 0.187 11.98 107.83 348/355/362 79/80/81 79/80/82 5324/5421/5470
    128 concurrent Split 0.504 32.23 290.03 12093/12209/12445 85/86/90 85/86/101 17460/17607/17855
    128 concurrent WCPB 0.517 33.07 297.59 11705/11859/12289 84/85/91 84/86/96 16951/17176/17588
    128 concurrent Atomic 0.482 30.87 277.79 12548/12589/12896 90/90/94 87/87/260 18206/18243/18551
    128 arrival Split 0.515 32.93 296.41 1920/4371/4393 85/85/86 84/88/96 7246/9732/9789
    128 arrival WCPB 0.519 33.25 299.22 1779/4058/4068 86/87/89 84/85/139 7225/9512/9525
    128 arrival Atomic 0.459 29.38 264.45 2046/5119/5227 95/96/106 88/91/338 8010/11134/11298

    All fixed-512 results had completed=100 and failed=0; the actual input length was {512: 100}, and the output length was {64: 100}.

    The number of generated-text differences among the three configurations is as follows. The values indicate the number of requests out of 100 whose generated text differed:

    Chunk Workload Split/WCPB Split/Atomic WCPB/Atomic Atomic 32/128
    32 serial 12/100 0/100 12/100 7/100
    32 concurrent 9/100 8/100 11/100 7/100
    32 arrival 10/100 11/100 10/100 11/100
    128 serial 12/100 0/100 12/100 7/100
    128 concurrent 16/100 10/100 14/100 7/100
    128 arrival 13/100 12/100 9/100 11/100

    Variable-Length Input 256/512/768

    A fixed JSONL custom dataset was used, with shuffle and chat template disabled. The actual tokenizer length distribution of the 100 requests was: 34 with 256 tokens, 33 with 512 tokens, and 33 with 768 tokens; each request generated 64 tokens. This distribution remained unchanged across the Split, WCPB, and Atomic runs.

    Chunk Workload Config Request/s Output tok/s Total tok/s TTFT TPOT ITL E2E
    32 serial Split 0.151 9.64 86.34 1376/2064/2079 83/84/84 83/84/91 6635/7329/7370
    32 serial WCPB 0.183 11.68 104.69 433/620/624 80/80/83 80/80/93 5472/5668/5742
    32 serial Atomic 0.159 10.18 91.24 1267/1906/1923 80/81/81 80/81/82 6290/6939/6992
    32 concurrent Split 0.455 29.12 260.87 8568/22089/25369 89/90/95 89/90/97 14171/27655/30985
    32 concurrent WCPB 0.552 35.35 316.70 7895/13910/17272 87/88/98 85/94/112 13378/19352/22723
    32 concurrent Atomic 0.373 23.88 214.00 11070/24180/30468 118/134/144 86/245/406 18433/31731/38335
    32 arrival Split 0.416 26.61 238.40 2137/9764/9939 88/89/90 88/89/91 7686/15307/15500
    32 arrival WCPB 0.510 32.66 292.63 1572/5588/6721 86/86/87 85/87/102 6912/10963/12098
    32 arrival Atomic 0.355 22.71 203.52 4044/8550/10415 112/122/123 85/87/400 10568/15336/16762
    128 serial Split 0.183 11.70 104.86 372/558/562 82/82/82 81/82/87 5489/5708/5724
    128 serial WCPB 0.194 12.39 110.99 191/319/323 78/80/80 79/80/82 5148/5320/5344
    128 serial Atomic 0.185 11.83 106.01 356/537/542 81/81/81 80/81/84 5428/5629/5648
    128 concurrent Split 0.567 36.28 325.11 7771/14088/16572 87/87/88 86/92/102 13225/19547/21968
    128 concurrent WCPB 0.578 36.98 331.36 6774/12518/17030 87/89/90 84/86/191 12217/17944/22526
    128 concurrent Atomic 0.536 34.32 307.50 6837/14692/19944 95/99/101 86/88/358 12972/20710/25959
    128 arrival Split 0.502 32.12 287.81 1557/5637/6651 86/87/88 86/89/102 7001/11150/12081
    128 arrival WCPB 0.524 33.54 300.50 1802/4586/5327 86/87/89 83/84/192 7208/10023/10780
    128 arrival Atomic 0.473 30.29 271.40 1734/5655/6181 93/96/97 85/87/353 7441/11562/12159

    All variable-length results had completed=100 and failed=0; the input length distribution was {256: 34, 512: 33, 768: 33}, and the output length was {64: 100}.

    The number of generated-text differences among the three configurations is as follows:

    Chunk Workload Split/WCPB Split/Atomic WCPB/Atomic Atomic 32/128
    32 serial 20/100 0/100 20/100 15/100
    32 concurrent 20/100 20/100 16/100 22/100
    32 arrival 16/100 15/100 15/100 14/100
    128 serial 19/100 0/100 19/100 15/100
    128 concurrent 15/100 17/100 16/100 22/100
    128 arrival 15/100 15/100 15/100 14/100

    For variable-length input, the WCPB p99 ITL under chunk128 concurrent and arrival was 191 ms and 192 ms, respectively, higher than Split's 102 ms; therefore the throughput improvement did not cover all tail-latency metrics.

    Performance Chart

    The chart shows request/s, output tok/s, total tok/s, and the p50/p90/p99 of TTFT, TPOT, ITL, and E2E, in seven vertical panels. Each panel uses the three workload profiles Serial, Concurrent, and Arrival as horizontal groups, and each group compares fixed 512 and variable-length input; colors distinguish paths, while solid/dashed lines and point shapes distinguish chunk_size=32/128. Latency uses p50 polylines, p90 diamonds, and p99 interval endpoints; TTFT uses a logarithmic y-axis so that serial and concurrent workloads can be viewed together. The chart labels max_num_seqs=8, max_num_batched_tokens=1024, output length, and scheduler mode. Each configuration has only one round of measurement, so there are no statistical error bars.

    Image

    GSM8K-87 Accuracy Comparison

    This is a single-request regression independent of the HTTP performance matrix, using the fixed docs/accuracy.md protocol, Ouro-1.4B, BF16, 4-layer greedy decode, and 87 questions. Split/WCPB used mode=mixed, split_prefill=true, and prefill_chunk_size=64; Atomic used mode=refill, atomic_prefill=true, and prefill_chunk_size=64, because mixed + atomic_prefill is not supported by the current scheduler. The native scheduler configuration for all three was max_num_seqs=1 and max_num_batched_tokens=128, which cannot be conflated with the HTTP matrix max_num_batched_tokens=1024.

    Path Correct Accuracy Delta vs HF 59/87 Token sequence differences
    Split 60/87 68.97% +1.15pp Baseline
    WCPB 63/87 72.41% +4.60pp vs Split: 24/87 different
    Atomic prefill 60/87 68.97% +1.15pp vs Split: 0/87 different

    For Atomic, the decode token depth was 4 for all 87 questions, and the token IDs were completely identical to those of Split; this result shows that under the single-request fixed protocol, atomic full-depth prefill maintained the generated sequence with Split. Between WCPB and Split, 2 questions differed starting from the first token; in the paired results, 4 questions changed from wrong to correct and 1 question changed from correct to wrong. All three results passed the minimum accuracy threshold of the fixed protocol, but WCPB did not pass the semantic acceptance criterion of "keeping the generated tokens unchanged."

    Layer-wise Error Propagation Diagnostic

    The following figures come from the same Split/WCPB comparison diagnostic record (prompt record 311), configured with Ouro-1.4B BF16, mode=mixed, prefill_chunk_size=64, max_num_batched_tokens=128, and fixed 4 recursions. This prompt has 303 positions. Error is defined as max(abs(x_split - x_wcpb)); before comparison, BF16 captured values were converted to FP32. The figures are not means, RMS, or relative errors.

    The first figure takes the maximum error over the 303 prompt positions and the hidden dimension for each recursion depth; depth numbering starts from 0. Divergence begins at the d0 output, with a maximum value of 0.25; afterward, the maximum values at the d1/d2/d3 outputs are 2.703125, 2.75, and 4.21875, respectively. The second figure tracks the maximum error of the hidden-state input and output for d0, token position 64, across 24 transformer blocks; the block 0 output is 0.0009765625, and the block 23 output is 0.125. The curve fluctuates, and one cannot infer from this that every layer monotonically amplifies the error.

    The third figure expands the attention error for the same token: the maximum difference between query and KV key is 0.0625 (block 1), the maximum KV value difference is 0.03125 (block 17), and the maximum attention output difference is 0.03125 (block 6). The block, depth/position mapping, and write-address checks for this record all showed no mismatch; this supports the existence of differences in the numerical path, but a single-sample trace cannot prove that all differences come from one particular kernel. For this sample, the first output token was Split 8696 and WCPB 1385, and the maximum absolute logits difference was 0.1875.

    Image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions