Nodes/SeFiMLXComfyNode/SeFi Turbo (MLX, all-in-one)
ComfyUI Node

SeFi Turbo (MLX, all-in-one)

The all-in-one MLX node

By jwooldridge234·Created 2 months ago·Updated 2 months ago· 0
SeFi Turbo (MLX, all-in-one)
  • clip
  • vae
  • image
  • texture_latent
modelSeFi-Image-5B-turbo
promptA blue ceramic mug on a white desk.
width1024
height1024
steps4
seed0
quantizeq8
mlx_encodertrue
mlx_vaetrue
negative_prompt
guidance_scale1.0
delta_t0.10
timestep_shift_alpha1.00
dynamic_shiftfalse
scheduler_shift1.00
rope_moderepo (5e6)
template_moderepo (bare)
max_length1024
pad_to_maxtrue
encoder_quantizeq8
bn_denormtrue
low_memoryfalse
vae_quantizebf16
hf_token
group_size64
dual_timetrue

SeFi-Image got buried at launch. The quality was genuinely good - strong text rendering, real realism, a 5B model trained on a tenth of Z-Image's compute - but launch week was mostly people asking "will we even get ComfyUI support?" and grumbling about the CC-BY-NC license. Then SeFiTurboMLX shipped: the whole SeFi-Image turbo pipeline in one node, running end-to-end in Apple MLX. On Apple Silicon, this is the reason the "semantic-first diffusion" family is finally a real option.

What the node actually does

The name is doing a lot of work. One node downloads the gated SeFi-Image-*-turbo checkpoint, converts its DiT to MLX under models/mlx/sefi/, runs the dual-time turbo denoise loop, and VAE-decodes - no CLIPLoader, no KSampler, no VAELoader wiring required. The one thing it can't do is run on your Nvidia box: MLX is Apple Silicon only, and the code checks for it up front.

Under the hood it's a faithful MLX port of the Flux2-style dual-stream backbone SeFi uses, with the Qwen3-VL-4B language tower as text encoder and a 32-channel AutoencoderKL decoder. Everything converts once and caches - first run pays for download plus conversion, reruns are fast.

The semantic-first bit, briefly

SeFi's trick is "dual-time" diffusion: instead of one latent, you get a semantic stream and a texture stream, and the semantic one runs ahead - by default delta_t = 0.1 - so composition is decided first, texture fills in behind. That's what the "turbo" recipe exploits: at 4 steps with guidance_scale = 1.0 (no CFG, matching the DMD2-distilled reference) you get fast generations that still compose well. Steps are tuned for 4/8/10; anything else is allowed but you're off the beaten path.

The inputs that actually matter

Beginners can touch these and ignore the rest:

  • model - SeFi-Image-5B-turbo by default, with 2B and 1B turbo variants if you want speed over quality.
  • prompt, width, height, seed - standard. 1024×1024 default, multiples of 16.
  • steps - 4 default; try 8 for a bit more polish.
  • quantize - q8 default, q4 to slim the DiT down, bf16 for full fidelity. Same ladder logic as GGUF: Q8 is basically indistinguishable from bf16 here, so if it fits, leave it.
  • hf_token - your HuggingFace token. The model repo is gated (CC-BY-NC), so you must accept the license on the HF model page while logged in before anything downloads. You can set HF_TOKEN in your environment instead.

The other two you'll actually meet in the wild: low_memory frees the MLX text encoder after encoding (~2.9GB resident instead of ~5.6GB, at the cost of re-loading it per new prompt), and bn_denorm stays ON - turn it off and output turns washed-out and grainy.

The node outputs image plus texture_latent - the raw texture stream, if you ever want to re-decode it yourself. And yes, you can override the MLX encoder and VAE with torch ones: wire a CLIP into the clip input or a VAE into vae, or flip mlx_encoder/mlx_vae off. Just don't point the VAE at a generic 16-channel Flux VAE - SeFi's texture VAE is 32-ch, and the node picks the right file by slug for a reason.

Installing it

Via ComfyUI Manager, search "SeFiMLXComfyNode" and install. Or the manual route:

cd ComfyUI/custom_nodes
git clone https://github.com/jwooldridge234/SeFiMLXComfyNode
cd SeFiMLXComfyNode
pip install -r requirements.txt

Then restart ComfyUI. Dependencies are light - mlx, huggingface_hub, safetensors, transformers - and no other custom nodes are required. The real heavy dependency is the model itself: the first generation triggers a multi-GB gated download plus a one-time torch→MLX conversion, so don't panic when the first run crawls. It's cached after that.

