Discover SeFa Directions
The free edit axes, no sampling required
- stylegan_model
- STYLEGAN_DIRECTIONS
SeFa is the other way to get edit directions out of a StyleGAN, and it's the one I'd try first. It needs no sampling, no seed, no statistics - it reads the generator's own weights and does one eigendecomposition. In ComfyUI it comes back effectively instantly, which makes it a much nicer thing to iterate on than GANSpace.
How it works
SeFa (Shen & Zhou) rests on the observation that in a StyleGAN2-style synthesis block, the thing a W vector actually does is modulate channels through a learned affine transform. Those affine weights are sitting right there in the model. So the node walks G.synthesis, collects the weight matrices from every SynthesisLayer and ToRGBLayer, concatenates them into one big [channels, w_dim] matrix, and computes AᵀA - a w_dim × w_dim symmetric matrix whose eigenvectors are the directions that most strongly excite the network's style modulation. Sort by eigenvalue magnitude, take the top num_components, unit-normalize.
Two implementation details are worth having in your head because they explain behaviour you'll see:
- The layers are matched by class name string, not
isinstance. That's deliberate: a.pklcheckpoint reconstructs its classes dynamically, soisinstancewould silently match nothing on that load path. More importantly for you, the code deliberately skips StyleGAN3'sSynthesisInput.affine- a different, geometric-transform affine that happens to share the attribute name. What you get are style-modulation directions, not rotation/translation ones. - The eigendecomposition runs on CPU, regardless of where the model lives, because
torch.linalg.eighisn't implemented on MPS. The matrix is onlyw_dim × w_dim, so it's cheap either way.
Direction scaling is the big practical difference from GANSpace: these are unit vectors, not sigma-scaled ones. Useful strengths in ApplyStyleGANDirection are therefore much larger - think ±5 to ±20, not ±1 to ±3. If you discover with SeFa and apply at strength 1, you'll conclude the node is broken. It isn't.
What you set
Only two things. stylegan_model - the STYLEGAN from LoadStyleGAN, same checkpoint you'll render with. And num_components, default 10, max 512. Ten is a fine default; the top components are the ones with real amplitude, and by component 30 you're usually into noise-level axes.
Output is a STYLEGAN_DIRECTIONS, wired into StyleGANDirectionSweep to find out what a component does, or straight into ApplyStyleGANDirection if you already know.
Why you'd pick this over GANSpace
SeFa is deterministic. Same model, same components, every run - no seed to pin, no PCA sign flips when you rerun. That alone makes it the better production choice for a workflow you intend to keep. GANSpace, in exchange, sees the actual distribution of the samples it drew, so its axes can be broader and more "global" in character. In practice people run both, sweep the top few components of each, and keep whichever axes actually do something they want. The pack's README suggests exactly that workflow, and warns that a negative strength just flips the edit - which is often all "the SeFa direction is backwards" means.
It's also the one you can run while your install is half-broken. SeFa only touches the synthesis affine weights, so it works even if the compiled CUDA/MPS kernels aren't built yet. Only rendering needs those.
Install
Manager → search ComfyUI-StyleGan (publisher dflfd), or:
cd ComfyUI/custom_nodes
git clone https://github.com/dfl/ComfyUI-StyleGan
Restart, put a checkpoint in ComfyUI/models/stylegan/ (.pkl gets converted to a .safetensors cache on first load). Pip dependencies are trivial - numpy, ninja, safetensors, packaging - but the pack compiles CUDA extensions at runtime, so CUDA Toolkit, ninja and MSVC/GCC have to be in place before anything renders. Expect a 30–60s plugin build on the first generation, logged as Setting up PyTorch plugin ... Done.
You can also discover offline and load the result:
python discover_directions.py model.safetensors --method sefa
That writes component_00, component_01, … into a .safetensors under models/stylegan_directions/ for LoadStyleGANDirections.
Where people get burned
- Strength scale, again. Unit vectors. Start at ±10 when you're sweeping.
- Component 0 isn't "the good one". SeFa orders by eigenvalue magnitude, which is a measure of energy, not of whether you'll like the result. Sweep the first five.
- Applying to the wrong layer band. The eigenvectors are global, but you still choose a
maskwhen applying. A coarse mask and a fine mask on the same direction are two different edits. - Assuming it generalises across checkpoints. Directions are per-model. SeFa on one face model has nothing to say about another, and the direction files carry no model name to warn you - the loader will happily hand you a mismatched bundle.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| stylegan_model | STYLEGAN | — | |
| num_components | INT | 101–512 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| STYLEGAN_DIRECTIONS | STYLEGAN_DIRECTIONS | — |