Pipeline API
The flashdreams.infra package defines the swappable abstractions that
every integration plugs into: a config system, an encoder / diffusion-model /
decoder triple, and the streaming inference pipeline that drives them.
See the Inferencing API overview for public runtime boundaries.
Config
Infra component configs are mutable InstantiateConfig dataclasses
built via config.setup(). PrintableConfig provides readable
configuration dumps, while derive_config deep-copies an existing
config before applying nested overrides.
flashdreams.infra.config.PrintableConfig
Config base class providing a multi-line __str__ for human-readable dumps.
flashdreams.infra.config.InstantiateConfig
dataclass
InstantiateConfig(_target: type)
Bases: PrintableConfig
Config carrying a _target class plus its kwargs, instantiable via setup.
setup
setup(**kwargs: Any) -> Any
Instantiate the configured object.
Source code in flashdreams/flashdreams/infra/config/base.py
33 34 35 | |
flashdreams.infra.config.derive_config
derive_config(base_config: T, **changes: Any) -> T
Deep-copy a base config and apply nested keyword overrides.
Nested dict values walk into both dataclass attributes and nested
dicts; leaf values overwrite directly. Raises KeyError on unknown
paths.
Example:
.. code-block:: python
new_config = derive_config(
base_config,
tokenizer=WanVAEInterfaceConfig(checkpoint_path=...),
dit=dict(len_t=3, checkpoint_path=...),
)
Source code in flashdreams/flashdreams/infra/config/base.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
Pipeline
The pipeline composes the model-side streaming inference stages. It
autoregressively generates one chunk at a time by running an optional encoder,
the diffusion model, and an optional decoder, with per-session caches for the
configured streaming components. Call finalize() after generate() to
advance the diffusion model's autoregressive cache.
flashdreams.infra.pipeline.StreamInferencePipelineConfig
dataclass
StreamInferencePipelineConfig(*, _target: type['StreamInferencePipeline'] = (lambda: StreamInferencePipeline)(), name: str, diffusion_model: DiffusionModelConfig, decoder: DecoderConfig | None = None, encoder: EncoderConfig | None = None)
Bases: InstantiateConfig
Config for the streaming inference pipeline.
Set encoder=None when the pipeline has no per-AR-step control input
(pure T2V). Set decoder=None to return the clean latent directly
(training, latent-space evaluation, or pipelines that own decoding).
name
instance-attribute
name: str
Stable slug for this pipeline variant; the primary key of
<NAME>_CONFIGS. Runners mirror it as runner_name so
flashdreams-run <slug> resolves to this pipeline.
diffusion_model
instance-attribute
diffusion_model: DiffusionModelConfig
Transformer + scheduler config.
decoder
class-attribute
instance-attribute
decoder: DecoderConfig | None = None
Optional output :class:StreamingDecoder with a per-rollout cache,
called as decoder(input, autoregressive_index, cache). Use
None to return the clean latent unchanged.
encoder
class-attribute
instance-attribute
encoder: EncoderConfig | None = None
Optional per-AR-step input encoder. Must be a
:class:StreamingEncoder; one-shot encoders go on
transformer.context_encoder instead.
enable_sync_and_profile
property
enable_sync_and_profile: bool
Whether to record synchronized per-stage CUDA timings.
Enabled process-wide with FLASHDREAMS_SYNC_AND_PROFILE=1
flashdreams.infra.pipeline.StreamInferencePipeline
StreamInferencePipeline(config: StreamInferencePipelineConfig)
Bases: Module, Generic[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
End-to-end streaming inference pipeline.
Generic over the encoder, transformer, and decoder cache types. The
encoder's input/output types are forwarded as Any so the
transformer's predict_flow / postprocess_clean_latent overrides
own the typing on the input argument they receive.
Examples:
cache = pipeline.initialize_cache(transformer_context={...})
output = pipeline.generate(0, cache, input=...)
pipeline.finalize(0, cache)
output = pipeline.generate(1, cache, input=...)
pipeline.finalize(1, cache) # optional for the last rollout
Source code in flashdreams/flashdreams/infra/pipeline/base.py
134 135 136 137 138 139 | |
initialize_cache
initialize_cache(transformer_context: dict[str, Any] | None = None, encoder_context: dict[str, Any] | None = None, decoder_context: dict[str, Any] | None = None) -> StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
Build a fresh per-rollout cache.
Each *_context dict is forwarded as keyword arguments to the
corresponding component's initialize_autoregressive_cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transformer_context
|
dict[str, Any] | None
|
Per-rollout state for the transformer
(e.g. |
None
|
encoder_context
|
dict[str, Any] | None
|
Per-rollout state for the encoder. Ignored when there is no encoder. |
None
|
decoder_context
|
dict[str, Any] | None
|
Per-rollout state for the decoder. Ignored when there is no decoder. |
None
|
Returns:
| Type | Description |
|---|---|
StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
|
A fresh cache to thread through |
Source code in flashdreams/flashdreams/infra/pipeline/base.py
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
generate
generate(autoregressive_index: int, cache: StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT], input: Any = None) -> Tensor
Generate one chunk for this AR step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
Must be |
required |
cache
|
StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
|
Per-rollout cache from |
required |
input
|
Any
|
Raw input fed to the encoder. Required when an encoder
is configured, must be |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Decoded tensor (e.g. RGB video) when a decoder is configured; |
Tensor
|
otherwise the unpatchified clean latent from the diffusion model. |
Source code in flashdreams/flashdreams/infra/pipeline/base.py
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 | |
finalize
finalize(autoregressive_index: int, cache: StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]) -> dict[str, float] | None
Advance the diffusion AR cache for the next AR step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
Must match the index passed to the most
recent |
required |
cache
|
StreamInferencePipelineCache[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
|
Same cache used by |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float] | None
|
|
dict[str, float] | None
|
or by a pipeline that recorded onto |
dict[str, float] | None
|
Otherwise a snapshot of this AR step's per-stage timings (ms) and |
dict[str, float] | None
|
GPU memory (GiB): |
dict[str, float] | None
|
``{ |
dict[str, float] | None
|
mem_reserved_gib, mem_peak_gib}``. The same numbers are also |
dict[str, float] | None
|
logged via |
Source code in flashdreams/flashdreams/infra/pipeline/base.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | |
flashdreams.infra.pipeline.StreamInferencePipelineCache
dataclass
StreamInferencePipelineCache(*, transformer_cache: TransformerCacheT, encoder_cache: StreamingEncoderCacheT | None = None, decoder_cache: StreamingDecoderCacheT | None = None, final_state: 'DiffusionModel.FinalState[TransformerCacheT] | None' = None, autoregressive_index: int | None = None, event_profiler: EventProfiler | None = None)
Bases: Generic[StreamingEncoderCacheT, TransformerCacheT, StreamingDecoderCacheT]
Per-rollout cache held by the pipeline.
transformer_cache
instance-attribute
transformer_cache: TransformerCacheT
Long-lived transformer AR cache (always present).
encoder_cache
class-attribute
instance-attribute
encoder_cache: StreamingEncoderCacheT | None = None
Encoder AR cache; None iff the pipeline has no encoder.
decoder_cache
class-attribute
instance-attribute
decoder_cache: StreamingDecoderCacheT | None = None
Decoder AR cache; None iff the pipeline has no decoder.
final_state
class-attribute
instance-attribute
final_state: 'DiffusionModel.FinalState[TransformerCacheT] | None' = None
Diffusion-model state from the most recent generate, consumed
by finalize.
autoregressive_index
class-attribute
instance-attribute
autoregressive_index: int | None = None
AR step index of the most recent generate.
event_profiler
class-attribute
instance-attribute
event_profiler: EventProfiler | None = None
Per-step profiler, populated only when profiling is on.
Diffusion model
The diffusion model wraps a transformer backbone with a denoising scheduler.
Callers see only noise to clean latent conversion; the per-step flow prediction
and iteration loop remain inside DiffusionModel.generate.
flashdreams.infra.diffusion.model.DiffusionModelConfig
dataclass
DiffusionModelConfig(*, _target: type['DiffusionModel'] = (lambda: DiffusionModel)(), transformer: TransformerConfig, scheduler: SchedulerConfig, seed: int | None = None, context_noise: int = 0, noise_in_unpatchified_shape: bool = False)
Bases: InstantiateConfig
Config for the autoregressive diffusion model.
seed
class-attribute
instance-attribute
seed: int | None = None
RNG seed for initial-noise draws and scheduler sampling.
None uses the global RNG.
context_noise
class-attribute
instance-attribute
context_noise: int = 0
Timestep used by finalize for the AR cache-update forward.
0 skips add_noise.
noise_in_unpatchified_shape
class-attribute
instance-attribute
noise_in_unpatchified_shape: bool = False
Debug-only: draw the initial noise in the unpatchified shape, then patchify. Slower than the default patchified path; useful when matching another implementation's RNG sequence.
flashdreams.infra.diffusion.model.DiffusionModel
DiffusionModel(config: DiffusionModelConfig)
Bases: Module, Generic[TransformerCacheT]
Autoregressive diffusion model (scheduler + transformer).
Generic over the transformer's AR cache type so user-facing typing on
cache is preserved end-to-end.
Examples:
model = config.setup().to("cuda")
cache = model.transformer.initialize_autoregressive_cache(...)
clean, final_state = model.generate(autoregressive_index=0, cache=cache)
model.finalize(final_state)
Source code in flashdreams/flashdreams/infra/diffusion/model/base.py
94 95 96 97 98 99 100 101 | |
rng
property
rng: Generator | None
Per-model generator, lazily built on the current device.
Returns None when config.seed is None. Rebuilt the first
time the model's device changes after a .to(...). A device move
resets the RNG stream — fine for "construct on CPU, .to(gpu)
once" but mid-rollout device hops lose RNG state.
FinalState
dataclass
FinalState(*, clean_latent: Tensor, autoregressive_index: int, cache: _FinalStateCacheT, input: Any = None)
Bases: Generic[_FinalStateCacheT]
State passed from generate to finalize.
clean_latent
instance-attribute
clean_latent: Tensor
Patchified clean latent at the end of denoising.
autoregressive_index
instance-attribute
autoregressive_index: int
AR step this state was produced at.
cache
instance-attribute
cache: _FinalStateCacheT
Long-lived AR cache used during generation.
input
class-attribute
instance-attribute
input: Any = None
Patchified per-AR-step encoder output, or None.
generate
generate(autoregressive_index: int, cache: TransformerCacheT, input: Any = None) -> tuple[Tensor, 'DiffusionModel.FinalState[TransformerCacheT]']
Run the denoising loop for one AR step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
AR step index. |
required |
cache
|
TransformerCacheT
|
Long-lived AR cache, mutated in place. |
required |
input
|
Any
|
Optional per-AR-step encoder output. Patchified here and
forwarded to |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
|
'DiffusionModel.FinalState[TransformerCacheT]'
|
|
Source code in flashdreams/flashdreams/infra/diffusion/model/base.py
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 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 223 224 225 226 | |
finalize
finalize(final_state: 'DiffusionModel.FinalState[TransformerCacheT]') -> None
Advance the AR cache using the clean latent from generate.
Re-noises the clean latent to config.context_noise and runs the
transformer's finalize_kv_cache (one forward for vanilla
transformers, multiple for dual-network DiTs).
context_noise == 0 skips add_noise (sigma=0 is identity) and
feeds the clean latent directly. This also dodges the requirement
for schedulers to support a t=0 lookup (UniPC's inference
schedule has no t=0 entry).
Source code in flashdreams/flashdreams/infra/diffusion/model/base.py
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | |
Transformer
flashdreams.infra.diffusion.transformer.TransformerConfig
dataclass
TransformerConfig(*, _target: type['Transformer'] = (lambda: Transformer)())
flashdreams.infra.diffusion.transformer.Transformer
Transformer(config: TransformerConfig)
Bases: Module, ABC, Generic[TransformerCacheT]
Flow-prediction transformer, generic over its AR cache subclass.
Subclasses implement predict_flow and the patchify hooks. AR
transformers also subclass TransformerAutoregressiveCache and
override initialize_autoregressive_cache.
Example:
.. code-block:: python
class MyTransformer(Transformer[MyCache]):
def predict_flow(self, noisy_latent, timestep, cache, input=None):
...
def initialize_autoregressive_cache(self, **context) -> MyCache:
...
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
78 79 80 | |
latent_shape
abstractmethod
property
latent_shape: tuple[int, ...]
Shape of the input/output latent tensor for this rank.
Includes batch dims. May depend on hierarchical context-parallel
group sizes (V/T/HW), so subclasses typically derive this from
self.cp_groups rather than from static config alone.
predict_flow
abstractmethod
predict_flow(noisy_latent: Tensor, timestep: Tensor, cache: TransformerCacheT, input: Any = None) -> Tensor
Predict the flow at timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
noisy_latent
|
Tensor
|
Patchified noisy latent for this denoising step. |
required |
timestep
|
Tensor
|
Scalar timestep tensor. |
required |
cache
|
TransformerCacheT
|
Per-rollout AR cache. |
required |
input
|
Any
|
Patchified encoder output for this AR step, or |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Predicted flow tensor with the same shape as |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
finalize_kv_cache
finalize_kv_cache(noisy_latent: Tensor, timestep: Tensor, cache: TransformerCacheT, input: Any = None) -> None
Advance the AR cache so it is ready for the next AR step.
Called by DiffusionModel.finalize after the denoising loop; the
flow is discarded — only the cache side effect matters. Default
runs a single predict_flow forward. Override for transformers
with multiple parallel networks that must stay in lock-step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
noisy_latent
|
Tensor
|
Patchified latent at the AR-step's context noise
(or the clean latent when |
required |
timestep
|
Tensor
|
0-d context-noise timestep tensor. |
required |
cache
|
TransformerCacheT
|
Per-rollout AR cache. |
required |
input
|
Any
|
Same patchified encoder output passed to |
None
|
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
initialize_autoregressive_cache
initialize_autoregressive_cache(**context: Any) -> TransformerCacheT
Build a fresh AR cache for a new rollout.
Default returns an empty cache, correct for non-AR transformers.
Subclasses with custom cache types must override this and may
declare typed per-rollout context (e.g. text_embeddings).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Any
|
Per-rollout state forwarded as keyword arguments. |
{}
|
Returns:
| Type | Description |
|---|---|
TransformerCacheT
|
Fresh AR cache. |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
initial_noise
initial_noise(*, latent_shape: tuple[int, ...], rng: Generator | None, cache: TransformerCacheT, input: Any = None) -> Tensor
Draw the starting latent for one denoising loop.
Default is Gaussian noise in latent_shape. Model integrations can
override this to seed from encoder outputs, pin I2V frames, or attach
per-step state to the cache while still using DiffusionModel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
latent_shape
|
tuple[int, ...]
|
Shape requested by the diffusion model. |
required |
rng
|
Generator | None
|
Per-model generator on |
required |
cache
|
TransformerCacheT
|
Per-rollout AR cache. |
required |
input
|
Any
|
Same patchified encoder output passed to |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Initial latent tensor for scheduler sampling. |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | |
postprocess_clean_latent
postprocess_clean_latent(clean_latent: Tensor, cache: TransformerCacheT, input: Any = None) -> Tensor
Optional postprocessing hook for the predicted clean latent.
Default is identity. Override to clamp or re-inject regions whose
clean value is known a priori (e.g. I2V first-frame pinning).
Called at the end of DiffusionModel.generate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clean_latent
|
Tensor
|
Patchified |
required |
cache
|
TransformerCacheT
|
Per-rollout AR cache. |
required |
input
|
Any
|
Same patchified encoder output passed to |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Postprocessed clean latent with the same shape. |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | |
patchify_and_maybe_split_cp
abstractmethod
patchify_and_maybe_split_cp(x: Any) -> Any
Patchify and (optionally) CP-split a noisy latent or encoder payload.
Tensors patchify and split. Structured payloads (e.g. an image-control
struct with latent + mask) patchify each tensor field and
return the same struct type. Implement as identity when neither
token packing nor CP sharding applies. Output preserves the input
Python type — only shapes change.
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
213 214 215 216 217 218 219 220 221 222 | |
unpatchify_and_maybe_gather_cp
abstractmethod
unpatchify_and_maybe_gather_cp(x: Tensor) -> Tensor
Inverse of patchify_and_maybe_split_cp for the network output.
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
224 225 226 | |
flashdreams.infra.diffusion.transformer.TransformerAutoregressiveCache
dataclass
TransformerAutoregressiveCache()
Cache that persists across an AR rollout.
Empty by default; safe to instantiate directly for non-AR transformers
(default start / finalize are no-ops). Subclass and add fields
plus AR bookkeeping for real per-rollout state.
Example:
.. code-block:: python
cache.start(autoregressive_index)
# one or more denoising steps...
cache.finalize(autoregressive_index)
start
start(autoregressive_index: int) -> None
Mark the start of an AR step. Default is a no-op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
Index of the AR step being started. |
required |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
37 38 39 40 41 42 | |
finalize
finalize(autoregressive_index: int) -> None
Finalize bookkeeping after use at this AR step. Default is a no-op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
Index of the AR step just finalized. |
required |
Source code in flashdreams/flashdreams/infra/diffusion/transformer/base.py
44 45 46 47 48 49 | |
Schedulers
A scheduler owns the denoising loop. Its internal operations broadcast per-step scalar sigmas, so the same scheduler works for any latent layout.
flashdreams.infra.diffusion.scheduler.Scheduler
Scheduler(config: SchedulerConfig)
Bases: Module, ABC
Denoising scheduler.
Owns the entire denoising loop. Callers see only noise → clean;
the loop shape (renoise / multistep / plain ODE) is private.
Concrete configs inherit SchedulerConfig and declare their own
num_inference_steps / shift fields (the base holds no
shared dataclass fields).
Examples:
scheduler = config.setup()
clean = scheduler.sample(initial_noise=noise, predict_flow=predictor)
noisy = scheduler.add_noise(clean_input=clean, timestep=t)
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/base.py
50 51 52 | |
sample
abstractmethod
sample(initial_noise: Tensor, predict_flow: FlowPredictor, rng: Generator | None = None) -> Tensor
Run the full denoising loop and return the clean latent.
Schedulers are shape-agnostic: every internal op broadcasts against
per-step scalar sigmas. In practice initial_noise is a video
latent [B, C, T, H, W], conventionally treated as a sample at
sigma=1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_noise
|
Tensor
|
Gaussian noise on the caller's device/dtype. |
required |
predict_flow
|
FlowPredictor
|
Per-step closure invoked
|
required |
rng
|
Generator | None
|
Generator on the same device. Used by self-forcing renoise loops; pure ODE solvers ignore it. |
None
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Clean latent with the same shape, device, and dtype as |
Tensor
|
|
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/base.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 78 | |
add_noise
abstractmethod
add_noise(clean_input: Tensor, timestep: Tensor, rng: Generator | None = None) -> Tensor
Apply the forward corruption x_t = (1 - sigma(t)) * x_0 + sigma(t) * eps.
Timestep value semantics are scheduler-specific: all schedulers snap to the nearest entry of their inference schedule.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/base.py
80 81 82 83 84 85 86 87 88 89 90 91 | |
flashdreams.infra.diffusion.scheduler.SchedulerConfig
dataclass
SchedulerConfig(*, _target: type['Scheduler'] = (lambda: Scheduler)())
flashdreams.infra.diffusion.scheduler.FlowPredictor
Bases: Protocol
Closure (noisy_latent, timestep) -> predicted_flow.
Built by DiffusionModel.generate by binding the per-AR-step cache
/ input to the transformer's predict_flow. A scheduler invokes
it once per denoising iteration. The scheduler decides the timestep
dtype (UniPC uses int64, flow-match uses float).
__call__
__call__(noisy_latent: Tensor, timestep: Tensor) -> Tensor
Predict the flow at timestep.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/base.py
28 29 30 | |
flashdreams.infra.diffusion.scheduler.FlowMatchSchedulerConfig
dataclass
FlowMatchSchedulerConfig(*, _target: type['FlowMatchScheduler'] = (lambda: FlowMatchScheduler)(), num_inference_steps: int = 4, shift: float = 8.0, denoising_timesteps: list[int] = (lambda: [1000, 750, 500, 250])(), warp_denoising_step: bool = True, num_train_timesteps: int = 1000, sigma_max: float = 1.0, sigma_min: float = 0.0, extra_one_step: bool = True, timestep_dtype: dtype = float32, reference_sampling: bool = False, enable_tqdm: bool = False)
Bases: SchedulerConfig
Config for the flow-matching scheduler.
num_inference_steps
class-attribute
instance-attribute
num_inference_steps: int = 4
Number of denoising steps; must equal len(denoising_timesteps).
shift
class-attribute
instance-attribute
shift: float = 8.0
Schedule warp factor.
denoising_timesteps
class-attribute
instance-attribute
denoising_timesteps: list[int] = field(default_factory=lambda: [1000, 750, 500, 250])
Per-step diffusion timesteps in [0, num_train_timesteps].
warp_denoising_step
class-attribute
instance-attribute
warp_denoising_step: bool = True
Map denoising_timesteps through the warped sigma schedule.
num_train_timesteps
class-attribute
instance-attribute
num_train_timesteps: int = 1000
Length of the training sigma table.
sigma_max
class-attribute
instance-attribute
sigma_max: float = 1.0
Top of the linspace before warping; 1.0 matches DiffSynth, upstream
Wan / Lingbot ships 0.999.
sigma_min
class-attribute
instance-attribute
sigma_min: float = 0.0
Bottom of the linspace before warping. Reserved for upstream parity;
only 0.0 is exercised.
extra_one_step
class-attribute
instance-attribute
extra_one_step: bool = True
If True, build the schedule from
linspace(sigma_max, sigma_min, N+1)[:-1] (matches DiffSynth /
upstream Wan); False uses N points and is kept for non-Wan
recipes.
timestep_dtype
class-attribute
instance-attribute
timestep_dtype: dtype = torch.float32
Dtype of denoising_step_list.
Set to an integer dtype (e.g.
torch.int64) when the network's time embedding is sensitive to the
fractional part of the warped timestep — upstream Wan stores
scheduler.timesteps as int64 and lets the embedding upcast to
float64 internally.
reference_sampling
class-attribute
instance-attribute
reference_sampling: bool = False
Keep timesteps exact and recurrent samples in the network flow dtype.
LingBot's reference noise bank is FP32 while its network is BF16. This mode
preserves integer timestep values and rounds each x0 before re-noising.
enable_tqdm
class-attribute
instance-attribute
enable_tqdm: bool = False
Whether to enable tqdm progress bar.
flashdreams.infra.diffusion.scheduler.FlowMatchScheduler
FlowMatchScheduler(config: FlowMatchSchedulerConfig)
Bases: Scheduler
Flow-matching scheduler with self-forcing renoise (DiffSynth-style).
Each iteration converts the predicted flow to an x0 estimate, then
re-noises at the same sigma to feed the next iteration. The final
x0 is returned::
x_t = initial_noise
for t in denoising_step_list:
v = predict_flow(x_t, t)
x0 = x_t - sigma(t) * v
x_t = (1 - sigma(t)) * x0 + sigma(t) * eps
return x0
Example:
.. code-block:: python
scheduler = FlowMatchSchedulerConfig(
num_inference_steps=4,
shift=8.0,
denoising_timesteps=[1000, 750, 500, 250],
).setup().to("cuda")
clean = scheduler.sample(initial_noise=noise, predict_flow=fn)
Schedule buffers are pinned to fp32 even after module.to(bf16);
integer timesteps like 1000 would otherwise round to 1024.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
sample
sample(initial_noise: Tensor, predict_flow: FlowPredictor, rng: Generator | None = None) -> Tensor
Run the self-forcing flow-match denoising loop.
Iteration 0 trusts initial_noise as the sigma=1 sample;
later iterations re-noise the previous x0 estimate to the new
sigma before the network forward. By default the result is cast back
to initial_noise.dtype after every step; reference sampling casts
each x0 to the network flow dtype.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
add_noise
add_noise(clean_input: Tensor, timestep: Tensor, rng: Generator | None = None) -> Tensor
Apply the forward corruption at an arbitrary timestep.
Snaps timestep to the nearest entry of the warped training table
and uses it as sigma in the standard lerp.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm.py
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | |
flashdreams.infra.diffusion.scheduler.FlowMatchEulerDiscreteSchedulerConfig
dataclass
FlowMatchEulerDiscreteSchedulerConfig(*, _target: type['FlowMatchEulerDiscreteScheduler'] = (lambda: FlowMatchEulerDiscreteScheduler)(), num_inference_steps: int = 4, shift: float = 5.0, num_train_timesteps: int = 1000, fixed_timesteps: tuple[float, ...] | None = None, enable_tqdm: bool = False)
Bases: SchedulerConfig
Config for the flow-matching Euler-discrete scheduler.
Defaults match diffusers' :class:FlowMatchEulerDiscreteScheduler
with num_train_timesteps=1000 and the standard
linspace + shift warp. Set :attr:fixed_timesteps to a length
num_inference_steps + 1 tuple (terminal value typically 0.0)
to pin an externally-derived distilled schedule.
num_inference_steps
class-attribute
instance-attribute
num_inference_steps: int = 4
Number of Euler steps. Matches the distilled WAN-5B 4-step path out of the box; bump to 30-50 for non-distilled checkpoints.
shift
class-attribute
instance-attribute
shift: float = 5.0
Schedule warp factor applied to the linspaced sigma grid. Ignored
when :attr:fixed_timesteps is set.
num_train_timesteps
class-attribute
instance-attribute
num_train_timesteps: int = 1000
Length of the training sigma table. Used to convert between
integer timesteps and [0, 1] sigmas (sigma = timestep / N).
fixed_timesteps
class-attribute
instance-attribute
fixed_timesteps: tuple[float, ...] | None = None
Override the derived schedule with a precomputed list of
timesteps. When set, must have length num_inference_steps + 1;
the trailing entry is typically 0.0 so the last Euler step
lands on the clean latent. None (default) derives the schedule
from :attr:num_inference_steps + :attr:shift via the standard
flow-matching linspace + warp.
The HY-WorldPlay distilled WAN-5B path pins this to
(1000.0, 960.0, 888.8889, 727.2728, 0.0).
enable_tqdm
class-attribute
instance-attribute
enable_tqdm: bool = False
Whether to enable the tqdm progress bar inside :meth:sample.
flashdreams.infra.diffusion.scheduler.FlowMatchUniPCSchedulerConfig
dataclass
FlowMatchUniPCSchedulerConfig(*, _target: type['FlowMatchUniPCScheduler'] = (lambda: FlowMatchUniPCScheduler)(), num_inference_steps: int = 50, shift: float = 5.0, num_train_timesteps: int = 1000, solver_order: int = 2, use_kerras_sigma: bool = False, enable_tqdm: bool = False)
Bases: SchedulerConfig
Config for the flow-matching UniPC scheduler.
Defaults match the official Wan 2.1 inference integration (UniPC, BH2,
order 2, shift 5.0). Override shift per checkpoint as recommended
upstream (e.g. 3.0 for Wan 2.1 14B I2V 480P).
num_inference_steps
class-attribute
instance-attribute
num_inference_steps: int = 50
Number of UniPC denoising steps.
shift
class-attribute
instance-attribute
shift: float = 5.0
Schedule warp factor.
num_train_timesteps
class-attribute
instance-attribute
num_train_timesteps: int = 1000
Length of the training sigma table.
solver_order
class-attribute
instance-attribute
solver_order: int = 2
UniPC solver order; only 2 is supported.
use_kerras_sigma
class-attribute
instance-attribute
use_kerras_sigma: bool = False
Whether to use the exact sigma used in edm sampler.
enable_tqdm
class-attribute
instance-attribute
enable_tqdm: bool = False
Whether to enable tqdm progress bar.
flashdreams.infra.diffusion.scheduler.FlowMatchUniPCScheduler
FlowMatchUniPCScheduler(config: FlowMatchUniPCSchedulerConfig)
Bases: Scheduler
Order-2 UniPC predictor-corrector for flow-matching.
Specialized + pre-baked variant of the upstream Wan 2.1 UniPC solver.
Schedule buffers (sigmas + per-step coefficients) stay fp32 regardless
of module.to(dtype).
Example:
.. code-block:: python
scheduler = FlowMatchUniPCSchedulerConfig(
num_inference_steps=50,
shift=5.0,
).setup().to("cuda")
clean = scheduler.sample(initial_noise=noise, predict_flow=fn)
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm_unipc.py
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | |
sample
sample(initial_noise: Tensor, predict_flow: FlowPredictor, rng: Generator | None = None) -> Tensor
Run the order-2 UniPC predictor-corrector denoising loop.
Each iteration: network → flow → x0 → corrector (skipped at
step 0) → predictor. All per-step coefficients are pre-baked at
construction; the loop is pure tensor ops. Internal arithmetic is
fp32; the result is cast back to initial_noise.dtype. rng
is unused (deterministic ODE) but accepted for interface conformance.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm_unipc.py
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | |
add_noise
add_noise(clean_input: Tensor, timestep: Tensor, rng: Generator | None = None) -> Tensor
Apply the forward corruption at an arbitrary timestep.
Snaps timestep to the nearest entry of the inference schedule
on-device (no Python sync) and uses the matching sigma in the lerp.
Source code in flashdreams/flashdreams/infra/diffusion/scheduler/fm_unipc.py
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | |
Encoder
Encoders turn raw conditioning into latent tensors. Encoder is stateless and
one-shot, while StreamingEncoder carries per-step state. The video variant
adds spatial and temporal size contracts.
flashdreams.infra.encoder.EncoderConfig
dataclass
flashdreams.infra.encoder.Encoder
Encoder(config: EncoderConfig)
Bases: ABC, Module
Stateless encoder.
forward is not pinned by the base. Encoders used as a
context_encoder (one-shot, called once inside
:meth:Transformer.initialize_autoregressive_cache) must match the
slim call shape forward(self, input).
For per-AR-step encoders that need a per-rollout cache, inherit
from :class:StreamingEncoder instead.
Source code in flashdreams/flashdreams/infra/encoder/base.py
46 47 48 | |
flashdreams.infra.encoder.StreamingEncoder
StreamingEncoder(config: EncoderConfig)
Bases: ABC, Module, Generic[StreamingEncoderCacheT]
Streaming encoder, generic over the per-rollout cache type.
forward is not pinned by the base. Streaming encoders called by
:class:StreamInferencePipeline must match its call shape:
forward(self, input, autoregressive_index=0, cache=None).
Source code in flashdreams/flashdreams/infra/encoder/base.py
82 83 84 | |
initialize_autoregressive_cache
abstractmethod
initialize_autoregressive_cache(**context: Any) -> StreamingEncoderCacheT
Build a fresh per-rollout cache.
Override to return the encoder's concrete cache type.
Source code in flashdreams/flashdreams/infra/encoder/base.py
86 87 88 89 90 91 | |
flashdreams.infra.encoder.StreamingVideoEncoder
StreamingVideoEncoder(config: EncoderConfig)
Bases: StreamingEncoder[StreamingEncoderCacheT]
Streaming pixel-video encoder.
Pins down the contracts that every streaming pixel→latent video
encoder satisfies in addition to :class:StreamingEncoder:
- Spatial and temporal compression ratios between the pixel and latent grids (constants of the architecture).
- AR-step-aware temporal size mappers, so a pipeline can size its inputs and outputs without knowing the encoder's concrete temporal cache topology (causal first-frame padding, sliding windows, etc.).
Spatial scaling is trivially side // spatial_compression_ratio
in either direction; the AR-step-asymmetric piece is the temporal
size, which gets its own mapper. Typically AR 0 takes
1 + (T_lat - 1) * r pixel frames to produce T_lat latent
frames because of causal first-frame padding, while AR ≥ 1 takes
T_lat * r pixel frames.
Source code in flashdreams/flashdreams/infra/encoder/base.py
82 83 84 | |
spatial_compression_ratio
abstractmethod
property
spatial_compression_ratio: int
Pixel side ÷ latent side. Constant across AR steps.
temporal_compression_ratio
abstractmethod
property
temporal_compression_ratio: int
Pixel frames ÷ latent frames in steady state (AR ≥ 1).
AR 0 typically takes one extra (un-grouped) pixel frame to
produce its first latent frame because of causal first-frame
padding; that asymmetry lives inside
:meth:get_output_temporal_size /
:meth:get_input_temporal_size.
get_output_temporal_size
abstractmethod
get_output_temporal_size(autoregressive_index: int, input_temporal_size: int) -> int
Latent frame count produced from input_temporal_size pixel frames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
AR step index (0-based). |
required |
input_temporal_size
|
int
|
Number of pixel frames fed at this step. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of latent frames emitted at this step. |
Source code in flashdreams/flashdreams/infra/encoder/base.py
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
get_input_temporal_size
abstractmethod
get_input_temporal_size(autoregressive_index: int, output_temporal_size: int) -> int
Pixel frame count needed to produce output_temporal_size latents.
Inverse of :meth:get_output_temporal_size. Implementations
should assert output_temporal_size is achievable at this AR
step (i.e. the corresponding pixel count comes out as a
positive integer).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
AR step index (0-based). |
required |
output_temporal_size
|
int
|
Desired number of latent frames. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of pixel frames needed at this step. |
Source code in flashdreams/flashdreams/infra/encoder/base.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
flashdreams.infra.encoder.StreamingEncoderCache
dataclass
StreamingEncoderCache()
Per-rollout cache for :class:StreamingEncoder.
Empty by default; subclass to add fields (e.g. last-frame latent, cross-step accumulators).
flashdreams.infra.encoder.NullEncoderConfig
dataclass
NullEncoderConfig(*, _target: type[NullEncoder] = (lambda: NullEncoder)())
flashdreams.infra.encoder.NullEncoder
NullEncoder(config: EncoderConfig)
Bases: Encoder
Identity encoder: returns its input unchanged.
Wire as the transformer's context_encoder slot to pass already-
encoded tensors straight to the diffusion model.
Example:
.. code-block:: python
config = TransformerConfig(
context_encoder=NullEncoderConfig(),
...,
)
Source code in flashdreams/flashdreams/infra/encoder/base.py
46 47 48 | |
forward
forward(input: Any) -> Any
Return input unchanged.
Source code in flashdreams/flashdreams/infra/encoder/base.py
193 194 195 | |
Decoder
Decoders turn emitted latents into frames. StreamingDecoder carries
per-rollout state; the video variant adds spatial and temporal size contracts.
flashdreams.infra.decoder.DecoderConfig
dataclass
DecoderConfig(*, _target: type[StreamingDecoder] = (lambda: StreamingDecoder)())
flashdreams.infra.decoder.StreamingDecoder
StreamingDecoder(config: DecoderConfig)
Bases: ABC, Module, Generic[StreamingDecoderCacheT]
Streaming decoder, generic over the per-rollout cache type.
forward is not pinned by the base. Streaming decoders called by
:class:StreamInferencePipeline must match its call shape:
forward(self, input, autoregressive_index=0, cache=None).
Source code in flashdreams/flashdreams/infra/decoder/base.py
55 56 57 | |
initialize_autoregressive_cache
abstractmethod
initialize_autoregressive_cache(**context: Any) -> StreamingDecoderCacheT
Build a fresh per-rollout cache.
Override to return the decoder's concrete cache type.
Source code in flashdreams/flashdreams/infra/decoder/base.py
59 60 61 62 63 64 | |
flashdreams.infra.decoder.StreamingVideoDecoder
StreamingVideoDecoder(config: DecoderConfig)
Bases: StreamingDecoder[StreamingDecoderCacheT]
Streaming pixel-video decoder.
Pins down the contracts that every streaming latent→pixel video
decoder satisfies in addition to :class:StreamingDecoder:
- Spatial and temporal compression ratios between the latent and pixel grids (constants of the architecture).
- AR-step-aware temporal size mappers, so a pipeline can size its inputs and outputs without knowing the decoder's concrete temporal cache topology (causal first-frame padding, sliding windows, etc.).
Spatial scaling is trivially side * spatial_compression_ratio
in either direction; the AR-step-asymmetric piece is the temporal
size, which gets its own mapper. Typically AR 0 produces fewer
pixel frames per latent frame than AR ≥ 1 because of causal
first-frame padding.
Source code in flashdreams/flashdreams/infra/decoder/base.py
55 56 57 | |
spatial_compression_ratio
abstractmethod
property
spatial_compression_ratio: int
Pixel side ÷ latent side. Constant across AR steps.
temporal_compression_ratio
abstractmethod
property
temporal_compression_ratio: int
Pixel frames ÷ latent frames in steady state (AR ≥ 1).
AR 0 typically yields fewer pixel frames per latent frame
because of causal first-frame padding; that asymmetry lives
inside :meth:get_output_temporal_size /
:meth:get_input_temporal_size.
get_output_temporal_size
abstractmethod
get_output_temporal_size(autoregressive_index: int, input_temporal_size: int) -> int
Pixel frame count produced by input_temporal_size latent frames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
AR step index (0-based). |
required |
input_temporal_size
|
int
|
Number of latent frames fed at this step. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of pixel frames emitted at this step. |
Source code in flashdreams/flashdreams/infra/decoder/base.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
get_input_temporal_size
abstractmethod
get_input_temporal_size(autoregressive_index: int, output_temporal_size: int) -> int
Latent frame count needed to produce output_temporal_size pixels.
Inverse of :meth:get_output_temporal_size. Implementations
should assert output_temporal_size is achievable at this AR
step (i.e. divisible by the right ratio after subtracting any
causal padding).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autoregressive_index
|
int
|
AR step index (0-based). |
required |
output_temporal_size
|
int
|
Desired number of pixel frames. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of latent frames needed at this step. |
Source code in flashdreams/flashdreams/infra/decoder/base.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | |
flashdreams.infra.decoder.StreamingDecoderCache
dataclass
StreamingDecoderCache()
Per-rollout cache for :class:StreamingDecoder.
Empty by default; subclass to add fields (e.g. temporal feature buffers carried across AR steps).