DS DevShelfHub Projects · AI tools
Cheatsheets / Stable Diffusion
Cheatsheet · AI frameworks

Stable Diffusion Cheatsheet: Pipelines, ControlNet, LoRA and img2img

By DevShelfHub

SD 1.5, SDXL, SD3, Flux — diffusers pipelines, samplers, schedulers, ControlNet, IP-Adapter, LoRA, img2img, inpainting — the image-generation surface.

116 items 8 min Diffusers LoRA ControlNet

Start hereQuick start · 6 you’ll reach for daily

LoadStableDiffusionXLPipeline.from_pretrained(…)
txt2imgpipe(prompt, steps, guidance)
img2imgstrength=0.55, image=init
Inpaintimage + mask_image
LoRApipe.load_lora_weights(repo)
ControlNetcontrolnet=ControlNetModel(…)

Target versions · paceVersions

Targets: diffusers ≥ 0.30 transformers ≥ 4.45 torch ≥ 2.2 safetensors ≥ 0.4

"Stable Diffusion" now spans several model families with different VAEs, schedulers, and prompt encoders. SD 1.5 (512×512, CLIP) is the legacy workhorse; SDXL (1024×1024, dual-CLIP) is the everyday default; SD 3 / 3.5 moves to MMDiT + T5; Flux (Black Forest Labs) is the current quality leader but isn’t formally "Stable Diffusion". Pipeline classes follow the architecture — mismatch a checkpoint and pipeline class and you get cryptic shape errors. All snippets here use the diffusers library.

Install · authSetup

bash
# Core — the Hugging Face Diffusers library
pip install -U diffusers transformers accelerate safetensors

# Speedups — pick what your GPU supports
pip install xformers          # memory-efficient attention (CUDA)
pip install bitsandbytes      # 4/8-bit quantization for big checkpoints

# Adapters / utilities
pip install peft              # LoRA / IP-Adapter helpers
pip install controlnet-aux    # canny / depth / openpose preprocessors
pip install invisible-watermark

# Auth — many SDXL / Flux checkpoints are gated
pip install huggingface_hub
hf auth login                 # paste token from huggingface.co/settings/tokens

Where things liveCommon imports

from diffusers import StableDiffusionPipelineSD 1.5 txt2img.
from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline, StableDiffusionXLInpaintPipelineSDXL family. Three classes, three modes.
from diffusers import StableDiffusion3PipelineSD 3 / 3.5 MMDiT.
from diffusers import FluxPipelineFlux.1 by Black Forest Labs.
from diffusers import ControlNetModel, StableDiffusionXLControlNetPipelineConditioning by edges / depth / pose.
from diffusers import AutoPipelineForText2Image, AutoPipelineForImage2ImageAuto-detect pipeline class from checkpoint config.
from diffusers import DPMSolverMultistepScheduler, EulerAncestralDiscreteScheduler, DDIMScheduler, …Samplers / schedulers. Swap via pipe.scheduler.
from diffusers.utils import load_image, make_image_gridConvenience helpers.

Pick the right oneModels

runwayml/stable-diffusion-v1-5Legacy 512×512, CLIP. Largest LoRA ecosystem.
stabilityai/stable-diffusion-2-1Legacy 768×768, OpenCLIP. Skipped by community.
stabilityai/stable-diffusion-xl-base-1.0SDXL base. 1024×1024, dual text encoders. The everyday default.
stabilityai/stable-diffusion-xl-refiner-1.0SDXL refiner. Use as img2img on top of base.
segmind/SSD-1B, lykon/sdxl-turbo, stabilityai/sdxl-lightningDistilled SDXL variants — 1–4 steps.
stabilityai/stable-diffusion-3-medium-diffusersSD3. MMDiT + T5. Better text rendering.
stabilityai/stable-diffusion-3.5-largeSD3.5. Current Stability flagship.
black-forest-labs/FLUX.1-dev, FLUX.1-schnellFlux dev (non-commercial) and schnell (4-step, Apache).

The call shapePipelines & params

Load

from_pretrained(repo_id, torch_dtype=torch.float16)Half precision. Required for most consumer GPUs.
variant="fp16"Pull the fp16 weight files when available.
use_safetensors=TruePrefer safetensors files. Default on most repos.
from_single_file("model.safetensors")Load a single Civitai-style checkpoint file.
.to("cuda" | "mps" | "cpu")Move the whole pipeline to a device.
AutoPipelineForText2Image.from_pretrained(…)Picks the right pipeline class from the config.

Call params (txt2img)

prompt="a cinematic photo of …"Main prompt. Pass a list for batched generation.
negative_prompt="blurry, text, watermark"Things to push away from.
num_inference_steps=25…50Denoising steps. Distilled models work at 1–8.
guidance_scale=7.0CFG. Higher = follow prompt, lower = creative. SDXL likes 5–8.
width=1024, height=1024Match the training resolution: 512 for SD1.5, 1024 for SDXL.
generator=torch.Generator(device).manual_seed(42)Reproducible noise.
num_images_per_prompt=4Generate variants from one prompt.
output_type="pil" | "np" | "latent"Decoder output. Latents skip the VAE for chained pipelines.

Worked example

python
import torch
from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler

pipe = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    torch_dtype=torch.float16,
    variant="fp16",
    use_safetensors=True,
).to("cuda")

# DPM++ 2M Karras — fast, low step count, looks great on SDXL
pipe.scheduler = DPMSolverMultistepScheduler.from_config(
    pipe.scheduler.config, use_karras_sigmas=True,
)
pipe.enable_xformers_memory_efficient_attention()

generator = torch.Generator(device="cuda").manual_seed(42)

image = pipe(
    prompt="cinematic photo of an old fisherman repairing nets at dawn, soft fog, 35mm",
    negative_prompt="cartoon, text, watermark, lowres",
    num_inference_steps=25,
    guidance_scale=7.0,
    width=1024, height=1024,
    generator=generator,
).images[0]

image.save("fisherman.png")

SamplersSchedulers

Swap by replacing pipe.scheduler. Most schedulers accept use_karras_sigmas=True for sharper outputs at low step counts.

DPMSolverMultistepSchedulerPreferred DPM++ 2M. Strong default. ~20–30 steps.
EulerAncestralDiscreteSchedulerEuler-A. Adds noise each step — stylistic, varied.
UniPCMultistepSchedulerNewer multistep. Good at very low step counts.
DDIMSchedulerClassic. Use with eta=0 for full determinism.
LCMSchedulerLatent Consistency. Pair with LCM-LoRA for 4-step inference.
PNDMScheduler, LMSDiscreteSchedulerOlder defaults from SD 1.x. Largely superseded.
pipe.scheduler = X.from_config(pipe.scheduler.config)Always copy config, never construct fresh — preserves training params.
pipe.scheduler.set_timesteps(steps)Manual scheduler stepping for custom loops.

Conditioning on pixelsimg2img & inpainting

img2img

StableDiffusionXLImg2ImgPipeline.from_pretrained(…)Use the refiner or base checkpoint here.
pipe(prompt, image=init_image, strength=0.55)Strength = how much noise to add. 0 keeps input; 1 ignores it.
load_image("url_or_path")Returns a PIL image, handles URL fetch.
denoising_start / denoising_endChain base → refiner over a fraction of timesteps.

Inpainting

StableDiffusionXLInpaintPipeline.from_pretrained(…)Or load a dedicated inpaint checkpoint.
pipe(prompt, image=…, mask_image=…)Mask: white = repaint, black = keep.
strength=0.8Higher = more freedom inside the mask.
padding_mask_crop=32Crop around the mask before generation, then composite back — sharper, faster.

Worked example

python
import torch
from diffusers import StableDiffusionXLImg2ImgPipeline
from diffusers.utils import load_image

pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-refiner-1.0",
    torch_dtype=torch.float16,
    variant="fp16",
).to("cuda")

init = load_image("sketch.png").resize((1024, 1024))

# strength = how much to ignore the input (0 = identity, 1 = pure txt2img)
result = pipe(
    prompt="oil painting of the same scene, brush texture, warm tones",
    image=init,
    strength=0.55,
    num_inference_steps=30,
    guidance_scale=7.5,
).images[0]

result.save("painting.png")

Structure + reference conditioningControlNet, IP-Adapter, T2I-Adapter

ControlNet

ControlNetModel.from_pretrained("…canny-sdxl-1.0")Conditioning by Canny edges. Other types: depth, openpose, lineart, scribble, segmentation.
StableDiffusionXLControlNetPipeline(…, controlnet=cn)Wrap your base pipeline.
controlnet=[cn1, cn2]Multi-ControlNet. Layer multiple guides.
controlnet_conditioning_scale=0.8How strongly the control map binds. 0–1 typical.
control_guidance_start / control_guidance_endApply guidance only over part of the schedule.
controlnet_aux preprocessorsCannyDetector, MidasDetector, OpenposeDetector, …

IP-Adapter (image prompts)

pipe.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models", weight_name="ip-adapter_sdxl.bin")Load adapter weights into an existing pipe.
pipe(…, ip_adapter_image=ref_image)"Use this image’s style/subject".
pipe.set_ip_adapter_scale(0.6)How heavily to weight the reference. 0 disables.
FaceID variantsUse insightface embeddings for identity-preserving generation.

T2I-Adapter

T2IAdapter.from_pretrained(…)Lighter than ControlNet. Less faithful but cheap.
StableDiffusionXLAdapterPipeline(…, adapter=t2i)Use when ControlNet is overkill or unavailable.

Worked example

python
import torch
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
from diffusers.utils import load_image
from controlnet_aux import CannyDetector

# 1 · Preprocess the conditioning image into a Canny edge map
canny = CannyDetector()
control = canny(load_image("photo.jpg"), low_threshold=100, high_threshold=200)

# 2 · Load matching ControlNet for SDXL
controlnet = ControlNetModel.from_pretrained(
    "diffusers/controlnet-canny-sdxl-1.0",
    torch_dtype=torch.float16,
)

pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    controlnet=controlnet,
    torch_dtype=torch.float16,
).to("cuda")
pipe.enable_xformers_memory_efficient_attention()

image = pipe(
    prompt="a sun-bleached temple at golden hour, ultra-detailed",
    image=control,
    controlnet_conditioning_scale=0.8,
    num_inference_steps=30,
    guidance_scale=6.5,
).images[0]
image.save("temple.png")

Style · subject adaptersLoRA & embeddings

pipe.load_lora_weights("repo/name")Load LoRA from the Hub.
pipe.load_lora_weights("repo/name", adapter_name="pixel")Name it — required for multi-LoRA.
pipe.set_adapters(["pixel","cyber"], adapter_weights=[0.7, 0.4])Stack LoRAs with per-adapter weight.
pipe.fuse_lora(lora_scale=0.8)Bake LoRA into the base weights. Faster inference, can’t toggle.
pipe.unload_lora_weights()Release adapter memory.
pipe.load_textual_inversion("repo/name", token="<style>")Embedding (Textual Inversion). Add a new word.
pipe.load_lora_weights("latent-consistency/lcm-lora-sdxl")LCM-LoRA. Pair with LCMScheduler for 4-step inference.
pipe.load_lora_weights(…, cross_attention_kwargs={"scale":0.8})Legacy Old way to scale a single LoRA. Use set_adapters.

Fitting it on your GPUMemory & speed

pipe.enable_xformers_memory_efficient_attention()~30–40% memory cut. CUDA only.
pipe.enable_attention_slicing()Fallback when xformers isn’t installed.
pipe.enable_model_cpu_offload()Shuttle weights to CPU between stages. Fits SDXL on 8GB.
pipe.enable_sequential_cpu_offload()Even more aggressive offload. Slower but fits SDXL on ~4GB.
pipe.enable_vae_tiling()Decode the VAE in tiles. Enables 4K+ output.
pipe.enable_vae_slicing()Batched VAE decode in slices. Saves memory on multi-image batches.
pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead")torch.compile the UNet. First call slow, then ~20% speedup.
torch_dtype=torch.bfloat16bf16 on Ampere+ GPUs. Better numerics than fp16 for SDXL refiner.

SDXL + stacked LoRAs · ~30 linesEnd-to-end · Styled image

SDXL with two stacked LoRAs (pixel-art + cyberpunk), a fast Euler-A scheduler, xformers, CPU offload, and VAE tiling for headroom.

python
import torch
from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler

pipe = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    torch_dtype=torch.float16,
    variant="fp16",
).to("cuda")
pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
pipe.enable_xformers_memory_efficient_attention()

# Load two LoRAs from the Hub and assign weights
pipe.load_lora_weights("nerijs/pixel-art-xl", adapter_name="pixel")
pipe.load_lora_weights("CiroN2022/cyberpunk-style", adapter_name="cyber")
pipe.set_adapters(["pixel", "cyber"], adapter_weights=[0.7, 0.4])

# Memory savers — useful when you stack adapters
pipe.enable_model_cpu_offload()        # weights to CPU between calls
pipe.enable_vae_tiling()               # tiled VAE for high-res

gen = torch.Generator(device="cuda").manual_seed(7)

image = pipe(
    prompt="pixel art, cyberpunk neon market street, rain, vending machines",
    negative_prompt="blurry, jpeg, photoreal, text",
    num_inference_steps=28,
    guidance_scale=7.0,
    generator=gen,
).images[0]

image.save("market.png")
pipe.unload_lora_weights()             # release adapter memory

Best practiceGood to know

Match resolution to the model. SD1.5 was trained on 512×512; SDXL on 1024×1024. Generate at the trained size, then upscale — off-aspect-ratio output at the wrong resolution produces extra limbs and tiled subjects.
Seed everything you want to compare. torch.Generator(device).manual_seed(42) is the only way to A/B prompts, samplers, or LoRAs honestly. Re-running without a seed reshuffles noise and hides the effect of your change.
DPM++ 2M Karras at 20–30 steps is a strong default. Don’t over-step — quality plateaus around 30 for most SDXL workloads, and going to 50 wastes time.

Common trapsWatch out for

VAE in fp16 produces black images on some GPUs. Symptom: the diffusion looks fine, then decoding returns pure black. Fix: load the VAE in fp32, or use the "fp16 fix" VAE (madebyollin/sdxl-vae-fp16-fix).
Loading a Civitai checkpoint with the wrong pipeline class fails silently or noisily. A SD1.5 single-file in StableDiffusionXLPipeline gives shape mismatches. Use AutoPipelineForText2Image or read the model card.
Stacking too many LoRAs blurs everything. Beyond 2–3 active adapters, outputs collapse into mush. Drop weights, fuse the ones you always use, or train a single LoRA combining them.

Go deeperSee also

Stable Diffusion FAQ

What is Stable Diffusion?

Stable Diffusion is an open-source latent diffusion model for text-to-image generation. It encodes images into a compact latent space, adds noise, and trains a U-Net to denoise iteratively guided by a CLIP text encoder. Modern variants include SDXL (higher resolution), SD3 (multi-modal diffusion transformer), and Flux (flow matching architecture), all runnable via the Hugging Face diffusers library.

How do samplers and schedulers work in Stable Diffusion?

A scheduler (sampler) defines the denoising algorithm applied at each step. DPM++ 2M Karras and DDIM converge in 20-30 steps with high quality; Euler a is fast and creative; UniPC is efficient for SDXL. Fewer steps produce faster but lower-quality images. Change the scheduler with pipe.scheduler = SchedulerClass.from_config(pipe.scheduler.config) without reloading model weights.

What is ControlNet in Stable Diffusion?

ControlNet adds spatial conditioning to a diffusion model by feeding a preprocessed control image (edge map, depth map, pose skeleton, etc.) through a trainable copy of the encoder. This constrains the composition of the generated image without fine-tuning the base model. Load a ControlNet checkpoint with ControlNetModel.from_pretrained() and pass the condition image to the pipeline.

What is LoRA in Stable Diffusion?

LoRA (Low-Rank Adaptation) is a fine-tuning technique that injects small trainable rank-decomposition matrices into the U-Net attention layers, adding a specific style, character, or concept without modifying the full model. Load a LoRA with pipe.load_lora_weights(path) and control its strength with the cross_attention_kwargs scale parameter. Multiple LoRAs can be composed with fuse_lora().

How do I reduce VRAM usage with Stable Diffusion?

Enable CPU offloading with pipe.enable_model_cpu_offload() to move model components to CPU between uses, reducing peak VRAM from 10+ GB to around 4 GB. Use half-precision weights (torch_dtype=torch.float16) and enable_xformers_memory_efficient_attention() for additional savings. For SDXL on consumer GPUs, sequential CPU offload and fp16 together typically fit a 12 GB card.