Skip to content

Core API

The flashdreams.core package collects the low-level attention primitives, KV-cache implementations, and process-group utilities that integrations share.

Attention

The attention package provides the kernels used by the transformer and the block-structured KV cache that backs streaming inference.

flashdreams.core.attention.NativeAttention

NativeAttention(qkv_format: Literal['bhsd', 'bshd'] = 'bhsd', backend: Literal['math', 'efficient', 'cudnn', 'flash'] = 'cudnn')

Bases: Module

Native attention module with configurable QKV layout and SDPA backend.

Configure attention format and backend.

Parameters:

Name Type Description Default
qkv_format Literal['bhsd', 'bshd']

Layout of the QKV tensors; "bhsd" is (B, H, S, D), "bshd" is (B, S, H, D).

'bhsd'
backend Literal['math', 'efficient', 'cudnn', 'flash']

SDPA backend selected via sdpa_kernel.

'cudnn'
Source code in flashdreams/flashdreams/core/attention/native.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def __init__(
    self,
    qkv_format: Literal["bhsd", "bshd"] = "bhsd",
    backend: Literal["math", "efficient", "cudnn", "flash"] = "cudnn",
) -> None:
    """Configure attention format and backend.

    Args:
        qkv_format: Layout of the QKV tensors; ``"bhsd"`` is ``(B, H, S, D)``,
            ``"bshd"`` is ``(B, S, H, D)``.
        backend: SDPA backend selected via ``sdpa_kernel``.
    """
    super().__init__()
    assert qkv_format in ["bhsd", "bshd"], f"Invalid qkv format: {qkv_format}"
    assert backend in ["math", "efficient", "cudnn", "flash"], (
        f"Invalid backend: {backend}"
    )
    self.qkv_format = qkv_format
    self.backend = backend
    self.device_mesh: DeviceMesh | None = None

set_context_parallel_group

set_context_parallel_group(cp_group: ProcessGroup | None) -> None

Enable or disable context parallelism for ring attention.

Parameters:

Name Type Description Default
cp_group ProcessGroup | None

Process group for context parallel; use None to disable.

required
Source code in flashdreams/flashdreams/core/attention/native.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def set_context_parallel_group(self, cp_group: ProcessGroup | None) -> None:
    """Enable or disable context parallelism for ring attention.

    Args:
        cp_group: Process group for context parallel; use None to disable.
    """
    if cp_group is None:
        self.device_mesh = None
    else:
        self.device_mesh = DeviceMesh.from_group(cp_group, device_type="cuda")

        # Need to disable load balance for torch context parallel to work.
        from torch.distributed.tensor.experimental._attention import (
            _cp_options,
            set_rotate_method,
        )

        _cp_options.enable_load_balance = False
        set_rotate_method("allgather")

is_context_parallel_enabled

is_context_parallel_enabled() -> bool

Return True if context parallelism is active.

Source code in flashdreams/flashdreams/core/attention/native.py
62
63
64
def is_context_parallel_enabled(self) -> bool:
    """Return True if context parallelism is active."""
    return self.device_mesh is not None

context_parallel_size

context_parallel_size() -> int

Return the context parallel world size, or 1 if disabled.

Source code in flashdreams/flashdreams/core/attention/native.py
66
67
68
def context_parallel_size(self) -> int:
    """Return the context parallel world size, or 1 if disabled."""
    return self.device_mesh.size() if self.device_mesh is not None else 1

forward

forward(query: Tensor, key: Tensor, value: Tensor) -> Tensor

Run context-parallel SDPA (or single-rank SDPA when CP is disabled).

Parameters:

Name Type Description Default
query Tensor

Query tensor in configured qkv_format.

required
key Tensor

Key tensor in configured qkv_format.

required
value Tensor

Value tensor in configured qkv_format.

required

Returns:

Type Description
Tensor

Attention output in the same format as inputs.

Source code in flashdreams/flashdreams/core/attention/native.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def forward(self, query: Tensor, key: Tensor, value: Tensor) -> Tensor:
    """Run context-parallel SDPA (or single-rank SDPA when CP is disabled).

    Args:
        query: Query tensor in configured ``qkv_format``.
        key: Key tensor in configured ``qkv_format``.
        value: Value tensor in configured ``qkv_format``.

    Returns:
        Attention output in the same format as inputs.
    """
    # SDPA / low-level ops expect (B, H, S, D). "bshd" is (B, S, H, D) → transpose once.
    if self.qkv_format == "bshd":
        query = query.transpose(1, 2)
        key = key.transpose(1, 2)
        value = value.transpose(1, 2)
    out = self._impl(query=query, key=key, value=value)
    if self.qkv_format == "bshd":
        out = out.transpose(1, 2)
    return out

