Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b7ffb3a
feat(ws2): add TP-aware logprob contract and dispatch metadata
ryankert01 Aug 2, 2026
cdc11ba
fix(ws2): address CodeRabbit review on logprob contract PR
ryankert01 Aug 2, 2026
6455715
fix(ws2): address second CodeRabbit round on logprob contract
ryankert01 Aug 2, 2026
3b4eaef
feat(ws2): make determinism scope and invocation surface part of the …
ryankert01 Aug 2, 2026
e6dbeef
docs(ws2): drop standalone design doc per review
ryankert01 Aug 2, 2026
878ba88
style(ws2): align comment density with sibling kernel modules
ryankert01 Aug 2, 2026
934bc5b
feat: add single-gpu logprob comparison harness
hihaluemen Aug 4, 2026
b69426d
fix: keep logprob CLI stdout machine readable
hihaluemen Aug 4, 2026
0efcfe1
refactor: simplify logprob comparison harness
hihaluemen Aug 4, 2026
115d86c
docs: document SM90 logprob validation
hihaluemen Aug 4, 2026
c028b5b
fix: address logprob harness lint and provenance
hihaluemen Aug 4, 2026
7ba09b5
fix: type heterogeneous logprob backends
hihaluemen Aug 4, 2026
4231625
fix comment
KJLdefeated Aug 6, 2026
2360a71
test(ws2): align dispatch tests with the auto+TP>1 unsafe-dispatch guard
KJLdefeated Aug 7, 2026
99e59f8
Merge branch 'RL-Align:main' into feat/ws2-logprob-single-gpu-harness…
hihaluemen Aug 8, 2026
4eebb3b
refactor: colocate logprob harness tooling and docs
hihaluemen Aug 8, 2026
19488cc
test: resolve logprob CLI path reliably
hihaluemen Aug 8, 2026
6e2a79e
Merge PR1 logprob contract into PR2 integration base
hihaluemen Aug 8, 2026
b7d9d89
init vocab parallel logp
KJLdefeated Aug 5, 2026
3866d3c
init vocab parallel logp
KJLdefeated Aug 5, 2026
65f3c6f
adding cross tp testing
KJLdefeated Aug 5, 2026
05d19eb
test: align PR3 dispatch with latest PR1 guard
hihaluemen Aug 8, 2026
a46891a
Merge branch 'RL-Align:main' into feat/ws2-logprob-single-gpu-harness…
hihaluemen Aug 10, 2026
57b04b1
Merge latest PR2 into PR1-PR3 integration base
hihaluemen Aug 11, 2026
f36a63d
feat(ws2): add distributed logprob drift runner
hihaluemen Aug 11, 2026
1d9bac1
ci(ws2): run logprob comparison tests
hihaluemen Aug 11, 2026
f6b5a07
fix(ws2): harden distributed drift reporting
hihaluemen Aug 11, 2026
8a4f4be
fix(ws2): clean up process groups on setup failure
hihaluemen Aug 11, 2026
c2c99c1
feat(ws2): record cross-topology logprob fingerprints
hihaluemen Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ jobs:
run: |
python -m pytest tests/test_kv_cache_attention.py -v -k "not large and not gpu"

- name: Run WS2 Logprob Contract Tests (CPU-safe)
run: python -m pytest tests/test_logprob_contract.py -v

- name: Run WS2 Vocab-Parallel Logprob Tests (CPU-safe)
run: python -m pytest tests/test_vocab_parallel_logp.py -v

- name: Run WS2 Logprob Comparison Tests (CPU-safe)
run: |
python -m pytest tests/test_logprob_comparison.py -v
python -m pytest tests/test_distributed_logprob_comparison.py -v

docs:
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 8 additions & 0 deletions docs/design/runtime-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ logical type, and the registry selects the first available backend for the curre
4. Cache successfully constructed operator instances.
5. Skip backends that already failed in the current process.

WS2 TP-aware logprob uses the stricter `KernelRegistry.get_logprob_op(contract)` path. In
addition to platform priority, this path requires a backend capability descriptor and checks
the requested role, dtype, TP/CP layout, padded-vs-real vocab masking, inactive-token
support, vocab-domain LSE export, and deterministic TP merge semantics. Incompatible
candidates produce explicit rejection reasons and are never used as an undeclared fallback.
The contract objects and their normative reduction semantics are documented in
`rl_engine.kernels.logprob_contract`.

## LogP Priority

| Platform | Priority |
Expand Down
200 changes: 198 additions & 2 deletions docs/operators/batch-invariant-logp.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@ CUDA priority list when the extension exposes `_C.batch_invariant_logp_sm90`
(built with `KERNEL_ALIGN_FORCE_SM90=1`) on an SM90 device. On any other build
or device, dispatch is unchanged (Triton -> PyTorch).

## Tensor Parallel

`VocabParallelLogprobOp`
(`rl_engine/kernels/ops/pytorch/loss/vocab_parallel_logp.py`)
defines a cross-TP bitwise contract for TP=1, TP=2, and TP=4 when
`num_vocab_tiles` is fixed and every vocabulary-shard boundary is tile-aligned.
The complete BF16 CUDA/NCCL validation matrix for this contract is tracked by
issue #241 PR4.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
1. Split the padded vocabulary into `num_vocab_tiles` fixed tiles.
2. Each rank computes fp32 `(max, sumexp)` for the tiles it owns. Every tile
is reduced as the same contiguous `[n, tile]` shape, on any rank.
3. All tile partials are shared with `all_gather`. The collective only moves
bytes; it never does math, so it cannot round anything.
4. Every rank merges all tiles in the same fixed order, over the same
`[n, num_vocab_tiles]` shape. `LSE = M + log(sum(s_t * exp(m_t - M)))`.
5. The target logit is copied from the rank that owns it (never summed).
6. `logp = target_logit - LSE`. Inactive rows become `0.0`.

Usage goes through the contract-aware entry point:

```python
from rl_engine.kernels.registry import kernel_registry

result = kernel_registry.get_logprob_op(contract) # LogprobContract from
op = result.op # rl_engine.kernels.logprob_contract
logp, lse = op(local_logits, target_ids, contract=contract, tp_group=tp_group)
```

## Benchmarks

`benchmarks/benchmark_batch_invariant_logp.py` compares Native, Triton, and the
Expand Down Expand Up @@ -179,6 +208,160 @@ fp16/bf16 backward: checked against fp32 reference with relaxed tolerance
CPU-vs-CUDA comparisons use tolerance-based checks; batch-invariance checks
within the same backend use exact equality where appropriate.

## TP=1 Comparison Harness

The single-GPU comparison harness is the TP=1 registration and regression guard
for issue #241. It uses the batch-invariant PyTorch implementation as the
reference and compares exact `pytorch`, `triton`, or `cuda-sm90` backends before
distributed communication is introduced.

Each backend exposes a diagnostic-only entry point while the production contract
remains unchanged:

```text
op(logits, target_ids) -> logp
op.forward_with_lse(logits, target_ids) -> (logp, lse)
```

The harness reports LSE drift over every logical token row and selected-logprob
drift over active response/action tokens only. Drift summaries contain max,
mean, p95, p99, and the number of compared values. Reports also record requested
and actual backends, implementation, direct-LSE provenance, input shape and
dtype, `tp_world=1`, and `communication=none`.

Backend selection is exact and does not use registry fallback. In particular,
an explicit `cuda-sm90` comparison fails unless the compiled SM90 extension,
Hopper hardware, input dtype, and vocab row stride satisfy the kernel contract.

Run the PyTorch TP=1 guard directly from the kernel-specific testing module:

```bash
python rl_engine/testing/logprob_comparison.py \
--candidate pytorch \
--device cpu \
--dtype fp32 \
--batch 2 \
--seq 16 \
--vocab 257
```

On a GPU, repeat `--candidate` to compare multiple exact backends:

```bash
python rl_engine/testing/logprob_comparison.py \
--candidate triton \
--candidate cuda-sm90 \
--device cuda \
--dtype bf16 \
--batch 2 \
--seq 16 \
--vocab 151936
```

The command writes structured JSON to stdout and routes backend diagnostics to
stderr. The harness does not implement vocab sharding, collective communication,
cross-rank LSE merging, or CP reconstruction.

### SM90 validation

SM90 validation requires a Hopper GPU, CUDA-enabled PyTorch, and an `nvcc`
toolkit matching `torch.version.cuda`. Build the extension with:

```bash
export FORCE_CUDA=1
export KERNEL_ALIGN_FORCE_SM90=1
export TORCH_CUDA_ARCH_LIST="9.0+PTX"

python -m pip install --no-build-isolation --no-deps -e .
```

Run the focused harness tests, the complete operator suite, and an explicit
SM90 comparison:

```bash
python -m pytest \
tests/test_logprob_comparison.py \
tests/test_operator_inputs.py \
tests/test_op_checks.py -q

python -m pytest tests/test_batch_invariant_logp.py -q

python rl_engine/testing/logprob_comparison.py \
--candidate cuda-sm90 \
--device cuda \
--dtype bf16 \
--batch 2 \
--seq 16 \
--vocab 151936 \
--prompt-tokens 8 \
--seed 241
```

