DGLS Swapping Loader
The node that swaps model layers in and out of VRAM while you sample
- model
- layers
- model
This is the node where DGLS earns its name. The DGLS Model Loader readies the model and hands you a MODEL plus a LAYERS descriptor; this node takes both, wraps the model in the swapping engine, and returns a MODEL you plug straight into your sampler. Same wire you'd normally run from "Load Diffusion Model" - that's the whole point. It's designed as a drop-in for workflows that already use the official loader.
How the swapping actually works
The design is "buffers on GPU, params on CPU." Module buffers stay resident on the GPU, but the master parameter tensors live on CPU. At each layer k, the engine computes the needed set - layers k through k + prefetch - in ring order over the swappable blocks. Layers you're done with get rebound to their CPU masters; layers coming up get copied CPU→GPU. The copy is bound in via an optimized _reassign_param that does nothing when shape, dtype, device, and storage already match - no redundant clones.
Why bother, when ComfyUI has its own offloading? Because dumb offloading thrashes parameters in and out wholesale, and that churn is slow. Here the hot state stays local and only what the sampler needs travels. The author claims a 10–30% speed improvement over the official node's approach. It's a pre-release project (actively bug-tested on an RTX 2060 and 2080Ti, not yet promoted), so take that number as a directional claim, not a benchmark you should bet a deadline on.
The inputs that matter
- prefetch (default 1) - how many future layers to stage ahead. Start at 1. Raise it if you see transfer stalls and have VRAM headroom; the README notes some models prefer 0.
- cpu_threading and cuda_streams - the overlap options. Try cuda_streams first if you have headroom; it uses CUDA streams/events to overlap copy with compute.
cpu_threadingis a single conservative CPU helper thread - it helps where transfer latency dominates, can add overhead elsewhere, and the tooltip warns it "May cause instability on some systems." - lora_size_mb - total size of all your LoRAs in MB, 0 if none. This one trips people. Run LoRAs and leave it at 0 and the engine's VRAM budget doesn't know they exist, which is how you get an OOM or overly aggressive eviction.
- gpu_layer_indices (optional) - comma-separated layer indices to keep pinned on GPU, e.g.
0,1,2,28,29. Overrides auto-selection. Reach for it when specific layers refuse to swap cleanly. - cast_target (optional) - one-time startup dtype recast like
f32 bf16. The tooltip's warning is worth quoting: "WARNING: don't cast to f8/fp4 here unless your kernels support it." - cuda_graphs - CUDA graph optimization for GPU-resident layers. Newer addition, default off.
- verbose - prints layer sizes, timings, and residency decisions. Genuinely the way you dial this thing in, and it slows inference.
Output is a single model (MODEL) that feeds your sampler or Apply Model node.
Getting it right
Minimal safe setup: prefetch 1, both overlap options off, gpu_layer_indices empty. That alone gets you the benefit. Then iterate: enable cuda_streams if your card has headroom, nudge prefetch up if you see stalls, use verbose to read what's actually happening. And set lora_size_mb if you use LoRAs - it's the easiest mistake to make and the cheapest to fix.
Troubleshooting
- "Cannot fit layer X on GPU" - shrink
gpu_layer_indices, lowerprefetch. The emergency path will try to clean up and re-stage; if it keeps failing, you're asking for more residency than you have. - Instability with overlap on - turn off
cuda_streamsandcpu_threading, then re-run withverboseto see the staging. - Odd dtype/buffers - prefer conservative
cast_targetrules; stats-like tensors are kept in fp32 by the loader.
One more thing: this is memory-hungry in a particular way. The README recommends 32GB+ of system RAM if you plan to use overlap or pinning (16GB can work, 64GB+ is best). CPU RAM is where those master weights live, so it's not just a VRAM question. On a box with 16GB of RAM and an 8GB card, budget accordingly.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| layers | LAYERS | — | |
| prefetch | INT | 10–100 | Number of layers to prefetch ahead of single layer transfer |
| cpu_threading | BOOLEAN | false | Enable CPU threading for async CPU transfers (May cause instability on some systems) |
| cuda_streams | BOOLEAN | false | Enable CUDA streams for copy-compute overlap (needs more VRAM) |
| cuda_graphs | BOOLEAN | false | Enable CUDA graph optimization for GPU-resident layers |
| lora_size_mb | INT | 00–10000 | Total size of all LoRAs in MB. Set to 0 if no LoRAs are used. |
| verbose | BOOLEAN | false | Enable verbose output with detailed timing and transfer information. This will slow down inference when on |
| gpu_layer_indicesopt | STRING | Comma-separated list of layer indices to keep permanently on GPU (e.g., '0,1,2,14,18,19,20,21,22'). Overrides initial_gpu_layers and final_gpu_layers | |
| cast_targetopt | STRING | Cast FROM dtype TO dtype at start-up (e.g., f32 bf16) choices=[f32, bf16, f16, f8_e4m3, f8_e5m2, nf4, fp4] WARNING: don't cast to f8/fp4 here unless your kernels support it |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |