Compare commits

..

No commits in common. "dff0e88265a54d45fdb0839c39a9f6522fea924c" and "b11c95a41c0c6ba39cfc8af9ffaded015b2d6636" have entirely different histories.

56 changed files with 198 additions and 1143 deletions

View File

@ -15,7 +15,7 @@ on:
[ [
".github/workflows/**", ".github/workflows/**",
".dockerignore", ".dockerignore",
"docker/Dockerfile*", "Dockerfile*",
"**/CMakeLists.txt", "**/CMakeLists.txt",
"**/Makefile", "**/Makefile",
"**/*.h", "**/*.h",
@ -32,7 +32,7 @@ on:
[ [
".github/workflows/**", ".github/workflows/**",
".dockerignore", ".dockerignore",
"docker/Dockerfile*", "Dockerfile*",
"**/CMakeLists.txt", "**/CMakeLists.txt",
"**/Makefile", "**/Makefile",
"**/*.h", "**/*.h",
@ -264,7 +264,7 @@ jobs:
context: . context: .
platforms: ${{ matrix.platform }} platforms: ${{ matrix.platform }}
push: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} push: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
file: docker/Dockerfile.${{ matrix.variant }} file: Dockerfile.${{ matrix.variant }}
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH_NAME }}-${{ matrix.variant }}${{ matrix.tag-suffix }} tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH_NAME }}-${{ matrix.variant }}${{ matrix.tag-suffix }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}

View File

@ -27,7 +27,7 @@ PRs should include:
Format code according to the repository style before submitting changes. Format code according to the repository style before submitting changes.
Formatting follows `.clang-format` (Chromium base, 4-space indent, no tabs). Run `scripts/format-code.sh` or `scripts/format-code.ps1` before opening a PR. Keep C++ standard at C++17-compatible patterns used in this repo. Formatting follows `.clang-format` (Chromium base, 4-space indent, no tabs). Run `format-code.sh` before opening a PR. Keep C++ standard at C++17-compatible patterns used in this repo.
Naming conventions: Naming conventions:

View File

@ -180,3 +180,19 @@ Thank you to all the people who have already contributed to stable-diffusion.cpp
## Star History ## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=leejet/stable-diffusion.cpp&type=Date)](https://star-history.com/#leejet/stable-diffusion.cpp&Date) [![Star History Chart](https://api.star-history.com/svg?repos=leejet/stable-diffusion.cpp&type=Date)](https://star-history.com/#leejet/stable-diffusion.cpp&Date)
## References
- [ggml](https://github.com/ggml-org/ggml)
- [diffusers](https://github.com/huggingface/diffusers)
- [stable-diffusion](https://github.com/CompVis/stable-diffusion)
- [sd3-ref](https://github.com/Stability-AI/sd3-ref)
- [stable-diffusion-stability-ai](https://github.com/Stability-AI/stablediffusion)
- [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)
- [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
- [k-diffusion](https://github.com/crowsonkb/k-diffusion)
- [latent-consistency-model](https://github.com/luosiallen/latent-consistency-model)
- [generative-models](https://github.com/Stability-AI/generative-models/)
- [PhotoMaker](https://github.com/TencentARC/PhotoMaker)
- [Wan2.1](https://github.com/Wan-Video/Wan2.1)
- [Wan2.2](https://github.com/Wan-Video/Wan2.2)

View File

@ -15,7 +15,7 @@
## Examples ## Examples
```sh ```sh
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\anima-preview.safetensors --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\qwen_3_06b_base.safetensors -p "a lovely cat holding a sign says 'anima.cpp'" --cfg-scale 6.0 --sampling-method euler -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\anima-preview.safetensors --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_06b_base.safetensors -p "a lovely cat holding a sign says 'anima.cpp'" --cfg-scale 6.0 --sampling-method euler -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="anima image example" src="../assets/anima/example.png" /> <img alt="anima image example" src="../assets/anima/example.png" />

View File

@ -17,7 +17,7 @@ Boogu Image uses a Boogu diffusion transformer, the FLUX VAE, and Qwen3-VL as th
### Boogu Image Base ### Boogu Image Base
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_base_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\ae.sft -p "a lovely cat" --diffusion-fa -v --offload-to-cpu .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\boogu_image_base_bf16.safetensors --llm ..\..\llm\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ae.sft -p "a lovely cat" --diffusion-fa -v --offload-to-cpu
``` ```
<img width="256" alt="Boogu Image Base example" src="../assets/boogu/example.png" /> <img width="256" alt="Boogu Image Base example" src="../assets/boogu/example.png" />
@ -25,7 +25,7 @@ Boogu Image uses a Boogu diffusion transformer, the FLUX VAE, and Qwen3-VL as th
### Boogu Image Edit ### Boogu Image Edit
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\boogu_image_edit_bf16.safetensors --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --llm_vision ..\models\text_encoders\mmproj-Qwen3VL-8B-Instruct-F16.gguf --vae ..\models\vae\ae.sft --diffusion-fa -v --offload-to-cpu -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'boogu.cpp'" .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\boogu_image_edit_bf16.safetensors --llm ..\..\llm\Qwen3VL-8B-Instruct-Q4_K_M.gguf --llm_vision ..\..\llm\mmproj-Qwen3VL-8B-Instruct-F16.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --diffusion-fa -v --offload-to-cpu -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'boogu.cpp'"
``` ```
<img width="256" alt="Boogu Image Edit example" src="../assets/boogu/edit_example.png" /> <img width="256" alt="Boogu Image Edit example" src="../assets/boogu/edit_example.png" />

View File

@ -15,7 +15,7 @@ You can run Chroma using stable-diffusion.cpp with a GPU that has 6GB or even 4G
You can download the preconverted gguf weights from [silveroxides/Chroma-GGUF](https://huggingface.co/silveroxides/Chroma-GGUF), this way you don't have to do the conversion yourself. You can download the preconverted gguf weights from [silveroxides/Chroma-GGUF](https://huggingface.co/silveroxides/Chroma-GGUF), this way you don't have to do the conversion yourself.
``` ```
.\bin\Release\sd-cli.exe -M convert -m ..\models\unet\chroma-unlocked-v40.safetensors -o ..\models\chroma-unlocked-v40-q8_0.gguf -v --type q8_0 .\bin\Release\sd-cli.exe -M convert -m ..\..\ComfyUI\models\unet\chroma-unlocked-v40.safetensors -o ..\models\chroma-unlocked-v40-q8_0.gguf -v --type q8_0
``` ```
## Run ## Run

View File

@ -12,7 +12,7 @@
## Examples ## Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Chroma1-Radiance-v0.4-Q8_0.gguf --t5xxl ..\models\clip\t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'chroma radiance cpp'" --cfg-scale 4.0 --sampling-method euler -v .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Chroma1-Radiance-v0.4-Q8_0.gguf --t5xxl ..\..\ComfyUI\models\clip\t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'chroma radiance cpp'" --cfg-scale 4.0 --sampling-method euler -v
``` ```
<img alt="Chroma1-Radiance" src="../assets/flux/chroma1-radiance.png" /> <img alt="Chroma1-Radiance" src="../assets/flux/chroma1-radiance.png" />

View File

@ -19,7 +19,7 @@ docker run --rm --init -v /path/to/models:/models -v /path/to/output/:/output -p
## Building using Docker ## Building using Docker
```shell ```shell
docker build -f docker/Dockerfile -t sd . docker build -t sd .
``` ```
## Building variants using Docker ## Building variants using Docker
@ -27,7 +27,7 @@ docker build -f docker/Dockerfile -t sd .
Vulkan: Vulkan:
```shell ```shell
docker build -f docker/Dockerfile.vulkan -t sd . docker build -f Dockerfile.vulkan -t sd .
``` ```
## Run locally built image's CLI ## Run locally built image's CLI

View File

@ -21,7 +21,7 @@ You can run ERNIE-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — o
### ERNIE-Image-Turbo ### ERNIE-Image-Turbo
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-turbo.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 8 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\ernie-image-turbo.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 8 -v --offload-to-cpu --diffusion-fa
``` ```
<img width="256" alt="ERNIE-Image Turbo example" src="../assets/ernie_image/turbo_example.png" /> <img width="256" alt="ERNIE-Image Turbo example" src="../assets/ernie_image/turbo_example.png" />
@ -29,7 +29,7 @@ You can run ERNIE-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — o
### ERNIE-Image ### ERNIE-Image
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\ernie-image-UD-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\ernie-image-UD-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\ministral-3-3b.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa
``` ```
<img width="256" alt="ERNIE-Image example" src="../assets/ernie_image/example.png" /> <img width="256" alt="ERNIE-Image example" src="../assets/ernie_image/example.png" />

View File

@ -17,7 +17,7 @@ You can download the preconverted gguf weights from [FLUX.1-dev-gguf](https://hu
For example: For example:
``` ```
.\bin\Release\sd-cli.exe -M convert -m ..\models\unet\flux1-dev.sft -o ..\models\flux1-dev-q8_0.gguf -v --type q8_0 .\bin\Release\sd-cli.exe -M convert -m ..\..\ComfyUI\models\unet\flux1-dev.sft -o ..\models\flux1-dev-q8_0.gguf -v --type q8_0
``` ```
## Run ## Run

View File

@ -16,7 +16,7 @@
### Examples ### Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux2-dev-Q4_K_S.gguf --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\Mistral-Small-3.2-24B-Instruct-2506-Q4_K_M.gguf -r .\kontext_input.png -p "change 'flux.cpp' to 'flux2-dev.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux2-dev-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Mistral-Small-3.2-24B-Instruct-2506-Q4_K_M.gguf -r .\kontext_input.png -p "change 'flux.cpp' to 'flux2-dev.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu
``` ```
<img alt="flux2 example" src="../assets/flux2/example.png" /> <img alt="flux2 example" src="../assets/flux2/example.png" />
@ -42,19 +42,19 @@
### Examples ### Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="flux2-klein-4b" src="../assets/flux2/flux2-klein-4b.png" /> <img alt="flux2-klein-4b" src="../assets/flux2/flux2-klein-4b.png" />
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-4b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_4b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4
``` ```
<img alt="flux2-klein-4b-edit" src="../assets/flux2/flux2-klein-4b-edit.png" /> <img alt="flux2-klein-4b-edit" src="../assets/flux2/flux2-klein-4b-edit.png" />
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-4b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-base-4b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_4b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="flux2-klein-base-4b" src="../assets/flux2/flux2-klein-base-4b.png" /> <img alt="flux2-klein-base-4b" src="../assets/flux2/flux2-klein-base-4b.png" />
@ -78,19 +78,19 @@
### Examples ### Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 1.0 --steps 4 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="flux2-klein-9b" src="../assets/flux2/flux2-klein-9b.png" /> <img alt="flux2-klein-9b" src="../assets/flux2/flux2-klein-9b.png" />
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-9b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_8b.safetensors -r .\kontext_input.png -p "change 'flux.cpp' to 'klein.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu --steps 4
``` ```
<img alt="flux2-klein-9b-edit" src="../assets/flux2/flux2-klein-9b-edit.png" /> <img alt="flux2-klein-9b-edit" src="../assets/flux2/flux2-klein-9b-edit.png" />
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-2-klein-base-9b.safetensors --vae ..\models\vae\flux2_ae.safetensors --llm ..\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux-2-klein-base-9b.safetensors --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_3_8b.safetensors -p "a lovely cat" --cfg-scale 4.0 --steps 20 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="flux2-klein-base-9b" src="../assets/flux2/flux2-klein-base-9b.png" /> <img alt="flux2-klein-base-9b" src="../assets/flux2/flux2-klein-base-9b.png" />

View File

@ -12,7 +12,7 @@
### HiDream-O1-Image-Dev ### HiDream-O1-Image-Dev
``` ```
.\bin\Release\sd-cli.exe -m ..\models\diffusion_models\hidream_o1_image_dev_bf16.safetensors -p "a lovely cat holding a sign says .\bin\Release\sd-cli.exe -m ..\..\ComfyUI\models\diffusion_models\hidream_o1_image_dev_bf16.safetensors -p "a lovely cat holding a sign says
'hidream o1 cpp'" --cfg-scale 1.0 -v -H 1024 -W 1024 'hidream o1 cpp'" --cfg-scale 1.0 -v -H 1024 -W 1024
``` ```

View File

@ -34,7 +34,7 @@ If you want lower VRAM usage, you can change the quantization from q8_0 to a low
## Examples ## Examples
```sh ```sh
.\bin\Release\sd-cli.exe --diffusion-model ideogram4-Q8_0.gguf --uncond-diffusion-model ideogram4_uncond-Q8_0.gguf --llm ..\models\text_encoders\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p '{"high_level_description":"A square 1024 x 1024 luxury fashion magazine cover featuring exactly one short chubby fluffy cat as the main model. The cat sits on a soft ivory studio floor, facing the viewer with a stylish calm expression, wearing tiny black sunglasses, a red silk scarf, and a small gold collar charm. In front of the cat on the floor is a wide horizontal luxury nameplate that clearly reads ideogram4.cpp. The whole design feels premium, fashionable, clean, and editorial.","style_description":{"aesthetics":"luxury fashion magazine cover, high-end pet couture campaign, minimalist editorial design, elegant studio photography, soft paper texture, refined typography, fashionable and polished","lighting":"Soft diffused studio lighting, gentle spotlight on the cat, subtle floor shadow, warm ivory highlights, clean separation between subject and background","photo":"high-resolution fashion editorial photography look, front-facing cat portrait, crisp fur details, glossy sunglasses, clear readable nameplate text, shallow depth of field","medium":"mixed media fashion photography and premium editorial graphic design","color_palette":["#F4EFE7","#111111","#D8B56D","#B73A3A","#FFFFFF","#8A7A6A"]},"compositional_deconstruction":{"canvas":"Square 1024 x 1024 canvas with a normal upright orientation. Do not rotate the poster or any text. Use a clean fashion magazine cover layout.","background":"Warm ivory studio backdrop with subtle paper grain, a soft spotlight gradient, faint floor shadow, and a few minimal gold editorial lines. The background is spacious, premium, and uncluttered.","layout":"Top center has a small elegant headline. Center area features one cat as the main fashion model. Lower foreground has a wide horizontal luxury nameplate placed on the floor in front of the cat. Bottom center has a small footer. All text is horizontal, upright, and readable left to right.","elements":[{"type":"text","desc":"Top center headline reading LOOK WHAT I FOUND in a refined high-fashion serif font. The headline is horizontal, centered, elegant, and secondary to the nameplate text."},{"type":"obj","desc":"Exactly one short chubby fluffy cat sitting in the center like a luxury fashion model. The cat has a large round head, compact body, short legs, soft detailed fur, expressive eyes, and a calm confident pose. The cat is cute and rounded, not tall, not stretched, not duplicated."},{"type":"obj","desc":"Tiny glossy black sunglasses worn naturally by the cat, slightly oversized but still showing the cat face clearly. The sunglasses add a chic fashion-editorial attitude."},{"type":"obj","desc":"A red silk scarf tied neatly around the cat neck, with soft folds and a couture feeling. The scarf must not cover the cat face or the nameplate."},{"type":"obj","desc":"A small gold collar charm or fashion accessory under the scarf, subtle and premium, adding a luxury campaign detail."},{"type":"obj","desc":"In the lower foreground, place a wide horizontal luxury nameplate on the floor in front of the cat. The nameplate is low, flat, landscape-oriented, much wider than tall, like a fashion show seat card or premium display plaque. It is centered, front-facing, level, and fully visible. It must not become vertical, tall, standing, rotated, or side-facing."},{"type":"text","desc":"Print the exact text ideogram4.cpp only on the wide horizontal nameplate. Use clean bold black lettering, perfectly spelled, lowercase, with the number 4 and .cpp extension. The text must fit completely inside the nameplate, stay horizontal, and be readable from left to right."},{"type":"obj","desc":"Add sparse premium editorial accents around the edges: thin gold lines, small code brackets, tiny cursor marks, subtle dots, and minimal geometric details. No extra cats, no stickers, no animal faces, no busy decorations."},{"type":"text","desc":"Bottom center footer reading tiny paws, big compile energy in a small refined monospace or editorial font. The footer is horizontal, centered, understated, and much smaller than the nameplate text."}]}}' --diffusion-fa -v --offload-to-cpu -H 1024 -W 1024 .\bin\Release\sd-cli.exe --diffusion-model ideogram4-Q8_0.gguf --uncond-diffusion-model ideogram4_uncond-Q8_0.gguf --llm ..\..\llm\Qwen3VL-8B-Instruct-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors -p '{"high_level_description":"A square 1024 x 1024 luxury fashion magazine cover featuring exactly one short chubby fluffy cat as the main model. The cat sits on a soft ivory studio floor, facing the viewer with a stylish calm expression, wearing tiny black sunglasses, a red silk scarf, and a small gold collar charm. In front of the cat on the floor is a wide horizontal luxury nameplate that clearly reads ideogram4.cpp. The whole design feels premium, fashionable, clean, and editorial.","style_description":{"aesthetics":"luxury fashion magazine cover, high-end pet couture campaign, minimalist editorial design, elegant studio photography, soft paper texture, refined typography, fashionable and polished","lighting":"Soft diffused studio lighting, gentle spotlight on the cat, subtle floor shadow, warm ivory highlights, clean separation between subject and background","photo":"high-resolution fashion editorial photography look, front-facing cat portrait, crisp fur details, glossy sunglasses, clear readable nameplate text, shallow depth of field","medium":"mixed media fashion photography and premium editorial graphic design","color_palette":["#F4EFE7","#111111","#D8B56D","#B73A3A","#FFFFFF","#8A7A6A"]},"compositional_deconstruction":{"canvas":"Square 1024 x 1024 canvas with a normal upright orientation. Do not rotate the poster or any text. Use a clean fashion magazine cover layout.","background":"Warm ivory studio backdrop with subtle paper grain, a soft spotlight gradient, faint floor shadow, and a few minimal gold editorial lines. The background is spacious, premium, and uncluttered.","layout":"Top center has a small elegant headline. Center area features one cat as the main fashion model. Lower foreground has a wide horizontal luxury nameplate placed on the floor in front of the cat. Bottom center has a small footer. All text is horizontal, upright, and readable left to right.","elements":[{"type":"text","desc":"Top center headline reading LOOK WHAT I FOUND in a refined high-fashion serif font. The headline is horizontal, centered, elegant, and secondary to the nameplate text."},{"type":"obj","desc":"Exactly one short chubby fluffy cat sitting in the center like a luxury fashion model. The cat has a large round head, compact body, short legs, soft detailed fur, expressive eyes, and a calm confident pose. The cat is cute and rounded, not tall, not stretched, not duplicated."},{"type":"obj","desc":"Tiny glossy black sunglasses worn naturally by the cat, slightly oversized but still showing the cat face clearly. The sunglasses add a chic fashion-editorial attitude."},{"type":"obj","desc":"A red silk scarf tied neatly around the cat neck, with soft folds and a couture feeling. The scarf must not cover the cat face or the nameplate."},{"type":"obj","desc":"A small gold collar charm or fashion accessory under the scarf, subtle and premium, adding a luxury campaign detail."},{"type":"obj","desc":"In the lower foreground, place a wide horizontal luxury nameplate on the floor in front of the cat. The nameplate is low, flat, landscape-oriented, much wider than tall, like a fashion show seat card or premium display plaque. It is centered, front-facing, level, and fully visible. It must not become vertical, tall, standing, rotated, or side-facing."},{"type":"text","desc":"Print the exact text ideogram4.cpp only on the wide horizontal nameplate. Use clean bold black lettering, perfectly spelled, lowercase, with the number 4 and .cpp extension. The text must fit completely inside the nameplate, stay horizontal, and be readable from left to right."},{"type":"obj","desc":"Add sparse premium editorial accents around the edges: thin gold lines, small code brackets, tiny cursor marks, subtle dots, and minimal geometric details. No extra cats, no stickers, no animal faces, no busy decorations."},{"type":"text","desc":"Bottom center footer reading tiny paws, big compile energy in a small refined monospace or editorial font. The footer is horizontal, centered, understated, and much smaller than the nameplate text."}]}}' --diffusion-fa -v --offload-to-cpu -H 1024 -W 1024
``` ```
<img alt="ideogram4 image example" src="../assets/ideogram4/example.png" /> <img alt="ideogram4 image example" src="../assets/ideogram4/example.png" />

View File

@ -16,7 +16,7 @@ You can run Kontext using stable-diffusion.cpp with a GPU that has 6GB or even 4
You can download the preconverted gguf weights from [FLUX.1-Kontext-dev-GGUF](https://huggingface.co/QuantStack/FLUX.1-Kontext-dev-GGUF), this way you don't have to do the conversion yourself. You can download the preconverted gguf weights from [FLUX.1-Kontext-dev-GGUF](https://huggingface.co/QuantStack/FLUX.1-Kontext-dev-GGUF), this way you don't have to do the conversion yourself.
``` ```
.\bin\Release\sd-cli.exe -M convert -m ..\models\unet\flux1-kontext-dev.safetensors -o ..\models\flux1-kontext-dev-q8_0.gguf -v --type q8_0 .\bin\Release\sd-cli.exe -M convert -m ..\..\ComfyUI\models\unet\flux1-kontext-dev.safetensors -o ..\models\flux1-kontext-dev-q8_0.gguf -v --type q8_0
``` ```
## Run ## Run

View File

@ -21,7 +21,7 @@ Krea2 uses a Krea2 diffusion transformer, the Wan2.1 VAE, and Qwen3-VL 4B as the
### Krea2 ### Krea2
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Krea-2-Raw-Q8_0.gguf --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" --diffusion-fa -v --offload-to-cpu .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Krea-2-Raw-Q8_0.gguf --llm ..\..\ComfyUI\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors -p "a lovely cat holding a sign says 'krea2.cpp'" --diffusion-fa -v --offload-to-cpu
``` ```
<img width="256" alt="Krea2 Raw example" src="../assets/krea2/example.png" /> <img width="256" alt="Krea2 Raw example" src="../assets/krea2/example.png" />

View File

@ -18,7 +18,7 @@ Lens uses a Lens diffusion transformer, the FLUX.2 VAE, and GPT-OSS-20B as the L
### Lens ### Lens
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 5.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\lens_bf16.safetensors --llm "..\..\llm\gpt-oss-20b-UD-Q8_K_XL.gguf" --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --cfg-scale 5.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v
``` ```
<img width="256" alt="Lens example" src="../assets/lens/example.png" /> <img width="256" alt="Lens example" src="../assets/lens/example.png" />
@ -26,7 +26,7 @@ Lens uses a Lens diffusion transformer, the FLUX.2 VAE, and GPT-OSS-20B as the L
### Lens Turbo ### Lens Turbo
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\lens_turbo_bf16.safetensors --llm "..\models\text_encoders\gpt-oss-20b-UD-Q8_K_XL.gguf" --vae ..\models\vae\flux2_ae.safetensors --cfg-scale 1.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v --steps 4 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\lens_turbo_bf16.safetensors --llm "..\..\llm\gpt-oss-20b-UD-Q8_K_XL.gguf" --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --cfg-scale 1.0 -p "A crystal dragon soaring through an aurora borealis sky, its entire body made of transparent faceted crystal refracting the green and purple aurora light into rainbow spectra, ice particles trailing from its wings, high fantasy digital art" --diffusion-fa -v --steps 4
``` ```
<img width="256" alt="Lens Turbo example" src="../assets/lens/turbo_example.png" /> <img width="256" alt="Lens Turbo example" src="../assets/lens/turbo_example.png" />

View File

@ -24,7 +24,7 @@ LongCat uses quoted text for character-level text rendering. Put target text ins
### LongCat Image ### LongCat Image
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\LongCat-Image-Q4_K_M.gguf --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p "a lovely cat holding a sign says 'longcat.cpp'" --cfg-scale 5.0 --sampling-method euler --flow-shift 3 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\LongCat-Image-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p "a lovely cat holding a sign says 'longcat.cpp'" --cfg-scale 5.0 --sampling-method euler --flow-shift 3 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="longcat example" src="../assets/longcat/example.png" /> <img alt="longcat example" src="../assets/longcat/example.png" />

View File

@ -21,7 +21,7 @@
### LTX-2.3 dev T2V ### LTX-2.3 dev T2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "worst quality, low quality, blurry, distorted, artifacts" -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 --fps 24 -o t2v.webm .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\..\ComfyUI\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "worst quality, low quality, blurry, distorted, artifacts" -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 --fps 24 -o t2v.webm
``` ```
<video <video
@ -33,7 +33,7 @@
### LTX-2.3 dev I2V ### LTX-2.3 dev I2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\ernie_image\turbo_example.png -o i2v.webm .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\..\ComfyUI\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\ernie_image\turbo_example.png -o i2v.webm
``` ```
<video <video
@ -45,7 +45,7 @@
### LTX-2.3 dev FLF2V ### LTX-2.3 dev FLF2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "glass flower blossom" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png -o flf2v.webm .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\..\ComfyUI\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors -p "glass flower blossom" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --diffusion-fa --offload-to-cpu --video-frames 33 --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png -o flf2v.webm
``` ```
<video <video
@ -61,7 +61,7 @@ LTX spatial latent upscale runs a model-backed x2 latent upsampler between the l
Put `ltx-2.3-spatial-upscaler-x2-1.1.safetensors` under the directory passed to `--hires-upscalers-dir`, then use the model name without path or extension in `--hires-upscaler`. Put `ltx-2.3-spatial-upscaler-x2-1.1.safetensors` under the directory passed to `--hires-upscalers-dir`, then use the model name without path or extension in `--hires-upscaler`.
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors --hires-upscalers-dir ..\models\latent_upscale_models --hires-upscaler ltx-2.3-spatial-upscaler-x2-1.1 --hires --hires-steps 4 -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 640 -H 360 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\ernie_image\turbo_example.png -o hires_i2v.webm .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\ltx-2.3-22b-dev-UD-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_video_vae.safetensors --audio-vae ..\..\ComfyUI\models\vae\ltx-2.3-22b-dev_audio_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\gemma-3-12b-it-qat-UD-Q4_K_XL.gguf --embeddings-connectors ..\..\ComfyUI\models\text_encoders\ltx-2.3-22b-dev_embeddings_connectors.safetensors --hires-upscalers-dir ..\..\ComfyUI\models\latent_upscale_models --hires-upscaler ltx-2.3-spatial-upscaler-x2-1.1 --hires --hires-steps 4 -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 640 -H 360 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\ernie_image\turbo_example.png -o hires_i2v.webm
``` ```
By default, the hires refine pass uses the main sampler and scheduler, then trims the second-pass sigma schedule by `--hires-denoising-strength` (`0.7` by default). To reproduce a ComfyUI-style explicit refine schedule, pass custom hires sigmas: By default, the hires refine pass uses the main sampler and scheduler, then trims the second-pass sigma schedule by `--hires-denoising-strength` (`0.7` by default). To reproduce a ComfyUI-style explicit refine schedule, pass custom hires sigmas:

View File

@ -13,7 +13,7 @@
## Examples ## Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ovis_image-Q4_0.gguf --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\ovis_2.5.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa .\bin\Release\sd-cli.exe --diffusion-model ovis_image-Q4_0.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\ovis_2.5.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa
``` ```
<img alt="ovis image example" src="../assets/ovis_image/example.png" /> <img alt="ovis image example" src="../assets/ovis_image/example.png" />

View File

@ -22,7 +22,7 @@ The official PiD model card should be checked before use. At the time of the ini
## Examples ## Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\pid_flux1_512_to_2048_4step_bf16.safetensors --llm "..\models\text_encoders\gemma_2_2b_it_elm_bf16.safetensors" --vae ..\models\vae\ae.sft --vae-format flux --cfg-scale 1.0 -p "a lovely cat" -r ..\assets\ernie_image\turbo_example.png --diffusion-fa -v --steps 4 -H 2048 -W 2048 --rng cpu .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\pid_flux1_512_to_2048_4step_bf16.safetensors --llm "..\..\ComfyUI\models\text_encoders\gemma_2_2b_it_elm_bf16.safetensors" --vae ..\..\ComfyUI\models\vae\ae.sft --vae-format flux --cfg-scale 1.0 -p "a lovely cat" -r ..\assets\ernie_image\turbo_example.png --diffusion-fa -v --steps 4 -H 2048 -W 2048 --rng cpu
``` ```
Before: Before:

View File

@ -52,7 +52,7 @@ to a `.pulidembd` binary file (about 131 KB). Run it once per source
person; the same file is reused for any number of generations. person; the same file is reused for any number of generations.
A reference Python script is provided alongside this docs file at A reference Python script is provided alongside this docs file at
[`scripts/pulid_extract_id.py`](../scripts/pulid_extract_id.py). It [`script/pulid_extract_id.py`](../script/pulid_extract_id.py). It
requires: requires:
- A working CUDA / CPU PyTorch stack - A working CUDA / CPU PyTorch stack
- `insightface`, `facexlib`, `eva-clip`, `torchvision`, `opencv-python`, - `insightface`, `facexlib`, `eva-clip`, `torchvision`, `opencv-python`,

View File

@ -14,7 +14,7 @@
## Examples ## Examples
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\qwen-image-Q8_0.gguf --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p '一个穿着"QWEN"标志的T恤的中国美女正拿着黑色的马克笔面相镜头微笑。她身后的玻璃板上手写体写着 “一、Qwen-Image的技术路线 探索视觉生成基础模型的极限开创理解与生成一体化的未来。二、Qwen-Image的模型特色1、复杂文字渲染。支持中英渲染、自动布局 2、精准图像编辑。支持文字编辑、物体增减、风格变换。三、Qwen-Image的未来愿景赋能专业内容创作、助力生成式AI发展。”' --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu -H 1024 -W 1024 --diffusion-fa --flow-shift 3 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\qwen-image-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p '一个穿着"QWEN"标志的T恤的中国美女正拿着黑色的马克笔面相镜头微笑。她身后的玻璃板上手写体写着 “一、Qwen-Image的技术路线 探索视觉生成基础模型的极限开创理解与生成一体化的未来。二、Qwen-Image的模型特色1、复杂文字渲染。支持中英渲染、自动布局 2、精准图像编辑。支持文字编辑、物体增减、风格变换。三、Qwen-Image的未来愿景赋能专业内容创作、助力生成式AI发展。”' --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu -H 1024 -W 1024 --diffusion-fa --flow-shift 3
``` ```
<img alt="qwen example" src="../assets/qwen/example.png" /> <img alt="qwen example" src="../assets/qwen/example.png" />

View File

@ -23,7 +23,7 @@
### Qwen Image Edit ### Qwen Image Edit
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Qwen_Image_Edit-Q8_0.gguf --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --seed 1118877715456453 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen_Image_Edit-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --seed 1118877715456453
``` ```
<img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" /> <img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" />
@ -32,7 +32,7 @@
### Qwen Image Edit 2509 ### Qwen Image Edit 2509
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Qwen-Image-Edit-2509-Q4_K_S.gguf --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf --llm_vision ..\models\text_encoders\Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'Qwen Image Edit 2509'" .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen-Image-Edit-2509-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf --llm_vision ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'Qwen Image Edit 2509'"
``` ```
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" /> <img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" />
@ -42,7 +42,7 @@
To use the new Qwen Image Edit 2511 mode, the `--qwen-image-zero-cond-t` flag must be enabled; otherwise, image editing quality will degrade significantly. To use the new Qwen Image Edit 2511 mode, the `--qwen-image-zero-cond-t` flag must be enabled; otherwise, image editing quality will degrade significantly.
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\qwen-image-edit-2511-Q4_K_M.gguf --vae ..\models\vae\qwen_image_vae.safetensors --llm ..\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --qwen-image-zero-cond-t .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\qwen-image-edit-2511-Q4_K_M.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --qwen-image-zero-cond-t
``` ```
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2511.png" /> <img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2511.png" />

View File

@ -13,8 +13,8 @@ The SeFi-Image family ships in three scales (1B / 2B / 5B) and three families (B
Convert the transformer and text encoder to sd.cpp safetensors: Convert the transformer and text encoder to sd.cpp safetensors:
```bash ```bash
python3 scripts/convert_sefi.py <hf_repo_dir> <out_dir>/sefi_<scale>_<family>.safetensors python3 script/convert_sefi.py <hf_repo_dir> <out_dir>/sefi_<scale>_<family>.safetensors
python3 scripts/convert_qwen3_vl.py <hf_repo_dir>/Qwen3-VL-XB-Instruct <out_dir>/qwen3_vl_<X>b.safetensors python3 script/convert_qwen3_vl.py <hf_repo_dir>/Qwen3-VL-XB-Instruct <out_dir>/qwen3_vl_<X>b.safetensors
``` ```
## Variant defaults ## Variant defaults

View File

@ -55,7 +55,7 @@
### Wan2.1 T2V 1.3B ### Wan2.1 T2V 1.3B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1_t2v_1.3B_fp16.safetensors --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 33 --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1_t2v_1.3B_fp16.safetensors --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 33 --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.1_1.3B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_1.3B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -63,7 +63,7 @@
### Wan2.1 T2V 14B ### Wan2.1 T2V 14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-t2v-14b-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-t2v-14b-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.1_14B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_14B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -73,7 +73,7 @@
### Wan2.1 I2V 14B ### Wan2.1 I2V 14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-i2v-14b-480p-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --clip_vision ..\models\clip_vision\clip_vision_h.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-i2v-14b-480p-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --clip_vision ..\..\ComfyUI\models\clip_vision\clip_vision_h.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.1_14B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_14B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -81,7 +81,7 @@
### Wan2.2 T2V A14B ### Wan2.2 T2V A14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_14B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_14B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -89,7 +89,7 @@
### Wan2.2 I2V A14B ### Wan2.2 I2V A14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-I2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-I2V-A14B-HighNoise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --offload-to-cpu -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-I2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-I2V-A14B-HighNoise-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --video-frames 33 --offload-to-cpu -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_14B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_14B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -97,7 +97,7 @@
### Wan2.2 T2V A14B T2I ### Wan2.2 T2V A14B T2I
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --flow-shift 3.0
``` ```
<img width="832" height="480" alt="Wan2 2_14B_t2i" src="../assets/wan/Wan2.2_14B_t2i.png" /> <img width="832" height="480" alt="Wan2 2_14B_t2i" src="../assets/wan/Wan2.2_14B_t2i.png" />
@ -105,7 +105,7 @@
### Wan2.2 T2V 14B with Lora ### Wan2.2 T2V 14B with Lora
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat<lora:wan2.2_t2v_lightx2v_4steps_lora_v1.1_low_noise:1><lora:|high_noise|wan2.2_t2v_lightx2v_4steps_lora_v1.1_high_noise:1>" --cfg-scale 3.5 --sampling-method euler --steps 4 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 4 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --lora-model-dir ..\models\loras --video-frames 33 --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-T2V-A14B-HighNoise-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat<lora:wan2.2_t2v_lightx2v_4steps_lora_v1.1_low_noise:1><lora:|high_noise|wan2.2_t2v_lightx2v_4steps_lora_v1.1_high_noise:1>" --cfg-scale 3.5 --sampling-method euler --steps 4 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 4 -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 832 -H 480 --diffusion-fa --offload-to-cpu --lora-model-dir ..\..\ComfyUI\models\loras --video-frames 33 --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_14B_t2v_lora.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_14B_t2v_lora.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -117,7 +117,7 @@
#### T2V #### T2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.2_ti2v_5B_fp16.safetensors --vae ..\models\vae\wan2.2_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.2_ti2v_5B_fp16.safetensors --vae ..\..\ComfyUI\models\vae\wan2.2_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --offload-to-cpu --video-frames 33 --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_5B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_5B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -125,7 +125,7 @@
#### I2V #### I2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.2_ti2v_5B_fp16.safetensors --vae ..\models\vae\wan2.2_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.2_ti2v_5B_fp16.safetensors --vae ..\..\ComfyUI\models\vae\wan2.2_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --offload-to-cpu --video-frames 33 -i ..\assets\cat_with_sd_cpp_42.png --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_5B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_5B_i2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -133,7 +133,7 @@
### Wan2.1 FLF2V 14B ### Wan2.1 FLF2V 14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-flf2v-14b-720p-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --clip_vision ..\models\clip_vision\clip_vision_h.safetensors -p "glass flower blossom" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-flf2v-14b-720p-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --clip_vision ..\..\ComfyUI\models\clip_vision\clip_vision_h.safetensors -p "glass flower blossom" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png --flow-shift 3.0
``` ```
@ -142,7 +142,7 @@
### Wan2.2 FLF2V 14B ### Wan2.2 FLF2V 14B
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-I2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-I2V-A14B-HighNoise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -p "glass flower blossom" -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png --flow-shift 3.0 .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-I2V-A14B-LowNoise-Q8_0.gguf --high-noise-diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.2-I2V-A14B-HighNoise-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -p "glass flower blossom" -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部畸形的毁容的形态畸形的肢体手指融合静止不动的画面杂乱的背景三条腿背景人很多倒着走" -W 480 -H 832 --diffusion-fa --video-frames 33 --offload-to-cpu --init-img ..\..\ComfyUI\input\start_image.png --end-img ..\..\ComfyUI\input\end_image.png --flow-shift 3.0
``` ```
<video src=../assets/wan/Wan2.2_14B_flf2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.2_14B_flf2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -152,7 +152,7 @@
#### T2V #### T2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 1 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 1 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_1.3B_vace_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_1.3B_vace_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -161,7 +161,7 @@
#### R2V #### R2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa -i ..\assets\cat_with_sd_cpp_42.png --video-frames 33 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa -i ..\assets\cat_with_sd_cpp_42.png --video-frames 33 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_1.3B_vace_r2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_1.3B_vace_r2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -172,7 +172,7 @@
``` ```
mkdir post+depth mkdir post+depth
ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\frame_%04d.jpg ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\frame_%04d.jpg
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "The girl is dancing in a sea of flowers, slowly moving her hands. There is a close - up shot of her upper body. The character is surrounded by other transparent glass flowers in the style of Nicoletta Ceccoli, creating a beautiful, surreal, and emotionally expressive movie scene with a white. transparent feel and a dreamyl atmosphere." --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 480 -H 832 --diffusion-fa -i ..\..\ComfyUI\input\dance_girl.jpg --control-video ./post+depth --video-frames 33 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\wan2.1-vace-1.3b-q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "The girl is dancing in a sea of flowers, slowly moving her hands. There is a close - up shot of her upper body. The character is surrounded by other transparent glass flowers in the style of Nicoletta Ceccoli, creating a beautiful, surreal, and emotionally expressive movie scene with a white. transparent feel and a dreamyl atmosphere." --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 480 -H 832 --diffusion-fa -i ..\..\ComfyUI\input\dance_girl.jpg --control-video ./post+depth --video-frames 33 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_1.3B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_1.3B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -182,7 +182,7 @@ ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\fr
#### T2V #### T2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 33 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa --video-frames 33 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_14B_vace_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_14B_vace_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -191,7 +191,7 @@ ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\fr
#### R2V #### R2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa -i ..\assets\cat_with_sd_cpp_42.png --video-frames 33 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa -i ..\assets\cat_with_sd_cpp_42.png --video-frames 33 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_14B_vace_r2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_14B_vace_r2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
@ -201,7 +201,7 @@ ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\fr
#### V2V #### V2V
``` ```
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "The girl is dancing in a sea of flowers, slowly moving her hands. There is a close - up shot of her upper body. The character is surrounded by other transparent glass flowers in the style of Nicoletta Ceccoli, creating a beautiful, surreal, and emotionally expressive movie scene with a white. transparent feel and a dreamyl atmosphere." --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 480 -H 832 --diffusion-fa -i ..\..\ComfyUI\input\dance_girl.jpg --control-video ./post+depth --video-frames 33 --offload-to-cpu .\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\..\ComfyUI\models\diffusion_models\Wan2.1_14B_VACE-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\wan_2.1_vae.safetensors --t5xxl ..\..\ComfyUI\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "The girl is dancing in a sea of flowers, slowly moving her hands. There is a close - up shot of her upper body. The character is surrounded by other transparent glass flowers in the style of Nicoletta Ceccoli, creating a beautiful, surreal, and emotionally expressive movie scene with a white. transparent feel and a dreamyl atmosphere." --cfg-scale 6.0 --sampling-method euler -v -n "色调艳丽过曝静态细节模糊不清字幕风格作品画作画面静止整体发灰最差质量低质量JPEG压缩残留丑陋的残缺的多余的手指画得不好的手部画得不好的脸部 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 480 -H 832 --diffusion-fa -i ..\..\ComfyUI\input\dance_girl.jpg --control-video ./post+depth --video-frames 33 --offload-to-cpu
``` ```
<video src=../assets/wan/Wan2.1_14B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video> <video src=../assets/wan/Wan2.1_14B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>

View File

@ -21,7 +21,7 @@ You can run Z-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — or ev
### Z-Image-Turbo ### Z-Image-Turbo
``` ```
.\bin\Release\sd-cli.exe --diffusion-model z_image_turbo-Q3_K.gguf --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\Qwen3-4B-Instruct-2507-Q4_K_M.gguf -p "A cinematic, melancholic photograph of a solitary hooded figure walking through a sprawling, rain-slicked metropolis at night. The city lights are a chaotic blur of neon orange and cool blue, reflecting on the wet asphalt. The scene evokes a sense of being a single component in a vast machine. Superimposed over the image in a sleek, modern, slightly glitched font is the philosophical quote: 'THE CITY IS A CIRCUIT BOARD, AND I AM A BROKEN TRANSISTOR.' -- moody, atmospheric, profound, dark academic" --cfg-scale 1.0 -v --offload-to-cpu --diffusion-fa -H 1024 -W 512 --steps 8 .\bin\Release\sd-cli.exe --diffusion-model z_image_turbo-Q3_K.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\Qwen3-4B-Instruct-2507-Q4_K_M.gguf -p "A cinematic, melancholic photograph of a solitary hooded figure walking through a sprawling, rain-slicked metropolis at night. The city lights are a chaotic blur of neon orange and cool blue, reflecting on the wet asphalt. The scene evokes a sense of being a single component in a vast machine. Superimposed over the image in a sleek, modern, slightly glitched font is the philosophical quote: 'THE CITY IS A CIRCUIT BOARD, AND I AM A BROKEN TRANSISTOR.' -- moody, atmospheric, profound, dark academic" --cfg-scale 1.0 -v --offload-to-cpu --diffusion-fa -H 1024 -W 512 --steps 8
``` ```
<img width="256" alt="z-image example" src="../assets/z_image/q3_K.png" /> <img width="256" alt="z-image example" src="../assets/z_image/q3_K.png" />
@ -29,7 +29,7 @@ You can run Z-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — or ev
### Z-Image-Base ### Z-Image-Base
``` ```
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\z_image_bf16.safetensors --vae ..\models\vae\ae.sft --llm ..\models\text_encoders\qwen_3_4b.safetensors -p "A cinematic, melancholic photograph of a solitary hooded figure walking through a sprawling, rain-slicked metropolis at night. The city lights are a chaotic blur of neon orange and cool blue, reflecting on the wet asphalt. The scene evokes a sense of being a single component in a vast machine. Superimposed over the image in a sleek, modern, slightly glitched font is the philosophical quote: 'THE CITY IS A CIRCUIT BOARD, AND I AM A BROKEN TRANSISTOR.' -- moody, atmospheric, profound, dark academic" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa -H 1024 -W 512 .\bin\Release\sd-cli.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\z_image_bf16.safetensors --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\qwen_3_4b.safetensors -p "A cinematic, melancholic photograph of a solitary hooded figure walking through a sprawling, rain-slicked metropolis at night. The city lights are a chaotic blur of neon orange and cool blue, reflecting on the wet asphalt. The scene evokes a sense of being a single component in a vast machine. Superimposed over the image in a sleek, modern, slightly glitched font is the philosophical quote: 'THE CITY IS A CIRCUIT BOARD, AND I AM A BROKEN TRANSISTOR.' -- moody, atmospheric, profound, dark academic" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa -H 1024 -W 512
``` ```
<img width="256" alt="z-image example" src="../assets/z_image/base_bf16.png" /> <img width="256" alt="z-image example" src="../assets/z_image/base_bf16.png" />

View File

@ -653,8 +653,7 @@ int main(int argc, const char* argv[]) {
cli_params.output_path.c_str(), cli_params.output_path.c_str(),
ctx_params.wtype, ctx_params.wtype,
ctx_params.tensor_type_rules.c_str(), ctx_params.tensor_type_rules.c_str(),
cli_params.convert_name, cli_params.convert_name);
ctx_params.n_threads);
if (!success) { if (!success) {
LOG_ERROR("convert '%s'/'%s' to '%s' failed", LOG_ERROR("convert '%s'/'%s' to '%s' failed",
ctx_params.model_path.c_str(), ctx_params.model_path.c_str(),

View File

@ -1106,7 +1106,7 @@ ArgOptions SDGenerationParams::get_options() {
&sample_params.guidance.slg.layer_end}, &sample_params.guidance.slg.layer_end},
{"", {"",
"--eta", "--eta",
"noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and res_2s; 1 for euler_a, er_sde, dpm++2s_a, dpm++2m_sde and dpm++2m_sde_bt)", "noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and res_2s; 1 for euler_a, er_sde and dpm++2s_a)",
&sample_params.eta}, &sample_params.eta},
{"", {"",
"--flow-shift", "--flow-shift",
@ -1138,7 +1138,7 @@ ArgOptions SDGenerationParams::get_options() {
&high_noise_sample_params.guidance.slg.layer_end}, &high_noise_sample_params.guidance.slg.layer_end},
{"", {"",
"--high-noise-eta", "--high-noise-eta",
"(high noise) noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and res_2s; 1 for euler_a, er_sde, dpm++2s_a, dpm++2m_sde and dpm++2m_sde_bt)", "(high noise) noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and res_2s; 1 for euler_a, er_sde and dpm++2s_a)",
&high_noise_sample_params.eta}, &high_noise_sample_params.eta},
{"", {"",
"--strength", "--strength",
@ -1509,12 +1509,12 @@ ArgOptions SDGenerationParams::get_options() {
on_seed_arg}, on_seed_arg},
{"", {"",
"--sampling-method", "--sampling-method",
"sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, dpm++2m_sde, dpm++2m_sde_bt, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]" "sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]"
"(default: euler for Flux/SD3/Wan, euler_a otherwise)", "(default: euler for Flux/SD3/Wan, euler_a otherwise)",
on_sample_method_arg}, on_sample_method_arg},
{"", {"",
"--high-noise-sampling-method", "--high-noise-sampling-method",
"(high noise) sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, dpm++2m_sde, dpm++2m_sde_bt, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]" "(high noise) sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]"
" default: euler for Flux/SD3/Wan, euler_a otherwise", " default: euler for Flux/SD3/Wan, euler_a otherwise",
on_high_noise_sample_method_arg}, on_high_noise_sample_method_arg},
{"", {"",

View File

@ -63,10 +63,6 @@ static enum sample_method_t get_sdapi_sample_method(std::string name) {
{"ddim", DDIM_TRAILING_SAMPLE_METHOD}, {"ddim", DDIM_TRAILING_SAMPLE_METHOD},
{"dpm++ 2m", DPMPP2M_SAMPLE_METHOD}, {"dpm++ 2m", DPMPP2M_SAMPLE_METHOD},
{"k_dpmpp_2m", DPMPP2M_SAMPLE_METHOD}, {"k_dpmpp_2m", DPMPP2M_SAMPLE_METHOD},
{"dpm++ 2m sde", DPMPP2M_SDE_SAMPLE_METHOD},
{"k_dpmpp_2m_sde", DPMPP2M_SDE_SAMPLE_METHOD},
{"dpm++ 2m sde gpu", DPMPP2M_SDE_BT_SAMPLE_METHOD},
{"k_dpmpp_2m_sde_gpu", DPMPP2M_SDE_BT_SAMPLE_METHOD},
{"res multistep", RES_MULTISTEP_SAMPLE_METHOD}, {"res multistep", RES_MULTISTEP_SAMPLE_METHOD},
{"k_res_multistep", RES_MULTISTEP_SAMPLE_METHOD}, {"k_res_multistep", RES_MULTISTEP_SAMPLE_METHOD},
{"res 2s", RES_2S_SAMPLE_METHOD}, {"res 2s", RES_2S_SAMPLE_METHOD},
@ -263,48 +259,6 @@ static bool build_sdapi_img_gen_request(const json& j,
return true; return true;
} }
static nlohmann::json prepare_info_field(const SDContextParams& ctx_params,
const SDGenerationParams& gen_params,
bool img2img) {
nlohmann::json jsoninfo = nlohmann::json::object();
jsoninfo["prompt"] = gen_params.prompt;
if (!gen_params.negative_prompt.empty()) {
jsoninfo["negative_prompt"] = gen_params.negative_prompt;
}
jsoninfo["seed"] = gen_params.seed;
jsoninfo["cfg_scale"] = gen_params.sample_params.guidance.txt_cfg;
jsoninfo["width"] = gen_params.get_resolved_width();
jsoninfo["height"] = gen_params.get_resolved_height();
jsoninfo["steps"] = gen_params.sample_params.sample_steps;
jsoninfo["sampler_name"] = sd_sample_method_name(gen_params.sample_params.sample_method);
if (gen_params.clip_skip != -1) {
jsoninfo["clip_skip"] = gen_params.clip_skip;
}
if (gen_params.sample_params.scheduler != scheduler_t::SCHEDULER_COUNT) {
jsoninfo["extra_generation_params"] = nlohmann::json::object();
jsoninfo["extra_generation_params"]["Schedule type"] = sd_scheduler_name(gen_params.sample_params.scheduler);
}
if (img2img) {
jsoninfo["denoising_strength"] = gen_params.strength;
}
// not clear what should happen if we have both model and diffusion_model
if (!ctx_params.diffusion_model_path.empty()) {
jsoninfo["sd_model_name"] = sd_basename(ctx_params.diffusion_model_path);
} else if (!ctx_params.model_path.empty()) {
jsoninfo["sd_model_name"] = sd_basename(ctx_params.model_path);
}
if (!ctx_params.vae_path.empty()) {
jsoninfo["sd_vae_name"] = sd_basename(ctx_params.vae_path);
}
jsoninfo["version"] = "stable-diffusion.cpp";
jsoninfo["infotexts"] = nlohmann::json::array();
jsoninfo["all_prompts"] = nlohmann::json::array();
jsoninfo["all_negative_prompts"] = nlohmann::json::array();
jsoninfo["all_seeds"] = nlohmann::json::array();
return jsoninfo;
}
void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) { void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
ServerRuntime* runtime = &rt; ServerRuntime* runtime = &rt;
@ -355,7 +309,7 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
json out; json out;
out["images"] = json::array(); out["images"] = json::array();
out["parameters"] = j; out["parameters"] = j;
json jsoninfo = prepare_info_field(*runtime->ctx_params, request.gen_params, img2img); out["info"] = "";
int images_per_batch = request.gen_params.batch_count > 0 ? std::max(1, num_results / request.gen_params.batch_count) : 1; int images_per_batch = request.gen_params.batch_count > 0 ? std::max(1, num_results / request.gen_params.batch_count) : 1;
for (int i = 0; i < num_results; ++i) { for (int i = 0; i < num_results; ++i) {
@ -363,18 +317,17 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
continue; continue;
} }
bool embed_meta = request.gen_params.embed_image_metadata; std::string params = request.gen_params.embed_image_metadata
? get_image_params(*runtime->ctx_params,
std::string params = get_image_params(*runtime->ctx_params, request.gen_params,
request.gen_params, request.gen_params.seed + i / images_per_batch)
request.gen_params.seed + i / images_per_batch); : "";
auto image_bytes = encode_image_to_vector(EncodedImageFormat::PNG,
auto image_bytes = encode_image_to_vector(EncodedImageFormat::PNG, results[i].data,
results[i].data, results[i].width,
results[i].width, results[i].height,
results[i].height, results[i].channel,
results[i].channel, params);
embed_meta ? params : "");
if (image_bytes.empty()) { if (image_bytes.empty()) {
LOG_ERROR("write image to mem failed"); LOG_ERROR("write image to mem failed");
@ -382,16 +335,8 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
} }
out["images"].push_back(base64_encode(image_bytes)); out["images"].push_back(base64_encode(image_bytes));
jsoninfo["infotexts"][i] = params;
jsoninfo["all_seeds"][i] = request.gen_params.seed + i;
jsoninfo["all_prompts"][i] = request.gen_params.prompt;
jsoninfo["all_negative_prompts"][i] = request.gen_params.negative_prompt;
} }
// not a mistake: it is supposed to be a string in json format
out["info"] = jsoninfo.dump();
res.set_content(out.dump(), "application/json"); res.set_content(out.dump(), "application/json");
res.status = 200; res.status = 200;

View File

@ -31,30 +31,24 @@ $patterns = @(
"examples/common/*.cpp" "examples/common/*.cpp"
) )
Push-Location (Join-Path $PSScriptRoot "..") $root = (Get-Location).Path
try { foreach ($pattern in $patterns) {
$root = (Get-Location).Path $files = Get-ChildItem -Path $pattern -File -ErrorAction SilentlyContinue | Sort-Object FullName
foreach ($pattern in $patterns) { foreach ($file in $files) {
$files = Get-ChildItem -Path $pattern -File -ErrorAction SilentlyContinue | Sort-Object FullName $relativePath = $file.FullName.Substring($root.Length).TrimStart('\', '/') -replace '\\', '/'
foreach ($file in $files) { if ($relativePath -like "vocab*") {
$relativePath = $file.FullName.Substring($root.Length).TrimStart('\', '/') -replace '\\', '/' continue
if ($relativePath -like "vocab*") {
continue
}
Write-Host "formatting '$relativePath'"
# if ($relativePath -ne "stable-diffusion.h") {
# clang-tidy -fix -p build_linux/ "$relativePath"
# }
& clang-format -style=file -i $relativePath
} }
Write-Host "formatting '$relativePath'"
# if ($relativePath -ne "stable-diffusion.h") {
# clang-tidy -fix -p build_linux/ "$relativePath"
# }
& clang-format -style=file -i $relativePath
} }
} finally {
Pop-Location
} }

View File

@ -1,10 +1,3 @@
#!/usr/bin/env bash
set -e
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
cd "$repo_root"
for f in src/*.cpp src/*.h src/*.hpp \ for f in src/*.cpp src/*.h src/*.hpp \
src/conditioning/*.cpp src/conditioning/*.h src/conditioning/*.hpp \ src/conditioning/*.cpp src/conditioning/*.h src/conditioning/*.hpp \
src/core/*.cpp src/core/*.h src/core/*.hpp \ src/core/*.cpp src/core/*.h src/core/*.hpp \

View File

@ -54,8 +54,6 @@ enum sample_method_t {
EULER_CFG_PP_SAMPLE_METHOD, EULER_CFG_PP_SAMPLE_METHOD,
EULER_A_CFG_PP_SAMPLE_METHOD, EULER_A_CFG_PP_SAMPLE_METHOD,
EULER_GE_SAMPLE_METHOD, EULER_GE_SAMPLE_METHOD,
DPMPP2M_SDE_SAMPLE_METHOD,
DPMPP2M_SDE_BT_SAMPLE_METHOD,
SAMPLE_METHOD_COUNT SAMPLE_METHOD_COUNT
}; };
@ -521,8 +519,7 @@ SD_API bool convert_with_components(const char* model_path,
const char* output_path, const char* output_path,
enum sd_type_t output_type, enum sd_type_t output_type,
const char* tensor_type_rules, const char* tensor_type_rules,
bool convert_name, bool convert_name);
int n_threads);
SD_API bool preprocess_canny(sd_image_t image, SD_API bool preprocess_canny(sd_image_t image,
float high_threshold, float high_threshold,

View File

@ -9,7 +9,7 @@ the text side; the vision side is converted by sd.cpp's own
Operates on raw safetensors bytes so any dtype (BF16/F16/F32) is preserved. Operates on raw safetensors bytes so any dtype (BF16/F16/F32) is preserved.
Usage: Usage:
python3 scripts/convert_qwen3_vl.py <hf_qwen3_vl_dir_or_safetensors> <output.safetensors> python3 script/convert_qwen3_vl.py <hf_qwen3_vl_dir_or_safetensors> <output.safetensors>
""" """
import argparse import argparse

View File

@ -5,7 +5,7 @@ Operates on raw safetensors bytes so any dtype (BF16, F32, ...) is preserved exa
No numpy or torch dependency required. No numpy or torch dependency required.
Usage: Usage:
python3 scripts/convert_sefi.py <sefi_diffusers_dir> <output.safetensors> python3 script/convert_sefi.py <sefi_diffusers_dir> <output.safetensors>
""" """
import argparse import argparse

View File

@ -13,7 +13,7 @@ packaging quirks):
- numpy, Pillow - numpy, Pillow
Usage: Usage:
python scripts/pulid_extract_id.py \\ python script/pulid_extract_id.py \\
--portrait /path/to/source-photo.jpg \\ --portrait /path/to/source-photo.jpg \\
--pulid-weights /path/to/pulid_flux_v0.9.1.safetensors \\ --pulid-weights /path/to/pulid_flux_v0.9.1.safetensors \\
--out /path/to/source.pulidembd --out /path/to/source.pulidembd

View File

@ -1,33 +1,14 @@
#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstring> #include <cstring>
#include <exception>
#include <fstream>
#include <memory>
#include <mutex> #include <mutex>
#include <regex> #include <regex>
#include <string>
#include <thread>
#include <vector> #include <vector>
#include "core/util.h"
#include "model_io/gguf_io.h" #include "model_io/gguf_io.h"
#include "model_io/safetensors_io.h" #include "model_io/safetensors_io.h"
#include "model_io/streaming_writer.h"
#include "model_loader.h" #include "model_loader.h"
#include "util.h"
struct TensorExportInfo { #include "ggml_extend_backend.h"
TensorStorage storage;
ggml_type type;
};
struct TensorExportJob {
TensorExportInfo info;
std::vector<uint8_t> data;
std::string error;
bool success = false;
};
static ggml_type get_export_tensor_type(ModelLoader& model_loader, static ggml_type get_export_tensor_type(ModelLoader& model_loader,
const TensorStorage& tensor_storage, const TensorStorage& tensor_storage,
@ -52,262 +33,47 @@ static ggml_type get_export_tensor_type(ModelLoader& model_loader,
return tensor_type; return tensor_type;
} }
static bool collect_tensors_for_export(ModelLoader& model_loader, static bool load_tensors_for_export(ModelLoader& model_loader,
ggml_type type, ggml_context* ggml_ctx,
const TensorTypeRules& tensor_type_rules, ggml_type type,
std::vector<TensorExportInfo>& tensors) { const TensorTypeRules& tensor_type_rules,
tensors.clear(); std::vector<TensorWriteInfo>& tensors) {
tensors.reserve(model_loader.get_tensor_storage_map().size()); std::mutex tensor_mutex;
for (const auto& kv : model_loader.get_tensor_storage_map()) { auto on_new_tensor_cb = [&](const TensorStorage& tensor_storage, ggml_tensor** dst_tensor) -> bool {
const TensorStorage& tensor_storage = kv.second; const std::string& name = tensor_storage.name;
TensorExportInfo info; ggml_type tensor_type = get_export_tensor_type(model_loader, tensor_storage, type, tensor_type_rules);
info.storage = tensor_storage;
info.type = get_export_tensor_type(model_loader, tensor_storage, type, tensor_type_rules);
tensors.push_back(std::move(info));
}
LOG_INFO("collected %zu tensors for export", tensors.size());
return true;
}
static size_t export_tensor_nbytes(const TensorExportInfo& info) { std::lock_guard<std::mutex> lock(tensor_mutex);
TensorStorage output_storage = info.storage; ggml_tensor* tensor = ggml_new_tensor(ggml_ctx, tensor_type, tensor_storage.n_dims, tensor_storage.ne);
output_storage.type = info.type; if (tensor == nullptr) {
return static_cast<size_t>(output_storage.nbytes()); LOG_ERROR("ggml_new_tensor failed");
}
static TensorWritePlan tensor_write_plan_from_export_info(const TensorExportInfo& info) {
TensorWritePlan plan;
plan.name = info.storage.name;
plan.type = info.type;
plan.n_dims = info.storage.n_dims;
for (int i = 0; i < SD_MAX_DIMS; i++) {
plan.ne[i] = info.storage.ne[i];
}
return plan;
}
static std::vector<TensorWritePlan> tensor_write_plans_from_export_infos(const std::vector<TensorExportInfo>& tensors) {
std::vector<TensorWritePlan> plans;
plans.reserve(tensors.size());
for (const TensorExportInfo& info : tensors) {
plans.push_back(tensor_write_plan_from_export_info(info));
}
return plans;
}
static bool preallocate_output_file(const std::string& output_path, uint64_t file_size, std::string* error) {
if (file_size == 0) {
return true;
}
std::fstream file(output_path, std::ios::binary | std::ios::in | std::ios::out);
if (!file.is_open()) {
if (error != nullptr) {
*error = "failed to open output file '" + output_path + "' for preallocation";
}
return false;
}
// This portable fallback sets the final file size. A platform-specific
// posix_fallocate/ftruncate path can replace it later.
file.seekp(static_cast<std::streamoff>(file_size - 1), std::ios::beg);
file.put('\0');
file.flush();
if (!file) {
if (error != nullptr) {
*error = "failed to preallocate output file '" + output_path + "'";
}
return false;
}
return true;
}
static bool load_tensor_for_export(ModelLoader& model_loader, TensorExportJob& job) {
size_t mem_size = 1 * 1024 * 1024;
mem_size += ggml_tensor_overhead();
TensorStorage output_storage = job.info.storage;
output_storage.type = job.info.type;
mem_size += static_cast<size_t>(output_storage.nbytes());
ggml_context* ggml_ctx = ggml_init({mem_size, nullptr, false});
if (ggml_ctx == nullptr) {
job.error = "ggml_init failed for tensor '" + job.info.storage.name + "'";
return false;
}
ggml_tensor* tensor = ggml_new_tensor(ggml_ctx, job.info.type, job.info.storage.n_dims, job.info.storage.ne);
if (tensor == nullptr) {
ggml_free(ggml_ctx);
job.error = "ggml_new_tensor failed for tensor '" + job.info.storage.name + "'";
return false;
}
ggml_set_name(tensor, job.info.storage.name.c_str());
const size_t tensor_nbytes = ggml_nbytes(tensor);
if (tensor_nbytes > 0 && !model_loader.load_tensor(job.info.storage, tensor)) {
ggml_free(ggml_ctx);
job.error = "failed to load tensor '" + job.info.storage.name + "'";
return false;
}
job.data.resize(tensor_nbytes);
if (tensor_nbytes > 0) {
memcpy(job.data.data(), tensor->data, tensor_nbytes);
}
ggml_free(ggml_ctx);
return true;
}
static bool stream_tensor_data(ModelLoader& model_loader,
const std::string& output_path,
const std::vector<TensorExportInfo>& tensors,
const StreamingModelWriter& writer,
int n_threads,
std::string* error) {
n_threads = n_threads > 0 ? n_threads : sd_get_num_physical_cores();
n_threads = std::max(1, n_threads);
LOG_INFO("streaming convert with %d threads", n_threads);
int64_t start_time = ggml_time_ms();
uint64_t bytes_written = 0;
size_t tensors_written = 0;
size_t next_tensor_index = 0;
bool failed = false;
std::string failure;
const size_t memory_budget = 1024ull * 1024ull * 1024ull;
size_t reserved_bytes = 0;
std::mutex work_mutex;
std::mutex progress_mutex;
std::condition_variable memory_cv;
std::vector<std::thread> workers;
workers.reserve(n_threads);
auto reserve_memory = [&](size_t bytes) -> bool {
std::unique_lock<std::mutex> lock(work_mutex);
memory_cv.wait(lock, [&]() {
return failed || reserved_bytes == 0 || reserved_bytes + bytes <= memory_budget;
});
if (failed) {
return false; return false;
} }
reserved_bytes += bytes; ggml_set_name(tensor, name.c_str());
if (!tensor->data) {
GGML_ASSERT(ggml_nelements(tensor) == 0);
// Avoid crashing writers by setting a dummy pointer for zero-sized tensors.
LOG_DEBUG("setting dummy pointer for zero-sized tensor %s", name.c_str());
tensor->data = ggml_get_mem_buffer(ggml_ctx);
}
TensorWriteInfo write_info;
write_info.tensor = tensor;
write_info.n_dims = tensor_storage.n_dims;
for (int i = 0; i < tensor_storage.n_dims; ++i) {
write_info.ne[i] = tensor_storage.ne[i];
}
*dst_tensor = tensor;
tensors.push_back(std::move(write_info));
return true; return true;
}; };
auto release_memory = [&](size_t bytes) { bool success = model_loader.load_tensors(on_new_tensor_cb);
{ LOG_INFO("load tensors done");
std::lock_guard<std::mutex> lock(work_mutex); return success;
reserved_bytes -= std::min(reserved_bytes, bytes);
}
memory_cv.notify_all();
};
auto fail = [&](const std::string& message) {
{
std::lock_guard<std::mutex> lock(work_mutex);
if (!failed) {
failed = true;
failure = message;
}
}
memory_cv.notify_all();
};
for (int worker = 0; worker < n_threads; worker++) {
workers.emplace_back([&]() {
std::fstream output_file(output_path, std::ios::binary | std::ios::in | std::ios::out);
if (!output_file.is_open()) {
fail("failed to open output file '" + output_path + "' for tensor writing");
return;
}
while (true) {
size_t tensor_index = 0;
{
std::lock_guard<std::mutex> lock(work_mutex);
if (failed || next_tensor_index >= tensors.size()) {
return;
}
tensor_index = next_tensor_index++;
}
const size_t tensor_bytes = export_tensor_nbytes(tensors[tensor_index]);
if (!reserve_memory(tensor_bytes)) {
return;
}
TensorExportJob job;
job.info = tensors[tensor_index];
try {
job.success = load_tensor_for_export(model_loader, job);
} catch (const std::exception& e) {
job.error = e.what();
job.success = false;
}
if (!job.success) {
release_memory(tensor_bytes);
fail(job.error.empty() ? "streaming conversion failed" : job.error);
return;
}
std::string write_error;
if (!writer.write_tensor(output_file,
tensor_index,
job.data.empty() ? nullptr : job.data.data(),
job.data.size(),
&write_error)) {
release_memory(tensor_bytes);
fail(write_error.empty() ? "streaming conversion write failed" : write_error);
return;
}
{
std::lock_guard<std::mutex> lock(progress_mutex);
bytes_written += job.data.size();
tensors_written++;
float elapsed_seconds = (ggml_time_ms() - start_time) / 1000.0f;
pretty_bytes_progress(static_cast<int>(tensors_written),
static_cast<int>(tensors.size()),
bytes_written,
elapsed_seconds);
}
release_memory(tensor_bytes);
}
});
}
for (auto& worker : workers) {
worker.join();
}
printf("\n");
if (failed) {
if (error != nullptr) {
*error = failure;
}
return false;
}
LOG_INFO("streaming conversion completed, taking %.2fs", (ggml_time_ms() - start_time) / 1000.f);
return true;
}
static bool write_model_file_streaming(ModelLoader& model_loader,
const std::string& output_path,
const std::vector<TensorExportInfo>& tensors,
StreamingModelWriter& writer,
int n_threads,
std::string* error) {
std::vector<TensorWritePlan> plans = tensor_write_plans_from_export_infos(tensors);
if (!writer.write_metadata(output_path, plans, error)) {
return false;
}
if (!preallocate_output_file(output_path, writer.file_size(), error)) {
return false;
}
model_loader.process_model_files(false, false);
return stream_tensor_data(model_loader, output_path, tensors, writer, n_threads, error);
} }
static bool init_convert_path(ModelLoader& model_loader, const char* path, const char* prefix, bool& loaded_any) { static bool init_convert_path(ModelLoader& model_loader, const char* path, const char* prefix, bool& loaded_any) {
@ -325,29 +91,42 @@ static bool init_convert_path(ModelLoader& model_loader, const char* path, const
static bool export_loaded_model(ModelLoader& model_loader, static bool export_loaded_model(ModelLoader& model_loader,
const char* output_path, const char* output_path,
sd_type_t output_type, sd_type_t output_type,
const char* tensor_type_rules, const char* tensor_type_rules) {
int n_threads) {
ggml_type type = sd_type_to_ggml_type(output_type); ggml_type type = sd_type_to_ggml_type(output_type);
bool output_is_safetensors = ends_with(output_path, ".safetensors"); bool output_is_safetensors = ends_with(output_path, ".safetensors");
TensorTypeRules type_rules = parse_tensor_type_rules(tensor_type_rules); TensorTypeRules type_rules = parse_tensor_type_rules(tensor_type_rules);
std::vector<TensorExportInfo> tensors; auto backend = sd_backend_cpu_init();
bool success = collect_tensors_for_export(model_loader, type, type_rules, tensors); size_t mem_size = 1 * 1024 * 1024; // for padding
mem_size += model_loader.get_tensor_storage_map().size() * ggml_tensor_overhead();
mem_size += model_loader.get_params_mem_size(backend, type);
LOG_INFO("model tensors mem size: %.2fMB", mem_size / 1024.f / 1024.f);
ggml_context* ggml_ctx = ggml_init({mem_size, nullptr, false});
if (ggml_ctx == nullptr) {
LOG_ERROR("ggml_init failed for converter");
ggml_backend_free(backend);
return false;
}
std::vector<TensorWriteInfo> tensors;
bool success = load_tensors_for_export(model_loader, ggml_ctx, type, type_rules, tensors);
ggml_backend_free(backend);
std::string error; std::string error;
if (success) { if (success) {
std::unique_ptr<StreamingModelWriter> writer;
if (output_is_safetensors) { if (output_is_safetensors) {
writer = std::make_unique<SafetensorsStreamingWriter>(); success = write_safetensors_file(output_path, tensors, &error);
} else { } else {
writer = std::make_unique<GGUFStreamingWriter>(); success = write_gguf_file(output_path, tensors, &error);
} }
success = write_model_file_streaming(model_loader, output_path, tensors, *writer, n_threads, &error);
} }
if (!success && !error.empty()) { if (!success && !error.empty()) {
LOG_ERROR("%s", error.c_str()); LOG_ERROR("%s", error.c_str());
} }
ggml_free(ggml_ctx);
return success; return success;
} }
@ -360,8 +139,7 @@ bool convert_with_components(const char* model_path,
const char* output_path, const char* output_path,
sd_type_t output_type, sd_type_t output_type,
const char* tensor_type_rules, const char* tensor_type_rules,
bool convert_name, bool convert_name) {
int n_threads) {
ModelLoader model_loader; ModelLoader model_loader;
bool loaded_any = false; bool loaded_any = false;
@ -383,7 +161,7 @@ bool convert_with_components(const char* model_path,
model_loader.convert_tensors_name(); model_loader.convert_tensors_name();
} }
return export_loaded_model(model_loader, output_path, output_type, tensor_type_rules, n_threads); return export_loaded_model(model_loader, output_path, output_type, tensor_type_rules);
} }
bool convert(const char* input_path, bool convert(const char* input_path,
@ -401,6 +179,5 @@ bool convert(const char* input_path,
output_path, output_path,
output_type, output_type,
tensor_type_rules, tensor_type_rules,
convert_name, convert_name);
0);
} }

View File

@ -9,48 +9,21 @@
namespace sd { namespace sd {
static bool layer_split_path_segment_starts_at(const std::string& name, size_t pos) {
return pos == 0 || name[pos - 1] == '.';
}
static bool layer_split_has_path_segment(const std::string& name, const char* segment) {
size_t pos = name.find(segment);
while (pos != std::string::npos) {
if (layer_split_path_segment_starts_at(name, pos)) {
return true;
}
pos = name.find(segment, pos + 1);
}
return false;
}
int layer_split_tensor_block_index(const std::string& name) { int layer_split_tensor_block_index(const std::string& name) {
static const char* unet_block_segments[] = {"input_blocks.", "output_blocks.", "middle_block.",
"down_blocks.", "up_blocks.", "mid_block."};
for (const char* segment : unet_block_segments) {
if (layer_split_has_path_segment(name, segment)) {
return -1;
}
}
static const char* block_keywords[] = {"transformer_blocks.", "joint_blocks.", "double_blocks.", static const char* block_keywords[] = {"transformer_blocks.", "joint_blocks.", "double_blocks.",
"single_blocks.", "blocks.", "block.", "layers."}; "single_blocks.", "blocks.", "block.", "layers."};
for (const char* keyword : block_keywords) { for (const char* keyword : block_keywords) {
size_t pos = name.find(keyword); size_t pos = name.find(keyword);
while (pos != std::string::npos) { if (pos == std::string::npos) {
if (!layer_split_path_segment_starts_at(name, pos)) { continue;
pos = name.find(keyword, pos + 1); }
continue; pos += std::strlen(keyword);
} size_t end = pos;
pos += std::strlen(keyword); while (end < name.size() && name[end] >= '0' && name[end] <= '9') {
size_t end = pos; end++;
while (end < name.size() && name[end] >= '0' && name[end] <= '9') { }
end++; if (end > pos && (end == name.size() || name[end] == '.')) {
} return std::atoi(name.substr(pos, end - pos).c_str());
if (end > pos && (end == name.size() || name[end] == '.')) {
return std::atoi(name.substr(pos, end - pos).c_str());
}
break;
} }
} }
return -1; return -1;

View File

@ -133,11 +133,7 @@ public:
int64_t H = input.shape()[1] / scale_factor; int64_t H = input.shape()[1] / scale_factor;
float tile_overlap; float tile_overlap;
int tile_size_x, tile_size_y; int tile_size_x, tile_size_y;
// Image VAE encode is more sensitive to tile boundary context than decode. get_tile_sizes(tile_size_x, tile_size_y, tile_overlap, tiling_params, W, H, 1.30539f);
// Keep the smaller legacy factor for video VAEs, but default image encode
// tiles to 64 latent pixels so a 512px SD image is encoded as one tile.
const float encode_tile_factor = (sd_version_is_wan(version) || sd_version_is_ltxav(version)) ? 1.30539f : 2.0f;
get_tile_sizes(tile_size_x, tile_size_y, tile_overlap, tiling_params, W, H, encode_tile_factor);
LOG_DEBUG("VAE Tile size: %dx%d", tile_size_x, tile_size_y); LOG_DEBUG("VAE Tile size: %dx%d", tile_size_x, tile_size_y);
output = tiled_compute(input, output = tiled_compute(input,
n_threads, n_threads,

View File

@ -1,10 +1,7 @@
#include "gguf_io.h" #include "gguf_io.h"
#include <algorithm>
#include <cstdint> #include <cstdint>
#include <cstdio>
#include <fstream> #include <fstream>
#include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
@ -124,115 +121,3 @@ bool write_gguf_file(const std::string& file_path,
gguf_free(gguf_ctx); gguf_free(gguf_ctx);
return success; return success;
} }
GGUFStreamingWriter::~GGUFStreamingWriter() {
close();
}
bool GGUFStreamingWriter::write_metadata(const std::string& file_path,
const std::vector<TensorWritePlan>& tensors,
std::string* error) {
close();
tensors_ = tensors;
file_size_ = 0;
size_t meta_mem = 1 * 1024 * 1024 + tensors.size() * ggml_tensor_overhead();
meta_ctx_ = ggml_init({meta_mem, nullptr, true});
if (meta_ctx_ == nullptr) {
set_error(error, "ggml_init failed for GGUF metadata");
return false;
}
gguf_ctx_ = gguf_init_empty();
if (gguf_ctx_ == nullptr) {
set_error(error, "gguf_init_empty failed");
close();
return false;
}
for (const TensorWritePlan& plan : tensors) {
ggml_tensor* tensor = ggml_new_tensor(meta_ctx_, plan.type, plan.n_dims, plan.ne);
if (tensor == nullptr) {
set_error(error, "ggml_new_tensor failed for tensor '" + plan.name + "'");
close();
return false;
}
ggml_set_name(tensor, plan.name.c_str());
gguf_add_tensor(gguf_ctx_, tensor);
}
LOG_INFO("trying to save tensors to %s", file_path.c_str());
FILE* file = fopen(file_path.c_str(), "wb+");
if (file == nullptr) {
set_error(error, "failed to open output file '" + file_path + "'");
close();
return false;
}
// ggml exposes GGUF metadata writing through FILE* only. Keep FILE usage
// isolated here; tensor data is written through std::fstream by the shared
// streaming pipeline.
if (!gguf_write_to_file_ptr(gguf_ctx_, file, true)) {
fclose(file);
set_error(error, "failed to write GGUF metadata to '" + file_path + "'");
close();
return false;
}
fclose(file);
const uint64_t data_start = gguf_get_meta_size(gguf_ctx_);
tensor_offsets_.resize(tensors.size());
file_size_ = data_start;
for (size_t i = 0; i < tensors.size(); i++) {
tensor_offsets_[i] = data_start + gguf_get_tensor_offset(gguf_ctx_, static_cast<int64_t>(i));
file_size_ = std::max(file_size_, tensor_offsets_[i] + tensors[i].nbytes());
}
return true;
}
bool GGUFStreamingWriter::write_tensor(std::ostream& output,
size_t tensor_index,
const uint8_t* data,
size_t size,
std::string* error) const {
if (tensor_index >= tensors_.size() || tensor_index >= tensor_offsets_.size()) {
set_error(error, "invalid GGUF tensor index");
return false;
}
const TensorWritePlan& plan = tensors_[tensor_index];
if (size != plan.nbytes()) {
set_error(error, "size mismatch while writing tensor '" + plan.name + "'");
return false;
}
output.seekp(static_cast<std::streamoff>(tensor_offsets_[tensor_index]), std::ios::beg);
if (!output) {
set_error(error, "failed to seek output for tensor '" + plan.name + "'");
return false;
}
if (size > 0) {
output.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
}
if (!output) {
set_error(error, "failed to write tensor '" + plan.name + "'");
return false;
}
return true;
}
uint64_t GGUFStreamingWriter::file_size() const {
return file_size_;
}
void GGUFStreamingWriter::close() {
tensor_offsets_.clear();
tensors_.clear();
file_size_ = 0;
if (gguf_ctx_ != nullptr) {
gguf_free(gguf_ctx_);
gguf_ctx_ = nullptr;
}
if (meta_ctx_ != nullptr) {
ggml_free(meta_ctx_);
meta_ctx_ = nullptr;
}
}

View File

@ -4,12 +4,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "streaming_writer.h"
#include "tensor_storage.h" #include "tensor_storage.h"
struct ggml_context;
struct gguf_context;
bool is_gguf_file(const std::string& file_path); bool is_gguf_file(const std::string& file_path);
bool read_gguf_file(const std::string& file_path, bool read_gguf_file(const std::string& file_path,
std::vector<TensorStorage>& tensor_storages, std::vector<TensorStorage>& tensor_storages,
@ -18,28 +14,4 @@ bool write_gguf_file(const std::string& file_path,
const std::vector<TensorWriteInfo>& tensors, const std::vector<TensorWriteInfo>& tensors,
std::string* error = nullptr); std::string* error = nullptr);
class GGUFStreamingWriter : public StreamingModelWriter {
public:
GGUFStreamingWriter() = default;
~GGUFStreamingWriter();
bool write_metadata(const std::string& file_path,
const std::vector<TensorWritePlan>& tensors,
std::string* error = nullptr) override;
bool write_tensor(std::ostream& output,
size_t tensor_index,
const uint8_t* data,
size_t size,
std::string* error = nullptr) const override;
uint64_t file_size() const override;
void close();
private:
std::vector<TensorWritePlan> tensors_;
std::vector<uint64_t> tensor_offsets_;
uint64_t file_size_ = 0;
ggml_context* meta_ctx_ = nullptr;
gguf_context* gguf_ctx_ = nullptr;
};
#endif // __SD_MODEL_IO_GGUF_IO_H__ #endif // __SD_MODEL_IO_GGUF_IO_H__

View File

@ -1,10 +1,8 @@
#include "safetensors_io.h" #include "safetensors_io.h"
#include <algorithm>
#include <cstdint> #include <cstdint>
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
@ -316,102 +314,3 @@ bool write_safetensors_file(const std::string& file_path,
return true; return true;
} }
bool SafetensorsStreamingWriter::write_metadata(const std::string& file_path,
const std::vector<TensorWritePlan>& tensors,
std::string* error) {
file_path_ = file_path;
tensors_ = tensors;
tensor_offsets_.clear();
data_start_ = 0;
file_size_ = 0;
nlohmann::ordered_json header = nlohmann::ordered_json::object();
uint64_t data_offset = 0;
tensor_offsets_.resize(tensors.size());
for (size_t i = 0; i < tensors.size(); i++) {
const TensorWritePlan& plan = tensors[i];
std::string dtype;
if (!ggml_type_to_safetensors_dtype(plan.type, &dtype)) {
set_error(error,
"unsupported safetensors dtype '" + std::string(ggml_type_name(plan.type)) +
"' for tensor '" + plan.name + "'");
return false;
}
nlohmann::ordered_json json_tensor_info = nlohmann::ordered_json::object();
json_tensor_info["dtype"] = dtype;
nlohmann::ordered_json shape = nlohmann::ordered_json::array();
for (int j = 0; j < plan.n_dims; ++j) {
shape.push_back(plan.ne[plan.n_dims - 1 - j]);
}
json_tensor_info["shape"] = shape;
nlohmann::ordered_json data_offsets = nlohmann::ordered_json::array();
data_offsets.push_back(data_offset);
data_offsets.push_back(data_offset + plan.nbytes());
json_tensor_info["data_offsets"] = data_offsets;
header[plan.name] = json_tensor_info;
tensor_offsets_[i] = data_offset;
data_offset += plan.nbytes();
}
const std::string header_str = header.dump();
data_start_ = ST_HEADER_SIZE_LEN + header_str.size();
LOG_INFO("trying to save tensors to %s", file_path.c_str());
std::ofstream file(file_path, std::ios::binary | std::ios::trunc);
if (!file.is_open()) {
set_error(error, "failed to open '" + file_path + "' for writing");
return false;
}
uint8_t header_size[ST_HEADER_SIZE_LEN];
for (int i = 0; i < static_cast<int>(ST_HEADER_SIZE_LEN); ++i) {
header_size[i] = static_cast<uint8_t>((header_str.size() >> (8 * i)) & 0xFF);
}
file.write(reinterpret_cast<const char*>(header_size), sizeof(header_size));
file.write(header_str.data(), static_cast<std::streamsize>(header_str.size()));
if (!file) {
set_error(error, "failed to write safetensors header to '" + file_path + "'");
return false;
}
file_size_ = data_start_ + data_offset;
return true;
}
bool SafetensorsStreamingWriter::write_tensor(std::ostream& output,
size_t tensor_index,
const uint8_t* data,
size_t size,
std::string* error) const {
if (tensor_index >= tensors_.size() || tensor_index >= tensor_offsets_.size()) {
set_error(error, "invalid safetensors tensor index");
return false;
}
const TensorWritePlan& plan = tensors_[tensor_index];
if (size != plan.nbytes()) {
set_error(error, "size mismatch while writing tensor '" + plan.name + "'");
return false;
}
output.seekp(static_cast<std::streamoff>(data_start_ + tensor_offsets_[tensor_index]), std::ios::beg);
if (!output) {
set_error(error, "failed to seek output for tensor '" + plan.name + "'");
return false;
}
if (size > 0) {
output.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
}
if (!output) {
set_error(error, "failed to write tensor '" + plan.name + "' to '" + file_path_ + "'");
return false;
}
return true;
}
uint64_t SafetensorsStreamingWriter::file_size() const {
return file_size_;
}

View File

@ -4,7 +4,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "streaming_writer.h"
#include "tensor_storage.h" #include "tensor_storage.h"
bool is_safetensors_file(const std::string& file_path); bool is_safetensors_file(const std::string& file_path);
@ -15,26 +14,4 @@ bool write_safetensors_file(const std::string& file_path,
const std::vector<TensorWriteInfo>& tensors, const std::vector<TensorWriteInfo>& tensors,
std::string* error = nullptr); std::string* error = nullptr);
class SafetensorsStreamingWriter : public StreamingModelWriter {
public:
SafetensorsStreamingWriter() = default;
bool write_metadata(const std::string& file_path,
const std::vector<TensorWritePlan>& tensors,
std::string* error = nullptr) override;
bool write_tensor(std::ostream& output,
size_t tensor_index,
const uint8_t* data,
size_t size,
std::string* error = nullptr) const override;
uint64_t file_size() const override;
private:
std::string file_path_;
std::vector<TensorWritePlan> tensors_;
std::vector<uint64_t> tensor_offsets_;
uint64_t data_start_ = 0;
uint64_t file_size_ = 0;
};
#endif // __SD_MODEL_IO_SAFETENSORS_IO_H__ #endif // __SD_MODEL_IO_SAFETENSORS_IO_H__

View File

@ -1,26 +0,0 @@
#ifndef __SD_MODEL_IO_STREAMING_WRITER_H__
#define __SD_MODEL_IO_STREAMING_WRITER_H__
#include <cstdint>
#include <iosfwd>
#include <string>
#include <vector>
#include "tensor_storage.h"
class StreamingModelWriter {
public:
virtual ~StreamingModelWriter() = default;
virtual bool write_metadata(const std::string& file_path,
const std::vector<TensorWritePlan>& tensors,
std::string* error = nullptr) = 0;
virtual bool write_tensor(std::ostream& output,
size_t tensor_index,
const uint8_t* data,
size_t size,
std::string* error = nullptr) const = 0;
virtual uint64_t file_size() const = 0;
};
#endif // __SD_MODEL_IO_STREAMING_WRITER_H__

View File

@ -127,25 +127,6 @@ struct TensorWriteInfo {
ggml_tensor* tensor = nullptr; ggml_tensor* tensor = nullptr;
}; };
struct TensorWritePlan {
std::string name;
ggml_type type = GGML_TYPE_F32;
int64_t ne[SD_MAX_DIMS] = {1, 1, 1, 1, 1};
int n_dims = 0;
int64_t nelements() const {
int64_t n = 1;
for (int i = 0; i < SD_MAX_DIMS; i++) {
n *= ne[i];
}
return n;
}
uint64_t nbytes() const {
return nelements() * ggml_type_size(type) / ggml_blck_size(type);
}
};
typedef std::function<bool(const TensorStorage&, ggml_tensor**)> on_new_tensor_cb_t; typedef std::function<bool(const TensorStorage&, ggml_tensor**)> on_new_tensor_cb_t;
#endif // __SD_TENSOR_STORAGE_H__ #endif // __SD_TENSOR_STORAGE_H__

View File

@ -943,8 +943,7 @@ std::vector<MmapTensorStore> ModelLoader::mmap_tensors(std::map<std::string, ggm
bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb,
bool enable_mmap, bool enable_mmap,
const std::set<std::string>* target_tensor_names, const std::set<std::string>* target_tensor_names) {
bool log_progress) {
process_model_files(enable_mmap, false); process_model_files(enable_mmap, false);
std::atomic<int64_t> read_time_ms(0); std::atomic<int64_t> read_time_ms(0);
@ -1213,7 +1212,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb,
} }
size_t curr_num = total_tensors_processed + current_idx; size_t curr_num = total_tensors_processed + current_idx;
float elapsed_seconds = (ggml_time_ms() - t_start) / 1000.0f; float elapsed_seconds = (ggml_time_ms() - t_start) / 1000.0f;
if (log_progress && total_tensors_to_process > 0) { if (total_tensors_to_process > 0) {
pretty_bytes_progress(static_cast<int>(curr_num), pretty_bytes_progress(static_cast<int>(curr_num),
static_cast<int>(total_tensors_to_process), static_cast<int>(total_tensors_to_process),
bytes_processed.load(), bytes_processed.load(),
@ -1231,81 +1230,27 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb,
break; break;
} }
total_tensors_processed += tensors_to_process.size(); total_tensors_processed += tensors_to_process.size();
if (log_progress && total_tensors_to_process > 0) { if (total_tensors_to_process > 0) {
pretty_bytes_progress(static_cast<int>(total_tensors_processed), pretty_bytes_progress(static_cast<int>(total_tensors_processed),
static_cast<int>(total_tensors_to_process), static_cast<int>(total_tensors_to_process),
bytes_processed.load(), bytes_processed.load(),
(ggml_time_ms() - t_start) / 1000.0f); (ggml_time_ms() - t_start) / 1000.0f);
} }
if (log_progress && total_tensors_processed < total_tensors_to_process && total_tensors_to_process > 0) { if (total_tensors_processed < total_tensors_to_process && total_tensors_to_process > 0) {
printf("\n"); printf("\n");
} }
} }
int64_t end_time = ggml_time_ms(); int64_t end_time = ggml_time_ms();
if (log_progress) { LOG_INFO("loading tensors completed, taking %.2fs (read: %.2fs, memcpy: %.2fs, convert: %.2fs, copy_to_backend: %.2fs)",
LOG_INFO("loading tensors completed, taking %.2fs (read: %.2fs, memcpy: %.2fs, convert: %.2fs, copy_to_backend: %.2fs)", (end_time - start_time) / 1000.f,
(end_time - start_time) / 1000.f, (read_time_ms.load() / (float)last_n_threads) / 1000.f,
(read_time_ms.load() / (float)last_n_threads) / 1000.f, (memcpy_time_ms.load() / (float)last_n_threads) / 1000.f,
(memcpy_time_ms.load() / (float)last_n_threads) / 1000.f, (convert_time_ms.load() / (float)last_n_threads) / 1000.f,
(convert_time_ms.load() / (float)last_n_threads) / 1000.f, (copy_to_backend_time_ms.load() / (float)last_n_threads) / 1000.f);
(copy_to_backend_time_ms.load() / (float)last_n_threads) / 1000.f);
}
return success; return success;
} }
bool ModelLoader::load_tensor(const TensorStorage& tensor_storage, ggml_tensor* dst_tensor) {
if (dst_tensor == nullptr || dst_tensor->data == nullptr) {
LOG_ERROR("load tensor failed: null destination for '%s'", tensor_storage.name.c_str());
return false;
}
bool loaded = false;
std::set<std::string> target_tensor_names{tensor_storage.name};
auto on_new_tensor_cb = [&](const TensorStorage& current_tensor_storage, ggml_tensor** out_tensor) -> bool {
*out_tensor = nullptr;
if (current_tensor_storage.name != tensor_storage.name) {
return true;
}
if (current_tensor_storage.file_index != tensor_storage.file_index ||
current_tensor_storage.offset != tensor_storage.offset ||
current_tensor_storage.index_in_zip != tensor_storage.index_in_zip) {
LOG_ERROR("load tensor failed: storage mismatch for '%s'", tensor_storage.name.c_str());
return false;
}
if (current_tensor_storage.n_dims != tensor_storage.n_dims ||
current_tensor_storage.nelements() != tensor_storage.nelements()) {
LOG_ERROR("load tensor failed: metadata changed for '%s'", tensor_storage.name.c_str());
return false;
}
for (int i = 0; i < current_tensor_storage.n_dims; i++) {
if (current_tensor_storage.ne[i] != dst_tensor->ne[i]) {
LOG_ERROR("load tensor failed: shape mismatch for '%s'", tensor_storage.name.c_str());
return false;
}
}
*out_tensor = dst_tensor;
loaded = true;
return true;
};
if (!load_tensors(on_new_tensor_cb, false, &target_tensor_names, false)) {
LOG_ERROR("load tensor failed: '%s'", tensor_storage.name.c_str());
return false;
}
if (!loaded) {
LOG_ERROR("load tensor failed: tensor '%s' not found", tensor_storage.name.c_str());
return false;
}
return true;
}
bool ModelLoader::load_float_tensor(const std::string& name, bool ModelLoader::load_float_tensor(const std::string& name,
std::vector<float>& data, std::vector<float>& data,
int n_threads, int n_threads,

View File

@ -70,8 +70,7 @@ public:
bool writable = true); bool writable = true);
bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb, bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb,
bool use_mmap = false, bool use_mmap = false,
const std::set<std::string>* target_tensor_names = nullptr, const std::set<std::string>* target_tensor_names = nullptr);
bool log_progress = true);
bool load_tensors(std::map<std::string, ggml_tensor*>& tensors, bool load_tensors(std::map<std::string, ggml_tensor*>& tensors,
std::set<std::string> ignore_tensors = {}, std::set<std::string> ignore_tensors = {},
bool use_mmap = false); bool use_mmap = false);
@ -79,7 +78,6 @@ public:
std::vector<float>& data, std::vector<float>& data,
int n_threads = 0, int n_threads = 0,
bool use_mmap = false); bool use_mmap = false);
bool load_tensor(const TensorStorage& tensor_storage, ggml_tensor* dst_tensor);
std::vector<std::string> get_tensor_names() const { std::vector<std::string> get_tensor_names() const {
std::vector<std::string> names; std::vector<std::string> names;

View File

@ -4,10 +4,7 @@
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <cstring>
#include <functional> #include <functional>
#include <limits>
#include <map>
#include <string> #include <string>
#include <utility> #include <utility>
@ -1016,7 +1013,6 @@ struct Denoiser {
const sd::Tensor<float>& latent) = 0; const sd::Tensor<float>& latent) = 0;
virtual sd::Tensor<float> inverse_noise_scaling(float sigma, virtual sd::Tensor<float> inverse_noise_scaling(float sigma,
const sd::Tensor<float>& latent) = 0; const sd::Tensor<float>& latent) = 0;
virtual float noise_level_to_sigma(float noise_level) = 0;
virtual std::vector<float> get_sigmas(uint32_t n, int image_seq_len, scheduler_t scheduler_type, SDVersion version, const char* extra_sample_args = nullptr) { virtual std::vector<float> get_sigmas(uint32_t n, int image_seq_len, scheduler_t scheduler_type, SDVersion version, const char* extra_sample_args = nullptr) {
auto bound_t_to_sigma = std::bind(&Denoiser::t_to_sigma, this, std::placeholders::_1); auto bound_t_to_sigma = std::bind(&Denoiser::t_to_sigma, this, std::placeholders::_1);
@ -1164,10 +1160,6 @@ struct CompVisDenoiser : public Denoiser {
SD_UNUSED(sigma); SD_UNUSED(sigma);
return latent; return latent;
} }
float noise_level_to_sigma(float noise_level) {
return noise_level / (1.0f - noise_level);
}
}; };
struct CompVisVDenoiser : public CompVisDenoiser { struct CompVisVDenoiser : public CompVisDenoiser {
@ -1255,10 +1247,6 @@ struct DiscreteFlowDenoiser : public Denoiser {
sd::Tensor<float> inverse_noise_scaling(float sigma, const sd::Tensor<float>& latent) override { sd::Tensor<float> inverse_noise_scaling(float sigma, const sd::Tensor<float>& latent) override {
return latent * (1.0f / (1.0f - sigma)); return latent * (1.0f / (1.0f - sigma));
} }
float noise_level_to_sigma(float noise_level) {
return noise_level;
}
}; };
struct FluxFlowDenoiser : public DiscreteFlowDenoiser { struct FluxFlowDenoiser : public DiscreteFlowDenoiser {
@ -1396,11 +1384,6 @@ struct MiniT2IFlowDenoiser : public Denoiser {
return latent; return latent;
} }
float noise_level_to_sigma(float noise_level) {
SD_UNUSED(noise_level);
return 1.0f;
}
std::vector<float> get_sigmas(uint32_t n, int image_seq_len, scheduler_t scheduler_type, SDVersion version, const char* extra_sample_args = nullptr) override { std::vector<float> get_sigmas(uint32_t n, int image_seq_len, scheduler_t scheduler_type, SDVersion version, const char* extra_sample_args = nullptr) override {
SD_UNUSED(image_seq_len); SD_UNUSED(image_seq_len);
SD_UNUSED(scheduler_type); SD_UNUSED(scheduler_type);
@ -1831,204 +1814,6 @@ static sd::Tensor<float> sample_dpmpp_2m_v2(denoise_cb_t model,
return x; return x;
} }
// DPM-Solver++(2M) SDE, midpoint variant. Ref: Lu et al. arXiv:2211.01095;
// k-diffusion sample_dpmpp_2m_sde.
static sd::Tensor<float> sample_dpmpp_2m_sde(denoise_cb_t model,
sd::Tensor<float> x,
const std::vector<float>& sigmas,
std::shared_ptr<RNG> rng,
float eta) {
sd::Tensor<float> old_denoised;
bool have_old_denoised = false;
float h_last = 0.f;
int steps = static_cast<int>(sigmas.size()) - 1;
for (int i = 0; i < steps; i++) {
auto denoised_opt = model(x, sigmas[i], i + 1);
if (denoised_opt.pred.empty()) {
return {};
}
sd::Tensor<float> denoised = std::move(denoised_opt.pred);
if (sigmas[i + 1] == 0.f) {
x = denoised;
} else {
float t = -std::log(sigmas[i]);
float s = -std::log(sigmas[i + 1]);
float h = s - t;
float eta_h = eta * h;
float a = sigmas[i + 1] / sigmas[i] * std::exp(-eta_h);
float b = -std::expm1(-h - eta_h);
x = a * x + b * denoised;
if (have_old_denoised) {
float r = h_last / h;
x += (0.5f * b / r) * (denoised - old_denoised);
}
if (eta > 0.f) {
x += sd::Tensor<float>::randn_like(x, rng) * (sigmas[i + 1] * std::sqrt(-std::expm1(-2.f * eta_h)));
}
h_last = h;
}
old_denoised = denoised;
have_old_denoised = true;
}
return x;
}
// Seeded Brownian tree providing deterministic, step-count-stable Gaussian
// increments for stochastic samplers. Constructed once per generation; each
// call returns unit-variance noise for interval [sigma_a, sigma_b].
// Reference: torchsde BrownianTree; k-diffusion BatchedBrownianTree.
class BrownianTreeNoiseSampler {
public:
BrownianTreeNoiseSampler(const sd::Tensor<float>& x_template,
double sigma_min,
double sigma_max,
uint64_t seed)
: t_min_(sigma_min),
t_max_(sigma_max),
shape_(x_template.shape()),
root_seed_(mix64(seed, 0x9E3779B97F4A7C15ULL)) {
auto rng = std::make_shared<STDDefaultRNG>();
rng->manual_seed(mix64(seed, 0xBF58476D1CE4E5B9ULL));
w_at_tmax_ = sd::Tensor<float>::randn(shape_, rng) * std::sqrt(static_cast<float>(t_max_ - t_min_));
}
sd::Tensor<float> operator()(double sigma_a, double sigma_b) {
double a = clamp(std::min(sigma_a, sigma_b));
double b = clamp(std::max(sigma_a, sigma_b));
auto dW = w(b) - w(a);
float span = static_cast<float>(std::max(std::abs(sigma_b - sigma_a), 1e-12));
return dW * (1.0f / std::sqrt(span));
}
private:
static constexpr int kMaxDepth = 24;
static uint64_t mix64(uint64_t v, uint64_t salt) {
uint64_t z = v + salt;
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
return z ^ (z >> 31);
}
double clamp(double t) const {
return std::min(std::max(t, t_min_), t_max_);
}
sd::Tensor<float> w(double t) {
auto it = cache_.find(t);
if (it != cache_.end()) {
return it->second;
}
sd::Tensor<float> zero = sd::Tensor<float>::zeros(shape_);
sd::Tensor<float> out = bridge(t_min_, t_max_, zero, w_at_tmax_, t, root_seed_, kMaxDepth);
cache_.emplace(t, out);
return out;
}
sd::Tensor<float> bridge(double a,
double c,
const sd::Tensor<float>& w_a,
const sd::Tensor<float>& w_c,
double t,
uint64_t node_seed,
int depth) {
if (depth <= 0 || c - a < 1e-9) {
float alpha = (c > a) ? static_cast<float>((t - a) / (c - a)) : 0.5f;
return (1.0f - alpha) * w_a + alpha * w_c;
}
double m = 0.5 * (a + c);
double std_dev = std::sqrt((c - m) * (m - a) / (c - a));
auto rng = std::make_shared<STDDefaultRNG>();
rng->manual_seed(node_seed);
auto z = sd::Tensor<float>::randn(shape_, rng);
auto w_m = 0.5f * (w_a + w_c) + static_cast<float>(std_dev) * z;
if (t == m) {
return w_m;
}
if (t < m) {
return bridge(a, m, w_a, w_m, t, mix64(node_seed, 1), depth - 1);
}
return bridge(m, c, w_m, w_c, t, mix64(node_seed, 2), depth - 1);
}
double t_min_;
double t_max_;
std::vector<int64_t> shape_;
uint64_t root_seed_;
sd::Tensor<float> w_at_tmax_;
std::map<double, sd::Tensor<float>> cache_;
};
// DPM-Solver++(2M) SDE, midpoint variant, with step-count-stable Brownian-tree
// noise. Same trajectory shape at any step count for a given seed. Aliased in
// k-diffusion / ComfyUI as sample_dpmpp_2m_sde_gpu.
// Ref: Lu et al. arXiv:2211.01095; torchsde BrownianTree.
static sd::Tensor<float> sample_dpmpp_2m_sde_bt(denoise_cb_t model,
sd::Tensor<float> x,
const std::vector<float>& sigmas,
std::shared_ptr<RNG> rng,
float eta) {
double sigma_max = 0.0;
double sigma_min = std::numeric_limits<double>::infinity();
for (float s : sigmas) {
if (s > 0.0f) {
sigma_max = std::max(sigma_max, static_cast<double>(s));
sigma_min = std::min(sigma_min, static_cast<double>(s));
}
}
if (sigma_max <= sigma_min) {
return x;
}
uint64_t tree_seed = 0;
{
auto draw = rng->randn(2);
std::memcpy(&tree_seed, draw.data(), sizeof(tree_seed));
}
BrownianTreeNoiseSampler noise_sampler(x, sigma_min, sigma_max, tree_seed);
sd::Tensor<float> old_denoised;
bool have_old_denoised = false;
float h_last = 0.f;
int steps = static_cast<int>(sigmas.size()) - 1;
for (int i = 0; i < steps; i++) {
auto denoised_opt = model(x, sigmas[i], i + 1);
if (denoised_opt.pred.empty()) {
return {};
}
sd::Tensor<float> denoised = std::move(denoised_opt.pred);
if (sigmas[i + 1] == 0.f) {
x = denoised;
} else {
float t = -std::log(sigmas[i]);
float s = -std::log(sigmas[i + 1]);
float h = s - t;
float eta_h = eta * h;
float a = sigmas[i + 1] / sigmas[i] * std::exp(-eta_h);
float b = -std::expm1(-h - eta_h);
x = a * x + b * denoised;
if (have_old_denoised) {
float r = h_last / h;
x += (0.5f * b / r) * (denoised - old_denoised);
}
if (eta > 0.f) {
x += noise_sampler(sigmas[i], sigmas[i + 1]) * (sigmas[i + 1] * std::sqrt(-std::expm1(-2.f * eta_h)));
}
h_last = h;
}
old_denoised = denoised;
have_old_denoised = true;
}
return x;
}
using SamplerExtraArgs = KeyValueArgs; using SamplerExtraArgs = KeyValueArgs;
static sd::Tensor<float> sample_lcm(denoise_cb_t model, static sd::Tensor<float> sample_lcm(denoise_cb_t model,
@ -2705,10 +2490,6 @@ static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
return sample_res_2s(model, std::move(x), sigmas, rng, is_flow_denoiser, eta); return sample_res_2s(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
case ER_SDE_SAMPLE_METHOD: case ER_SDE_SAMPLE_METHOD:
return sample_er_sde(model, std::move(x), sigmas, rng, is_flow_denoiser, eta); return sample_er_sde(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
case DPMPP2M_SDE_SAMPLE_METHOD:
return sample_dpmpp_2m_sde(model, std::move(x), sigmas, rng, eta);
case DPMPP2M_SDE_BT_SAMPLE_METHOD:
return sample_dpmpp_2m_sde_bt(model, std::move(x), sigmas, rng, eta);
case DDIM_TRAILING_SAMPLE_METHOD: case DDIM_TRAILING_SAMPLE_METHOD:
// DDIM is equivalent to Euler Ancestral with the Simple scheduler // DDIM is equivalent to Euler Ancestral with the Simple scheduler
return sample_euler_ancestral(model, std::move(x), sigmas, rng, is_flow_denoiser, eta); return sample_euler_ancestral(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);

View File

@ -2818,8 +2818,6 @@ const char* sample_method_to_str[] = {
"euler_cfg_pp", "euler_cfg_pp",
"euler_a_cfg_pp", "euler_a_cfg_pp",
"euler_ge", "euler_ge",
"dpm++2m_sde",
"dpm++2m_sde_bt",
}; };
const char* sd_sample_method_name(enum sample_method_t sample_method) { const char* sd_sample_method_name(enum sample_method_t sample_method) {
@ -3521,8 +3519,6 @@ static float resolve_eta(sd_ctx_t* sd_ctx,
case DPMPP2S_A_SAMPLE_METHOD: case DPMPP2S_A_SAMPLE_METHOD:
case ER_SDE_SAMPLE_METHOD: case ER_SDE_SAMPLE_METHOD:
case EULER_A_CFG_PP_SAMPLE_METHOD: case EULER_A_CFG_PP_SAMPLE_METHOD:
case DPMPP2M_SDE_SAMPLE_METHOD:
case DPMPP2M_SDE_BT_SAMPLE_METHOD:
return 1.0f; return 1.0f;
default:; default:;
} }
@ -4321,56 +4317,13 @@ static std::optional<ImageGenerationLatents> prepare_image_generation_latents(sd
LOG_INFO("IMG2IMG"); LOG_INFO("IMG2IMG");
if (request->strength < 1.f) { if (request->strength < 1.f) {
bool strength_as_noise_level = false; size_t t_enc = static_cast<size_t>(plan->sample_steps * request->strength);
bool force_first_sigma = false; if (t_enc == static_cast<size_t>(plan->sample_steps)) {
for (const auto& [key, value] : parse_key_value_args(sd_img_gen_params->sample_params.extra_sample_args, "img2img arg")) { t_enc--;
if (key == "strength_as_noise_level") {
if (!parse_strict_bool(value, strength_as_noise_level)) {
LOG_WARN("ignoring invalid img2img sample arg '%s=%s'", key.c_str(), value.c_str());
}
} else if (key == "force_first_sigma") {
if (!parse_strict_bool(value, force_first_sigma)) {
LOG_WARN("ignoring invalid img2img sample arg '%s=%s'", key.c_str(), value.c_str());
}
}
}
size_t t_enc;
float target_sigma = -1;
if (!strength_as_noise_level) {
t_enc = static_cast<size_t>(plan->sample_steps * request->strength);
if (t_enc == static_cast<size_t>(plan->sample_steps)) {
t_enc--;
}
} else {
LOG_DEBUG("Interpreting denoise strength as relative noise level");
// assume x_noised = K * (x * (1-noise_level) + noise * noise_level) = K * lerp(x, noise, noise_level)
// K = 1, noise_level = sigma for flow models
// K = 1+sigma, noise_level=sigma/(1+sigma) for diffusion models
float target_noise_level = request->strength;
target_sigma = sd_ctx->sd->denoiser->noise_level_to_sigma(target_noise_level);
size_t start_index = 0;
for (size_t i = 0; i < plan->sigmas.size(); ++i) {
if (plan->sigmas[i] <= target_sigma) {
start_index = i;
break;
}
}
if (start_index >= plan->sigmas.size() - 1) {
start_index = plan->sigmas.size() - 2; // Leave at least 1 step
}
t_enc = plan->sample_steps - start_index - 1;
} }
LOG_INFO("target t_enc is %zu steps", t_enc); LOG_INFO("target t_enc is %zu steps", t_enc);
std::vector<float> sigma_sched; std::vector<float> sigma_sched;
sigma_sched.assign(plan->sigmas.begin() + plan->sample_steps - t_enc - 1, plan->sigmas.end()); sigma_sched.assign(plan->sigmas.begin() + plan->sample_steps - t_enc - 1, plan->sigmas.end());
if (target_sigma > 0 && force_first_sigma && strength_as_noise_level) {
LOG_DEBUG("force_first_sigma to %.4f (from %.4f)", target_sigma, sigma_sched[0]);
sigma_sched[0] = target_sigma;
}
plan->sigmas = std::move(sigma_sched); plan->sigmas = std::move(sigma_sched);
plan->sample_steps = static_cast<int>(plan->sigmas.size() - 1); plan->sample_steps = static_cast<int>(plan->sigmas.size() - 1);
} }