backend/python/diffusers/README.md
This backend provides gRPC access to Hugging Face diffusers pipelines with dynamic pipeline loading.
make diffusers
The diffusers backend includes a dynamic pipeline loader (diffusers_dynamic_loader.py) that automatically discovers and loads diffusers pipelines at runtime. This eliminates the need for per-pipeline conditional statements - new pipelines added to diffusers become available automatically without code changes.
Pipeline Discovery: On first use, the loader scans the diffusers package to find all classes that inherit from DiffusionPipeline.
Registry Caching: Discovery results are cached for the lifetime of the process to avoid repeated scanning.
Task Aliases: The loader automatically derives task aliases from class names (e.g., "text-to-image", "image-to-image", "inpainting") without hardcoding.
Multiple Resolution Methods: Pipelines can be resolved by:
StableDiffusionPipeline)text-to-image, img2img)from diffusers_dynamic_loader import (
load_diffusers_pipeline,
get_available_pipelines,
get_available_tasks,
resolve_pipeline_class,
discover_diffusers_classes,
get_available_classes,
)
# List all available pipelines
pipelines = get_available_pipelines()
print(f"Available pipelines: {pipelines[:10]}...")
# List all task aliases
tasks = get_available_tasks()
print(f"Available tasks: {tasks}")
# Resolve a pipeline class by name
cls = resolve_pipeline_class(class_name="StableDiffusionPipeline")
# Resolve by task alias
cls = resolve_pipeline_class(task="stable-diffusion")
# Load and instantiate a pipeline
pipe = load_diffusers_pipeline(
class_name="StableDiffusionPipeline",
model_id="runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
)
# Load from single file
pipe = load_diffusers_pipeline(
class_name="StableDiffusionPipeline",
model_id="/path/to/model.safetensors",
from_single_file=True,
torch_dtype=torch.float16
)
# Discover other diffusers classes (schedulers, models, etc.)
schedulers = discover_diffusers_classes("SchedulerMixin")
print(f"Available schedulers: {list(schedulers.keys())[:5]}...")
# Get list of available scheduler classes
scheduler_list = get_available_classes("SchedulerMixin")
The dynamic loader can discover not just pipelines but any class type from diffusers:
# Discover all scheduler classes
schedulers = discover_diffusers_classes("SchedulerMixin")
# Discover all model classes
models = discover_diffusers_classes("ModelMixin")
# Get a sorted list of available classes
scheduler_names = get_available_classes("SchedulerMixin")
Most pipelines are loaded dynamically through load_diffusers_pipeline(). Only pipelines requiring truly custom initialization logic are handled explicitly:
FluxTransformer2DModel: Requires quantization and custom transformer loading (cannot use dynamic loader)WanPipeline / WanImageToVideoPipeline: Uses dynamic loader with special VAE (float32 dtype)SanaPipeline: Uses dynamic loader with post-load dtype conversion for VAE/text encoderStableVideoDiffusionPipeline: Uses dynamic loader with CPU offload handlingVideoDiffusionPipeline: Alias for DiffusionPipeline with video flagsAll other pipelines (StableDiffusionPipeline, StableDiffusionXLPipeline, FluxPipeline, etc.) are loaded purely through the dynamic loader.
When a pipeline cannot be resolved, the loader provides helpful error messages listing available pipelines and tasks:
ValueError: Unknown pipeline class 'NonExistentPipeline'.
Available pipelines: AnimateDiffPipeline, AnimateDiffVideoToVideoPipeline, ...
| Variable | Default | Description |
|---|---|---|
COMPEL | 0 | Enable Compel for prompt weighting |
SD_EMBED | 0 | Enable sd_embed for prompt weighting |
XPU | 0 | Enable Intel XPU support |
CLIPSKIP | 1 | Enable CLIP skip support |
SAFETENSORS | 1 | Use safetensors format |
CHUNK_SIZE | 8 | Decode chunk size for video |
FPS | 7 | Video frames per second |
DISABLE_CPU_OFFLOAD | 0 | Disable CPU offload |
FRAMES | 64 | Number of video frames |
BFL_REPO | ChuckMcSneed/FLUX.1-dev | Flux base repo |
PYTHON_GRPC_MAX_WORKERS | 1 | Max gRPC workers |
./test.sh
The test suite includes:
test_dynamic_loader.py)test.py)