Pipelines¶
mlx_diffuser.pipelines.DiffusionPipeline
¶
Source code in src/mlx_diffuser/pipelines/base.py
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | |
denoising_loop(scheduler, latents, predict, key, progress=False)
¶
Run the reverse process, calling predict(scaled_latents, t) per step.
predict returns the (already guidance-combined) model output. Evaluation
is forced once per step to keep the lazy graph bounded.
Source code in src/mlx_diffuser/pipelines/base.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | |
mlx_diffuser.pipelines.ClassConditionalPipeline
¶
Bases: DiffusionPipeline
Source code in src/mlx_diffuser/pipelines/class_conditional.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 | |
mlx_diffuser.pipelines.TextToVideoPipeline
¶
Bases: DiffusionPipeline
Source code in src/mlx_diffuser/pipelines/text_to_video.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 107 108 109 110 | |
__call__(prompt_embeds, *, negative_embeds=None, num_frames=16, height=256, width=256, num_inference_steps=50, guidance_scale=5.0, seed=None, key=None, compile=True, decode=True, progress=False)
¶
Generate video(s) from text embeddings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt_embeds
|
array
|
|
required |
negative_embeds
|
array | None
|
|
None
|
num_frames
|
int
|
number of output frames. |
16
|
height
|
int
|
output height in pixels. |
256
|
width
|
int
|
output width in pixels. |
256
|
decode
|
bool
|
if |
True
|
Returns:
| Type | Description |
|---|---|
array
|
|
array
|
|
Source code in src/mlx_diffuser/pipelines/text_to_video.py
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 107 108 109 110 | |
mlx_diffuser.pipelines.WanPipeline
¶
WAN 2.1 text-to-video pipeline (channels-last (B, T, H, W, C)).
Source code in src/mlx_diffuser/pipelines/wan.py
33 34 35 36 37 38 39 40 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 107 108 109 110 111 112 113 114 115 116 117 118 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 184 185 186 | |
__call__(prompt, *, negative_prompt='', num_frames=17, height=256, width=256, num_inference_steps=40, guidance_scale=5.0, seed=0, cache_threshold=0.0, release_text_encoder=True, progress=True)
¶
Generate a video (1, num_frames, height, width, 3) in [-1, 1].
num_frames must satisfy (num_frames - 1) % 4 == 0 and height /
width must be multiples of 8 (the VAE's spatial compression).
cache_threshold enables First-Block Cache (0 = off, exact). On the
1.3B model, 0.1 ≈ 1.5x and 0.2 ≈ 2.2x faster with no visible quality
change; >= 0.3 starts to degrade.
Source code in src/mlx_diffuser/pipelines/wan.py
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 184 185 186 | |
encode_text(prompt)
¶
Tokenize and encode prompt into (1, L, text_dim) embeddings.
Source code in src/mlx_diffuser/pipelines/wan.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
from_diffusers(folder, *, text_encoder=None, quantize_text=4, quantize_transformer=None, transformer_dtype=mx.bfloat16, shift=3.0)
classmethod
¶
Load + convert an official Wan2.1-T2V-*-Diffusers folder into MLX.
quantize_text keeps the 5.6B umT5 encoder small (4-bit ≈ 3 GB);
quantize_transformer optionally quantizes the DiT (defaults to bf16).
text_encoder overrides where the umT5 weights come from — a folder or a
single .safetensors file (e.g. an fp16 community checkpoint, half the
size of the fp32 default); falls back to folder/text_encoder.
Source code in src/mlx_diffuser/pipelines/wan.py
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 | |
release_text_encoder()
¶
Free the text encoder (call after encoding to reclaim memory).
Source code in src/mlx_diffuser/pipelines/wan.py
113 114 115 116 117 | |
mlx_diffuser.pipelines.StableDiffusionXLPipeline
¶
SDXL base text-to-image pipeline (channels-last (B, H, W, C)).
Source code in src/mlx_diffuser/pipelines/sdxl.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 107 108 109 110 111 112 113 114 115 116 117 118 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 184 185 186 187 | |
__call__(prompt, *, negative_prompt='', height=1024, width=1024, num_inference_steps=30, guidance_scale=5.0, seed=0, cache_interval=1, tile_vae=False, progress=True)
¶
Generate an image (1, height, width, 3) in [-1, 1].
height / width must be multiples of 8. cache_interval enables
DeepCache (1 = off/exact; 2 ≈ 1.5-1.8x by skipping the deep UNet blocks on every
other step). tile_vae decodes the VAE in tiles to bound memory at high res.
Source code in src/mlx_diffuser/pipelines/sdxl.py
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 184 185 186 187 | |
encode_prompt(prompt)
¶
Tokenize + encode with both CLIPs.
Returns (prompt_embeds (1, 77, 2048), pooled (1, 1280)): the two encoders'
penultimate hidden states concatenated, and the bigG projected pooled embed.
Source code in src/mlx_diffuser/pipelines/sdxl.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
from_diffusers(folder, *, dtype=mx.float16, quantize_unet=None)
classmethod
¶
Load + convert a stable-diffusion-xl-base folder into MLX.
The UNet and text encoders run in dtype (fp16 by default, SDXL's native
precision); the VAE runs in fp32 because SDXL's VAE overflows fp16.
quantize_unet (4/8) weight-quantizes the UNet to save memory.
Source code in src/mlx_diffuser/pipelines/sdxl.py
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 | |
mlx_diffuser.pipelines.FluxPipeline
¶
FLUX.1 text-to-image pipeline (channels-last (B, H, W, C)).
Source code in src/mlx_diffuser/pipelines/flux.py
36 37 38 39 40 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 107 108 109 110 111 112 113 114 115 116 117 118 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 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 227 228 | |
__call__(prompt, *, height=1024, width=1024, num_inference_steps=4, guidance_scale=0.0, max_sequence_length=256, seed=0, cache_threshold=0.0, release_text_encoders=False, tile_vae=False, progress=True)
¶
Generate an image (1, height, width, 3) in [-1, 1].
height / width must be multiples of 16 (8× VAE × 2× patch packing).
For schnell use the defaults (4 steps, guidance_scale=0); for dev use ~50
steps and guidance_scale≈3.5. cache_threshold (>0) enables First-Block
caching for a speed-up. release_text_encoders frees CLIP + T5 right after
encoding to lower peak memory before the denoising loop. tile_vae decodes the
final latent in tiles: at 1024px the fp32 VAE decode is the memory high-water mark
(~18 GB), and tiling brings it under 16 GB so it fits a 16 GB Mac without swapping.
Source code in src/mlx_diffuser/pipelines/flux.py
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 | |
encode_prompt(prompt, max_sequence_length)
¶
Encode prompt with CLIP (pooled) and T5 (sequence).
Returns (t5_embeds (1, L, 4096), pooled (1, 768)): FLUX conditions joint
attention on the T5 token sequence and modulation on CLIP's pooled embedding.
Source code in src/mlx_diffuser/pipelines/flux.py
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
from_diffusers(folder, *, dtype=mx.bfloat16, quantize_transformer=4, quantize_t5=4)
classmethod
¶
Load + convert a FLUX.1-schnell / FLUX.1-dev folder into MLX.
The transformer and CLIP run in dtype (bf16); the VAE runs in fp32. The
12B transformer and the T5 encoder default to 4-bit weights so the pipeline
fits in ~10 GB; pass quantize_transformer=None / quantize_t5=None for
full precision (needs far more memory).
Source code in src/mlx_diffuser/pipelines/flux.py
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 | |
release_text_encoders()
¶
Free the CLIP + T5 encoders after encoding (they are ~half the footprint).
Source code in src/mlx_diffuser/pipelines/flux.py
105 106 107 108 109 110 | |
Inference caching¶
mlx_diffuser.caching.FirstBlockCache
¶
Decide, per step, whether to reuse the cached transformer residual.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
float
|
accumulated relative first-block change that triggers a full
recompute. |
0.0
|
Source code in src/mlx_diffuser/caching.py
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 107 108 109 | |
reset()
¶
Clear state before a new generation.
Source code in src/mlx_diffuser/caching.py
76 77 78 79 80 81 82 | |
should_reuse(first_residual)
¶
Given this step's first-block contribution, return whether to reuse.
Accumulates the relative L1 change of the first block's residual (its output
minus its input); while the running total stays under threshold we reuse,
and we force a recompute (resetting the accumulator) once it crosses. The
first step, and any step before a residual exists, always recomputes.
Source code in src/mlx_diffuser/caching.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
mlx_diffuser.caching.DeepCache
¶
DeepCache for U-Net diffusion: skip the deep blocks on most steps.
A U-Net's deep (bottleneck) features change slowly across denoising steps, while
the shallow blocks carry the high-frequency detail. DeepCache recomputes the full
network only every interval steps; in between it runs just the shallowest
down/up blocks and reuses the cached deep feature — skipping the most expensive
levels (for SDXL, the 1280-channel / 10-transformer-layer blocks).
interval = 1 disables caching (every step full). interval = 2 caches every
other step (~1.5-1.8x). The first step is always full (no cache yet).
Source code in src/mlx_diffuser/caching.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
should_reuse()
¶
Return whether this step should reuse the cached deep feature.
Source code in src/mlx_diffuser/caching.py
48 49 50 51 52 53 54 | |