flashdreams.core.attention.ContextParallelAttention

ContextParallelAttention(qkv_format: Literal['bhsd', 'bshd'] = 'bhsd', backend: Literal['cudnn', 'flash'] = 'cudnn', method: Literal['ring', 'ulysses'] = 'ring', convert_to_fp32: bool = True)

Bases: NativeAttention

Context-parallel attention with selectable method and SDPA backend.

Configure context-parallel attention method and backend.

Parameters:

Name Type Description Default
qkv_format Literal['bhsd', 'bshd']

Layout of the QKV tensors; "bhsd" or "bshd".

'bhsd'
backend Literal['cudnn', 'flash']

SDPA backend; "cudnn" or "flash".

'cudnn'
method Literal['ring', 'ulysses']

Context-parallelism strategy; "ring" or "ulysses".

'ring'
convert_to_fp32 bool

Promote LSE accumulators to fp32 during ring merges.

True
Source code in flashdreams/flashdreams/core/attention/cp.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(
    self,
    qkv_format: Literal["bhsd", "bshd"] = "bhsd",
    backend: Literal["cudnn", "flash"] = "cudnn",
    method: Literal["ring", "ulysses"] = "ring",
    convert_to_fp32: bool = True,
) -> None:
    """Configure context-parallel attention method and backend.

    Args:
        qkv_format: Layout of the QKV tensors; ``"bhsd"`` or ``"bshd"``.
        backend: SDPA backend; ``"cudnn"`` or ``"flash"``.
        method: Context-parallelism strategy; ``"ring"`` or ``"ulysses"``.
        convert_to_fp32: Promote LSE accumulators to fp32 during ring merges.
    """
    super().__init__()
    assert qkv_format in ["bhsd", "bshd"], f"Invalid qkv format: {qkv_format}"
    assert backend in ["cudnn", "flash"], f"Invalid backend: {backend}"
    assert method in ["ring", "ulysses"], f"Invalid cp method: {method}"
    self.qkv_format = qkv_format
    self.backend = backend
    self.method = method
    self.device_mesh: DeviceMesh | None = None
    self.convert_to_fp32 = convert_to_fp32

flashdreams.core.attention.BlockKVCache dataclass

BlockKVCache(k_shape: tuple[int, ...], v_shape: tuple[int, ...], seq_dim: int, chunk_size: int, window_size: int, sink_size: int = 0, device: device | str = device('cuda'), dtype: dtype = float16, _prev_chunk_idx: int = -1, _curr_chunk_idx: int | None = None, _n_cached: int = 0)

KV cache for causal attention with a fixed-size local window, CUDA-graph compatible.

Keys and values can have arbitrary shape [..., total_size, ...]; the sequence (rolling) dimension is given by seq_dim (dimension index, can be negative). Layout along that dimension: [sink tokens | local window tokens]. Sink tokens are never evicted; the local window rolls left as new chunks are added if full. Chunks are non-overlapping: each update adds one chunk of chunk_size tokens at the next logical position in the full sequence.

Phases
  • Filling: cache not yet full; tokens are written contiguously; cached_k() / cached_v() return only the valid prefix.
  • Steady-state: if adding a chunk would exceed the fixed cache size, the local window rolls left by the overflow amount and the new chunk overwrites the rightmost positions; cached_k() / cached_v() return the full buffer.

The argument chunk_idx (0, 1, 2, ...) is the index of the new chunk in the full sequence (not an index into the cache). If chunk_idx is greater than the previous one, the chunk is appended (or, in steady-state, written after the roll). If chunk_idx equals the previous one, the same cache positions are overwritten.

Per-step usage
  1. before_update(chunk_idx) — prepare (roll local window if steady-state).
  2. update(k, v) — write the new chunk's keys/values into the cache.
  3. cached_k() / cached_v() — get cached keys/values for attention.
  4. after_update(chunk_idx) — update internal bookkeeping.

k_shape instance-attribute

k_shape: tuple[int, ...]

Shape of the keys. Must be the same as the values shape except for the last dimension.

v_shape instance-attribute

v_shape: tuple[int, ...]

Shape of the values. Must be the same as the keys shape except for the last dimension.

seq_dim instance-attribute

seq_dim: int

Sequence dimension that will be rolled. Can be negative.

chunk_size instance-attribute

chunk_size: int

Number of tokens processed each time.

window_size instance-attribute

window_size: int

Size of the local attention window (excluding sink tokens).

sink_size class-attribute instance-attribute

sink_size: int = 0

Number of sink tokens at the start of the cache that are never evicted. Defaults to 0.

device class-attribute instance-attribute

device: device | str = torch.device('cuda')

Device to store the cache on.

dtype class-attribute instance-attribute

dtype: dtype = torch.float16

Data type to store the cache in.

size property

size: int

Number of valid cached tokens visible to attention.

write_end property

write_end: int

Right edge of the current chunk in the physical cache layout.

from_tensor classmethod

from_tensor(k: Tensor, v: Tensor, seq_dim: int) -> Self

Build a single-chunk cache pre-filled with the given key and value tensors.

Source code in flashdreams/flashdreams/core/attention/kvcache.py
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
@classmethod
def from_tensor(cls, k: Tensor, v: Tensor, seq_dim: int) -> Self:
    """Build a single-chunk cache pre-filled with the given key and value tensors."""
    cache = cls(
        k_shape=k.shape,
        v_shape=v.shape,
        seq_dim=seq_dim,
        chunk_size=k.shape[seq_dim],
        window_size=k.shape[seq_dim],
        device=k.device,
        dtype=k.dtype,
    )
    cache.before_update(0)
    cache.update(k, v)
    cache.after_update(0)
    cache._curr_chunk_idx = 0
    return cache

is_steady_state

is_steady_state() -> bool

Return True if the cache is full (steady-state phase).

Source code in flashdreams/flashdreams/core/attention/kvcache.py
745
746
747
748
749
750
751
752
753
754
755
756
757
def is_steady_state(self) -> bool:
    """Return True if the cache is full (steady-state phase)."""
    assert self._curr_chunk_idx is not None, (
        "Must call before_update() before is_steady_state()"
    )
    total_size = self._k.shape[self.seq_dim]
    is_full = total_size == self._n_cached
    is_overlapping_with_sink = (
        self.sink_size > 0
        and self._curr_chunk_idx * self.chunk_size
        < self.sink_size  # start < sink_size
    )
    return is_full and not is_overlapping_with_sink

before_update

before_update(chunk_idx: int) -> None

Prepare the cache before writing new tokens.

If chunk_idx equals the previous chunk index, this is a no-op. Otherwise, we expect the chunk_idx to be +1 from the previous chunk index. In this case, we will roll the local window left if the cache is in steady-state, or no op if the cache is in filling phase.

Parameters:

Name Type Description Default
chunk_idx int

Chunk index of the new chunk in the full sequence.

required
Source code in flashdreams/flashdreams/core/attention/kvcache.py
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
def before_update(self, chunk_idx: int) -> None:
    """
    Prepare the cache before writing new tokens.

    If ``chunk_idx`` equals the previous chunk index, this is a no-op. Otherwise,
    we expect the ``chunk_idx`` to be +1 from the previous chunk index. In this case,
    we will roll the local window left if the cache is in steady-state, or no op
    if the cache is in filling phase.

    Args:
        chunk_idx: Chunk index of the new chunk in the full sequence.
    """
    assert self._curr_chunk_idx is None, (
        "Must call after_update() before before_update()"
    )
    self._curr_chunk_idx = chunk_idx

    if chunk_idx == self._prev_chunk_idx:
        return

    assert chunk_idx == self._prev_chunk_idx + 1, (
        "Expected the new chunk_idx to be +1 from the previous chunk_idx, "
        f"got {chunk_idx} != {self._prev_chunk_idx} + 1"
    )
    total_size = self._k.shape[self.seq_dim]
    if not self._current_chunk_overlaps_sink():
        overflow = self._n_cached + self.chunk_size - total_size
        if overflow > 0:
            self._roll_local_window_left(overflow)

update

update(k: Tensor, v: Tensor) -> None

Write the new chunk's keys and values into the cache.

Must be called after before_update() and before after_update().

Parameters:

Name Type Description Default
k Tensor

Keys; shape must match cached keys except at seq_dim, where length must be chunk_size.

required
v Tensor

Values; shape must match cached values except at seq_dim, where length must be chunk_size.

required
Source code in flashdreams/flashdreams/core/attention/kvcache.py
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
def update(self, k: Tensor, v: Tensor) -> None:
    """
    Write the new chunk's keys and values into the cache.

    Must be called after ``before_update()`` and before ``after_update()``.

    Args:
        k: Keys; shape must match cached keys except at seq_dim, where length must be chunk_size.
        v: Values; shape must match cached values except at seq_dim, where length must be chunk_size.
    """
    assert self._curr_chunk_idx is not None, (
        "Must call before_update() before update()"
    )

    chunk_size_k = k.shape[self.seq_dim]
    chunk_size_v = v.shape[self.seq_dim]
    assert chunk_size_k == self.chunk_size, (
        f"Expected input k to have chunk_size ({chunk_size_k}) at seq_dim ({self.seq_dim}), "
        f"got {chunk_size_k} != {self.chunk_size}"
    )
    assert chunk_size_v == self.chunk_size, (
        f"Expected input v to have chunk_size ({chunk_size_v}) at seq_dim ({self.seq_dim}), "
        f"got {chunk_size_v} != {self.chunk_size}"
    )
    self._write_current_chunk(k, v)

after_update

after_update(chunk_idx: int) -> None

Finalize bookkeeping after writing new tokens.

Updates _prev_chunk_idx and, in filling phase, _n_cached.

Parameters:

Name Type Description Default
chunk_idx int

The index of the new chunk in the full sequence.

required
Source code in flashdreams/flashdreams/core/attention/kvcache.py
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
def after_update(self, chunk_idx: int) -> None:
    """
    Finalize bookkeeping after writing new tokens.

    Updates ``_prev_chunk_idx`` and, in filling phase, ``_n_cached``.

    Args:
        chunk_idx: The index of the new chunk in the full sequence.
    """
    assert chunk_idx == self._curr_chunk_idx, (
        f"Expected chunk_idx to be {self._curr_chunk_idx}, got {chunk_idx}"
    )

    if self._curr_chunk_idx == self._prev_chunk_idx + 1:
        if self.is_steady_state():
            pass
        else:
            total_size = self._k.shape[self.seq_dim]
            self._n_cached = min(self._n_cached + self.chunk_size, total_size)
        self._prev_chunk_idx += 1
    elif self._curr_chunk_idx == self._prev_chunk_idx:
        pass
    else:
        raise ValueError(
            f"{self._curr_chunk_idx=} should be either {self._prev_chunk_idx + 1} or {self._prev_chunk_idx}."
        )

    self._curr_chunk_idx = None

cached_k

cached_k() -> Tensor

Return cached keys for attention (valid prefix in filling phase, full buffer in steady-state).

Source code in flashdreams/flashdreams/core/attention/kvcache.py
844
845
846
847
848
def cached_k(self) -> Tensor:
    """
    Return cached keys for attention (valid prefix in filling phase, full buffer in steady-state).
    """
    return self._k[self._seq_slice(0, self._visible_end())]

cached_v

cached_v() -> Tensor

Return cached values for attention (valid prefix in filling phase, full buffer in steady-state).

Source code in flashdreams/flashdreams/core/attention/kvcache.py
850
851
852
853
854
def cached_v(self) -> Tensor:
    """
    Return cached values for attention (valid prefix in filling phase, full buffer in steady-state).
    """
    return self._v[self._seq_slice(0, self._visible_end())]

reset

reset() -> None

Reset bookkeeping while preserving the allocated tensor storage.

Source code in flashdreams/flashdreams/core/attention/kvcache.py
856
857
858
859
860
def reset(self) -> None:
    """Reset bookkeeping while preserving the allocated tensor storage."""
    self._prev_chunk_idx = -1
    self._curr_chunk_idx = None
    self._n_cached = 0

clone_kv

clone_kv() -> tuple[Tensor, Tensor]

Return clones of the full physical K/V buffers.

Source code in flashdreams/flashdreams/core/attention/kvcache.py
862
863
864
def clone_kv(self) -> tuple[Tensor, Tensor]:
    """Return clones of the full physical K/V buffers."""
    return self._k.clone(), self._v.clone()

overwrite_kv_

overwrite_kv_(k: Tensor, v: Tensor) -> None

Overwrite the full K/V buffers without changing their addresses.

Parameters:

Name Type Description Default
k Tensor

Replacement keys with the exact cache shape.

required
v Tensor

Replacement values with the exact cache shape.

required
Source code in flashdreams/flashdreams/core/attention/kvcache.py
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
def overwrite_kv_(self, k: Tensor, v: Tensor) -> None:
    """Overwrite the full K/V buffers without changing their addresses.

    Args:
        k: Replacement keys with the exact cache shape.
        v: Replacement values with the exact cache shape.
    """
    if k.shape != self._k.shape or v.shape != self._v.shape:
        raise ValueError(
            "overwrite_kv_ shape mismatch: "
            f"got k {tuple(k.shape)} / v {tuple(v.shape)}, "
            f"cache holds k {tuple(self._k.shape)} / v {tuple(self._v.shape)}"
        )
    self._k.copy_(k)
    self._v.copy_(v)

Distributed

Helpers for multi-GPU / multi-node inference. init boots the NCCL process group with sensible defaults and replaces the boilerplate at the top of example launchers.

flashdreams.core.distributed.init

init() -> int | None

Initialize distributed training.

Source code in flashdreams/flashdreams/core/distributed/__init__.py
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
def init() -> int | None:
    """Initialize distributed training."""
    if dist.is_initialized():
        return torch.cuda.current_device()

    pynvml.nvmlInit()
    local_rank = int(os.getenv("LOCAL_RANK", 0))
    try:
        device = Device(local_rank)
        sched_setaffinity = getattr(os, "sched_setaffinity", None)
        if sched_setaffinity is not None:
            sched_setaffinity(0, device.get_cpu_affinity())
    except (pynvml.NVMLError, OSError) as e:
        logger.warning(f"Failed to set device affinity: {e}")

    os.environ["TORCH_NCCL_BLOCKING_WAIT"] = "0"
    os.environ["TORCH_NCCL_ASYNC_ERROR_HANDLING"] = "1"
    if dist.is_available():
        torch.cuda.set_device(local_rank)
        timeout_seconds = os.getenv("TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC", 1800)
        timeout_timedelta = timedelta(seconds=int(timeout_seconds))
        dist.init_process_group(
            backend="nccl",
            init_method="env://",
            timeout=timeout_timedelta,
            device_id=local_rank,
        )
        # Always destroy the process group on interpreter shutdown so NCCL
        # does not warn about a leaked group at the end of every run; the
        # handler is idempotent if a caller (e.g. a long-lived gRPC server)
        # already destroyed the group explicitly before exiting.
        atexit.register(_safe_destroy_pg)
        configure_loguru_for_distributed(get_global_rank())
        logger.critical(
            f"Initialized distributed inference with local rank {local_rank} with timeout {timeout_seconds}",
        )

    # Bump cudaLimitMaxL2FetchGranularity (id=0x05) to 128 bytes for better bandwidth.
    _libcudart = ctypes.CDLL("libcudart.so")
    p_value = ctypes.cast((ctypes.c_int * 1)(), ctypes.POINTER(ctypes.c_int))
    _libcudart.cudaDeviceSetLimit(ctypes.c_int(0x05), ctypes.c_int(128))
    _libcudart.cudaDeviceGetLimit(p_value, ctypes.c_int(0x05))
    logger.info(f"Inference with {dist.get_world_size()} GPUs.")

flashdreams.core.distributed.Device

Device(device_idx: int)

Lightweight wrapper around an NVML device handle for CPU-affinity queries.

Bind to the NVML handle for the GPU at device_idx.

Source code in flashdreams/flashdreams/core/distributed/__init__.py
158
159
160
161
def __init__(self, device_idx: int):
    """Bind to the NVML handle for the GPU at ``device_idx``."""
    super().__init__()
    self.handle = pynvml.nvmlDeviceGetHandleByIndex(device_idx)

get_name

get_name() -> str

Return the marketing name reported by NVML for this device.

Source code in flashdreams/flashdreams/core/distributed/__init__.py
163
164
165
def get_name(self) -> str:
    """Return the marketing name reported by NVML for this device."""
    return pynvml.nvmlDeviceGetName(self.handle)

get_cpu_affinity

get_cpu_affinity() -> list[int]

Return the indices of CPUs ideally affined to this GPU per NVML.

Source code in flashdreams/flashdreams/core/distributed/__init__.py
167
168
169
170
171
172
173
174
175
176
177
def get_cpu_affinity(self) -> list[int]:
    """Return the indices of CPUs ideally affined to this GPU per NVML."""
    affinity_string = ""
    for j in pynvml.nvmlDeviceGetCpuAffinity(
        self.handle, Device._nvml_affinity_elements
    ):
        # NVML returns a sequence of 64-bit affinity bitmasks, low word first.
        affinity_string = "{:064b}".format(j) + affinity_string
    affinity_list = [int(x) for x in affinity_string]
    affinity_list.reverse()  # so core 0 is in the 0th element of the list
    return [i for i, e in enumerate(affinity_list) if e != 0]