fast-ulysses
Ulysses sequence-parallel all-to-all as a torch custom op, moved by the GPU copy engines.
Ulysses sequence parallelism shards a long sequence across GPUs: one all-to-all before attention trades the sequence shard for a head shard, a second trades it back. For long-sequence video DiT workloads those two collectives are the critical communication.
This ships that 4D all-to-all as torch.ops.fast_ulysses.all_to_all_4d, over NVLink, on one node.
Key features
- No SMs. The peer transfers are pitched
cudaMemcpy2D/3DAsyncstraight into peers' symmetric-memory addresses, so they run on the copy engines while compute kernels hold every SM. (Measured: a peer copy overlaps a concurrent GEMM completely; a same-device copy does not, which is whyout=fromempty_output()— which removes the copy-out — is the faster path.) - Relayout for free. The sequence/head permutation is expressed as source and destination
strides on those copies, not as two permute kernels. That is roughly half of what the
torch.distributedpath spends. - Uneven shards. Per-rank
seq_splits/head_splits, which is what lets a caller drop sequence padding. Even splits are the special case, not a separate path.
Performance
8 GPUs, one exclusively allocated node per row, the same wheel and the same .so on all of them.
base is torch.distributed permute + all_to_all_single + permute. Wan 720p, bf16, ms.
| GPU | fabric | base | ours | vs base | transfer | of the fabric |
|---|---|---|---|---|---|---|
| H200 | NVLink | 1.569 | 0.860 | 1.82× | 0.680 | 99% |
| B200 | NVLink | 1.194 | 0.550 | 2.17× | 0.410 | 90% |
| B300 | NVLink | 1.184 | 0.548 | 2.16× | 0.411 | 90% |
| H100 | NVLink | 1.616 | 0.971 | 1.66× | 0.715 | 94% |
47–60% of the baseline is relayout that costs nothing here. "Of the fabric" is the transfer against
what a flat peer copy achieves on the same machine — at 90–99% there is nothing left to schedule.
out= from empty_output() removes the copy-out for a further 1.14–1.28×.
Every number was taken twice, on two different nodes except H100, whose two samples are the same node. Full tables, per-stage timings and the method: docs/benchmark.md.
Quick start
Save this as example.py and run torchrun --nproc_per_node=8 example.py:
import os
import torch
import torch.distributed as dist
from fast_ulysses import UlyssesGroup
dist.init_process_group("nccl")
torch.cuda.set_device(int(os.environ["LOCAL_RANK"]))
group = UlyssesGroup()
b, s_local, heads, d = 1, 4096, 8, 128
ws = dist.get_world_size()
x = torch.randn(b, s_local, heads * ws, d, dtype=torch.bfloat16, device="cuda")
y = group.all_to_all_4d(x, mode=0) # (b, s_local * ws, heads, d)
z = group.all_to_all_4d(y, mode=1) # back to x's shape
group.destroy()
dist.destroy_process_group()
Every rank must issue the same sequence of shapes. More: docs/quickstart.md.
A real one — a DiT attention block, sequence-parallel, forward and backward, checked against the same block without sequence parallelism:
torchrun --nproc_per_node=8 examples/dit_attention.py
The collective is differentiable, so that block is an ordinary nn.Module: no autograd.Function
wrapper, no manual backward.
API
| Entry point | Purpose |
|---|---|
UlyssesGroup(process_group=None, device=None, *, require_nvlink=True) |
Collective. Refuses a group whose GPUs are not NVLink-joined. |
group.all_to_all_4d(x, *, mode=0, out=None, seq_splits=None, head_splits=None) |
The collective. Returns a tensor the caller owns. |
group.all_to_all_4d_async(x, *, ...) |
The same, on a comm stream, returning an AsyncCollectiveTensor. lend=True drops the copy-out without a buffer of your own, bounded at 4 live results. |
group.empty_output(x, *, mode=0, ...) |
A symmetric buffer to pass as out=, which removes the copy-out. out= gives up the gradient. |
group.destroy() |
Release the windows. Collective. |
fast-ulysses doctor |
Build, devices, NVLink matrix. |
Shapes, splits and the collective contract: docs/api.md. Why the code is shaped
this way, and what it rests on that is not guaranteed: docs/design.md. Coming from
DeepSpeed-Ulysses, sglang's usp.py or yunchang — what each call becomes, and what this does not
have: docs/migration.md.
Limits
- NVLink, one node,
world_sizein [1, 8], including odd sizes. Over PCIe — especially across a CPU socket —torch.distributedis faster, because the pitched copies this transport is built on degrade badly there. The constructor refuses such a group. float16/bfloat16/float32/float8_e4m3fn/float8_e5m2/int8/uint8, andd * elem_sizemust be 16-byte aligned — sod % 8at bfloat16,d % 16at float8.- Differentiable, and it propagates shapes under
FakeTensor. Not traceable bytorch.compile: the group is a torchbind object with no registered fake class, so Dynamo graph-breaks on it. - Forward-mode AD works —
torch.autograd.forward_ad,torch.func.jvp,torch.func.linearize— at one extra collective for the tangent. Reverse-modetorch.funcdoes not:grad/vjp/jacrevraise, andvmapraises by an explicit check, since it would run one collective per batch element and ranks that disagree on the batch size hang. - The async form is not differentiable and says so: its
AsyncCollectiveTensoris a leaf, so a gradient would be dropped silently. Useall_to_all_4dwhen you need one. out=is not differentiable either, and cannot say so: it reaches a mutating op with no autograd formula, so the result is the caller's buffer, detached. It is a speed knob for inference and no-grad regions, not for a training graph.- CUDA-graph capture covers the sync call on an already-warmed shape; see docs/design.md.
Install
Requires PyTorch 2.10+, CUDA 12.8+ or 13, and sm80 / sm90 / sm100 / sm120. torch is the only runtime dependency.
A wheel is built against one (torch minor, CUDA major) and embeds that torch's C++ ABI, so the pair has to match. Install torch first, then pick the index by the CUDA major it was built against:
pip install fast-ulysses --index-url https://triple-mu.github.io/fast-ulysses/whl/cu13/ # or cu12
That index carries fast-ulysses and nothing else, so pip cannot move your torch to satisfy it: it
backtracks to the wheel pinned to the torch minor you already have. fast-ulysses wheel-url names
the row for the environment running now and prints the same install as a fully pinned
--find-links command against the release assets, when you want the file itself.
pip install fast-ulysses # PyPI: torch 2.13.x + CUDA 13
pip install -e . --no-build-isolation # from source, all four arches
FAST_ULYSSES_CUDA_ARCH=90 pip install -e . --no-build-isolation # one arch, much faster
PyPI carries that one pair, pinned torch==2.13.*. On any other torch the first command does not
fail — pip upgrades torch to 2.13, a different CUDA build than the one you chose.
The one thing to know before reaching for --find-links: PEP 440 orders local versions, so an
install that does not write +torch210cu128 out in full takes torch213cu130 whatever torch you
have, silently. That, the per-row indexes and what to do when the import fails:
docs/install.md.
Testing
pytest # the host-only plan tests always run; the GPU workers skip below 2 GPUs
pytest -m "not multigpu" # host-only, no GPU needed
torchrun --nproc_per_node=8 test/distributed/correctness.py
Development setup: docs/develop.md.
License
Apache-2.0. See LICENSE.
Metadata
Release files for fast-ulysses 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fast_ulysses-0.2.1.tar.gz | 115.4 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| fast_ulysses-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| fast_ulysses-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| fast_ulysses-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| fast_ulysses-0.2.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
Total release size: 1.5 MB
Release files / fast_ulysses-0.2.1.tar.gz
| Download URL | fast_ulysses-0.2.1.tar.gz |
|---|---|
| Size | 115.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eeeb73c5e1a5463df2fdcc121460684ecdc8ed443323b06c72389cfb0779b954
|
|
BLAKE2b-256 checksum How to use checksums |
fa3e99bcbf104a9a1dc708685b872d2ed16fb76dc87430b2cc6f62c7e5a2bf74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / fast_ulysses-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fast_ulysses-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 340.4 kB |
| Tags | CPython 3.13 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
372dc21f2090cef25ffa0937eb3b6b699d14f58a210d53616b5b4c1c4e623ef4
|
|
BLAKE2b-256 checksum How to use checksums |
bdab035a9aae95f071bf75ee71ea85a7eb27bfb09f1dc45dc3a7b9996cd45d58
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / fast_ulysses-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fast_ulysses-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 340.3 kB |
| Tags | CPython 3.12 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
49d0469a02310dfbd94bd4fe5996b87924298a73399e832a5c574aaeeecad6bd
|
|
BLAKE2b-256 checksum How to use checksums |
8b7d1b139c36d3375629e6a4f3da3997543c04f58162575ee52e8d3893a7a411
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / fast_ulysses-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fast_ulysses-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 339.5 kB |
| Tags | CPython 3.11 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
72dfd59233574040ec89e12c522aedf1533c78f6bd814c4458c0e540a9406613
|
|
BLAKE2b-256 checksum How to use checksums |
e625b4bce12572e7e0d5739f6bbb52f686b73735f41d70d82fb000f146f5386e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / fast_ulysses-0.2.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fast_ulysses-0.2.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 337.8 kB |
| Tags | CPython 3.10 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
7d0970dc564ddf98a72271599790d7d0c2d5bfd9ddccf73b0898de229ad15650
|
|
BLAKE2b-256 checksum How to use checksums |
4f5140689a83e4dedaa75d9fe680b7b4531fc3acdfca8b52d2378dec80ecb15f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency log