Pixels2GenAI
Path iii Generative
M 12 · 12.1.3 · conceptual

12.1.3 StyleGAN Exploration

Explore the disentangled W-space of a trained StyleGAN2 model — generate fabric patterns, navigate latent paths with interpolation, mix coarse and fine styles across crossover layers, and tune diversity with the truncation trick.

Duration35–45 min
Leveladvanced
Load4 core concepts
PrereqsLessons 12.1.1 (GAN Architecture) and 12.1.2 (DCGAN Art); PyTorch; ~500 MB disk for the pre-trained checkpoint
Fig. 1 StyleGAN2 walking through its latent space, generating new African fabric patterns frame by frame. Each step decodes to a plausible fabric — the smoothness is structural, not an artefact of training.

Overview

DCGAN Lesson 12.1.2 generates images from random vectors but doesn’t give you much control over what comes out. Change the seed, get a different image; that’s the only knob. StyleGAN, introduced by Karras, Laine and Aila at NVIDIA in 2018 [1] and refined in StyleGAN2 [2], introduced an architecture that separates the entangled “random vector” from the styled controls — and once that separation exists, you can navigate the space deliberately rather than just sampling from it.

The mechanism is conceptually simple. Before feeding the latent vector to the synthesis network, run it through an 8-layer fully-connected “mapping network” that produces an intermediate vector w. Inject w into the synthesis network at every resolution level via adaptive instance normalisation. The intermediate w ends up far more disentangled than the input z — different dimensions tend to control different visual features — which means you can interpolate, mix, and truncate in w-space and get predictable visual results.

This lesson uses a StyleGAN2 model trained on the African fabric dataset (same source as 12.1.2) to demonstrate the three operations that make this architecture famous: smooth latent walks, style mixing across layer ranges, and the truncation trick for trading diversity against quality.

Learning objectives

  1. Distinguish StyleGAN’s intermediate w-space from the original z-space and explain why disentanglement matters for control.
  2. Walk a path between two latent vectors and produce a smooth morphing animation; understand why the smoothness is a property of w-space, not interpolation magic.
  3. Combine coarse features from one source with fine features from another via style mixing — and predict which layer ranges control which feature scales.
  4. Apply the truncation trick to trade off diversity for quality; pick the right ψ value for a given use case.

Quick start — generate four fabrics from the trained model

The pre-trained checkpoint is hosted on a GitHub Release. Place it under models/african_fabrics/model_99.pt, then run the generation script.

model_99.pt — pre-trained StyleGAN2 checkpoint (~189 MB, GitHub Release)
python · quick-start.py
from stylegan2_pytorch import ModelLoader
import torch

loader = ModelLoader(
    base_dir='./',
    name='african_fabrics',                  # expects models/african_fabrics/model_99.pt
)

noise = torch.randn(4, 512)                  # 4 latent vectors in z-space
images = loader.styles_to_images(loader.noise_to_styles(noise, trunc_psi=0.7))

for i, img in enumerate(images):
    img.save(f'fabric_{i}.png')

Four random vectors → four distinct fabric patterns. The trunc_psi=0.7 argument is the truncation trick at default strength; we’ll unpack what it does in Concept 4.

Core concepts

Concept 1 — From entangled z to disentangled w

DCGAN’s generator takes a random latent vector z ~ N(0, I) and runs it through transposed convolutions until an image emerges. Every dimension of z participates in every aspect of the output simultaneously — pose, colour, texture, and content are all entangled. Change one coordinate of z slightly and many visual features shift together; you can’t isolate “change the colour without changing the pose.”

StyleGAN [1] adds a small auxiliary network before the generator: an 8-layer fully-connected mapping network that transforms z into an intermediate latent vector w. Instead of feeding z directly to the synthesis network, the architecture feeds w into every resolution level via adaptive instance normalisation. The mapping network has no architectural reason to preserve z’s Gaussian shape, and during training it learns to map z into a more uniformly-distributed w where dimensions tend to align with semantically meaningful features.

Fig. 2 StyleGAN architecture. The mapping network transforms `z ∈ R^512` (Gaussian) into `w ∈ R^512` (learned distribution). The synthesis network upsamples 4×4 → 8×8 → ... → final resolution, with `w` injected at every level via AdaIN.

The practical consequence: walks through w-space produce smoother visual transitions than walks through z-space, and individual w dimensions are far more likely to control isolated features. White’s survey of latent-space techniques [3] documents the difference quantitatively across multiple StyleGAN variants.

Concept 2 — Latent walks and the smoothness of w-space

Once you have a trained StyleGAN, the most basic creative operation is interpolation: pick two w vectors, walk a straight line between them, decode every step into an image. The intermediate frames form a smooth morphing animation because w-space is continuous in a way that matters — nearby points decode to similar images.

python · latent interpolation in w-space
import numpy as np

def interpolate_w(w_a, w_b, steps=10):
    alphas = np.linspace(0, 1, steps)
    return [(1 - a) * w_a + a * w_b for a in alphas]

That’s the entire formula. The interesting question is why it works — the answer is the mapping network. The original z-space is a 512-dimensional Gaussian; straight lines through Gaussian space pass through low-density regions that the generator was rarely shown during training. w-space is more uniformly distributed (because the mapping network learned to make it so), so straight lines stay in regions the generator handles well.

Fig. 3 Visualisation of 10-step interpolation in latent space. Each column is one step; each row is one latent dimension. The smooth gradients are what becomes smooth visual transitions when decoded.

Concept 3 — Style mixing across layer ranges

StyleGAN injects w into the synthesis network at every resolution level — 4×4, 8×8, 16×16, 32×32, 64×64 (and beyond for larger models). Different layers control different scales of features. The trick that gives the architecture its name: use different w vectors at different layer ranges.

For a model that outputs 1024×1024 images (18 layers), Karras et al. [1] map the layer ranges to feature scales:

Layer rangeResolutionControls
0–3 (coarse)4×4 → 16×16overall pose, face shape, presence of accessories
4–7 (middle)32×32 → 128×128facial features, hairstyle, eye shape
8–17 (fine)256×256 → 1024×1024colour, texture, lighting, micro-details

For the 64×64 fabric model in this lesson the structure is similar but compressed — early layers control overall pattern layout, later layers control colour and fine texture.

Fig. 4 Style mixing across crossover layers. Rows are source A images (coarse features); columns are source B images (fine features); the diagonal-off cells show the mix — A's pose/shape with B's colour/texture.

The implementation is direct: produce 18 w vectors per generated image (one per layer), and choose which source provides each one.

python · style mixing
def mix_styles(w_a, w_b, crossover_layer, num_layers=18):
    mixed = w_a.clone()                              # take all from A initially
    mixed[crossover_layer:] = w_b[crossover_layer:]  # overwrite later layers from B
    return mixed

For the fabric model, mixing at layer 4 gives you the overall pattern structure of A with the colour palette of B. Mixing at layer 6 keeps less of A and more of B. The right crossover depends on what feature transfer you want.

Concept 4 — The truncation trick: trading diversity for quality

Latent vectors sampled from N(0, I) are not all created equal. Most samples cluster near the mean — the regions where the generator saw the most training data and produces high-quality outputs. Samples from the tails of the distribution are rare both during training and during inference, and the generator’s behaviour there is less reliable; you’ll occasionally get artefacts, off-palette colours, or implausible structure.

The truncation trick [1] pulls every latent vector back toward the mean of the distribution before decoding:

w_truncated = w̄ + ψ · (w − w̄)

where is the mean of many sampled w vectors (computed once, after training) and ψ ∈ [0, 1] is the truncation parameter. ψ = 1.0 is no truncation (use the original sample); ψ = 0 is full collapse to the mean (every output is the same). Intermediate values trade diversity for reliability.

Fig. 5 Same four random seeds at four truncation values. `ψ = 0.3` produces very similar, safe outputs. `ψ = 1.0` produces maximum diversity but some samples look unusual. `ψ = 0.7` is the conventional default.

The conventional defaults: ψ = 0.7 for general-purpose generation, ψ = 0.5 for showcasing the model’s best work, ψ = 1.0 when you want the full diversity (and are willing to filter outputs manually). The fabric model in this lesson uses ψ = 0.7 in the quick start.

Fig. 6 The truncation operation geometrically. Vectors at the tails of the latent distribution (left) get pulled toward the mean (centre); the resulting trade-off (right) is essentially a Pareto frontier between sample quality and sample diversity.

Exercises

EXECUTE I.

Generate 16 fabric patterns and compare two random seeds

model_99.pt — pre-trained StyleGAN2 checkpoint (189 MB) exercise1_generate.py — generates 4x4 grid at one seed

Drop the checkpoint into models/african_fabrics/model_99.pt, then:

bash
pip install stylegan2-pytorch torch torchvision
python exercise1_generate.py

This produces generated_fabrics_seed42.png — a 4×4 grid of patterns sampled at ψ = 0.7. Open the script, change RANDOM_SEED = 42 to RANDOM_SEED = 100, and rerun. You now have two grids to compare.

Fig. 7 16 fabric patterns generated at seed 42, truncation ψ = 0.7. Each is a unique sample; all share the trained model's sense of what an African fabric looks like.

Reflection

  1. Every pattern in the two grids is unique, but both grids share an identifiable “African fabric” style. Which component of the StyleGAN architecture is responsible for the style consistency, and which is responsible for the per-sample variation?
  2. The seed controls where in the 512-dimensional latent space we sample. Why does every point in this space produce a valid fabric pattern rather than occasional nonsense?
  3. The model was trained on 1,059 fabric images. How can it generate visually distinct samples beyond what’s literally in the dataset?
MODIFY II.

Truncation sweep and morphing animation

exercise2_explore.py — truncation comparison + morphing animation
bash
python exercise2_explore.py

Produces three files:

  • truncation_comparison.png — same 4 seeds at 4 truncation values (Figure 5).
  • fabric_morph.gif — smooth interpolation between two w vectors.
  • morph_endpoints.png — the start and end frames of the morph, side by side.
Fig. 8 A smooth morph between two `w`-space points. Every intermediate frame is a valid fabric pattern, generated by decoding the interpolated latent vector at that step.

Goal 1 — Truncation tuning. The script generates at ψ ∈ 1. Compare the grids: which ψ produces the most visually pleasing results for you? There’s no universal answer — the “right” ψ depends on whether you prioritise quality or diversity for your specific application.

Goal 2 — Different morph endpoints. Edit the script:

SEED_A = 777     # try other starting patterns
SEED_B = 2024    # try other ending patterns

Goal 3 — Custom truncation values. Try TRUNCATION_VALUES = [0.2, 0.4, 0.6, 0.8] to see the finer-grained progression.

TRAIN III.

Use the pre-trained model, or train from scratch (10-12 hours GPU)

Two options. Most learners should use Option A unless they specifically want to live through a long training run.

exercise3_generate.py — generate with pre-trained checkpoint exercise3_train.py — train from scratch (10-12 hours on GPU)

Summary

Common pitfalls

  • Interpolating in z-space instead of w-space. The morphs will be visibly less smooth and may pass through bad regions.
  • Using ψ = 0.3 because “high quality is good.” You’ll get nearly-identical outputs and the model’s range disappears.
  • Crossover layers off by one. Layer 0 vs layer 1 vs layer 2 makes a real difference in which features get inherited from which source.
  • Forgetting that truncation is computed against the mean , not the origin. The script samples thousands of w vectors to estimate once; if you skip that, truncation pulls toward zero instead of toward the trained distribution centre and outputs degrade.
  • Confusing model.eval() with model.train() mode. AdaIN behaves differently between modes; always evaluate in eval.

References

  1. [1] Karras, T., Laine, S. & Aila, T. (2019). A Style-Based Generator Architecture for Generative Adversarial Networks. IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR). arxiv:1812.04948
  2. [2] Karras, T., Laine, S., Aittala, M., Hellsten, J., Lehtinen, J. & Aila, T. (2020). Analyzing and Improving the Image Quality of StyleGAN. CVPR. arxiv:1912.04958
  3. [3] White, T. (2016). Sampling Generative Networks. arXiv preprint. arxiv:1609.04468
  4. [4] Goodfellow, I., Pouget-Abadie, J., Mirza, M., Xu, B., Warde-Farley, D., Ozair, S., Courville, A. & Bengio, Y. (2014). Generative Adversarial Nets. Advances in Neural Information Processing Systems. arxiv:1406.2661
  5. [5] Radford, A., Metz, L. & Chintala, S. (2016). Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks. ICLR. arxiv:1511.06434
  6. [6] Härkönen, E., Hertzmann, A., Lehtinen, J. & Paris, S. (2020). GANSpace: Discovering Interpretable GAN Controls. NeurIPS. arxiv:2004.02546
  7. [7] Karras, T., Aittala, M., Laine, S., Härkönen, E., Hellsten, J., Lehtinen, J. & Aila, T. (2021). Alias-Free Generative Adversarial Networks (StyleGAN3). NeurIPS. arxiv:2106.12423
  8. [8] Wang, P. (2024). stylegan2-pytorch: Simplest working implementation of StyleGAN2. GitHub repository (MIT License). github.com/lucidrains/stylegan2-pytorch