Mass Batch transformation of images with all the latest image-edit models
Python
0
103 commits
updated Oct 17, 2026
Batch image processing with FLUX.2 [klein 9B] Q4_K_M GGUF, HiDream-O1-Image, Boogu-Image-0.1-Edit, or Qwen-Image-2.1 including the uncensored models when available using both sd.cpp and transformers with hardware detection.
Run the same prompt across many images with dynamic prompting, static and dynamic reference images, support for multiple generations and step count modification along with multiple text encoders and loras. Optionally use HiDream-O1-Image, Boogu-Image-0.1-Edit, or Qwen-Image-2.1 as the backend model.
Repos, GGUFs, and other dependencies are cached under ~/.cache/flux-batch/.
# Base dependencies for all backends (flux, hidream, boogu)
uv pip install -r pyproject.toml # or: pip install -r requirements.txt
# Qwen-Image-2.1 (--model qwen-image-2.1) additionally requires a diffusers build with
# QwenImage21Pipeline (upstream PR #14804, not yet in pip releases) plus transformers>=5.17:
uv pip install "git+https://github.com/huggingface/diffusers" "transformers>=5.17"
flash-attn is optional and excluded from the base install. It builds from source (no prebuilt wheel covers this platform) and needs a CUDA toolkit (nvcc); it is also missing torch from its own build env, so the isolated build fails without one. No backend imports or requires it — attention falls back automatically — so only install it on a machine with the CUDA toolkit where you want the flash kernels:
uv pip install -e ".[attn]"
-o) is created automatically if it doesn't exist.-rf) is also reread on each iteration — changes are detected by content comparison, and images are only reloaded when the file actually changes.edit-batch -i "*.jpg" -o new/ -p prompt.txt
# are skipped as comments.--count is automatically overridden to match the number of lines.Inline reference images (ref:<path>):
Prompt lines can embed reference image paths directly using ref:<path> syntax. These are extracted, loaded as reference images, and removed from the prompt text before it reaches the model. This composes with -r and -rf — all sources contribute to the reference pool.
# prompt.txt
Make the character wear the outfit ref:/tmp/hat.png ref:/tmp/jacket.png
Put the ball on the table ref:/tmp/ball.png
# No -r needed — refs are embedded in the prompt
edit-batch -i "*.jpg" -o out/ -p prompt.txt
Inline aspect ratio (ratio:<W>:<H>):
Prompt lines can embed an aspect ratio override using ratio:<W>:<H> syntax. This overrides --ratio from the command line for that prompt line.
# prompt.txt
Wide cinematic shot ratio:16:9
Square format ratio:1:1
Inline steps (steps:<int>):
Prompt lines can embed a step count override using steps:<int> syntax. This overrides --steps from the command line for that prompt line.
# prompt.txt
Quick draft steps:4
High quality render steps:20
Here's an example. This is 960 frames.
Look at how frame-matched it is with the original. I even have a nice little peek-a-boo window to compare
https://github.com/user-attachments/assets/08e5e7ea-d49c-4cbd-9391-237583cf7396
A version posted on YouTube: https://youtu.be/8TdXRJQygyY?si=RCVXLUbkEInJ_Z0r
I did this for over 5,000 frames in the video, automatically with edit-batch. Here's a few up close!
By default, edit-batch uses the censored FLUX text encoder. Alternative text encoders can be enabled:
--exact: Loads dx8152/Flux2-Klein-9B-Consistency LoRA for improved consistency--nsfw: Uses ponpoke/flux2-klein-9b-uncensored-text-encoder text encoder for unrestricted content# Use exact encoder (LoRA)
edit-batch --exact -i "*.jpg" -o out/ -p prompt.txt
# Use uncensored encoder
edit-batch --nsfw -i "*.jpg" -o out/ -p prompt.txt
Use --model hidream to run HiDream-O1-Image, a natively unified 8B image generation model. This is text-to-image only (no img2img conditioning) — input image globs provide size reference but aren't used for content.
# Basic text-to-image
edit-batch --model hidream -o out/ -p prompt.txt --width 1024 --height 1024
# Use dev model (28-step distilled variant)
edit-batch --model hidream --model-type dev -o out/ -p prompt.txt
You'll need the HiDream repo dependencies installed (pip install -r /path/to/HiDream-O1-Image/requirements.txt) and transformers>=4.57.1.
HiDream-only flags:
| Flag | Default | Description |
|---|---|---|
--model | flux | Model to use: flux, hidream, boogu, or qwen-image-2.1 |
--model-type | full | full (25 steps, guidance 5.0) or dev (28 steps, guidance 0.0) |
--guidance-scale | * | Guidance scale (5.0 full, 0.0 dev) |
--seed | 42 | Random seed for reproducibility |
Use --model boogu to run Boogu-Image-0.1-Edit-Turbo, a 10B unified image editing model with DMD few-step inference.
When no --boogu-path is given, the script automatically:
The pipeline runs in DMD turbo mode (4 steps, no CFG by default). When the default guidance scales (--text-guidance-scale 5.0 --image-guidance-scale 1.0) are unchanged, the script auto-adjusts both to 1.0 for DMD.
# Basic image editing
edit-batch --model boogu -i "*.jpg" -o out/ -p prompt.txt
# Text-to-image only (no input image)
edit-batch --model boogu -o out/ -p prompt.txt --width 1024 --height 1024
Boogu flags:
| Flag | Default | Description |
|---|---|---|
--boogu-path | — | Path to local full-precision Boogu-Image-0.1-Edit directory (skips GGUF auto-setup) |
--text-guidance-scale | 5.0 | Text guidance scale; auto-set to 1.0 for DMD turbo if defaults unchanged |
--image-guidance-scale | 1.0 | Image guidance scale |
Requirements: bitsandbytes (installed automatically) for 4-bit MLLM quantization. ~12 GiB VRAM needed for 1024² generation.
Use --model qwen-image-2.1 to run Qwen-Image-2.1, a unified 7B text-to-image generation and image editing model with native RGBA transparency and up to 10 reference images for multi-subject composition.
Requires a diffusers release with QwenImage21Pipeline (upstream PR #14804, not yet in pip releases) and transformers>=5.17:
pip install -U "git+https://github.com/huggingface/diffusers" "transformers>=5.17" accelerate
For the uncensored Q4 path (-nsfw) the script instead shells out to stable-diffusion.cpp (sd-cli), the engine the Qwen-Image-2.1 GGUF ecosystem uses — no diffusers load required. See "Uncensored Q4 / sd.cpp backend" below.
# Image editing (input image is the edit target)
edit-batch --model qwen-image-2.1 -i "*.jpg" -o out/ -p prompt.txt
# Text-to-image
edit-batch --model qwen-image-2.1 -o out/ -p prompt.txt --width 1024 --height 1024
# Multi-reference composition: input + -r/-rf refs + inline ref: all become condition images
edit-batch --model qwen-image-2.1 -i "photo.jpg" -r "refs/*.jpg" -o out/ -p prompt.txt
Qwen notes:
-s overrides); flow-matching, so quality barely improves past 20. The model is meant to be sampled without CFG guidance (true_cfg_scale=1.0).-r/-rf, inline ref:, or --cumulative outputs) are passed together as condition images to the pipeline's image argument (capped at 10).This is an RGBA image with transparency. <desc>. The image has alpha channel and the background is transparent.enable_model_cpu_offload() — one component resident at a time. Do not switch to .to("cuda"); the Quick Start snippet on the model page does that and OOMs instantly at any resolution (measured). With offload on a 24 GB 4090: 1024² t2i peaks ~16.4 GiB, a 128 px edit of a 3024×4032 photo ~19.1 GiB. Reference image size is irrelevant: the pipeline inflates every condition image to ~output_resolution² (1024² default) before encoding, so a 180×180 thumbnail costs the same VRAM as a full-size photo — the memory scales with ref count, not ref size. Measured limit at the default: 2 refs fine (~19.1 GiB), 4+ refs OOM. Lower --output-resolution (e.g. --output-resolution 512) to shrink ref encoding cost without changing your requested output size: 8 refs at 512 fit in ~19.1 GiB and all 10 in ~20.4 GiB. The script clamps qwen output to a max side of 1024 by default — native 2K (2048², ~16k latent tokens) is the true 24 GB breaker; raise the cap with -w/-h or --max-width/--max-height.-nsfw)-m qwen-image-2.1 -nsfw runs the uncensored Qwen-Image-2.1 GGUF through sd-cli (Vulkan backend) instead of the diffusers pipeline, matching how the 400k+ GGUF downloads are actually run on consumer cards. Everything runs on the GPU: quantized DiT (Q4 ~4.6 GB), the Qwen3-VL encoder (~4.3 GB) and the VAE all fit in ~24 GB VRAM. Do not pass --offload-to-cpu here — it forces weights to RAM and at 1024² + refs the model manager CPU-falls back (prefix caching disabled, encoder recomputed every step, ~30 min/image); sd.cpp streams weights automatically when VRAM runs out.
Setup (one-time): install the stable-diffusion.cpp Vulkan Linux build (sd.cpp ships no Linux CUDA prebuilt — Linux releases are CPU / Vulkan / ROCm only; CUDA requires a source build with -DSD_CUDA=ON) and the companion files next to the model:
# 1. sd-cli binary -> ~/.cache/flux-batch/sd-cpp/
# (sd-master-...-bin-Linux-Ubuntu-24.04-x86_64-vulkan.zip from
# https://github.com/leejet/stable-diffusion.cpp/releases;
# the plain ...-x86_64.zip is the CPU-only build)
# Needs a Vulkan-capable driver (nvidia_icd.json + libvulkan.so.1); the
# 4090 then shows up as "Vulkan0" and all compute runs on the GPU.
# 2. companions -> ~/.cache/flux-batch/qwen-2.1-sd/
# Qwen3VL-8B-Instruct-Q4_K_M.gguf (text encoder, Q4_K_M)
# mmproj-Qwen3VL-8B-Instruct-F16.gguf (vision encoder, required for refs/editing)
# qwen_image_2.1_vae_bf16.safetensors (VAE)
# 3. the uncensored DiT -> repo root (or point --qwen-gguf at it)
# qwen-image-2.1-UC-Q4_0.gguf (Q4_0; Q4_K_M recommended)
Then:
edit-batch -m qwen-image-2.1 -nsfw -p "prompt.txt" -o out/ --width 1024 --height 1024 # t2i
edit-batch -m qwen-image-2.1 -nsfw -i "photo.jpg" -r "refs/*.jpg" -o out/ -p prompt.txt # edit + refs
--qwen-backend forces the engine: auto (default; sd when -nsfw and --qwen-gguf exists, else diffusers), sd, or diffusers. --qwen-gguf points at the DiT GGUF; --qwen-sd-dir overrides the companion directory; --qwen-sd-cfg and --guidance-scale set CFG (default 6.0). --output-resolution maps to sd-cli's vae_input_max_pixels (i.e. resolution²) to control ref encode cost.
-nsfw auto-applies Wickedlizerd/NSFW-Qwen-Image-2.1-LoRA on top of the uncensored GGUF. It is downloaded once to ~/.cache/flux-batch/loras/nsfw_qwen_21.safetensors and verified against its published SHA-256 on every use.
| Flag | Default | Meaning |
|---|---|---|
--qwen-lora | cached NSFW LoRA | LoRA path or URL; empty means "no LoRA" |
--qwen-lora-strength | 1.0 | --lora-strength multiplier passed to sd-cli |
--no-qwen-lora | off | With -nsfw, use the uncensored GGUF alone |
--qwen-sampler | euler | sd-cli --sampling-method |
--qwen-scheduler | model default | sd-cli --scheduler |
The LoRA is documented against er_sde + beta scheduler + ≥25 steps, so pass those for best results:
edit-batch -m qwen-image-2.1 -nsfw -p prompt.txt -o out/ -i "in/*.jpg" \
-s 25 --qwen-sampler er_sde --qwen-scheduler beta
Two caveats:
This needs a patched sd-cli. Upstream has no CLI flag to load a LoRA file (only --lora-model-dir / --lora-apply-mode), even though the C API supports sd_lora_t. edit-batch therefore uses a second binary at ~/.cache/flux-batch/sd-cpp-lora/sd-cli and only when a LoRA is requested; plain -nsfw runs keep using ~/.cache/flux-batch/sd-cpp/sd-cli. Apply sd-cpp-lora.patch to a checkout of stable-diffusion.cpp at 88411ef and build it:
git clone https://github.com/leejet/stable-diffusion.cpp && cd stable-diffusion.cpp
git checkout 88411ef && git apply /path/to/sd-cpp-lora.patch
apt-get install -y glslc spirv-headers
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSD_VULKAN=ON -DGGML_VULKAN=ON
cmake --build build -j"$(nproc)"
mkdir -p ~/.cache/flux-batch/sd-cpp-lora
install -m755 build/bin/sd-cli ~/.cache/flux-batch/sd-cpp-lora/sd-cli
160 of 192 target modules apply. sd.cpp logs the 32 unused img_mlp.gate_up A/B tensors as attn_norm-style mismatches: the LoRA targets a fused img_mlp.gate_up, while sd.cpp names those weights img_mlp.gate_layer and img_mlp.proj. A plain alias is not enough — the fused tensor has to be split before mapping. The remaining 320/384 tensors do apply, and the rest of the LoRA (attention to_q/to_k/to_v/to_out.0 and img_mlp.out) is correct.
Ref distribution (Qwen montage avoidance): Qwen-Image-2.1 treats ≥2 reference images as "multi-subject composition" (it reproduces them side-by-side — e.g. "person on the left, coat on the right") instead of actually editing. To keep big batches unattended, refs from -r, -rf, and inline ref: are pooled and round-robin delivered by image index: each output gets at most --qwen-refs-per-image refs (default 1), i.e. the -i input (edit target) plus the next rotating ref — -r "coats/*.jpg" on a 100k input batch cycles the coat pool across all outputs with no montage. Set --qwen-refs-per-image 0 for pure single-image edit mode (input only, identity-preserving). Raised values (2+) explicitly opt back into composition mode. Each iteration prints qwen refs[N]: <input> + inline:... so you can see exactly which refs (including inline ref: tokens) reached the model; sd.cpp's tensor-load log spam is filtered to WARN/ERROR only.
Measured performance (24 GB 4090, Vulkan, Q4 UC DiT): t2i at 1024² = ~2.7 s/it (55 s/20 steps), refs (image editing) up to 768² max side = ~2 s/it — both no retry. At 1024² + refs sd-cli's FP32 ref-prefix cache (~4 GiB per 4096 tokens) misses by ~60 MB, so it drops the cache and recomputes the full sequence every step: ~30 min/image — the script warns when it sees refs above 768. Keep ref/editing jobs ≤ 768² (edit-batch warns if you exceed it); 1024² is for t2i.
Use --skeleton to guide generation with detected human poses or custom skeleton images:
# Auto-detect pose from input images and apply skeleton control
edit-batch --skeleton -in "*.jpg" -out pose_out/ -p prompt.txt
# Pure skeleton lines (no Canny edges)
edit-batch --skeleton --skeleton-mode skeleton -in "*.jpg" -out pose_out/ -p prompt.txt
# Use pre-generated skeleton image (reused for all inputs)
edit-batch --skeleton --skeleton-image pose.png -in "*.jpg" -out out/ -p prompt.txt
# Use globbed skeleton images paired with input images
edit-batch --skeleton --skeleton-image "poses/*.png" -in "*.jpg" -out out/ -p prompt.txt
# Adjust control strength (0.0-1.0)
edit-batch --skeleton --skeleton-strength 0.8 -in "*.jpg" -out out/ -p prompt.txt
Skeleton modes:
auto (default): Renders skeleton lines, then applies Canny edge detectionskeleton: Pose skeleton lines onlyedges: Skeleton lines + Canny edges on skeletoncanny: Canny edge detection on original input image| Flag | Description |
|---|---|
-p / --prompt | Prompt file |
-o / --out | Output directory |
| Flag | Default | Description |
|---|---|---|
-i / --in | — | Glob pattern for input images (e.g. "*.jpg") |
-c / --count | 1 | Number of images to make |
--cumulative | false | Chain generations: each output becomes a reference for the next (boogu: added as input_images; other models: tracked in memory) |
-d / --device | cuda | Torch device |
-s / --steps | 4 | Inference steps |
-r / --ref | — | Reference image(s) for style/content. Supports glob patterns; matched files cycle in cadence with input images |
--skeleton | — | Enable skeleton ControlNet mode for pose-guided generation |
--skeleton-mode | auto | Skeleton extraction mode: auto, skeleton, edges, canny |
--skeleton-strength | 0.6 | ControlNet conditioning scale (0.0-1.0) |
--skeleton-image | — | Pre-generated skeleton/control image (supports glob patterns) |
--controlnet | InstantX/FLUX.1-dev-Controlnet-Canny | ControlNet model |
--exact | false | Use exact text encoder (LoRA) |
--nsfw | false | Use uncensored text encoder + anatomy fixer LoRA |
--nsfw-lora | — | Custom LoRA URL/path for --nsfw (default: Klein anatomy fixer from CivitAI) |
--lora-strength | 2.5 | LoRA strength (recommended range: 1.0-3.0) |
--scale | 1.0 | Output size multiplier relative to input (e.g. 0.5 for half, 2.0 for double) |
--max-width | — | Maximum width constraint; overrides --scale, maintains aspect ratio |
--max-height | — | Maximum height constraint; overrides --scale, maintains aspect ratio |
--ratio | — | Target aspect ratio (e.g. 16:9, 4:3); applied after scale/max constraints, then reclamped to max bounds |
--output-resolution | 1024 | Qwen-Image-2.1 only: target side length every condition/reference image is resized to before encoding; lower it (e.g. 512) to fit many refs in 24 GB VRAM |
--qwen-backend | auto | Qwen-Image-2.1 engine: auto (sd when -nsfw and the Q4 GGUF exists, else diffusers), sd, or diffusers |
--qwen-gguf | ./qwen-image-2.1-UC-Q4_0.gguf | Uncensored Qwen-Image-2.1 diffusion GGUF for the sd backend |
--qwen-sd-dir | ~/.cache/flux-batch/qwen-2.1-sd | Directory with Qwen3VL text encoder, mmproj, and VAE for the sd backend |
--qwen-sd-cfg | 6.0 | CFG scale for the sd backend (overridden by --guidance-scale) |
--qwen-lora | cached NSFW LoRA | Qwen-Image-2.1 LoRA path or URL; auto-applied with -nsfw (requires the patched sd-cli) |
--qwen-lora-strength | 1.0 | Multiplier for --qwen-lora |
--no-qwen-lora | off | With -nsfw, use the uncensored GGUF without the LoRA |
--qwen-sampler | euler | sd-cli --sampling-method; the NSFW LoRA is documented against er_sde |
--qwen-scheduler | model default | sd-cli --scheduler; the NSFW LoRA is documented against beta |
--qwen-refs-per-image | 1 | Qwen round-robin refs per output (from -r/-rf/inline, cycled by image index); avoid montage. 0 = input-only edit mode |
--offset | 0 | Start reading prompt file from this line (default: 0) |
-rf / --ref-file | — | File listing reference images (one per line); re-read each iteration like --prompt, reloads images only on content change |
--shuf | false | Shuffle input file order randomly |
-nc | false | No Clobber — skip existing outputs |
--model | flux | Model backend: flux, hidream, boogu, or qwen-image-2.1 |
--model-type | full | HiDream variant: full (25 steps) or dev (28 steps) |
--guidance-scale | * | HiDream guidance scale (5.0 full, 0.0 dev) |
--text-guidance-scale | 5.0 | Text guidance scale for Boogu |
--image-guidance-scale | 1.0 | Image guidance scale for Boogu |
--seed | 42 | Random seed for generation |
Mass Batch transformation of images with all the latest image-edit models
Python
0
103 commits
updated Oct 17, 2026
Batch image processing with FLUX.2 [klein 9B] Q4_K_M GGUF, HiDream-O1-Image, Boogu-Image-0.1-Edit, or Qwen-Image-2.1 including the uncensored models when available using both sd.cpp and transformers with hardware detection.
Run the same prompt across many images with dynamic prompting, static and dynamic reference images, support for multiple generations and step count modification along with multiple text encoders and loras. Optionally use HiDream-O1-Image, Boogu-Image-0.1-Edit, or Qwen-Image-2.1 as the backend model.
Repos, GGUFs, and other dependencies are cached under ~/.cache/flux-batch/.
# Base dependencies for all backends (flux, hidream, boogu)
uv pip install -r pyproject.toml # or: pip install -r requirements.txt
# Qwen-Image-2.1 (--model qwen-image-2.1) additionally requires a diffusers build with
# QwenImage21Pipeline (upstream PR #14804, not yet in pip releases) plus transformers>=5.17:
uv pip install "git+https://github.com/huggingface/diffusers" "transformers>=5.17"
flash-attn is optional and excluded from the base install. It builds from source (no prebuilt wheel covers this platform) and needs a CUDA toolkit (nvcc); it is also missing torch from its own build env, so the isolated build fails without one. No backend imports or requires it — attention falls back automatically — so only install it on a machine with the CUDA toolkit where you want the flash kernels:
uv pip install -e ".[attn]"
-o) is created automatically if it doesn't exist.-rf) is also reread on each iteration — changes are detected by content comparison, and images are only reloaded when the file actually changes.edit-batch -i "*.jpg" -o new/ -p prompt.txt
# are skipped as comments.--count is automatically overridden to match the number of lines.Inline reference images (ref:<path>):
Prompt lines can embed reference image paths directly using ref:<path> syntax. These are extracted, loaded as reference images, and removed from the prompt text before it reaches the model. This composes with -r and -rf — all sources contribute to the reference pool.
# prompt.txt
Make the character wear the outfit ref:/tmp/hat.png ref:/tmp/jacket.png
Put the ball on the table ref:/tmp/ball.png
# No -r needed — refs are embedded in the prompt
edit-batch -i "*.jpg" -o out/ -p prompt.txt
Inline aspect ratio (ratio:<W>:<H>):
Prompt lines can embed an aspect ratio override using ratio:<W>:<H> syntax. This overrides --ratio from the command line for that prompt line.
# prompt.txt
Wide cinematic shot ratio:16:9
Square format ratio:1:1
Inline steps (steps:<int>):
Prompt lines can embed a step count override using steps:<int> syntax. This overrides --steps from the command line for that prompt line.
# prompt.txt
Quick draft steps:4
High quality render steps:20
Here's an example. This is 960 frames.
Look at how frame-matched it is with the original. I even have a nice little peek-a-boo window to compare
https://github.com/user-attachments/assets/08e5e7ea-d49c-4cbd-9391-237583cf7396
A version posted on YouTube: https://youtu.be/8TdXRJQygyY?si=RCVXLUbkEInJ_Z0r
I did this for over 5,000 frames in the video, automatically with edit-batch. Here's a few up close!
By default, edit-batch uses the censored FLUX text encoder. Alternative text encoders can be enabled:
--exact: Loads dx8152/Flux2-Klein-9B-Consistency LoRA for improved consistency--nsfw: Uses ponpoke/flux2-klein-9b-uncensored-text-encoder text encoder for unrestricted content# Use exact encoder (LoRA)
edit-batch --exact -i "*.jpg" -o out/ -p prompt.txt
# Use uncensored encoder
edit-batch --nsfw -i "*.jpg" -o out/ -p prompt.txt
Use --model hidream to run HiDream-O1-Image, a natively unified 8B image generation model. This is text-to-image only (no img2img conditioning) — input image globs provide size reference but aren't used for content.
# Basic text-to-image
edit-batch --model hidream -o out/ -p prompt.txt --width 1024 --height 1024
# Use dev model (28-step distilled variant)
edit-batch --model hidream --model-type dev -o out/ -p prompt.txt
You'll need the HiDream repo dependencies installed (pip install -r /path/to/HiDream-O1-Image/requirements.txt) and transformers>=4.57.1.
HiDream-only flags:
| Flag | Default | Description |
|---|---|---|
--model | flux | Model to use: flux, hidream, boogu, or qwen-image-2.1 |
--model-type | full | full (25 steps, guidance 5.0) or dev (28 steps, guidance 0.0) |
--guidance-scale | * | Guidance scale (5.0 full, 0.0 dev) |
--seed | 42 | Random seed for reproducibility |
Use --model boogu to run Boogu-Image-0.1-Edit-Turbo, a 10B unified image editing model with DMD few-step inference.
When no --boogu-path is given, the script automatically:
The pipeline runs in DMD turbo mode (4 steps, no CFG by default). When the default guidance scales (--text-guidance-scale 5.0 --image-guidance-scale 1.0) are unchanged, the script auto-adjusts both to 1.0 for DMD.
# Basic image editing
edit-batch --model boogu -i "*.jpg" -o out/ -p prompt.txt
# Text-to-image only (no input image)
edit-batch --model boogu -o out/ -p prompt.txt --width 1024 --height 1024
Boogu flags:
| Flag | Default | Description |
|---|---|---|
--boogu-path | — | Path to local full-precision Boogu-Image-0.1-Edit directory (skips GGUF auto-setup) |
--text-guidance-scale | 5.0 | Text guidance scale; auto-set to 1.0 for DMD turbo if defaults unchanged |
--image-guidance-scale | 1.0 | Image guidance scale |
Requirements: bitsandbytes (installed automatically) for 4-bit MLLM quantization. ~12 GiB VRAM needed for 1024² generation.
Use --model qwen-image-2.1 to run Qwen-Image-2.1, a unified 7B text-to-image generation and image editing model with native RGBA transparency and up to 10 reference images for multi-subject composition.
Requires a diffusers release with QwenImage21Pipeline (upstream PR #14804, not yet in pip releases) and transformers>=5.17:
pip install -U "git+https://github.com/huggingface/diffusers" "transformers>=5.17" accelerate
For the uncensored Q4 path (-nsfw) the script instead shells out to stable-diffusion.cpp (sd-cli), the engine the Qwen-Image-2.1 GGUF ecosystem uses — no diffusers load required. See "Uncensored Q4 / sd.cpp backend" below.
# Image editing (input image is the edit target)
edit-batch --model qwen-image-2.1 -i "*.jpg" -o out/ -p prompt.txt
# Text-to-image
edit-batch --model qwen-image-2.1 -o out/ -p prompt.txt --width 1024 --height 1024
# Multi-reference composition: input + -r/-rf refs + inline ref: all become condition images
edit-batch --model qwen-image-2.1 -i "photo.jpg" -r "refs/*.jpg" -o out/ -p prompt.txt
Qwen notes:
-s overrides); flow-matching, so quality barely improves past 20. The model is meant to be sampled without CFG guidance (true_cfg_scale=1.0).-r/-rf, inline ref:, or --cumulative outputs) are passed together as condition images to the pipeline's image argument (capped at 10).This is an RGBA image with transparency. <desc>. The image has alpha channel and the background is transparent.enable_model_cpu_offload() — one component resident at a time. Do not switch to .to("cuda"); the Quick Start snippet on the model page does that and OOMs instantly at any resolution (measured). With offload on a 24 GB 4090: 1024² t2i peaks ~16.4 GiB, a 128 px edit of a 3024×4032 photo ~19.1 GiB. Reference image size is irrelevant: the pipeline inflates every condition image to ~output_resolution² (1024² default) before encoding, so a 180×180 thumbnail costs the same VRAM as a full-size photo — the memory scales with ref count, not ref size. Measured limit at the default: 2 refs fine (~19.1 GiB), 4+ refs OOM. Lower --output-resolution (e.g. --output-resolution 512) to shrink ref encoding cost without changing your requested output size: 8 refs at 512 fit in ~19.1 GiB and all 10 in ~20.4 GiB. The script clamps qwen output to a max side of 1024 by default — native 2K (2048², ~16k latent tokens) is the true 24 GB breaker; raise the cap with -w/-h or --max-width/--max-height.-nsfw)-m qwen-image-2.1 -nsfw runs the uncensored Qwen-Image-2.1 GGUF through sd-cli (Vulkan backend) instead of the diffusers pipeline, matching how the 400k+ GGUF downloads are actually run on consumer cards. Everything runs on the GPU: quantized DiT (Q4 ~4.6 GB), the Qwen3-VL encoder (~4.3 GB) and the VAE all fit in ~24 GB VRAM. Do not pass --offload-to-cpu here — it forces weights to RAM and at 1024² + refs the model manager CPU-falls back (prefix caching disabled, encoder recomputed every step, ~30 min/image); sd.cpp streams weights automatically when VRAM runs out.
Setup (one-time): install the stable-diffusion.cpp Vulkan Linux build (sd.cpp ships no Linux CUDA prebuilt — Linux releases are CPU / Vulkan / ROCm only; CUDA requires a source build with -DSD_CUDA=ON) and the companion files next to the model:
# 1. sd-cli binary -> ~/.cache/flux-batch/sd-cpp/
# (sd-master-...-bin-Linux-Ubuntu-24.04-x86_64-vulkan.zip from
# https://github.com/leejet/stable-diffusion.cpp/releases;
# the plain ...-x86_64.zip is the CPU-only build)
# Needs a Vulkan-capable driver (nvidia_icd.json + libvulkan.so.1); the
# 4090 then shows up as "Vulkan0" and all compute runs on the GPU.
# 2. companions -> ~/.cache/flux-batch/qwen-2.1-sd/
# Qwen3VL-8B-Instruct-Q4_K_M.gguf (text encoder, Q4_K_M)
# mmproj-Qwen3VL-8B-Instruct-F16.gguf (vision encoder, required for refs/editing)
# qwen_image_2.1_vae_bf16.safetensors (VAE)
# 3. the uncensored DiT -> repo root (or point --qwen-gguf at it)
# qwen-image-2.1-UC-Q4_0.gguf (Q4_0; Q4_K_M recommended)
Then:
edit-batch -m qwen-image-2.1 -nsfw -p "prompt.txt" -o out/ --width 1024 --height 1024 # t2i
edit-batch -m qwen-image-2.1 -nsfw -i "photo.jpg" -r "refs/*.jpg" -o out/ -p prompt.txt # edit + refs
--qwen-backend forces the engine: auto (default; sd when -nsfw and --qwen-gguf exists, else diffusers), sd, or diffusers. --qwen-gguf points at the DiT GGUF; --qwen-sd-dir overrides the companion directory; --qwen-sd-cfg and --guidance-scale set CFG (default 6.0). --output-resolution maps to sd-cli's vae_input_max_pixels (i.e. resolution²) to control ref encode cost.
-nsfw auto-applies Wickedlizerd/NSFW-Qwen-Image-2.1-LoRA on top of the uncensored GGUF. It is downloaded once to ~/.cache/flux-batch/loras/nsfw_qwen_21.safetensors and verified against its published SHA-256 on every use.
| Flag | Default | Meaning |
|---|---|---|
--qwen-lora | cached NSFW LoRA | LoRA path or URL; empty means "no LoRA" |
--qwen-lora-strength | 1.0 | --lora-strength multiplier passed to sd-cli |
--no-qwen-lora | off | With -nsfw, use the uncensored GGUF alone |
--qwen-sampler | euler | sd-cli --sampling-method |
--qwen-scheduler | model default | sd-cli --scheduler |
The LoRA is documented against er_sde + beta scheduler + ≥25 steps, so pass those for best results:
edit-batch -m qwen-image-2.1 -nsfw -p prompt.txt -o out/ -i "in/*.jpg" \
-s 25 --qwen-sampler er_sde --qwen-scheduler beta
Two caveats:
This needs a patched sd-cli. Upstream has no CLI flag to load a LoRA file (only --lora-model-dir / --lora-apply-mode), even though the C API supports sd_lora_t. edit-batch therefore uses a second binary at ~/.cache/flux-batch/sd-cpp-lora/sd-cli and only when a LoRA is requested; plain -nsfw runs keep using ~/.cache/flux-batch/sd-cpp/sd-cli. Apply sd-cpp-lora.patch to a checkout of stable-diffusion.cpp at 88411ef and build it:
git clone https://github.com/leejet/stable-diffusion.cpp && cd stable-diffusion.cpp
git checkout 88411ef && git apply /path/to/sd-cpp-lora.patch
apt-get install -y glslc spirv-headers
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSD_VULKAN=ON -DGGML_VULKAN=ON
cmake --build build -j"$(nproc)"
mkdir -p ~/.cache/flux-batch/sd-cpp-lora
install -m755 build/bin/sd-cli ~/.cache/flux-batch/sd-cpp-lora/sd-cli
160 of 192 target modules apply. sd.cpp logs the 32 unused img_mlp.gate_up A/B tensors as attn_norm-style mismatches: the LoRA targets a fused img_mlp.gate_up, while sd.cpp names those weights img_mlp.gate_layer and img_mlp.proj. A plain alias is not enough — the fused tensor has to be split before mapping. The remaining 320/384 tensors do apply, and the rest of the LoRA (attention to_q/to_k/to_v/to_out.0 and img_mlp.out) is correct.
Ref distribution (Qwen montage avoidance): Qwen-Image-2.1 treats ≥2 reference images as "multi-subject composition" (it reproduces them side-by-side — e.g. "person on the left, coat on the right") instead of actually editing. To keep big batches unattended, refs from -r, -rf, and inline ref: are pooled and round-robin delivered by image index: each output gets at most --qwen-refs-per-image refs (default 1), i.e. the -i input (edit target) plus the next rotating ref — -r "coats/*.jpg" on a 100k input batch cycles the coat pool across all outputs with no montage. Set --qwen-refs-per-image 0 for pure single-image edit mode (input only, identity-preserving). Raised values (2+) explicitly opt back into composition mode. Each iteration prints qwen refs[N]: <input> + inline:... so you can see exactly which refs (including inline ref: tokens) reached the model; sd.cpp's tensor-load log spam is filtered to WARN/ERROR only.
Measured performance (24 GB 4090, Vulkan, Q4 UC DiT): t2i at 1024² = ~2.7 s/it (55 s/20 steps), refs (image editing) up to 768² max side = ~2 s/it — both no retry. At 1024² + refs sd-cli's FP32 ref-prefix cache (~4 GiB per 4096 tokens) misses by ~60 MB, so it drops the cache and recomputes the full sequence every step: ~30 min/image — the script warns when it sees refs above 768. Keep ref/editing jobs ≤ 768² (edit-batch warns if you exceed it); 1024² is for t2i.
Use --skeleton to guide generation with detected human poses or custom skeleton images:
# Auto-detect pose from input images and apply skeleton control
edit-batch --skeleton -in "*.jpg" -out pose_out/ -p prompt.txt
# Pure skeleton lines (no Canny edges)
edit-batch --skeleton --skeleton-mode skeleton -in "*.jpg" -out pose_out/ -p prompt.txt
# Use pre-generated skeleton image (reused for all inputs)
edit-batch --skeleton --skeleton-image pose.png -in "*.jpg" -out out/ -p prompt.txt
# Use globbed skeleton images paired with input images
edit-batch --skeleton --skeleton-image "poses/*.png" -in "*.jpg" -out out/ -p prompt.txt
# Adjust control strength (0.0-1.0)
edit-batch --skeleton --skeleton-strength 0.8 -in "*.jpg" -out out/ -p prompt.txt
Skeleton modes:
auto (default): Renders skeleton lines, then applies Canny edge detectionskeleton: Pose skeleton lines onlyedges: Skeleton lines + Canny edges on skeletoncanny: Canny edge detection on original input image| Flag | Description |
|---|---|
-p / --prompt | Prompt file |
-o / --out | Output directory |
| Flag | Default | Description |
|---|---|---|
-i / --in | — | Glob pattern for input images (e.g. "*.jpg") |
-c / --count | 1 | Number of images to make |
--cumulative | false | Chain generations: each output becomes a reference for the next (boogu: added as input_images; other models: tracked in memory) |
-d / --device | cuda | Torch device |
-s / --steps | 4 | Inference steps |
-r / --ref | — | Reference image(s) for style/content. Supports glob patterns; matched files cycle in cadence with input images |
--skeleton | — | Enable skeleton ControlNet mode for pose-guided generation |
--skeleton-mode | auto | Skeleton extraction mode: auto, skeleton, edges, canny |
--skeleton-strength | 0.6 | ControlNet conditioning scale (0.0-1.0) |
--skeleton-image | — | Pre-generated skeleton/control image (supports glob patterns) |
--controlnet | InstantX/FLUX.1-dev-Controlnet-Canny | ControlNet model |
--exact | false | Use exact text encoder (LoRA) |
--nsfw | false | Use uncensored text encoder + anatomy fixer LoRA |
--nsfw-lora | — | Custom LoRA URL/path for --nsfw (default: Klein anatomy fixer from CivitAI) |
--lora-strength | 2.5 | LoRA strength (recommended range: 1.0-3.0) |
--scale | 1.0 | Output size multiplier relative to input (e.g. 0.5 for half, 2.0 for double) |
--max-width | — | Maximum width constraint; overrides --scale, maintains aspect ratio |
--max-height | — | Maximum height constraint; overrides --scale, maintains aspect ratio |
--ratio | — | Target aspect ratio (e.g. 16:9, 4:3); applied after scale/max constraints, then reclamped to max bounds |
--output-resolution | 1024 | Qwen-Image-2.1 only: target side length every condition/reference image is resized to before encoding; lower it (e.g. 512) to fit many refs in 24 GB VRAM |
--qwen-backend | auto | Qwen-Image-2.1 engine: auto (sd when -nsfw and the Q4 GGUF exists, else diffusers), sd, or diffusers |
--qwen-gguf | ./qwen-image-2.1-UC-Q4_0.gguf | Uncensored Qwen-Image-2.1 diffusion GGUF for the sd backend |
--qwen-sd-dir | ~/.cache/flux-batch/qwen-2.1-sd | Directory with Qwen3VL text encoder, mmproj, and VAE for the sd backend |
--qwen-sd-cfg | 6.0 | CFG scale for the sd backend (overridden by --guidance-scale) |
--qwen-lora | cached NSFW LoRA | Qwen-Image-2.1 LoRA path or URL; auto-applied with -nsfw (requires the patched sd-cli) |
--qwen-lora-strength | 1.0 | Multiplier for --qwen-lora |
--no-qwen-lora | off | With -nsfw, use the uncensored GGUF without the LoRA |
--qwen-sampler | euler | sd-cli --sampling-method; the NSFW LoRA is documented against er_sde |
--qwen-scheduler | model default | sd-cli --scheduler; the NSFW LoRA is documented against beta |
--qwen-refs-per-image | 1 | Qwen round-robin refs per output (from -r/-rf/inline, cycled by image index); avoid montage. 0 = input-only edit mode |
--offset | 0 | Start reading prompt file from this line (default: 0) |
-rf / --ref-file | — | File listing reference images (one per line); re-read each iteration like --prompt, reloads images only on content change |
--shuf | false | Shuffle input file order randomly |
-nc | false | No Clobber — skip existing outputs |
--model | flux | Model backend: flux, hidream, boogu, or qwen-image-2.1 |
--model-type | full | HiDream variant: full (25 steps) or dev (28 steps) |
--guidance-scale | * | HiDream guidance scale (5.0 full, 0.0 dev) |
--text-guidance-scale | 5.0 | Text guidance scale for Boogu |
--image-guidance-scale | 1.0 | Image guidance scale for Boogu |
--seed | 42 | Random seed for generation |