kristopolous/edit-batch

Mass Batch transformation of images with all the latest image-edit models

Python

0

103 commits

updated Oct 17, 2026

See the code

README

edit-batch

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/.

Installation

# 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]"
  • Output directory (-o) is created automatically if it doesn't exist.
  • The prompt file is reread at each image, so you can modify it mid-batch.
  • The ref file (-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
  • The prompt file can contain multiple lines. Each line generates a separate image per input, cycling through prompts sequentially. Lines starting with # are skipped as comments.
  • When multiple prompt lines are present, --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!

0388403534
0343103575

Text Encoders

By default, edit-batch uses the censored FLUX text encoder. Alternative text encoders can be enabled:

# 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

HiDream-O1-Image Mode

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:

FlagDefaultDescription
--modelfluxModel to use: flux, hidream, boogu, or qwen-image-2.1
--model-typefullfull (25 steps, guidance 5.0) or dev (28 steps, guidance 0.0)
--guidance-scale*Guidance scale (5.0 full, 0.0 dev)
--seed42Random seed for reproducibility

Boogu-Image-0.1-Edit-Turbo GGUF Mode

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:

  1. Clones the Boogu-Image repo on first run
  2. Downloads the GGUF-quantized transformer (Q4_1, ~6.9 GiB) from HuggingFace
  3. Loads the Qwen3VL MLLM in 4-bit via bitsandbytes to save VRAM

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:

FlagDefaultDescription
--boogu-path—Path to local full-precision Boogu-Image-0.1-Edit directory (skips GGUF auto-setup)
--text-guidance-scale5.0Text guidance scale; auto-set to 1.0 for DMD turbo if defaults unchanged
--image-guidance-scale1.0Image guidance scale

Requirements: bitsandbytes (installed automatically) for 4-bit MLLM quantization. ~12 GiB VRAM needed for 1024² generation.

Qwen-Image-2.1 Mode

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:

  • Defaults to 20 inference steps (-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).
  • The input image and every reference (from -r/-rf, inline ref:, or --cumulative outputs) are passed together as condition images to the pipeline's image argument (capped at 10).
  • Use the transparency prompt format for RGBA output: This is an RGBA image with transparency. <desc>. The image has alpha channel and the background is transparent.
  • Memory: the model is ~16B params total (7.1B DiT + 8.8B Qwen3-VL text encoder + 0.34B fp32 VAE ≈ 33 GB in bf16/fp32), so it only fits a 24 GB card because edit-batch uses 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.

Uncensored Q4 / sd.cpp backend (-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 Qwen-Image-2.1 LoRA

-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.

FlagDefaultMeaning
--qwen-loracached NSFW LoRALoRA path or URL; empty means "no LoRA"
--qwen-lora-strength1.0--lora-strength multiplier passed to sd-cli
--no-qwen-loraoffWith -nsfw, use the uncensored GGUF alone
--qwen-samplereulersd-cli --sampling-method
--qwen-schedulermodel defaultsd-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.

Skeleton ControlNet Mode

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 detection
  • skeleton: Pose skeleton lines only
  • edges: Skeleton lines + Canny edges on skeleton
  • canny: Canny edge detection on original input image

Required Flags

FlagDescription
-p / --promptPrompt file
-o / --outOutput directory

Optional Flags

FlagDefaultDescription
-i / --in—Glob pattern for input images (e.g. "*.jpg")
-c / --count1Number of images to make
--cumulativefalseChain generations: each output becomes a reference for the next (boogu: added as input_images; other models: tracked in memory)
-d / --devicecudaTorch device
-s / --steps4Inference 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-modeautoSkeleton extraction mode: auto, skeleton, edges, canny
--skeleton-strength0.6ControlNet conditioning scale (0.0-1.0)
--skeleton-image—Pre-generated skeleton/control image (supports glob patterns)
--controlnetInstantX/FLUX.1-dev-Controlnet-CannyControlNet model
--exactfalseUse exact text encoder (LoRA)
--nsfwfalseUse uncensored text encoder + anatomy fixer LoRA
--nsfw-lora—Custom LoRA URL/path for --nsfw (default: Klein anatomy fixer from CivitAI)
--lora-strength2.5LoRA strength (recommended range: 1.0-3.0)
--scale1.0Output 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-resolution1024Qwen-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-backendautoQwen-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.ggufUncensored Qwen-Image-2.1 diffusion GGUF for the sd backend
--qwen-sd-dir~/.cache/flux-batch/qwen-2.1-sdDirectory with Qwen3VL text encoder, mmproj, and VAE for the sd backend
--qwen-sd-cfg6.0CFG scale for the sd backend (overridden by --guidance-scale)
--qwen-loracached NSFW LoRAQwen-Image-2.1 LoRA path or URL; auto-applied with -nsfw (requires the patched sd-cli)
--qwen-lora-strength1.0Multiplier for --qwen-lora
--no-qwen-loraoffWith -nsfw, use the uncensored GGUF without the LoRA
--qwen-samplereulersd-cli --sampling-method; the NSFW LoRA is documented against er_sde
--qwen-schedulermodel defaultsd-cli --scheduler; the NSFW LoRA is documented against beta
--qwen-refs-per-image1Qwen round-robin refs per output (from -r/-rf/inline, cycled by image index); avoid montage. 0 = input-only edit mode
--offset0Start 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
--shuffalseShuffle input file order randomly
-ncfalseNo Clobber — skip existing outputs
--modelfluxModel backend: flux, hidream, boogu, or qwen-image-2.1
--model-typefullHiDream variant: full (25 steps) or dev (28 steps)
--guidance-scale*HiDream guidance scale (5.0 full, 0.0 dev)
--text-guidance-scale5.0Text guidance scale for Boogu
--image-guidance-scale1.0Image guidance scale for Boogu
--seed42Random seed for generation

kristopolous/edit-batch

Mass Batch transformation of images with all the latest image-edit models

Python

0

103 commits

updated Oct 17, 2026

See the code

README

edit-batch

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/.

Installation

# 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]"
  • Output directory (-o) is created automatically if it doesn't exist.
  • The prompt file is reread at each image, so you can modify it mid-batch.
  • The ref file (-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
  • The prompt file can contain multiple lines. Each line generates a separate image per input, cycling through prompts sequentially. Lines starting with # are skipped as comments.
  • When multiple prompt lines are present, --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!

0388403534
0343103575

Text Encoders

By default, edit-batch uses the censored FLUX text encoder. Alternative text encoders can be enabled:

# 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

HiDream-O1-Image Mode

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:

FlagDefaultDescription
--modelfluxModel to use: flux, hidream, boogu, or qwen-image-2.1
--model-typefullfull (25 steps, guidance 5.0) or dev (28 steps, guidance 0.0)
--guidance-scale*Guidance scale (5.0 full, 0.0 dev)
--seed42Random seed for reproducibility

Boogu-Image-0.1-Edit-Turbo GGUF Mode

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:

  1. Clones the Boogu-Image repo on first run
  2. Downloads the GGUF-quantized transformer (Q4_1, ~6.9 GiB) from HuggingFace
  3. Loads the Qwen3VL MLLM in 4-bit via bitsandbytes to save VRAM

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:

FlagDefaultDescription
--boogu-path—Path to local full-precision Boogu-Image-0.1-Edit directory (skips GGUF auto-setup)
--text-guidance-scale5.0Text guidance scale; auto-set to 1.0 for DMD turbo if defaults unchanged
--image-guidance-scale1.0Image guidance scale

Requirements: bitsandbytes (installed automatically) for 4-bit MLLM quantization. ~12 GiB VRAM needed for 1024² generation.

Qwen-Image-2.1 Mode

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:

  • Defaults to 20 inference steps (-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).
  • The input image and every reference (from -r/-rf, inline ref:, or --cumulative outputs) are passed together as condition images to the pipeline's image argument (capped at 10).
  • Use the transparency prompt format for RGBA output: This is an RGBA image with transparency. <desc>. The image has alpha channel and the background is transparent.
  • Memory: the model is ~16B params total (7.1B DiT + 8.8B Qwen3-VL text encoder + 0.34B fp32 VAE ≈ 33 GB in bf16/fp32), so it only fits a 24 GB card because edit-batch uses 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.

Uncensored Q4 / sd.cpp backend (-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 Qwen-Image-2.1 LoRA

-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.

FlagDefaultMeaning
--qwen-loracached NSFW LoRALoRA path or URL; empty means "no LoRA"
--qwen-lora-strength1.0--lora-strength multiplier passed to sd-cli
--no-qwen-loraoffWith -nsfw, use the uncensored GGUF alone
--qwen-samplereulersd-cli --sampling-method
--qwen-schedulermodel defaultsd-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.

Skeleton ControlNet Mode

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 detection
  • skeleton: Pose skeleton lines only
  • edges: Skeleton lines + Canny edges on skeleton
  • canny: Canny edge detection on original input image

Required Flags

FlagDescription
-p / --promptPrompt file
-o / --outOutput directory

Optional Flags

FlagDefaultDescription
-i / --in—Glob pattern for input images (e.g. "*.jpg")
-c / --count1Number of images to make
--cumulativefalseChain generations: each output becomes a reference for the next (boogu: added as input_images; other models: tracked in memory)
-d / --devicecudaTorch device
-s / --steps4Inference 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-modeautoSkeleton extraction mode: auto, skeleton, edges, canny
--skeleton-strength0.6ControlNet conditioning scale (0.0-1.0)
--skeleton-image—Pre-generated skeleton/control image (supports glob patterns)
--controlnetInstantX/FLUX.1-dev-Controlnet-CannyControlNet model
--exactfalseUse exact text encoder (LoRA)
--nsfwfalseUse uncensored text encoder + anatomy fixer LoRA
--nsfw-lora—Custom LoRA URL/path for --nsfw (default: Klein anatomy fixer from CivitAI)
--lora-strength2.5LoRA strength (recommended range: 1.0-3.0)
--scale1.0Output 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-resolution1024Qwen-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-backendautoQwen-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.ggufUncensored Qwen-Image-2.1 diffusion GGUF for the sd backend
--qwen-sd-dir~/.cache/flux-batch/qwen-2.1-sdDirectory with Qwen3VL text encoder, mmproj, and VAE for the sd backend
--qwen-sd-cfg6.0CFG scale for the sd backend (overridden by --guidance-scale)
--qwen-loracached NSFW LoRAQwen-Image-2.1 LoRA path or URL; auto-applied with -nsfw (requires the patched sd-cli)
--qwen-lora-strength1.0Multiplier for --qwen-lora
--no-qwen-loraoffWith -nsfw, use the uncensored GGUF without the LoRA
--qwen-samplereulersd-cli --sampling-method; the NSFW LoRA is documented against er_sde
--qwen-schedulermodel defaultsd-cli --scheduler; the NSFW LoRA is documented against beta
--qwen-refs-per-image1Qwen round-robin refs per output (from -r/-rf/inline, cycled by image index); avoid montage. 0 = input-only edit mode
--offset0Start 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
--shuffalseShuffle input file order randomly
-ncfalseNo Clobber — skip existing outputs
--modelfluxModel backend: flux, hidream, boogu, or qwen-image-2.1
--model-typefullHiDream variant: full (25 steps) or dev (28 steps)
--guidance-scale*HiDream guidance scale (5.0 full, 0.0 dev)
--text-guidance-scale5.0Text guidance scale for Boogu
--image-guidance-scale1.0Image guidance scale for Boogu
--seed42Random seed for generation