The PR2 path was validated on an NVIDIA H800 PCIe with PyTorch 2.11.0+cu128,
CUDA 12.8, and Triton 3.6.0. The focused tests passed 41 cases and the complete
batch-invariant suite passed 67 cases. For BF16 shape `[2, 16, 151936]`, both
LSE and active-token dlogp had maximum absolute drift
`9.5367431640625e-07` against the PyTorch reference, with no backend fallback.

## Distributed WS2 Drift Report

The issue #241 PR4 runner materializes one TP/CP topology per `torchrun`
invocation. TP partitions the vocabulary and is the only numerical merge axis;
CP partitions token rows and is recorded in provenance without participating in
the vocab-domain LSE merge. For global rank `r`:

```text
tp_rank = r % tp_world_size
cp_rank = r // tp_world_size
```

Every case generates the same seeded FP32 logical logits, targets, and active
mask. The candidate receives a BF16 token/vocab shard through the explicit
`pytorch-vocab-parallel-logp-ws2` backend, while the independent oracle computes
`torch.logsumexp` over the complete real-vocab FP32 token slice. Distributed
dispatch rejects `auto`, capability fallback, topology mismatches, non-tileable
vocabularies, and incomplete materialization.

Reports follow the issue #116 fields and contain per-rank and aggregate LSE and
active-token dlogp summaries: max/mean/p95/p99 absolute drift, max relative
drift, worst global token position, target id, target owner rank, #108 tolerance,
and pass/fail. Provenance includes TP/CP topology, dtype, shard bounds, backend
capability, contract fingerprint, reduction spec, merge order, transport, and
the exact launch command. Replicated TP outputs are checked bitwise before one
representative per CP shard is included in aggregate statistics.

Print the scoped TP=1/2/4 x CP=1/2 launch matrix without starting workers:

```bash
python rl_engine/testing/distributed_logprob_comparison.py \
--plan \
--device cuda \
--dtype bf16 \
--output artifacts/ws2-logprob/report.json
```

Run one TP=2, CP=2 Qwen3-vocab case on four local GPUs:

```bash
torchrun --standalone --nproc-per-node=4 \
rl_engine/testing/distributed_logprob_comparison.py \
--tp 2 \
--cp 2 \
--dtype bf16 \
--backend pytorch-vocab-parallel-logp-ws2 \
--real-vocab 151936 \
--padded-vocab 151936 \
--num-vocab-tiles 64 \
--batch 2 \
--seq 16 \
--prompt-tokens 8 \
--output artifacts/ws2-logprob/tp2-cp2.json
```

The full matrix requires up to eight ranks for TP=4, CP=2. CPU/Gloo cases are
available for topology and artifact validation; the scoped numerical gate is
BF16 on CUDA/NCCL.

## Minimal Example

```python
Expand Down Expand Up @@ -206,11 +389,17 @@ out.sum().backward()
python -m pytest tests/test_batch_invariant_logp.py -q -rs
```

All backends (Native, Triton) are tested in a single file. Coverage includes:
All production backends are tested in a single file. Coverage includes
correctness, leading-shape preservation, batch-invariance (bitwise), validation,
ignore-index behavior, backward correctness, CUDA smoke cases, registry
dispatch, and Triton-specific fp32/fp16/bf16 correctness, large vocab, backward
gradient batch-invariance, and ignored-row zero gradients.
gradient batch-invariance, and ignored-row zero gradients. The focused
`tests/test_logprob_comparison.py` suite covers TP=1 bitwise regression, direct
LSE identity, active-token drift statistics, structured serialization, exact
backend diagnostics, and fail-closed provenance.
`tests/test_distributed_logprob_comparison.py` covers topology planning, TP/CP
rank mapping, token/vocab sharding, explicit backend materialization, #116 JSON
artifacts, and a real four-process TP=2, CP=2 Gloo smoke case.

Triton tests skip when Triton or CUDA is unavailable. On Windows, run via
WSL/Linux with CUDA.
Expand All @@ -223,4 +412,11 @@ WSL/Linux with CUDA.
- `csrc/cuda/batch_invariant_logp_kernel_sm90.cu`
- `rl_engine/kernels/registry.py`
- `tests/test_batch_invariant_logp.py`
- `tests/test_logprob_comparison.py`
- `rl_engine/testing/logprob_drift.py`
- `rl_engine/testing/distributed_logprob_comparison.py`
- `tests/test_distributed_logprob_comparison.py`
- `benchmarks/benchmark_batch_invariant_logp.py`
- `rl_engine/kernels/ops/pytorch/loss/vocab_parallel_logp.py`
- `rl_engine/kernels/logprob_contract.py`
- `tests/test_vocab_parallel_logp.py`
Loading