How to Use Composable Diffusion in AUTOMATIC1111: Mastering the AND Syntax for Multi-Prompt Generation
Composable Diffusion allows you to condition a single image generation on multiple independent text prompts by separating them with the AND keyword, with optional per-prompt weights specified via :weight syntax.
Composable Diffusion is a core feature of the AUTOMATIC1111/stable-diffusion-webui that enables complex image synthesis by treating each AND-separated clause as an independent conditioning tensor. Instead of merging concepts into a single prompt embedding, the system computes separate embeddings for each sub-prompt and combines them through weighted summation during the diffusion sampling loop. This architecture is implemented primarily in modules/prompt_parser.py and integrated into the sampling pipeline through modules/sd_samplers_cfg_denoiser.py.
What is Composable Diffusion?
Composable Diffusion refers to the method of constructing a final conditioning vector by linearly combining multiple independent prompt conditionings. In the AUTOMATIC1111 implementation, each sub-prompt separated by AND is parsed, encoded by the text encoder, and stored as a ComposableScheduledPromptConditioning object. During sampling, these are assembled into a MulticondLearnedConditioning batch, where the sampler applies user-specified weights and sums the tensors before feeding them to the UNet.
The Internal Pipeline: How AND Syntax is Parsed
The parsing pipeline resides in modules/prompt_parser.py and executes the following sequence:
Step 1: Detection
The regex re_AND = re.compile(r"\bAND\b") splits the user prompt on the literal word AND at line 205.
Step 2: Weight Extraction
Each sub-prompt can carry a :weight suffix. The regex re_weight extracts the text and numeric weight (defaulting to 1.0) at lines 206-207.
Step 3: Flat List Construction
The function get_multicond_prompt_list (lines 209-237) creates three critical data structures:
prompt_flat_list: unique prompt stringsres_indexes: per-prompt lists of(index, weight)tuplesprompt_indexes: a lookup mapping
Step 4: Conditioning Schedule Generation
get_learned_conditioning produces a list of ScheduledPromptConditioning objects for every unique prompt in the flat list.
Step 5: Weight Wrapping
ComposableScheduledPromptConditioning stores each schedule alongside its user-specified weight (lines 240-244).
Step 6: Batch Assembly
get_multicond_learned_conditioning (lines 252-267) assembles a MulticondLearnedConditioning object whose batch field contains a list-of-lists: one outer list per full prompt, inner lists per sub-prompt.
Step 7: Step-wise Reconstruction
During sampling, reconstruct_multicond_batch (lines 221-240) iterates through sub-prompts, selects the appropriate schedule entry for the current diffusion step, stacks the tensors, and records (tensor_index, weight) pairs.
Step 8: Weighted Summation The sampler receives the stacked tensor and weight list, multiplies each conditioning by its weight, and sums them to produce the final composed conditioning fed to the UNet.
Using Composable Diffusion in Practice
Basic Prompt Syntax in the Web UI
Open txt2img or img2img and enter:
a cat :1.2 AND a dog AND a penguin :2.2
a catreceives weight 1.2a doguses the default weight 1.0a penguinreceives weight 2.2
The UI processes this single line as three independent conditioning streams internally.
Programmatic API Usage
To leverage Composable Diffusion programmatically:
from modules import prompt_parser, shared
# Reference to the loaded diffusion model
model = shared.sd_model
prompts = ["a cat :1.2 AND a dog AND a penguin :2.2"]
steps = 50
# Build the composable conditioning object
cond = prompt_parser.get_multicond_learned_conditioning(
model, prompts, steps, hires_steps=None, use_old_scheduling=False
)
# Inspect the structure
print(cond.shape) # (1,)
print(len(cond.batch)) # 1 outer list (one full prompt)
print(len(cond.batch[0])) # 3 inner items (three sub-prompts)
Sampler Integration Details
Inside the diffusion loop, the sampler calls:
# Reconstruct batch for current step
conds_list, stacked = prompt_parser.reconstruct_multicond_batch(cond, current_step)
# conds_list contains: [(0, 1.2), (1, 1.0), (2, 2.2)]
# stacked tensor shape: (3, C, H, W)
# The sampler computes the weighted combination
combined_conditioning = sum(w * stacked[i] for i, w in conds_list)
This combined_conditioning is what the UNet receives to predict noise during that sampling step.
Summary
- Composable Diffusion enables multi-prompt generation by splitting on the
ANDkeyword in AUTOMATIC1111. - The parser in
modules/prompt_parser.pyhandles splitting, weight extraction, and batch construction viaget_multicond_learned_conditioning. - Each sub-prompt becomes a separate conditioning tensor wrapped in
ComposableScheduledPromptConditioning. reconstruct_multicond_batchmanages the per-step assembly and stacking of tensors during sampling.- Weights are applied as a linear combination before the UNet forward pass, allowing precise control over multiple concepts.
Frequently Asked Questions
What is the difference between AND syntax and attention brackets?
Attention brackets (prompt:weight) modify the emphasis of specific tokens within a single conditioning vector, while AND creates entirely separate conditioning tensors that are summed together. Use AND when you want distinct conceptual regions or separate objects, and use attention brackets for adjusting emphasis within a single concept.
Can I use negative weights with the AND syntax?
Yes, you can specify negative weights such as night :-1.0 AND day :1.0 to subtract concepts from the generation. The weighted summation logic in reconstruct_multicond_batch correctly handles negative values, reducing the influence of that conditioning vector during the diffusion process.
Does Composable Diffusion work with all samplers?
Composable Diffusion is compatible with most standard samplers in AUTOMATIC1111, as implemented in modules/sd_samplers_cfg_denoiser.py. However, some specialized samplers may have specific limitations regarding batch composition. The feature operates at the conditioning level, making it broadly supported across the sampling ecosystem.
How does performance compare to single-prompt generation?
Using AND syntax requires computing text embeddings for each sub-prompt separately, increasing memory usage proportionally to the number of AND clauses. However, the actual diffusion sampling speed remains comparable because the weighted summation occurs after text encoding, and the UNet processes only the final combined conditioning vector rather than multiple separate batches.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →