From 75baabc4cd45d74e6f50ee2c2adaf8e266612f18 Mon Sep 17 00:00:00 2001
From: frank-2077
Date: Tue, 1 Sep 2026 06:10:16 +0000
Subject: [PATCH 01/36] docs(readme): update feature and platform support
Signed-off-by: frank-2077
---
README.md | 67 ++++++++-----------------------------------------------
1 file changed, 9 insertions(+), 58 deletions(-)
diff --git a/README.md b/README.md
index e2788c6a..1bff6395 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-
+
@@ -27,10 +27,10 @@
# Our Core Philosophy
**1. Operator-Level Train-Inference Consistency**
-The biggest hidden barrier in large-scale RL is the subtle numerical divergence between rollout engines (e.g., vLLM) and training engines (e.g., Megatron/DeepSpeed). RL-Kernel provides mathematically rigorous, fused operators that lock down the computational graph. By guaranteeing absolute numerical consistency and deterministic reduction orders across the entire RL loop, we prevent reward hacking and distribution drift at the operator level.
+The biggest hidden barrier in large-scale RL is the subtle numerical divergence between rollout engines (e.g., vLLM) and training engines (e.g., Megatron/DeepSpeed). RL-Kernel implements deterministic operators for dense-model workloads to align numerical behavior between rollout and training paths. By pinning computational graphs and reduction orders at the operator level, it helps prevent reward hacking and distribution drift caused by numerical divergence.
**2. Extreme Memory & Compute Efficiency**
-We replace naive PyTorch paths—which suffer from $O(G \cdot L \cdot V)$ memory explosion—with specialized industrial-grade kernels (like `prefix_shared_attention` and `fused_logp`). This reduces VRAM consumption by up to 10x, unlocking massive batch sizes for GRPO workloads without triggering Out-Of-Memory (OOM) errors.
+We replace naive PyTorch paths—which suffer from $O(G \cdot L \cdot V)$ memory explosion—with specialized industrial-grade kernels (like `prefix_shared_attention` and `fused_logp`). This reduces VRAM consumption and supports larger batch sizes for GRPO workloads.
---
@@ -42,70 +42,21 @@ RL-Kernel sits strictly at the operator layer, acting as a non-intrusive bridge
-*Note: RL-Kernel integrates natively into Rollout Engines (vLLM, sglang, LMDeploy) and Training Engines (Megatron, DeepSpeed) via non-intrusive custom operator hooks, powered by underlying CUDA, Triton, and ROCm backends.*
+*Note: RL-Kernel integrates natively into Rollout Engines (vLLM, sglang, LMDeploy) and Training Engines (Megatron, DeepSpeed) via non-intrusive custom operator hooks, powered by CUDA, Triton, and ROCm backends, with an Ascend CANN backend for batch-invariant logprob.*
---
-# Performance Benchmarks: Breaking the Memory Wall
-
-RL-Kernel is designed to solve the $O(G \cdot L \cdot V)$ memory explosion in DeepSeek-style **GRPO** training. A typical scenario is as follows:
-
-### 1. Logprob Computation (Training Stability)
-By implementing **Pre-allocated Chunking**, RL-Kernel maintains constant additional VRAM overhead regardless of the group size ($G$).
-
-**Testbed**: NVIDIA A100 80GB | **Model**: Llama-3-8B | **Vocab**: 128,256 | **SeqLen**: 512
-
-| Group Size ($G$) | TRL (Standard) | PyTorch Native | **RL-Kernel (Ours)** | Status |
-| :--- | :--- | :--- | :--- | :--- |
-| **G = 64** | OOM | 15.66 GB | **16.15 GB** | Success |
-| **G = 128** | OOM | 31.31 GB | **31.80 GB** | Success |
-| **G = 256** | **FAILED (OOM)** | 62.63 GB | **63.12 GB** | **Optimized** |
-
-*Note: RL-Kernel is the only solution that successfully scales G=256 on a single A100 by keeping extra VRAM usage to a constant ~0.5GB.*
-
-
-
-
-
-
-### 2. Sampling Latency (Rollout Speed)
-Integrating **FlashInfer** fused kernels to accelerate the bottleneck of RL training: the sampling phase.
-
-| Batch Size ($G$) | Native PyTorch | **RL-Kernel (Fused)** | **Speedup** |
-| :--- | :--- | :--- | :--- |
-| 32 | 176.79 ms | **1.08 ms** | **163x** |
-| 64 | 10.54 ms | **1.31 ms** | **8x** |
-| 128 | 18.89 ms | **1.86 ms** | **10x** |
-| 256 | 36.23 ms | **2.94 ms** | **12x** |
-
-
-
-
-
-
-### 3. Real Model Validation (Qwen3-30B-A3B MoE)
-
-**Testbed**: NVIDIA A100 80GB | **Model**: Qwen3-30B-A3B | **Vocab**: 151,936 | **dtype**: fp16
-
-Model weights consume 56.9 GB — only 23 GB headroom remaining for training computation.
-
-
-
-
-
-
# Key Features
-- **Zero-Growth Memory Pool**: Uses pre-allocated buffers and micro-chunking to prevent VRAM spikes during advantage calculation.
-- **Fused Sampling Pipeline**: Direct integration with **FlashInfer** and **vLLM** backends for sub-2ms sampling latency.
-- **Universal Backend Abstraction**: Unified API supporting both **NVIDIA (CUDA/FlashInfer)** and **AMD (ROCm/AITER)**.
-- **Post-Training Ready**: Drop-in replacement for standard sampling and logprob operators in TRL or DeepSpeed-Chat.
+- **Dense-Model Train–Inference Consistency**: Implements operator-level consistency for dense-model workloads, validated end to end on Qwen3-8B Dense.
+- **Multi-Platform Accelerator Support**: Supports **NVIDIA CUDA** and **AMD ROCm**, with **HUAWEI Ascend (NPU/CANN)** support for batch-invariant logprob.
+- **Hardware Roadmap**: Broader support is planned for **MetaX**, **Cambricon**, **Moore Threads**, and more.
---
# Architecture
-RL-Kernel sits between high-level alignment libraries and low-level GPU kernels, ensuring maximum throughput without sacrificing flexibility.
+RL-Kernel sits between high-level alignment libraries and low-level accelerator kernels, ensuring maximum throughput without sacrificing flexibility.
---
@@ -151,7 +102,7 @@ Featured docs:
RL-Kernel builds on the shoulders of excellent open-source projects:
-- **[FlashInfer](https://github.com/flashinfer-ai/flashinfer)** — We integrate FlashInfer's fused sampling kernels as the NVIDIA backend for our sampling pipeline. The sub-2ms sampling latency results are enabled by FlashInfer's highly optimized CUDA operators.
+- **[FlashInfer](https://github.com/flashinfer-ai/flashinfer)** — We integrate FlashInfer's fused sampling kernels as an NVIDIA backend for sampling workloads.
- **[vLLM](https://github.com/vllm-project/vllm)** — Inspired by vLLM's kernel design philosophy and hardware-aware scheduling approach.
- **[DeepSpeed](https://github.com/microsoft/DeepSpeed)** — Inspired by DeepSpeed's approach to memory-efficient training infrastructure.
From 9ca6008caf4f08cf51598ac12b68ddb6d1fe54f9 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 05:53:46 +0000
Subject: [PATCH 02/36] docs(readme): highlight release results and accelerator
support
---
README.md | 233 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 165 insertions(+), 68 deletions(-)
diff --git a/README.md b/README.md
index 1bff6395..10d79313 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
-
+
RL-Kernel
- Extreme Infrastructure for GRPO & Large-Scale Reinforcement Learning.
+ Bitwise train–inference consistency. Faster RL post-training.
@@ -14,96 +14,193 @@
-
-
+
+
-
-**RL-Kernel** is a high-performance, memory-efficient infrastructure for Reinforcement Learning post-training. It eliminates the memory and latency bottlenecks in Large Language Model alignment, This project targets AI infrastructure engineers, algorithm researchers, and enterprise-level large model alignment scenarios, providing specialized kernels for algorithms like **GRPO**, **PPO**, and **DPO**.
-
-
----
-
-# Our Core Philosophy
-
-**1. Operator-Level Train-Inference Consistency**
-The biggest hidden barrier in large-scale RL is the subtle numerical divergence between rollout engines (e.g., vLLM) and training engines (e.g., Megatron/DeepSpeed). RL-Kernel implements deterministic operators for dense-model workloads to align numerical behavior between rollout and training paths. By pinning computational graphs and reduction orders at the operator level, it helps prevent reward hacking and distribution drift caused by numerical divergence.
-
-**2. Extreme Memory & Compute Efficiency**
-We replace naive PyTorch paths—which suffer from $O(G \cdot L \cdot V)$ memory explosion—with specialized industrial-grade kernels (like `prefix_shared_attention` and `fused_logp`). This reduces VRAM consumption and supports larger batch sizes for GRPO workloads.
-
----
-
-# Global Architecture
-
-RL-Kernel sits strictly at the operator layer, acting as a non-intrusive bridge between high-level alignment orchestration (e.g., vime, slime) and foundational execution engines. We ensure maximum throughput and rigorous numerical parity without modifying upstream framework source code.
-
-
+ Results ·
+ Hardware support ·
+ Architecture ·
+ Quick start ·
+ Documentation
-*Note: RL-Kernel integrates natively into Rollout Engines (vLLM, sglang, LMDeploy) and Training Engines (Megatron, DeepSpeed) via non-intrusive custom operator hooks, powered by CUDA, Triton, and ROCm backends, with an Ascend CANN backend for batch-invariant logprob.*
+**RL-Kernel** is a high-performance operator library for **GRPO and PPO-style RL
+post-training**. It aligns numerical computation between rollout and training engines
+with deterministic attention, dense FFN, log-probability, and collective operations.
+Hardware-specific kernels optimize execution and memory use beneath the RL framework.
----
-
-# Key Features
-
-- **Dense-Model Train–Inference Consistency**: Implements operator-level consistency for dense-model workloads, validated end to end on Qwen3-8B Dense.
-- **Multi-Platform Accelerator Support**: Supports **NVIDIA CUDA** and **AMD ROCm**, with **HUAWEI Ascend (NPU/CANN)** support for batch-invariant logprob.
-- **Hardware Roadmap**: Broader support is planned for **MetaX**, **Cambricon**, **Moore Threads**, and more.
+With **VIME + vLLM + Megatron-LM**, the published Qwen3-8B experiment achieves **zero
+train–rollout LogP mismatches at every one of 200 steps**, **68.7% higher rollout
+throughput**, and **8.2% lower end-to-end step time** than VIME's native production
+operator path. [See the configuration and results below](#benchmark-highlights).
+
+## Why RL-Kernel?
+
+Rollout and training engines can produce different log probabilities for the same tokens
+and model weights because their kernels, batching, and reduction orders differ. Those
+differences enter the policy ratios and KL terms used by RL algorithms.
+
+- **Exact train–inference consistency:** deterministic operator contracts align the strict
+ dense-model path. The published experiment verifies exact runtime LogP agreement across
+ all 200 training steps.
+- **Efficient RL execution:** fused log-probability computation, optimized attention and FFN
+ paths, and deterministic collectives target rollout, memory, and synchronization costs.
+- **Framework integration:** provider and runtime adapters connect RL-Kernel to VIME,
+ vLLM, and Megatron-LM. VIME orchestrates the workflow; RL-Kernel supplies the operators.
+- **Multiple accelerators:** dense-model train–inference consistency is supported on CUDA
+ and ROCm, with Ascend and Moore Threads adaptation in progress.
+
+## Benchmark Highlights
+
+### VIME native operators vs. VIME + RL-Kernel
+
+The completed experiment in [PR #377](https://github.com/RL-Align/RL-Kernel/pull/377)
+compares **G10**, VIME's native production operator path, with **optimized G11**, the
+strict RL-Kernel path. Both use VIME with vLLM rollout and Megatron-LM training, and both
+enable rollout-logp reuse. G11 applies RL-Kernel attention, FFN, and LogP on both paths.
+
+**Setup:** Qwen3-8B BF16 · GRPO · 1 node with 8×H100 80GB · actor TP4/CP2/PP1 ·
+two TP4 rollout engines · 8 prompts × 16 samples (batch 128) · 200 steps · seed 1234 ·
+maximum response length 7,168 · KL-loss coefficient 0.001.
+
+| Metric | VIME native (G10) | VIME + RL-Kernel (G11) | G11 result |
+| :--- | ---: | ---: | :--- |
+| Steps with nonzero train–rollout LogP mismatch | 200 / 200 | **0 / 200** | **Exact agreement at every step** |
+| Maximum absolute Δlogp across the run | 1.591547 | **0** | **Zero measured difference** |
+| Mean rollout time | 130.22 s/step | **82.75 s/step** | **36.5% lower** |
+| Mean rollout throughput | 672.39 tok/GPU/s | **1,134.00 tok/GPU/s** | **68.7% higher** |
+| Mean reference LogP time | 20.90 s/step | 20.92 s/step | Approximately equal |
+| Mean actor training time | **80.51 s/step** | 107.18 s/step | 33.1% higher |
+| Mean end-to-end step time | 251.99 s/step | **231.27 s/step** | **8.2% lower** |
+
+G11 saves **47.47 seconds per rollout step**, offsetting the additional actor training
+cost for a net saving of **20.72 seconds per end-to-end step**.
+
+
+
+
+200-step consistency and training curves
+
+G11 records `mismatch_count == 0` and `max_abs_diff == 0` at all 200 steps; G10
+records nonzero mismatch at every step. The bottom panels show the runtime LogP checks.
+The upper panels show raw reward and `train/kl_loss`.
+
+
+
+
+
+**How to read these results.** Timing and throughput are arithmetic means over all 200
+steps. This is a comparison of implementations under the same workload configuration;
+the arms use different implementation revisions and generate different trajectories
+(G11's mean response length is 4.8% higher). Exact agreement refers to the measured
+train–rollout LogP on this strict path. Results come from one training seed on H100;
+speedups depend on the workload and hardware. Mean raw reward is 0.528555 for G10 and
+0.491445 for G11, so these results establish consistency and execution performance,
+without establishing a model-quality improvement.
+
+[Experiment and version provenance](https://github.com/RL-Align/RL-Kernel/pull/377) ·
+[Published result report](https://github.com/RL-Align/RL-Kernel/tree/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized) ·
+[200-step CSV](https://github.com/RL-Align/RL-Kernel/blob/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized/rounds.csv) ·
+[Statistics JSON](https://github.com/RL-Align/RL-Kernel/blob/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized/summary.json)
+
+## Hardware Support
+
+The following matrix tracks **dense-model train–inference consistency**. Accelerator
+support and the scope of published benchmarks are listed separately.
+
+| Vendor | Accelerator | Software stack | Dense train–inference consistency | Coverage / progress |
+| :--- | :--- | :--- | :---: | :--- |
+| **NVIDIA** | GPU | CUDA | ✅ **Supported** | Dense-model strict path; Qwen3-8B H100 end-to-end results above |
+| **AMD** | GPU | ROCm | ✅ **Supported** | Dense-model strict path; backend-specific setup and validation |
+| **Huawei** | Ascend NPU | CANN / Ascend C | 🟡 **Partially adapted** | Selected operators adapted; broader dense-model integration in progress |
+| **Moore Threads** | GPU | MUSA | 🚧 **In progress** | Accelerator adaptation and dense-model integration underway |
+
+✅ **Supported** · 🟡 **Partial adaptation** · 🚧 **Active development**
+
+Support applies to the implemented dense-model paths; model, dtype, operator, and
+parallelism coverage varies by backend. The performance numbers above are CUDA/H100
+measurements. See the [installation guide](./docs/getting_started/installation.md) and
+[operator catalog](./docs/operators/README.md) for backend requirements and contracts.
+
+## Architecture
+
+RL-Kernel sits between framework execution engines and accelerator backends. Runtime
+adapters select operators through a hardware-aware registry; strict routes enforce the
+required numerical contract and expose execution provenance.
+
+```mermaid
+flowchart TB
+ VIME["VIME · RL orchestration"] --> VLLM["vLLM · rollout"]
+ VIME --> MEGATRON["Megatron-LM · training"]
+ VLLM --> RLK["RL-Kernel · deterministic and optimized operators"]
+ MEGATRON --> RLK
+ RLK --> CUDA["CUDA · supported"]
+ RLK --> ROCM["ROCm · supported"]
+ RLK -.-> ASCEND["Ascend · partial adaptation"]
+ RLK -.-> MUSA["Moore Threads / MUSA · in progress"]
+```
----
+The benchmark above validates **VIME + vLLM + Megatron-LM on CUDA**. Framework and
+backend coverage are documented independently. See [runtime dispatch](./docs/design/runtime-dispatch.md)
+for operator selection and strict execution contracts.
-# Architecture
+## Operator Families
-RL-Kernel sits between high-level alignment libraries and low-level accelerator kernels, ensuring maximum throughput without sacrificing flexibility.
+| Family | Purpose | Documentation |
+| :--- | :--- | :--- |
+| **Attention** | Deterministic attention and context-parallel execution | [Attention](./docs/operators/attention.md) |
+| **Dense FFN** | Deterministic GEMM, SiLU, and SwiGLU paths | [GEMM](./docs/operators/det-gemm.md) · [Activations](./docs/operators/activation.md) |
+| **Log probabilities** | Fused, linear, batch-invariant, and vocabulary-parallel LogP | [Fused LogP](./docs/operators/fused-logp.md) · [Linear LogP](./docs/operators/linear-logp.md) · [Batch-invariant LogP](./docs/operators/batch-invariant-logp.md) |
+| **GRPO / PPO objectives** | Group normalization, policy ratios, KL penalties, and clipped losses | [GRPO loss](./docs/operators/grpo-loss.md) · [Ratio / KL](./docs/operators/ratio-kl.md) |
+| **Collectives** | Deterministic reductions for supported distributed topologies | [Collectives](./rl_engine/distributed/collectives.py) |
----
+## Quick Start
-# Quick Start
+Install a PyTorch build matching your accelerator runtime, then install RL-Kernel from
+source. Python 3.10 or newer is required.
-### Installation
```bash
-# Clone the repository
git clone https://github.com/RL-Align/RL-Kernel.git
cd RL-Kernel
-# CPU-only / pure-Python fallback
-python -m pip install -e .
-
-# Native CUDA or ROCm extension (install a matching PyTorch build first)
+# Native CUDA or ROCm extension
RL_KERNEL_REQUIRE_EXT=1 python -m pip install --no-build-isolation -e .
python -c "import rl_engine._C as _C; assert hasattr(_C, 'fused_logp'); print(_C.__file__)"
```
-### Contributions
-Inspired by the kernel designs of vLLM and DeepSpeed. As an active contributor to the AI Infrastructure ecosystem, RL-Kernel aims to push the boundaries of RL efficiency.
-
-Target: Building the most efficient RLHF toolchain for the open-source community.
-
-# Support
-Don’t hesitate to ask!
-
-Contact the developers and community in [Slack](https://rl-align.slack.com/join/shared_invite/zt-46bxj7uyt-gEK3xzwSJr_lppJsZolR~g#/shared-invite/email) if you need any help.
-
-[Open an issue](https://github.com/RL-Align/RL-Kernel/issues) if you find a bug in **RL-Kernel**.
-
-# Documentation
+For CPU-only or pure-Python development, use `python -m pip install -e .`.
+Strict train–inference consistency requires the corresponding operators and runtime
+configuration in both engines. Follow the [installation guide](./docs/getting_started/installation.md)
+and [quick-start guide](./docs/getting_started/quickstart.md); the full benchmark
+configuration and companion VIME revision are linked in [PR #377](https://github.com/RL-Align/RL-Kernel/pull/377).
-The documentation of **RL-Kernel** is located on the website: [https://rl-align.github.io/RL-Kernel](https://rl-align.github.io/RL-Kernel)
-or in the [docs](./docs) directory of the source code.
+## Documentation
-Featured docs:
+| Resource | What you will find |
+| :--- | :--- |
+| [Documentation site](https://rl-align.github.io/RL-Kernel/) | Setup, design, API, and usage guides |
+| [Operator catalog](./docs/operators/README.md) | Operator contracts and backend coverage |
+| [Benchmarking](./docs/benchmarking/README.md) | Benchmark entry points and reporting methods |
+| [VIME integration](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime.md) | Linear LogP integration and measurements |
+| [中文:发布 vime + RL-Kernel](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime-zh.md) | Chinese VIME integration announcement |
-- [Announcing RL-Kernel for vime: Faster and Leaner `linear_logp` for Full RL Rollouts](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime.md)
-- [中文版:发布 vime + RL-Kernel](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime-zh.md)
+## Community and Contributions
-# Acknowledgments
+Join us on [Slack](https://rl-align.slack.com/join/shared_invite/zt-46bxj7uyt-gEK3xzwSJr_lppJsZolR~g#/shared-invite/email)
+or [WeChat](./docs/community/wechat.md), and
+[open an issue](https://github.com/RL-Align/RL-Kernel/issues) for bugs and feature requests.
+Contributions to kernels, framework integrations, hardware adaptation, and benchmarks
+are welcome. See the [contributing guide](./docs/contributing/README.md).
-RL-Kernel builds on the shoulders of excellent open-source projects:
+## Acknowledgments
-- **[FlashInfer](https://github.com/flashinfer-ai/flashinfer)** — We integrate FlashInfer's fused sampling kernels as an NVIDIA backend for sampling workloads.
-- **[vLLM](https://github.com/vllm-project/vllm)** — Inspired by vLLM's kernel design philosophy and hardware-aware scheduling approach.
-- **[DeepSpeed](https://github.com/microsoft/DeepSpeed)** — Inspired by DeepSpeed's approach to memory-efficient training infrastructure.
+RL-Kernel builds on the work of the open-source AI infrastructure community, including
+[VIME](https://github.com/RL-Align/vime), [vLLM](https://github.com/vllm-project/vllm),
+[Megatron-LM](https://github.com/NVIDIA/Megatron-LM),
+[DeepSpeed](https://github.com/deepspeedai/DeepSpeed), and
+[FlashInfer](https://github.com/flashinfer-ai/flashinfer).
+We thank their contributors and everyone helping bring RL-Kernel to new accelerators.
-We are grateful to these teams for their contributions to the open-source AI infrastructure ecosystem.
+Licensed under the [Apache License 2.0](./LICENSE).
From b790d817f3625261fa1b9505f016b66a8f4e7225 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 17:13:10 +0800
Subject: [PATCH 03/36] docs(readme): restore global architecture diagram
Signed-off-by: vensen
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index 10d79313..353623f2 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,16 @@ RL-Kernel sits between framework execution engines and accelerator backends. Run
adapters select operators through a hardware-aware registry; strict routes enforce the
required numerical contract and expose execution provenance.
+The complete architecture shows the external scheduling, rollout and training engines,
+operator-library layers, and hardware abstraction boundary.
+
+
+
+
+
+The following diagram is a concise view of the validated runtime path and accelerator
+coverage.
+
```mermaid
flowchart TB
VIME["VIME · RL orchestration"] --> VLLM["vLLM · rollout"]
From 2f13b0c86399e0cd23e73820fdfa6f90cabbdf6f Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 17:35:49 +0800
Subject: [PATCH 04/36] docs(readme): clarify current scope and roadmap
Signed-off-by: vensen
---
README.md | 62 ++++++++++++++++++++++++-------------------------------
1 file changed, 27 insertions(+), 35 deletions(-)
diff --git a/README.md b/README.md
index 353623f2..bc6670d8 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
Results ·
+ Current scope ·
Hardware support ·
Architecture ·
Quick start ·
@@ -47,11 +48,22 @@ differences enter the policy ratios and KL terms used by RL algorithms.
all 200 training steps.
- **Efficient RL execution:** fused log-probability computation, optimized attention and FFN
paths, and deterministic collectives target rollout, memory, and synchronization costs.
-- **Framework integration:** provider and runtime adapters connect RL-Kernel to VIME,
- vLLM, and Megatron-LM. VIME orchestrates the workflow; RL-Kernel supplies the operators.
+- **Current integration:** VIME is the supported RL orchestration layer, with vLLM for
+ rollout and Megatron-LM for training. RL-Kernel supplies the operators beneath them.
- **Multiple accelerators:** dense-model train–inference consistency is supported on CUDA
and ROCm, with Ascend and Moore Threads adaptation in progress.
+## Current Scope and Roadmap
+
+Current end-to-end support is deliberately scoped to **Qwen3-8B Dense** and **VIME**.
+Items in development or on the roadmap are not yet part of the supported path.
+
+| Dimension | Available today | In development / roadmap |
+| :--- | :--- | :--- |
+| **Model architecture** | Qwen3-8B Dense | [DeepSeek-V4-Flash-0731 MoE](./docs/blog/2026-08-09-dsv4-flash-moe-consistency-roadmap.md) — active development |
+| **RL orchestration** | VIME | Miles and AReaL |
+| **Execution engines** | vLLM rollout + Megatron-LM training | Additional engine integrations will follow validated operator coverage |
+
## Benchmark Highlights
### VIME native operators vs. VIME + RL-Kernel
@@ -80,35 +92,10 @@ cost for a net saving of **20.72 seconds per end-to-end step**.

-
-200-step consistency and training curves
-
-G11 records `mismatch_count == 0` and `max_abs_diff == 0` at all 200 steps; G10
-records nonzero mismatch at every step. The bottom panels show the runtime LogP checks.
-The upper panels show raw reward and `train/kl_loss`.
-
-
-
-
-
-**How to read these results.** Timing and throughput are arithmetic means over all 200
-steps. This is a comparison of implementations under the same workload configuration;
-the arms use different implementation revisions and generate different trajectories
-(G11's mean response length is 4.8% higher). Exact agreement refers to the measured
-train–rollout LogP on this strict path. Results come from one training seed on H100;
-speedups depend on the workload and hardware. Mean raw reward is 0.528555 for G10 and
-0.491445 for G11, so these results establish consistency and execution performance,
-without establishing a model-quality improvement.
-
-[Experiment and version provenance](https://github.com/RL-Align/RL-Kernel/pull/377) ·
-[Published result report](https://github.com/RL-Align/RL-Kernel/tree/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized) ·
-[200-step CSV](https://github.com/RL-Align/RL-Kernel/blob/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized/rounds.csv) ·
-[Statistics JSON](https://github.com/RL-Align/RL-Kernel/blob/40db4d31982cd4a7ba28fbc96982b2af1f62921d/examples/vime_qwen3_8b_tp4_cp2_200/results/scale_reference_s1234_g10_g11_optimized/summary.json)
-
## Hardware Support
-The following matrix tracks **dense-model train–inference consistency**. Accelerator
-support and the scope of published benchmarks are listed separately.
+The following matrix tracks accelerator coverage for the current dense-model path. It
+does not extend the end-to-end model claim beyond Qwen3-8B Dense.
| Vendor | Accelerator | Software stack | Dense train–inference consistency | Coverage / progress |
| :--- | :--- | :--- | :---: | :--- |
@@ -130,20 +117,25 @@ RL-Kernel sits between framework execution engines and accelerator backends. Run
adapters select operators through a hardware-aware registry; strict routes enforce the
required numerical contract and expose execution provenance.
-The complete architecture shows the external scheduling, rollout and training engines,
-operator-library layers, and hardware abstraction boundary.
+The complete architecture below is a layer map, not a current support matrix. It shows
+the broader external scheduling and engine ecosystem, operator-library layers, and
+hardware abstraction boundary.
-The following diagram is a concise view of the validated runtime path and accelerator
-coverage.
+The following diagram is a concise view of the validated runtime path, planned
+orchestration integrations, and accelerator coverage. Solid arrows represent the current
+VIME path; dashed arrows from Miles and AReaL represent roadmap work.
```mermaid
flowchart TB
- VIME["VIME · RL orchestration"] --> VLLM["vLLM · rollout"]
- VIME --> MEGATRON["Megatron-LM · training"]
+ VIME["VIME · integrated"] --> ORCH["RL orchestration integration"]
+ MILES["Miles · roadmap"] -.-> ORCH
+ AREAL["AReaL · roadmap"] -.-> ORCH
+ ORCH --> VLLM["vLLM · rollout"]
+ ORCH --> MEGATRON["Megatron-LM · training"]
VLLM --> RLK["RL-Kernel · deterministic and optimized operators"]
MEGATRON --> RLK
RLK --> CUDA["CUDA · supported"]
From 76bf4556ab04ad0424bb5cd5b33ad43b5b40f58a Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 17:42:21 +0800
Subject: [PATCH 05/36] docs(readme): streamline project overview
Signed-off-by: vensen
---
README.md | 101 +++++++++++++++++++++++-------------------------------
1 file changed, 42 insertions(+), 59 deletions(-)
diff --git a/README.md b/README.md
index bc6670d8..47b25000 100644
--- a/README.md
+++ b/README.md
@@ -19,10 +19,10 @@
- Results ·
+ Architecture ·
Current scope ·
+ Results ·
Hardware support ·
- Architecture ·
Quick start ·
Documentation
@@ -46,6 +46,9 @@ differences enter the policy ratios and KL terms used by RL algorithms.
- **Exact train–inference consistency:** deterministic operator contracts align the strict
dense-model path. The published experiment verifies exact runtime LogP agreement across
all 200 training steps.
+- **RL-native operator stack:** deterministic attention and dense FFN, fused and
+ batch-invariant LogP, GRPO/PPO objectives, and deterministic collectives cover the
+ numerical boundaries that matter to RL post-training.
- **Efficient RL execution:** fused log-probability computation, optimized attention and FFN
paths, and deterministic collectives target rollout, memory, and synchronization costs.
- **Current integration:** VIME is the supported RL orchestration layer, with vLLM for
@@ -53,6 +56,43 @@ differences enter the policy ratios and KL terms used by RL algorithms.
- **Multiple accelerators:** dense-model train–inference consistency is supported on CUDA
and ROCm, with Ascend and Moore Threads adaptation in progress.
+## Architecture
+
+RL-Kernel sits between framework execution engines and accelerator backends. Runtime
+adapters select operators through a hardware-aware registry; strict routes enforce the
+required numerical contract and expose execution provenance.
+
+The complete architecture below is a layer map, not a current support matrix. It shows
+the broader external scheduling and engine ecosystem, operator-library layers, and
+hardware abstraction boundary.
+
+
+
+
+
+The following diagram is a concise view of the validated runtime path, planned
+orchestration integrations, and accelerator coverage. Solid arrows represent the current
+VIME path; dashed arrows from Miles and AReaL represent roadmap work.
+
+```mermaid
+flowchart TB
+ VIME["VIME · integrated"] --> ORCH["RL orchestration integration"]
+ MILES["Miles · roadmap"] -.-> ORCH
+ AREAL["AReaL · roadmap"] -.-> ORCH
+ ORCH --> VLLM["vLLM · rollout"]
+ ORCH --> MEGATRON["Megatron-LM · training"]
+ VLLM --> RLK["RL-Kernel · deterministic and optimized operators"]
+ MEGATRON --> RLK
+ RLK --> CUDA["CUDA · supported"]
+ RLK --> ROCM["ROCm · supported"]
+ RLK -.-> ASCEND["Ascend · partial adaptation"]
+ RLK -.-> MUSA["Moore Threads / MUSA · in progress"]
+```
+
+The published benchmark validates **VIME + vLLM + Megatron-LM on CUDA**. Framework and
+backend coverage are documented independently. See [runtime dispatch](./docs/design/runtime-dispatch.md)
+for operator selection and strict execution contracts.
+
## Current Scope and Roadmap
Current end-to-end support is deliberately scoped to **Qwen3-8B Dense** and **VIME**.
@@ -111,53 +151,6 @@ parallelism coverage varies by backend. The performance numbers above are CUDA/H
measurements. See the [installation guide](./docs/getting_started/installation.md) and
[operator catalog](./docs/operators/README.md) for backend requirements and contracts.
-## Architecture
-
-RL-Kernel sits between framework execution engines and accelerator backends. Runtime
-adapters select operators through a hardware-aware registry; strict routes enforce the
-required numerical contract and expose execution provenance.
-
-The complete architecture below is a layer map, not a current support matrix. It shows
-the broader external scheduling and engine ecosystem, operator-library layers, and
-hardware abstraction boundary.
-
-
-
-
-
-The following diagram is a concise view of the validated runtime path, planned
-orchestration integrations, and accelerator coverage. Solid arrows represent the current
-VIME path; dashed arrows from Miles and AReaL represent roadmap work.
-
-```mermaid
-flowchart TB
- VIME["VIME · integrated"] --> ORCH["RL orchestration integration"]
- MILES["Miles · roadmap"] -.-> ORCH
- AREAL["AReaL · roadmap"] -.-> ORCH
- ORCH --> VLLM["vLLM · rollout"]
- ORCH --> MEGATRON["Megatron-LM · training"]
- VLLM --> RLK["RL-Kernel · deterministic and optimized operators"]
- MEGATRON --> RLK
- RLK --> CUDA["CUDA · supported"]
- RLK --> ROCM["ROCm · supported"]
- RLK -.-> ASCEND["Ascend · partial adaptation"]
- RLK -.-> MUSA["Moore Threads / MUSA · in progress"]
-```
-
-The benchmark above validates **VIME + vLLM + Megatron-LM on CUDA**. Framework and
-backend coverage are documented independently. See [runtime dispatch](./docs/design/runtime-dispatch.md)
-for operator selection and strict execution contracts.
-
-## Operator Families
-
-| Family | Purpose | Documentation |
-| :--- | :--- | :--- |
-| **Attention** | Deterministic attention and context-parallel execution | [Attention](./docs/operators/attention.md) |
-| **Dense FFN** | Deterministic GEMM, SiLU, and SwiGLU paths | [GEMM](./docs/operators/det-gemm.md) · [Activations](./docs/operators/activation.md) |
-| **Log probabilities** | Fused, linear, batch-invariant, and vocabulary-parallel LogP | [Fused LogP](./docs/operators/fused-logp.md) · [Linear LogP](./docs/operators/linear-logp.md) · [Batch-invariant LogP](./docs/operators/batch-invariant-logp.md) |
-| **GRPO / PPO objectives** | Group normalization, policy ratios, KL penalties, and clipped losses | [GRPO loss](./docs/operators/grpo-loss.md) · [Ratio / KL](./docs/operators/ratio-kl.md) |
-| **Collectives** | Deterministic reductions for supported distributed topologies | [Collectives](./rl_engine/distributed/collectives.py) |
-
## Quick Start
Install a PyTorch build matching your accelerator runtime, then install RL-Kernel from
@@ -178,16 +171,6 @@ configuration in both engines. Follow the [installation guide](./docs/getting_st
and [quick-start guide](./docs/getting_started/quickstart.md); the full benchmark
configuration and companion VIME revision are linked in [PR #377](https://github.com/RL-Align/RL-Kernel/pull/377).
-## Documentation
-
-| Resource | What you will find |
-| :--- | :--- |
-| [Documentation site](https://rl-align.github.io/RL-Kernel/) | Setup, design, API, and usage guides |
-| [Operator catalog](./docs/operators/README.md) | Operator contracts and backend coverage |
-| [Benchmarking](./docs/benchmarking/README.md) | Benchmark entry points and reporting methods |
-| [VIME integration](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime.md) | Linear LogP integration and measurements |
-| [中文:发布 vime + RL-Kernel](./docs/blog/2026-07-08-announcing-rl-kernel-linear-logp-for-vime-zh.md) | Chinese VIME integration announcement |
-
## Community and Contributions
Join us on [Slack](https://rl-align.slack.com/join/shared_invite/zt-46bxj7uyt-gEK3xzwSJr_lppJsZolR~g#/shared-invite/email)
From 4c0aaf66fbc437b1038663740d2a30830a04b4ea Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 17:51:19 +0800
Subject: [PATCH 06/36] docs(readme): align introduction with project
positioning
Signed-off-by: vensen
---
README.md | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 47b25000..45b7c0ed 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,13 @@
RL-Kernel
- Bitwise train–inference consistency. Faster RL post-training.
+ Building cross-hardware and multi-model RL post-training infrastructure for kernel-level train–inference consistency.
+
@@ -27,10 +28,16 @@
Documentation
-**RL-Kernel** is a high-performance operator library for **GRPO and PPO-style RL
-post-training**. It aligns numerical computation between rollout and training engines
-with deterministic attention, dense FFN, log-probability, and collective operations.
-Hardware-specific kernels optimize execution and memory use beneath the RL framework.
+**RL-Kernel** is high-performance **RL post-training infrastructure** designed for
+bitwise, operator-level train–inference consistency across heterogeneous rollout and
+training engines. It combines deterministic operators, hardware-aware runtime dispatch,
+and accelerator-specific kernels to improve execution speed and memory efficiency for
+GRPO, PPO, and related RL workloads.
+
+The project is building toward cross-hardware and multi-model coverage. Today, the
+validated end-to-end path is **Qwen3-8B Dense with VIME, vLLM, and Megatron-LM**;
+DeepSeek-V4 Flash MoE and additional RL orchestration integrations are under active
+development or on the roadmap.
With **VIME + vLLM + Megatron-LM**, the published Qwen3-8B experiment achieves **zero
train–rollout LogP mismatches at every one of 200 steps**, **68.7% higher rollout
From 11ee862238d5b418dda3f895dae1814dfb28b0f1 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 17:57:22 +0800
Subject: [PATCH 07/36] docs(readme): remove opening benchmark summary
Signed-off-by: vensen
---
README.md | 5 -----
1 file changed, 5 deletions(-)
diff --git a/README.md b/README.md
index 45b7c0ed..1302c110 100644
--- a/README.md
+++ b/README.md
@@ -39,11 +39,6 @@ validated end-to-end path is **Qwen3-8B Dense with VIME, vLLM, and Megatron-LM**
DeepSeek-V4 Flash MoE and additional RL orchestration integrations are under active
development or on the roadmap.
-With **VIME + vLLM + Megatron-LM**, the published Qwen3-8B experiment achieves **zero
-train–rollout LogP mismatches at every one of 200 steps**, **68.7% higher rollout
-throughput**, and **8.2% lower end-to-end step time** than VIME's native production
-operator path. [See the configuration and results below](#benchmark-highlights).
-
## Why RL-Kernel?
Rollout and training engines can produce different log probabilities for the same tokens
From fb25ffed52abf7582488f048d3f8ac8036419b3f Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 18:02:52 +0800
Subject: [PATCH 08/36] docs(readme): split quick start by accelerator
Signed-off-by: vensen
---
README.md | 48 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 38 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index 1302c110..e5e2a9fd 100644
--- a/README.md
+++ b/README.md
@@ -155,23 +155,51 @@ measurements. See the [installation guide](./docs/getting_started/installation.m
## Quick Start
-Install a PyTorch build matching your accelerator runtime, then install RL-Kernel from
-source. Python 3.10 or newer is required.
+Install Python 3.10 or newer, a PyTorch build matching your accelerator runtime, and the
+corresponding CUDA or ROCm compiler toolchain. Then clone RL-Kernel:
```bash
git clone https://github.com/RL-Align/RL-Kernel.git
cd RL-Kernel
+```
+
+### NVIDIA CUDA
+
+Build against a visible NVIDIA GPU. Set `TORCH_CUDA_ARCH_LIST` when you want to pin the
+target architecture instead of relying on device detection.
+
+```bash
+# H100 / H200 (SM90)
+TORCH_CUDA_ARCH_LIST="9.0+PTX" python3 setup.py develop
+```
+
+Common CUDA targets are `8.0` for A100, `8.6` for A10/A40, and `9.0+PTX` for H100/H200.
+
+### AMD ROCm
+
+Set the target explicitly. The current MI300/MI325 build command is:
-# Native CUDA or ROCm extension
-RL_KERNEL_REQUIRE_EXT=1 python -m pip install --no-build-isolation -e .
-python -c "import rl_engine._C as _C; assert hasattr(_C, 'fused_logp'); print(_C.__file__)"
+```bash
+PYTORCH_ROCM_ARCH=gfx942 python3 setup.py develop
+```
+
+Common ROCm targets are `gfx90a` for MI200, `gfx942` for MI300/MI325, and `gfx950` for
+MI350/MI355. A portable build can target more than one architecture:
+
+```bash
+PYTORCH_ROCM_ARCH='gfx90a;gfx942;gfx950' python3 setup.py develop
+```
+
+### Verify the Native Extension
+
+```bash
+python3 -c "import rl_engine._C as _C; assert hasattr(_C, 'fused_logp'); print(_C.__file__)"
```
-For CPU-only or pure-Python development, use `python -m pip install -e .`.
-Strict train–inference consistency requires the corresponding operators and runtime
-configuration in both engines. Follow the [installation guide](./docs/getting_started/installation.md)
-and [quick-start guide](./docs/getting_started/quickstart.md); the full benchmark
-configuration and companion VIME revision are linked in [PR #377](https://github.com/RL-Align/RL-Kernel/pull/377).
+For CPU-only or pure-Python development, use `python3 -m pip install -e .`. Ascend and
+Moore Threads support is still under development and does not yet have a general-purpose
+Quick Start build command. See the [installation guide](./docs/getting_started/installation.md)
+for backend dependencies and troubleshooting.
## Community and Contributions
From f5b14c51f29f0314024c5044db375c9f2b528e40 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 18:29:18 +0800
Subject: [PATCH 09/36] build: defer C++ standard selection to PyTorch
---
README.md | 9 ++++++---
setup.py | 4 +++-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index e5e2a9fd..07c12fe4 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,8 @@ target architecture instead of relying on device detection.
```bash
# H100 / H200 (SM90)
-TORCH_CUDA_ARCH_LIST="9.0+PTX" python3 setup.py develop
+RL_KERNEL_REQUIRE_EXT=1 TORCH_CUDA_ARCH_LIST="9.0+PTX" \
+ python3 -m pip install --no-build-isolation --no-deps -e .
```
Common CUDA targets are `8.0` for A100, `8.6` for A10/A40, and `9.0+PTX` for H100/H200.
@@ -180,14 +181,16 @@ Common CUDA targets are `8.0` for A100, `8.6` for A10/A40, and `9.0+PTX` for H10
Set the target explicitly. The current MI300/MI325 build command is:
```bash
-PYTORCH_ROCM_ARCH=gfx942 python3 setup.py develop
+RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH=gfx942 \
+ python3 -m pip install --no-build-isolation --no-deps -e .
```
Common ROCm targets are `gfx90a` for MI200, `gfx942` for MI300/MI325, and `gfx950` for
MI350/MI355. A portable build can target more than one architecture:
```bash
-PYTORCH_ROCM_ARCH='gfx90a;gfx942;gfx950' python3 setup.py develop
+RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH='gfx90a;gfx942;gfx950' \
+ python3 -m pip install --no-build-isolation --no-deps -e .
```
### Verify the Native Extension
diff --git a/setup.py b/setup.py
index 79f882d9..6a9c7f2d 100644
--- a/setup.py
+++ b/setup.py
@@ -211,7 +211,9 @@ def get_extensions():
nvcc_flags.append("-allow-unsupported-compiler")
nvcc_flags.append("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")
- cxx_flags = ["-O3", "-std=c++17", "-DKERNEL_ALIGN_WITH_CUDA"]
+ # Let PyTorch's BuildExtension choose the C++ standard required by the
+ # installed PyTorch release (for example, C++20 in PyTorch 2.14).
+ cxx_flags = ["-O3", "-DKERNEL_ALIGN_WITH_CUDA"]
extra_link_args = list(torch_rpath)
if os.name != "nt":
# CUDA IPC metadata queries use the driver API (cuPointerGetAttribute).
From d4588da384d9c5046feb2c8af61e8ee4c10c6d7e Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 18:52:27 +0800
Subject: [PATCH 10/36] docs(readme): specify supported accelerator targets
---
README.md | 62 +++++++++++++++++++++++++++----------------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/README.md b/README.md
index 07c12fe4..70e766d6 100644
--- a/README.md
+++ b/README.md
@@ -55,8 +55,9 @@ differences enter the policy ratios and KL terms used by RL algorithms.
paths, and deterministic collectives target rollout, memory, and synchronization costs.
- **Current integration:** VIME is the supported RL orchestration layer, with vLLM for
rollout and Megatron-LM for training. RL-Kernel supplies the operators beneath them.
-- **Multiple accelerators:** dense-model train–inference consistency is supported on CUDA
- and ROCm, with Ascend and Moore Threads adaptation in progress.
+- **Current accelerator targets:** NVIDIA SM90 (H100, H200, and GH200) and AMD gfx942
+ (MI300A, MI300X, and MI325X) are the supported targets. Ascend `dav_c220` has partial
+ operator coverage; other hardware models are being adapted.
## Architecture
@@ -85,9 +86,9 @@ flowchart TB
ORCH --> MEGATRON["Megatron-LM · training"]
VLLM --> RLK["RL-Kernel · deterministic and optimized operators"]
MEGATRON --> RLK
- RLK --> CUDA["CUDA · supported"]
- RLK --> ROCM["ROCm · supported"]
- RLK -.-> ASCEND["Ascend · partial adaptation"]
+ RLK --> CUDA["CUDA · SM90
H100 / H200 / GH200"]
+ RLK --> ROCM["ROCm · gfx942
MI300A / MI300X / MI325X"]
+ RLK -.-> ASCEND["Ascend · dav_c220
partial adaptation"]
RLK -.-> MUSA["Moore Threads / MUSA · in progress"]
```
@@ -136,22 +137,24 @@ cost for a net saving of **20.72 seconds per end-to-end step**.
## Hardware Support
-The following matrix tracks accelerator coverage for the current dense-model path. It
-does not extend the end-to-end model claim beyond Qwen3-8B Dense.
+The following matrix lists the current architecture targets and their corresponding
+hardware models. It does not imply published end-to-end validation on every listed model,
+or extend the current end-to-end model claim beyond Qwen3-8B Dense on H100.
-| Vendor | Accelerator | Software stack | Dense train–inference consistency | Coverage / progress |
-| :--- | :--- | :--- | :---: | :--- |
-| **NVIDIA** | GPU | CUDA | ✅ **Supported** | Dense-model strict path; Qwen3-8B H100 end-to-end results above |
-| **AMD** | GPU | ROCm | ✅ **Supported** | Dense-model strict path; backend-specific setup and validation |
-| **Huawei** | Ascend NPU | CANN / Ascend C | 🟡 **Partially adapted** | Selected operators adapted; broader dense-model integration in progress |
-| **Moore Threads** | GPU | MUSA | 🚧 **In progress** | Accelerator adaptation and dense-model integration underway |
+| Vendor | Architecture target | Corresponding hardware models | Software stack | Coverage / progress |
+| :--- | :--- | :--- | :--- | :--- |
+| **NVIDIA** | SM90 (compute capability 9.0) | H100, H200, GH200 | CUDA | ✅ **Supported** — dense-model strict path; published end-to-end results use H100 |
+| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | ✅ **Supported** — dense-model strict path with backend-specific setup and validation |
+| **Huawei** | `dav_c220` (CANN `dav-2201` target) | Ascend `dav_c220` | CANN 9.1.0 / Ascend C | 🟡 **Partially adapted** — selected operators are available; other Ascend models are being adapted |
+| **Moore Threads** | Under adaptation | — | MUSA | 🚧 **In progress** — hardware adaptation and dense-model integration are underway |
✅ **Supported** · 🟡 **Partial adaptation** · 🚧 **Active development**
-Support applies to the implemented dense-model paths; model, dtype, operator, and
-parallelism coverage varies by backend. The performance numbers above are CUDA/H100
-measurements. See the [installation guide](./docs/getting_started/installation.md) and
-[operator catalog](./docs/operators/README.md) for backend requirements and contracts.
+Support applies to the listed architecture targets and implemented dense-model paths;
+model, dtype, operator, and parallelism coverage varies by backend. The performance
+numbers above are CUDA/H100 measurements. **Other hardware models are being adapted.**
+See the [installation guide](./docs/getting_started/installation.md) and [operator
+catalog](./docs/operators/README.md) for backend requirements and contracts.
## Quick Start
@@ -169,29 +172,25 @@ Build against a visible NVIDIA GPU. Set `TORCH_CUDA_ARCH_LIST` when you want to
target architecture instead of relying on device detection.
```bash
-# H100 / H200 (SM90)
+# H100 / H200 / GH200 (SM90)
RL_KERNEL_REQUIRE_EXT=1 TORCH_CUDA_ARCH_LIST="9.0+PTX" \
python3 -m pip install --no-build-isolation --no-deps -e .
```
-Common CUDA targets are `8.0` for A100, `8.6` for A10/A40, and `9.0+PTX` for H100/H200.
+The supported CUDA target is SM90 (compute capability 9.0), corresponding to NVIDIA H100,
+H200, and GH200. Other CUDA architectures are being adapted.
### AMD ROCm
-Set the target explicitly. The current MI300/MI325 build command is:
+Set the target explicitly. The supported gfx942 target corresponds to AMD Instinct MI300A,
+MI300X, and MI325X:
```bash
RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH=gfx942 \
python3 -m pip install --no-build-isolation --no-deps -e .
```
-Common ROCm targets are `gfx90a` for MI200, `gfx942` for MI300/MI325, and `gfx950` for
-MI350/MI355. A portable build can target more than one architecture:
-
-```bash
-RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH='gfx90a;gfx942;gfx950' \
- python3 -m pip install --no-build-isolation --no-deps -e .
-```
+Other ROCm architectures are being adapted.
### Verify the Native Extension
@@ -199,10 +198,11 @@ RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH='gfx90a;gfx942;gfx950' \
python3 -c "import rl_engine._C as _C; assert hasattr(_C, 'fused_logp'); print(_C.__file__)"
```
-For CPU-only or pure-Python development, use `python3 -m pip install -e .`. Ascend and
-Moore Threads support is still under development and does not yet have a general-purpose
-Quick Start build command. See the [installation guide](./docs/getting_started/installation.md)
-for backend dependencies and troubleshooting.
+For CPU-only or pure-Python development, use `python3 -m pip install -e .`. Ascend support
+is currently limited to partial operator coverage on `dav_c220` (CANN `dav-2201` target);
+other Ascend models are being adapted. Moore Threads support is also under development.
+Neither backend has a general-purpose Quick Start build command yet. See the [installation
+guide](./docs/getting_started/installation.md) for backend dependencies and troubleshooting.
## Community and Contributions
From e535a66580bb414c95b3125ce0b87e3f5a91e3e8 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:44:29 +0800
Subject: [PATCH 11/36] docs(readme): record validated H100 build command
---
README.md | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 70e766d6..a07c12de 100644
--- a/README.md
+++ b/README.md
@@ -173,12 +173,21 @@ target architecture instead of relying on device detection.
```bash
# H100 / H200 / GH200 (SM90)
-RL_KERNEL_REQUIRE_EXT=1 TORCH_CUDA_ARCH_LIST="9.0+PTX" \
+MAX_JOBS=8 \
+RL_KERNEL_REQUIRE_EXT=1 \
+TORCH_CUDA_ARCH_LIST="9.0+PTX" \
python3 -m pip install --no-build-isolation --no-deps -e .
```
The supported CUDA target is SM90 (compute capability 9.0), corresponding to NVIDIA H100,
-H200, and GH200. Other CUDA architectures are being adapted.
+H200, and GH200. This build command and the native extension check below have been
+validated on an NVIDIA H100 80GB HBM3. Other CUDA architectures are being adapted.
+
+Verify the loaded extension, GPU, SM capability, and required native symbol:
+
+```bash
+python3 -c "import torch, rl_engine._C as C; print('GPU:', torch.cuda.get_device_name(0)); print('Capability:', torch.cuda.get_device_capability(0)); print('Extension:', C.__file__); print('fused_logp:', hasattr(C, 'fused_logp')); assert hasattr(C, 'fused_logp'); print('H100 build: PASS')"
+```
### AMD ROCm
From fe594b7240c38ae6381e50cdef7b332843e465f1 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:47:13 +0800
Subject: [PATCH 12/36] docs(readme): record MI300X validation
---
README.md | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index a07c12de..5957c494 100644
--- a/README.md
+++ b/README.md
@@ -144,7 +144,7 @@ or extend the current end-to-end model claim beyond Qwen3-8B Dense on H100.
| Vendor | Architecture target | Corresponding hardware models | Software stack | Coverage / progress |
| :--- | :--- | :--- | :--- | :--- |
| **NVIDIA** | SM90 (compute capability 9.0) | H100, H200, GH200 | CUDA | ✅ **Supported** — dense-model strict path; published end-to-end results use H100 |
-| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | ✅ **Supported** — dense-model strict path with backend-specific setup and validation |
+| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | ✅ **Supported** — native extension loading and backend checks verified on MI300X |
| **Huawei** | `dav_c220` (CANN `dav-2201` target) | Ascend `dav_c220` | CANN 9.1.0 / Ascend C | 🟡 **Partially adapted** — selected operators are available; other Ascend models are being adapted |
| **Moore Threads** | Under adaptation | — | MUSA | 🚧 **In progress** — hardware adaptation and dense-model integration are underway |
@@ -199,14 +199,16 @@ RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH=gfx942 \
python3 -m pip install --no-build-isolation --no-deps -e .
```
-Other ROCm architectures are being adapted.
-
-### Verify the Native Extension
+Verify the ROCm environment and required native symbol:
```bash
-python3 -c "import rl_engine._C as _C; assert hasattr(_C, 'fused_logp'); print(_C.__file__)"
+python3 scripts/check_rocm_env.py
+python3 -c "import torch, rl_engine._C as C; print('GPU:', torch.cuda.get_device_name(0)); print('HIP:', torch.version.hip); print('Extension:', C.__file__); print('fused_logp:', hasattr(C, 'fused_logp')); assert hasattr(C, 'fused_logp'); print('MI300X build: PASS')"
```
+The native extension load and environment checks have been validated on an AMD Instinct
+MI300X reporting `gfx942`. Other ROCm architectures are being adapted.
+
For CPU-only or pure-Python development, use `python3 -m pip install -e .`. Ascend support
is currently limited to partial operator coverage on `dav_c220` (CANN `dav-2201` target);
other Ascend models are being adapted. Moore Threads support is also under development.
From edfa45f5644c2f7301795892d5d3e34868128b2a Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:50:12 +0800
Subject: [PATCH 13/36] docs(readme): use validated MI300X build command
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5957c494..5ef89e21 100644
--- a/README.md
+++ b/README.md
@@ -195,8 +195,7 @@ Set the target explicitly. The supported gfx942 target corresponds to AMD Instin
MI300X, and MI325X:
```bash
-RL_KERNEL_REQUIRE_EXT=1 PYTORCH_ROCM_ARCH=gfx942 \
- python3 -m pip install --no-build-isolation --no-deps -e .
+PYTORCH_ROCM_ARCH=gfx942 python3 setup.py develop
```
Verify the ROCm environment and required native symbol:
From a740c894b12f0da0e9eef5f535faa1f54d66cc3d Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:53:41 +0800
Subject: [PATCH 14/36] docs(readme): simplify hardware support language
---
README.md | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 5ef89e21..72e7d993 100644
--- a/README.md
+++ b/README.md
@@ -143,18 +143,14 @@ or extend the current end-to-end model claim beyond Qwen3-8B Dense on H100.
| Vendor | Architecture target | Corresponding hardware models | Software stack | Coverage / progress |
| :--- | :--- | :--- | :--- | :--- |
-| **NVIDIA** | SM90 (compute capability 9.0) | H100, H200, GH200 | CUDA | ✅ **Supported** — dense-model strict path; published end-to-end results use H100 |
-| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | ✅ **Supported** — native extension loading and backend checks verified on MI300X |
-| **Huawei** | `dav_c220` (CANN `dav-2201` target) | Ascend `dav_c220` | CANN 9.1.0 / Ascend C | 🟡 **Partially adapted** — selected operators are available; other Ascend models are being adapted |
-| **Moore Threads** | Under adaptation | — | MUSA | 🚧 **In progress** — hardware adaptation and dense-model integration are underway |
-
-✅ **Supported** · 🟡 **Partial adaptation** · 🚧 **Active development**
+| **NVIDIA** | SM90 (compute capability 9.0) | H100, H200, GH200 | CUDA | **Supported**, dense-model strict path. Published end-to-end results use H100. |
+| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | **Supported**, native extension loading and backend checks verified on MI300X. |
+| **Huawei** | `dav_c220` (CANN `dav-2201` target) | Ascend `dav_c220` | CANN 9.1.0 / Ascend C | **Partially adapted**, selected operators are available. Other Ascend models are being adapted. |
+| **Moore Threads** | Under adaptation | Not specified | MUSA | **In progress**, hardware adaptation and dense-model integration are underway. |
Support applies to the listed architecture targets and implemented dense-model paths;
model, dtype, operator, and parallelism coverage varies by backend. The performance
numbers above are CUDA/H100 measurements. **Other hardware models are being adapted.**
-See the [installation guide](./docs/getting_started/installation.md) and [operator
-catalog](./docs/operators/README.md) for backend requirements and contracts.
## Quick Start
From 267d85658fd1f3f626942037e2224dca128dd2c6 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:57:06 +0800
Subject: [PATCH 15/36] docs(readme): remove inline code styling
---
README.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 72e7d993..8c5cacfa 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ differences enter the policy ratios and KL terms used by RL algorithms.
- **Current integration:** VIME is the supported RL orchestration layer, with vLLM for
rollout and Megatron-LM for training. RL-Kernel supplies the operators beneath them.
- **Current accelerator targets:** NVIDIA SM90 (H100, H200, and GH200) and AMD gfx942
- (MI300A, MI300X, and MI325X) are the supported targets. Ascend `dav_c220` has partial
+ (MI300A, MI300X, and MI325X) are the supported targets. Ascend dav_c220 has partial
operator coverage; other hardware models are being adapted.
## Architecture
@@ -145,7 +145,7 @@ or extend the current end-to-end model claim beyond Qwen3-8B Dense on H100.
| :--- | :--- | :--- | :--- | :--- |
| **NVIDIA** | SM90 (compute capability 9.0) | H100, H200, GH200 | CUDA | **Supported**, dense-model strict path. Published end-to-end results use H100. |
| **AMD** | gfx942 (CDNA 3) | Instinct MI300A, MI300X, MI325X | ROCm | **Supported**, native extension loading and backend checks verified on MI300X. |
-| **Huawei** | `dav_c220` (CANN `dav-2201` target) | Ascend `dav_c220` | CANN 9.1.0 / Ascend C | **Partially adapted**, selected operators are available. Other Ascend models are being adapted. |
+| **Huawei** | dav_c220 (CANN dav-2201 target) | Ascend dav_c220 | CANN 9.1.0 / Ascend C | **Partially adapted**, selected operators are available. Other Ascend models are being adapted. |
| **Moore Threads** | Under adaptation | Not specified | MUSA | **In progress**, hardware adaptation and dense-model integration are underway. |
Support applies to the listed architecture targets and implemented dense-model paths;
@@ -164,7 +164,7 @@ cd RL-Kernel
### NVIDIA CUDA
-Build against a visible NVIDIA GPU. Set `TORCH_CUDA_ARCH_LIST` when you want to pin the
+Build against a visible NVIDIA GPU. Set TORCH_CUDA_ARCH_LIST when you want to pin the
target architecture instead of relying on device detection.
```bash
@@ -202,10 +202,10 @@ python3 -c "import torch, rl_engine._C as C; print('GPU:', torch.cuda.get_device
```
The native extension load and environment checks have been validated on an AMD Instinct
-MI300X reporting `gfx942`. Other ROCm architectures are being adapted.
+MI300X reporting gfx942. Other ROCm architectures are being adapted.
-For CPU-only or pure-Python development, use `python3 -m pip install -e .`. Ascend support
-is currently limited to partial operator coverage on `dav_c220` (CANN `dav-2201` target);
+For CPU-only or pure-Python development, use an editable pip installation. Ascend support
+is currently limited to partial operator coverage on dav_c220 (CANN dav-2201 target);
other Ascend models are being adapted. Moore Threads support is also under development.
Neither backend has a general-purpose Quick Start build command yet. See the [installation
guide](./docs/getting_started/installation.md) for backend dependencies and troubleshooting.
From b69c5d5ebffdbf8bccb529348fea9fe7e3cd4d78 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sat, 5 Sep 2026 20:59:52 +0800
Subject: [PATCH 16/36] docs(readme): rename benchmark comparison
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 8c5cacfa..0c1341d7 100644
--- a/README.md
+++ b/README.md
@@ -109,7 +109,7 @@ Items in development or on the roadmap are not yet part of the supported path.
## Benchmark Highlights
-### VIME native operators vs. VIME + RL-Kernel
+### VIME native vs. RL-Kernel + VIME
The completed experiment in [PR #377](https://github.com/RL-Align/RL-Kernel/pull/377)
compares **G10**, VIME's native production operator path, with **optimized G11**, the
From 7dc1a9bc45467514b3972749c80292b5b7b322e8 Mon Sep 17 00:00:00 2001
From: vensen
Date: Sun, 6 Sep 2026 00:15:49 +0800
Subject: [PATCH 17/36] docs(readme): link Qwen3-8B integration runbook
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index 0c1341d7..27855630 100644
--- a/README.md
+++ b/README.md
@@ -162,6 +162,9 @@ git clone https://github.com/RL-Align/RL-Kernel.git
cd RL-Kernel
```
+For the Qwen3-8B train–rollout command and setup for VIME with RL-Kernel, see the
+[8×H100 integration runbook](https://github.com/RL-Align/RL-Kernel/issues/342).
+
### NVIDIA CUDA
Build against a visible NVIDIA GPU. Set TORCH_CUDA_ARCH_LIST when you want to pin the
From 9af6f990da0397d160c7931e313dfe825a8ce91e Mon Sep 17 00:00:00 2001
From: vensen
Date: Sun, 6 Sep 2026 00:22:38 +0800
Subject: [PATCH 18/36] docs(readme): fix benchmark chart label overlap
---
README.md | 2 +-
docs/assets/qwen3-8b-performance-summary.png | Bin 0 -> 394076 bytes
2 files changed, 1 insertion(+), 1 deletion(-)
create mode 100644 docs/assets/qwen3-8b-performance-summary.png
diff --git a/README.md b/README.md
index 27855630..e5a5753e 100644
--- a/README.md
+++ b/README.md
@@ -133,7 +133,7 @@ maximum response length 7,168 · KL-loss coefficient 0.001.
G11 saves **47.47 seconds per rollout step**, offsetting the additional actor training
cost for a net saving of **20.72 seconds per end-to-end step**.
-
+
## Hardware Support
diff --git a/docs/assets/qwen3-8b-performance-summary.png b/docs/assets/qwen3-8b-performance-summary.png
new file mode 100644
index 0000000000000000000000000000000000000000..39b4cc13b26b03183b331410c7e2d8d1edd86e94
GIT binary patch
literal 394076
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