Where people get burned

  • 403 / "not authorized" - the gated-repo classic. Accept the license at huggingface.co/SeFi-Image/SeFi-Image-5B-turbo with the account that token belongs to, then pass the token.
  • Washed-out output - bn_denorm flipped off, or pad_to_max off (the DiT was trained on the padded sequence; turning it off is out-of-distribution → noise).
  • Outputs that look "off" at a given seed - this is a fresh MLX port. The key mappings are verified statically, but the numeric forward was never run on Apple hardware before release. The README ships a parity harness for exactly this: python custom_nodes/ComfyUI-SeFi-MLX/dev/parity.py builds a tiny model and checks torch vs MLX on identical weights. Run it before you judge the model. Images also won't bit-match the native torch node at the same seed - the initial noise deliberately uses torch's RNG, since MLX's normal RNG gives worse compositions here.

Honest caveat: it's non-commercial by license, and the corner is weeks old. But as the one-stop shop for SeFi-Image on a Mac, it's the one you'd reach for.

CategorySeFi-Image/MLX

Inputs (28)

NameTypeDefaultDescription
modelCOMBOSeFi-Image-5B-turbo3 options: SeFi-Image-5B-turbo, SeFi-Image-2B-turbo, SeFi-Image-1B-turbo
promptSTRINGA blue ceramic mug on a white desk.
widthINT1024256–4096
heightINT1024256–4096
stepsINT41–200Denoise steps. Turbo is tuned for 4/8/10, but any value is allowed.
seedINT00–18446744073709550000
quantizeCOMBOq83 options: q8, q4, bf16
clipoptCLIPOVERRIDE: a torch CLIP (CLIPLoader). If wired, used instead of the MLX encoder.
vaeoptVAEOVERRIDE: a torch VAE (VAELoader). If wired, used instead of the MLX VAE.
mlx_encoderoptBOOLEANtrueRun the Qwen3-VL-4B text encoder in MLX (torch-free). Ignored if a `clip` is wired.
mlx_vaeoptBOOLEANtrueRun the VAE decode in MLX (torch-free). Ignored if a `vae` is wired.
negative_promptoptSTRING
guidance_scaleoptFLOAT1.01–12Turbo = 1.0 (no CFG). >1 runs two passes/step.
delta_toptFLOAT0.100–1Semantic lead (5B turbo = 0.1).
timestep_shift_alphaoptFLOAT1.000.01–8SeFi runner u-warp (sefi_schedule.apply_timestep_shift). 1.0 = identity. Lower (e.g. 0.3) front-loads denoising; tune per resolution if adherence is off.
dynamic_shiftoptBOOLEANfalseApply a resolution-aware flow shift exp(mu) to the sigma table (~1.88 at 512, ~3.16 at 1024) instead of scheduler_shift. Experimental.
scheduler_shiftoptFLOAT1.000.1–12Flow-match table shift (sigma warp). 1.0 = linear, as the runner uses; the warping is normally done by timestep_shift_alpha.
rope_modeoptCOMBOrepo (5e6)Encoder RoPE. 'repo' = official SeFi (theta 5e6, standard). 'comfy' = comfy's value (1e6). 'interleaved' = Qwen3-VL M-RoPE (5e6; == standard for text).
template_modeoptCOMBOrepo (bare)Prompt template. 'repo' = official bare user/assistant. 'comfy' = adds an empty <think> block. 'none' = raw prompt, no chat template.
max_lengthoptINT102416–8192Encoder token length. 1024 = the official SeFi value (sefi_config).
pad_to_maxoptBOOLEANtruePad conditioning to max_length. The SeFi DiT was trained on the padded sequence — leave ON; OFF is out-of-distribution -> noise.
encoder_quantizeoptCOMBOq8Quantization for the Qwen3-VL-4B encoder. q4 is the fastest per-prompt encode (and smallest); bf16 is most accurate.
bn_denormoptBOOLEANtrueRescale the latent from bn-normalized (std ~1.8) to the VAE's raw space before MLX decode. ON fixes washed-out/grainy output.
low_memoryoptBOOLEANfalseFree the MLX text encoder after encoding so only the DiT (+VAE) stay resident (~2.9GB vs ~5.6GB). Re-encoding a new prompt reloads it.
vae_quantizeoptCOMBObf16VAE storage + decode compute dtype. bf16 ~halves VAE weight and decode-activation memory vs fp32 (matches comfy's MPS VAE).
hf_tokenoptSTRINGHF token for the gated repo (or set HF_TOKEN env). License must be accepted.
group_sizeoptINT6432–128
dual_timeoptBOOLEANtrue

Outputs (2)

NameTypeDescription
imageIMAGE
texture_latentLATENT