Compare commits
125 Commits
master-664
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5114672c48 | ||
|
|
8a51eb9284 | ||
|
|
35fb21f3e0 | ||
|
|
cfd4cff2e6 | ||
|
|
5e4e03c8dd | ||
|
|
2961182365 | ||
|
|
ea4e566ccf | ||
|
|
b290693977 | ||
|
|
7717e82c00 | ||
|
|
fafe8e606c | ||
|
|
a8a91b24cd | ||
|
|
c00a9e956d | ||
|
|
833369da84 | ||
|
|
74bce049d0 | ||
|
|
b5d812008e | ||
|
|
c79d24bdbd | ||
|
|
1b042838d9 | ||
|
|
ead6bf521b | ||
|
|
9beb6aca69 | ||
|
|
12b6fbff28 | ||
|
|
cc73429228 | ||
|
|
6314af404a | ||
|
|
885f01a555 | ||
|
|
9ef6e7398f | ||
|
|
bb84971129 | ||
|
|
e22272ee63 | ||
|
|
4fcc6fef10 | ||
|
|
9e1055d2e3 | ||
|
|
8b135b5489 | ||
|
|
e071aa390b | ||
|
|
dff0e88265 | ||
|
|
c674225b38 | ||
|
|
0321ce17fb | ||
|
|
2abbc773ac | ||
|
|
da6db07c5c | ||
|
|
e9dee542c4 | ||
|
|
c60b36af0f | ||
|
|
38a51f8105 | ||
|
|
45714b1069 | ||
|
|
e790073e1c | ||
|
|
b11c95a41c | ||
|
|
68f3d6df9f | ||
|
|
7bcd189639 | ||
|
|
2574f59365 | ||
|
|
7dab3668d0 | ||
|
|
556f04bb3f | ||
|
|
3590aa8d62 | ||
|
|
1a13107bac | ||
|
|
484baa41e5 | ||
|
|
2bb0389683 | ||
|
|
ccda89e09c | ||
|
|
f0271076ad | ||
|
|
3b6c9ca97c | ||
|
|
57e19fa954 | ||
|
|
61a637bfd5 | ||
|
|
3ec374aecc | ||
|
|
0484600284 | ||
|
|
c1790754d3 | ||
|
|
9f855c933b | ||
|
|
7b5f34d93e | ||
|
|
d77b8f5ee8 | ||
|
|
03e9a22f4d | ||
|
|
f54e45e81c | ||
|
|
9956436c92 | ||
|
|
ec4cb8104b | ||
|
|
3973015ed7 | ||
|
|
9ee77fc227 | ||
|
|
39f7962d69 | ||
|
|
8caa3f908a | ||
|
|
2938272d82 | ||
|
|
f440ad9c29 | ||
|
|
41f7acbfb0 | ||
|
|
b395a6972d | ||
|
|
854bebfe02 | ||
|
|
787d229d84 | ||
|
|
b12098f5d0 | ||
|
|
2bd249c971 | ||
|
|
e9e952462f | ||
|
|
e8e012eef2 | ||
|
|
7f0e728b7d | ||
|
|
92a3b73cdb | ||
|
|
710bc91c8f | ||
|
|
5a34bc7f6e | ||
|
|
146b6cc49e | ||
|
|
93527fda74 | ||
|
|
6e66a1a4a4 | ||
|
|
bb90bfa00f | ||
|
|
517abc777d | ||
|
|
6f00939f75 | ||
|
|
c2df4e1228 | ||
|
|
9838264c49 | ||
|
|
17d70b91e6 | ||
|
|
5db680c2c7 | ||
|
|
749186c0eb | ||
|
|
bdb431ad95 | ||
|
|
276025e054 | ||
|
|
8d4c7af95b | ||
|
|
9b0fceb41b | ||
|
|
563137a592 | ||
|
|
3a54597776 | ||
|
|
1365008348 | ||
|
|
1fb6b22850 | ||
|
|
c20769b2c8 | ||
|
|
1b702a51e7 | ||
|
|
19bdfe22d2 | ||
|
|
138da14cc3 | ||
|
|
17a2b4a315 | ||
|
|
b3d56d0ba1 | ||
|
|
2a07540c2a | ||
|
|
81abfb2548 | ||
|
|
f3fd359b58 | ||
|
|
dfb2390dd4 | ||
|
|
cfbc19d186 | ||
|
|
b9254dda0d | ||
|
|
0648f4426b | ||
|
|
74f513d512 | ||
|
|
064001b524 | ||
|
|
1f9ee88e09 | ||
|
|
a7f2e03da4 | ||
|
|
4513e3fda9 | ||
|
|
2d40a8b2ad | ||
|
|
9c7f9a20b3 | ||
|
|
ed74577c40 | ||
|
|
7948df8ac1 | ||
|
|
02f06370a7 |
75
.github/workflows/build.yml
vendored
@@ -15,7 +15,7 @@ on:
|
||||
[
|
||||
".github/workflows/**",
|
||||
".dockerignore",
|
||||
"Dockerfile*",
|
||||
"docker/Dockerfile*",
|
||||
"**/CMakeLists.txt",
|
||||
"**/Makefile",
|
||||
"**/*.h",
|
||||
@@ -32,7 +32,7 @@ on:
|
||||
[
|
||||
".github/workflows/**",
|
||||
".dockerignore",
|
||||
"Dockerfile*",
|
||||
"docker/Dockerfile*",
|
||||
"**/CMakeLists.txt",
|
||||
"**/Makefile",
|
||||
"**/*.h",
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON
|
||||
cmake .. -DSD_BUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_INSTALL_RPATH='$ORIGIN'
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Get commit hash
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSD_BUILD_SHARED_LIBS=ON -DSD_VULKAN=ON
|
||||
cmake .. -DSD_BUILD_SHARED_LIBS=ON -DSD_VULKAN=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_INSTALL_RPATH='$ORIGIN'
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Get commit hash
|
||||
@@ -207,6 +207,7 @@ jobs:
|
||||
UBUNTU_VERSION=24.04
|
||||
CUDA_ARCHITECTURES=121
|
||||
GGML_CUDA_FA_ALL_QUANTS=ON
|
||||
GGML_CUDA_ENABLE_DYNAMIC_CPU_BACKENDS=OFF
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
@@ -263,7 +264,7 @@ jobs:
|
||||
context: .
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
file: Dockerfile.${{ matrix.variant }}
|
||||
file: docker/Dockerfile.${{ matrix.variant }}
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH_NAME }}-${{ matrix.variant }}${{ matrix.tag-suffix }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
@@ -341,18 +342,12 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- build: "noavx"
|
||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX=OFF -DGGML_AVX2=OFF -DGGML_FMA=OFF -DSD_BUILD_SHARED_LIBS=ON"
|
||||
- build: "avx2"
|
||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||
- build: "avx"
|
||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX=ON -DGGML_AVX2=OFF -DSD_BUILD_SHARED_LIBS=ON"
|
||||
- build: "avx512"
|
||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX512=ON -DGGML_AVX=ON -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||
- build: "cpu"
|
||||
defines: "-DGGML_NATIVE=OFF -DSD_BUILD_SHARED_LIBS=ON -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON"
|
||||
- build: "cuda12"
|
||||
defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES='61;70;75;80;86;89;90;100;120' -DCMAKE_CUDA_FLAGS='-Xcudafe \"--diag_suppress=177\" -Xcudafe \"--diag_suppress=550\"'"
|
||||
defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES='61;70;75;80;86;89;90;100;120' -DCMAKE_CUDA_FLAGS='-Xcudafe \"--diag_suppress=177\" -Xcudafe \"--diag_suppress=550\"' -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON"
|
||||
- build: "vulkan"
|
||||
defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||
defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON"
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
@@ -400,19 +395,6 @@ jobs:
|
||||
cmake .. -DCMAKE_CXX_FLAGS='/bigobj' -G Ninja -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_BUILD_TYPE=Release ${{ matrix.defines }}
|
||||
cmake --build .
|
||||
|
||||
- name: Check AVX512F support
|
||||
id: check_avx512f
|
||||
if: ${{ matrix.build == 'avx512' }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd build
|
||||
$vcdir = $(vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath)
|
||||
$msvc = $(join-path $vcdir $('VC\Tools\MSVC\'+$(gc -raw $(join-path $vcdir 'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt')).Trim()))
|
||||
$cl = $(join-path $msvc 'bin\Hostx64\x64\cl.exe')
|
||||
echo 'int main(void){unsigned int a[4];__cpuid(a,7);return !(a[1]&65536);}' >> avx512f.c
|
||||
& $cl /O2 /GS- /kernel avx512f.c /link /nodefaultlib /entry:main
|
||||
.\avx512f.exe && echo "AVX512F: YES" && ( echo HAS_AVX512F=1 >> $env:GITHUB_ENV ) || echo "AVX512F: NO"
|
||||
|
||||
- name: Get commit hash
|
||||
id: commit
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
@@ -722,6 +704,25 @@ jobs:
|
||||
run: |
|
||||
sudo apt install -y build-essential cmake wget zip ninja-build
|
||||
|
||||
- name: Free disk space
|
||||
run: |
|
||||
df -h
|
||||
|
||||
# Remove preinstalled SDKs and caches not needed for this job before
|
||||
# installing ROCm. The legacy ROCm apt packages are large enough to
|
||||
# exhaust ubuntu-latest if cleanup runs after installation.
|
||||
sudo rm -rf /usr/share/dotnet || true
|
||||
sudo rm -rf /usr/local/lib/android || true
|
||||
sudo rm -rf /opt/ghc || true
|
||||
sudo rm -rf /usr/local/.ghcup || true
|
||||
sudo rm -rf /opt/hostedtoolcache || true
|
||||
sudo rm -rf /usr/share/swift || true
|
||||
sudo rm -rf /usr/local/share/boost || true
|
||||
docker system prune -af || true
|
||||
|
||||
sudo apt clean
|
||||
df -h
|
||||
|
||||
- name: Setup Legacy ROCm
|
||||
if: matrix.ROCM_VERSION == '7.2.1'
|
||||
id: legacy_env
|
||||
@@ -743,19 +744,6 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt-get install -y libssl-dev rocm-hip-sdk
|
||||
|
||||
- name: Free disk space
|
||||
run: |
|
||||
# Remove preinstalled SDKs and caches not needed for this job
|
||||
sudo rm -rf /usr/share/dotnet || true
|
||||
sudo rm -rf /usr/local/lib/android || true
|
||||
sudo rm -rf /opt/ghc || true
|
||||
sudo rm -rf /usr/local/.ghcup || true
|
||||
sudo rm -rf /opt/hostedtoolcache || true
|
||||
|
||||
# Remove old package lists and caches
|
||||
sudo rm -rf /var/lib/apt/lists/* || true
|
||||
sudo apt clean
|
||||
|
||||
- name: Setup TheRock
|
||||
if: matrix.ROCM_VERSION != '7.2.1'
|
||||
id: therock_env
|
||||
@@ -794,6 +782,11 @@ jobs:
|
||||
-DGPU_TARGETS="${{ matrix.gpu_targets }}" \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DCMAKE_INSTALL_RPATH='$ORIGIN' \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DSD_BUILD_SHARED_GGML_LIB=ON \
|
||||
-DGGML_BACKEND_DL=ON \
|
||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DSD_BUILD_SHARED_LIBS=ON
|
||||
cmake --build . --config Release
|
||||
|
||||
|
||||
48
.github/workflows/close-inactive-issues.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Close inactive issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run daily. GitHub cron schedules use UTC.
|
||||
- cron: "30 1 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug_only:
|
||||
description: "Dry run: log intended actions without changing issues"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
close-inactive-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Comment and close inactive issues
|
||||
uses: actions/stale@v10
|
||||
with:
|
||||
days-before-issue-stale: 365
|
||||
days-before-issue-close: 0
|
||||
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
|
||||
stale-issue-label: issue:inactive
|
||||
close-issue-label: issue:auto-closed
|
||||
close-issue-reason: completed
|
||||
stale-issue-message: ""
|
||||
close-issue-message: >
|
||||
This issue has had no activity for one year. The latest version of
|
||||
the code may already have fixed the problem.
|
||||
|
||||
If the issue still exists in the latest version, you can reopen
|
||||
this issue at any time with updated reproduction details.
|
||||
|
||||
remove-issue-stale-when-updated: true
|
||||
operations-per-run: 1000
|
||||
debug-only: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_only || false }}
|
||||
4
.gitignore
vendored
@@ -13,3 +13,7 @@ output*.png
|
||||
models*
|
||||
*.log
|
||||
preview.png
|
||||
.claude/
|
||||
CLAUDE.local.md
|
||||
.agents/
|
||||
.codex/
|
||||
|
||||
183
AGENTS.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Instructions for stable-diffusion.cpp
|
||||
|
||||
This document is for AI coding agents working in this repository. It should
|
||||
describe agent-specific workflow, repository routing, editing boundaries, and
|
||||
project-specific pitfalls.
|
||||
|
||||
For general contribution rules, including PR scope, commit conventions, code
|
||||
style, dependency updates, security hygiene, and AI-assisted contribution policy,
|
||||
see `CONTRIBUTING.md`.
|
||||
|
||||
---
|
||||
|
||||
## Agent Operating Rules
|
||||
|
||||
Before analyzing or modifying the repository:
|
||||
|
||||
1. Read this file.
|
||||
2. Use `rg` / `rg --files` or directory listing commands to confirm the current
|
||||
tree before relying on a path.
|
||||
3. Start from `src/` and relevant `docs/` for runtime behavior.
|
||||
4. Read the relevant code before editing.
|
||||
5. Prefer the smallest change that fits the existing architecture.
|
||||
6. Report focused verification and mention any tests not run.
|
||||
|
||||
Agents must not:
|
||||
|
||||
* Run `git push`, create PRs, or submit issue/PR comments on the user's behalf.
|
||||
* Create commits unless the user explicitly requests that specific commit.
|
||||
* Modify `ggml/`, `thirdparty/`, or `examples/server/frontend/` unless
|
||||
explicitly requested and necessary.
|
||||
* Read large local model files or tokenizer vocabulary files.
|
||||
* Rewrite unrelated code for style-only reasons.
|
||||
* Add secrets, model weights, generated binaries, local absolute paths, or
|
||||
machine-specific output.
|
||||
|
||||
When a change is large, architectural, or likely to affect public behavior,
|
||||
pause and present a short plan before editing.
|
||||
|
||||
---
|
||||
|
||||
## Repository Map and Editing Boundaries
|
||||
|
||||
This is a routing map for agents, not a full architecture document. The layout
|
||||
can change, so verify paths before using them. Do not inspect excluded
|
||||
large-data directories while checking the tree.
|
||||
|
||||
### Primary Project Code
|
||||
|
||||
Core implementation lives under `src/`.
|
||||
|
||||
Current source layout includes:
|
||||
|
||||
* `src/core/` - shared tensor, ggml integration, backend, graph, RNG, and utility
|
||||
code.
|
||||
* `src/model/` - model families and model components.
|
||||
* `src/model_io/` - model file loading, GGUF, safetensors, pickle, and related
|
||||
serialization helpers.
|
||||
* `src/runtime/` - sampling, denoising, guidance, caching, preprocessing, and
|
||||
runtime execution helpers.
|
||||
* `src/tokenizers/` - tokenizer implementations.
|
||||
* `src/conditioning/` - conditioning and prompt-related implementation.
|
||||
* `src/extensions/` - optional feature extensions.
|
||||
* top-level `src/*.cpp` and `src/*.h` files - public implementation entry
|
||||
points, model loading, conversion, versioning, and shared managers.
|
||||
|
||||
`src/tokenizers/vocab/` contains large tokenizer vocabulary data. Do not read or
|
||||
parse files in this directory; reference the path only when necessary.
|
||||
|
||||
### Public API
|
||||
|
||||
`include/` contains the C API exposed by the project. Currently the primary
|
||||
public header is `include/stable-diffusion.h`.
|
||||
|
||||
Treat public headers as stable API. Avoid breaking compatibility unless the user
|
||||
explicitly requests it. If public behavior changes, update relevant examples or
|
||||
documentation.
|
||||
|
||||
### Examples
|
||||
|
||||
`examples/` contains programs demonstrating library usage.
|
||||
|
||||
* `examples/cli/` - command line program for running models, testing features,
|
||||
and debugging.
|
||||
* `examples/common/` - shared example support code.
|
||||
* `examples/server/` - server application built on top of the library.
|
||||
* `examples/server/frontend/` - git submodule containing independent frontend
|
||||
code. Avoid modifying it unless explicitly requested.
|
||||
|
||||
### Documentation and Tooling
|
||||
|
||||
* `docs/` - documentation for supported models, build options, behavior, and
|
||||
workflows.
|
||||
* `scripts/` - development, model processing, build automation, formatting, and
|
||||
tooling scripts.
|
||||
* `cmake/` - CMake support modules.
|
||||
* `docker/` - Docker-related project files.
|
||||
* `assets/` - documentation assets; not runtime code.
|
||||
|
||||
### External, Local, and Generated State
|
||||
|
||||
* `ggml/` - git submodule for the ggml dependency.
|
||||
* `thirdparty/` - vendored third-party dependencies.
|
||||
* `models/` - local model storage. Ignore this directory and do not read model
|
||||
files.
|
||||
* `test/` - local testing scripts. Use only when relevant to the task.
|
||||
* `build/`, `build_*`, and similar directories - generated build outputs.
|
||||
Inspect them only when debugging a build result.
|
||||
|
||||
---
|
||||
|
||||
## Agent Workflow for Code Changes
|
||||
|
||||
1. Identify the relevant modules under `src/`.
|
||||
2. Check whether the change touches the public API in `include/`.
|
||||
3. Consult relevant `docs/` and examples before changing user-facing behavior.
|
||||
4. Follow existing local patterns before adding new abstractions.
|
||||
5. Keep edits scoped to the requested behavior.
|
||||
6. Run the narrowest useful build, test, or inspection command available.
|
||||
|
||||
Follow `CONTRIBUTING.md` for formatting, naming, PR expectations, dependency
|
||||
update policy, and security rules.
|
||||
|
||||
---
|
||||
|
||||
## Code Comments
|
||||
|
||||
Keep comments rare and useful.
|
||||
|
||||
Do not add comments that only describe what the code does. Add comments only
|
||||
when the code cannot fully express the logic, the logic is unusually complex, or
|
||||
there are historical reasons, invariants, constraints, compatibility concerns,
|
||||
or known pitfalls that future maintainers need to understand.
|
||||
|
||||
Do not add task-specific comments that will be meaningless after review.
|
||||
|
||||
Examples from the current codebase:
|
||||
|
||||
```cpp
|
||||
// GOOD: explains a safety constraint that is not obvious from the assignment.
|
||||
// From src/model_io/pickle_io.cpp.
|
||||
// Non-tensor checkpoint metadata can use REDUCE for arbitrary
|
||||
// Python objects. Do not execute it; keep stack shape only.
|
||||
stack.push_back(make_none_value());
|
||||
|
||||
// BAD: describes only what the next line does.
|
||||
// Set the token count to zero.
|
||||
token_count = 0;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Text File Encoding
|
||||
|
||||
When reading or editing repository text files:
|
||||
|
||||
* Prefer UTF-8 with LF for Markdown, frontend source, JSON, and other text-first
|
||||
project files unless the file already clearly uses a different encoding.
|
||||
* Do not assume terminal output encoding matches file encoding on Windows.
|
||||
* A file that looks garbled in PowerShell output may still be valid UTF-8.
|
||||
* When inspecting UTF-8 files in PowerShell, prefer explicit UTF-8 reads such as:
|
||||
* `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8`
|
||||
* `Get-Content -Encoding utf8 <path>`
|
||||
* Avoid rewriting a file purely because console output looked garbled; verify
|
||||
the actual file encoding first.
|
||||
|
||||
---
|
||||
|
||||
## Tensor and Layout Notes
|
||||
|
||||
Additional tensor/layout rules for this codebase:
|
||||
|
||||
* `sd::Tensor` shape order is not PyTorch/NumPy-style. `shape()[0]` is the
|
||||
lowest and most contiguous dimension, and higher indices are higher
|
||||
dimensions.
|
||||
* Broadcasting for `sd::Tensor` must align dimensions from low to high dimension
|
||||
indices. If one tensor has fewer dimensions, append implicit `1`s at the
|
||||
higher-dimension end.
|
||||
* `ggml_n_dims` / `ggml_n_dims(tensor)` can drop trailing singleton high
|
||||
dimensions. Do not assume a logical trailing dimension of `1` will still be
|
||||
counted in ggml metadata.
|
||||
* Internal tensor-returning interfaces use an empty `sd::Tensor` to represent
|
||||
null, absent, or failure states. Do not add `std::optional<sd::Tensor<...>>`
|
||||
for internal APIs unless a distinct semantic state is truly required.
|
||||
11
CLAUDE.md
Normal file
@@ -0,0 +1,11 @@
|
||||
@AGENTS.md
|
||||
|
||||
## Claude Code
|
||||
|
||||
Follow `AGENTS.md` as the shared repository instructions.
|
||||
|
||||
Do not duplicate contribution, style, PR, dependency, or security policy here;
|
||||
use `CONTRIBUTING.md` as the canonical source for those rules.
|
||||
|
||||
Keep Claude-specific project notes in this file only when they do not apply to
|
||||
other coding agents.
|
||||
@@ -125,6 +125,12 @@ endif ()
|
||||
if (SD_HIPBLAS)
|
||||
message("-- Use HIPBLAS as backend stable-diffusion")
|
||||
set(GGML_HIP ON)
|
||||
# ggml-hip's device-stub objects must be position-independent, or the
|
||||
# default-PIE sd-cli link fails with `relocation R_X86_64_32 ... cannot be
|
||||
# used when making a PIE object` on distros that default to PIE
|
||||
# (Ubuntu 24.04, Fedora 40+, Debian 12+). The shared-library branch below
|
||||
# already sets this; the static build (the HIP default) did not.
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif ()
|
||||
|
||||
if(SD_MUSA)
|
||||
@@ -198,12 +204,33 @@ if(SD_WEBM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (SD_RPC)
|
||||
message("-- Use RPC as backend stable-diffusion")
|
||||
set(GGML_RPC ON)
|
||||
add_definitions(-DSD_USE_RPC)
|
||||
endif ()
|
||||
|
||||
set(SD_LIB stable-diffusion)
|
||||
|
||||
file(GLOB SD_LIB_SOURCES CONFIGURE_DEPENDS
|
||||
"src/*.h"
|
||||
"src/*.cpp"
|
||||
"src/*.hpp"
|
||||
"src/conditioning/*.h"
|
||||
"src/conditioning/*.cpp"
|
||||
"src/conditioning/*.hpp"
|
||||
"src/core/*.h"
|
||||
"src/core/*.cpp"
|
||||
"src/core/*.hpp"
|
||||
"src/extensions/*.h"
|
||||
"src/extensions/*.cpp"
|
||||
"src/extensions/*.hpp"
|
||||
"src/model/*/*.h"
|
||||
"src/model/*/*.cpp"
|
||||
"src/model/*/*.hpp"
|
||||
"src/runtime/*.h"
|
||||
"src/runtime/*.cpp"
|
||||
"src/runtime/*.hpp"
|
||||
"src/model_io/*.h"
|
||||
"src/model_io/*.cpp"
|
||||
"src/tokenizers/*.h"
|
||||
@@ -285,7 +312,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
if (NOT SD_USE_SYSTEM_GGML)
|
||||
# see https://github.com/ggerganov/ggml/pull/682
|
||||
add_definitions(-DGGML_MAX_NAME=128)
|
||||
add_definitions(-DGGML_MAX_NAME=160)
|
||||
endif()
|
||||
|
||||
# deps
|
||||
@@ -304,8 +331,10 @@ endif()
|
||||
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
target_link_libraries(${SD_LIB} PUBLIC ggml zip)
|
||||
target_sources(${SD_LIB} PRIVATE $<TARGET_OBJECTS:zip>)
|
||||
target_link_libraries(${SD_LIB} PUBLIC ggml)
|
||||
target_include_directories(${SD_LIB} PUBLIC . src include)
|
||||
target_include_directories(${SD_LIB} PRIVATE src/core)
|
||||
target_include_directories(${SD_LIB} PUBLIC . thirdparty)
|
||||
target_compile_features(${SD_LIB} PUBLIC c_std_11 cxx_std_17)
|
||||
|
||||
@@ -314,7 +343,58 @@ if (SD_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
set(SD_PUBLIC_HEADERS include/stable-diffusion.h)
|
||||
set_target_properties(${SD_LIB} PROPERTIES PUBLIC_HEADER "${SD_PUBLIC_HEADERS}")
|
||||
|
||||
install(TARGETS ${SD_LIB} LIBRARY PUBLIC_HEADER)
|
||||
|
||||
#
|
||||
# install
|
||||
#
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(SD_INSTALL_VERSION "${SDCPP_BUILD_VERSION}")
|
||||
set(SD_INSTALL_COMMIT "${SDCPP_BUILD_COMMIT}")
|
||||
set(SD_SHARED_LIB ${SD_BUILD_SHARED_LIBS})
|
||||
|
||||
set(SD_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Location of header files")
|
||||
set(SD_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of library files")
|
||||
set(SD_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Location of binary files")
|
||||
|
||||
set(SD_PUBLIC_HEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/stable-diffusion.h)
|
||||
|
||||
set_target_properties(${SD_LIB}
|
||||
PROPERTIES
|
||||
PUBLIC_HEADER "${SD_PUBLIC_HEADERS}")
|
||||
|
||||
|
||||
install(TARGETS ${SD_LIB}
|
||||
ARCHIVE
|
||||
LIBRARY
|
||||
RUNTIME
|
||||
PUBLIC_HEADER)
|
||||
|
||||
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/stable-diffusion-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/stable-diffusion
|
||||
PATH_VARS SD_INCLUDE_INSTALL_DIR
|
||||
SD_LIB_INSTALL_DIR
|
||||
SD_BIN_INSTALL_DIR )
|
||||
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion-version.cmake
|
||||
VERSION ${SD_INSTALL_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/stable-diffusion)
|
||||
|
||||
configure_file(cmake/stable-diffusion.pc.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.pc"
|
||||
@ONLY)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.pc"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
@@ -27,7 +27,7 @@ PRs should include:
|
||||
|
||||
Format code according to the repository style before submitting changes.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Naming conventions:
|
||||
|
||||
@@ -44,6 +44,8 @@ Naming conventions:
|
||||
|
||||
Some older code in the project may not fully follow the current conventions. Please do not submit PRs that only rewrite existing code to match style rules.
|
||||
|
||||
When adding or modifying model implementations, follow the model config and weight detection conventions in [docs/model_config.md](docs/model_config.md).
|
||||
|
||||
## AI-Assisted Contributions
|
||||
|
||||
AI tools may be used to assist development, but contributors are responsible for the quality and correctness of the submitted code.
|
||||
|
||||
23
Dockerfile
@@ -1,23 +0,0 @@
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git cmake
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cmake . -B ./build
|
||||
RUN cmake --build ./build --config Release --parallel
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
@@ -1,31 +0,0 @@
|
||||
ARG CUDA_VERSION=12.6.3
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM nvidia/cuda:${CUDA_VERSION}-cudnn-devel-ubuntu${UBUNTU_VERSION} AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git ccache cmake
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG CUDACXX=/usr/local/cuda/bin/nvcc
|
||||
ARG CUDA_ARCHITECTURES=""
|
||||
ARG GGML_CUDA_FA_ALL_QUANTS=""
|
||||
|
||||
RUN cmake . -B ./build \
|
||||
-DSD_CUDA=ON \
|
||||
${CUDA_ARCHITECTURES:+-DCMAKE_CUDA_ARCHITECTURES="${CUDA_ARCHITECTURES}"} \
|
||||
${GGML_CUDA_FA_ALL_QUANTS:+-DGGML_CUDA_FA_ALL_QUANTS=${GGML_CUDA_FA_ALL_QUANTS}}
|
||||
RUN cmake --build ./build --config Release -j$(nproc)
|
||||
|
||||
FROM nvidia/cuda:${CUDA_VERSION}-cudnn-runtime-ubuntu${UBUNTU_VERSION} AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
@@ -1,24 +0,0 @@
|
||||
ARG MUSA_VERSION=rc4.2.0
|
||||
ARG UBUNTU_VERSION=22.04
|
||||
|
||||
FROM mthreads/musa:${MUSA_VERSION}-devel-ubuntu${UBUNTU_VERSION}-amd64 as build
|
||||
|
||||
RUN apt-get update && apt-get install -y ccache cmake git
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mkdir build && cd build && \
|
||||
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
|
||||
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
|
||||
-DSD_MUSA=ON -DCMAKE_BUILD_TYPE=Release && \
|
||||
cmake --build . --config Release
|
||||
|
||||
FROM mthreads/musa:${MUSA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}-amd64 as runtime
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
@@ -1,21 +0,0 @@
|
||||
# ggml SYCL hardware detection uses BMG G31/WCL architecture enums added in oneAPI 2025.3.
|
||||
ARG SYCL_VERSION=2025.3.2-0
|
||||
|
||||
FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y cmake
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mkdir build && cd build && \
|
||||
cmake .. -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DSD_SYCL=ON -DCMAKE_BUILD_TYPE=Release && \
|
||||
cmake --build . --config Release -j$(nproc)
|
||||
|
||||
FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS runtime
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
@@ -1,23 +0,0 @@
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git cmake libvulkan-dev glslc spirv-headers
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cmake . -B ./build -DSD_VULKAN=ON
|
||||
RUN cmake --build ./build --config Release --parallel
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 libvulkan1 mesa-vulkan-drivers && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
68
README.md
@@ -15,6 +15,8 @@ API and command-line option may change frequently.***
|
||||
|
||||
## 🔥Important News
|
||||
|
||||
* **2026/06/25** 🚀 stable-diffusion.cpp now supports **Krea2**
|
||||
* **2026/06/04** 🚀 stable-diffusion.cpp now supports **Ideogram4**
|
||||
* **2026/05/31** 🚀 stable-diffusion.cpp now supports **PiD**
|
||||
* **2026/05/27** 🚀 stable-diffusion.cpp now supports **Lens**
|
||||
* **2026/05/17** 🚀 stable-diffusion.cpp now supports **LTX-2.3**
|
||||
@@ -33,8 +35,8 @@ API and command-line option may change frequently.***
|
||||
- Super lightweight and without external dependencies
|
||||
- Supported models
|
||||
- Image Models
|
||||
- SD1.x, SD2.x, [SD-Turbo](https://huggingface.co/stabilityai/sd-turbo)
|
||||
- SDXL, [SDXL-Turbo](https://huggingface.co/stabilityai/sdxl-turbo)
|
||||
- [SD1.x, SD2.x, SD-Turbo](./docs/sd.md)
|
||||
- [SDXL, SDXL-Turbo](./docs/sd.md)
|
||||
- [Some SD1.x and SDXL distilled models](./docs/distilled_sd.md)
|
||||
- [SD3/SD3.5](./docs/sd3.md)
|
||||
- [FLUX.1-dev/FLUX.1-schnell](./docs/flux.md)
|
||||
@@ -46,23 +48,34 @@ API and command-line option may change frequently.***
|
||||
- [PiD](./docs/pid.md)
|
||||
- [LongCat Image](./docs/longcat_image.md)
|
||||
- [Z-Image](./docs/z_image.md)
|
||||
- [MiniT2I](./docs/minit2i.md)
|
||||
- [Ovis-Image](./docs/ovis_image.md)
|
||||
- [Anima](./docs/anima.md)
|
||||
- [ERNIE-Image](./docs/ernie_image.md)
|
||||
- [Boogu Image](./docs/boogu_image.md)
|
||||
- [Krea2](./docs/krea2.md)
|
||||
- [Mage-Flow](./docs/mage_flow.md)
|
||||
- [SeFi-Image](./docs/sefi_image.md)
|
||||
- [HiDream-O1-Image](./docs/hidream_o1_image.md)
|
||||
- Image Edit Models
|
||||
- [Ideogram4](./docs/ideogram4.md)
|
||||
- [Image Edit Models](./docs/edit.md)
|
||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||
- [Qwen Image Edit series](./docs/qwen_image_edit.md)
|
||||
- [LongCat Image Edit](./docs/longcat_image.md)
|
||||
- [Boogu Image Edit](./docs/boogu_image.md)
|
||||
- [Mage-Flow-Edit](./docs/mage_flow.md#image-editing)
|
||||
- Video Models
|
||||
- [Wan2.1/Wan2.2](./docs/wan.md)
|
||||
- [LTX-2.3](./docs/ltx2.md)
|
||||
- [PhotoMaker](https://github.com/TencentARC/PhotoMaker) support.
|
||||
- [HunyuanVideo 1.5](./docs/hunyuan_video.md)
|
||||
- [LingBot-Video](./docs/lingbot_video.md)
|
||||
- [PhotoMaker](./docs/photo_maker.md) support.
|
||||
- Control Net support with SD 1.5
|
||||
- [ADetailer](./docs/adetailer.md)
|
||||
- LoRA support, same as [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#lora)
|
||||
- Latent Consistency Models support (LCM/LCM-LoRA)
|
||||
- Faster and memory efficient latent decoding with [TAESD](https://github.com/madebyollin/taesd)
|
||||
- Upscale images generated with [ESRGAN](https://github.com/xinntao/Real-ESRGAN)
|
||||
- Faster and memory efficient latent decoding with [TAESD](./docs/taesd.md)
|
||||
- Upscale images generated with [ESRGAN](./docs/esrgan.md)
|
||||
- Supported backends
|
||||
- CPU (AVX, AVX2 and AVX512 support for x86 architectures)
|
||||
- CUDA
|
||||
@@ -112,7 +125,7 @@ API and command-line option may change frequently.***
|
||||
- Stable Diffusion v1.5 from https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5
|
||||
|
||||
```sh
|
||||
curl -L -O https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
||||
curl -L -O https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
||||
```
|
||||
|
||||
### Generate an image with just one command
|
||||
@@ -131,28 +144,9 @@ For runtime and parameter backend placement, see the [backend selection guide](.
|
||||
## More Guides
|
||||
|
||||
- [Backend selection](./docs/backend.md)
|
||||
- [SD1.x/SD2.x/SDXL](./docs/sd.md)
|
||||
- [SD3/SD3.5](./docs/sd3.md)
|
||||
- [FLUX.1-dev/FLUX.1-schnell](./docs/flux.md)
|
||||
- [FLUX.2-dev/FLUX.2-klein](./docs/flux2.md)
|
||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||
- [Chroma](./docs/chroma.md)
|
||||
- [🔥Qwen Image](./docs/qwen_image.md)
|
||||
- [🔥Qwen Image Edit series](./docs/qwen_image_edit.md)
|
||||
- [🔥Wan2.1/Wan2.2](./docs/wan.md)
|
||||
- [🔥LTX-2.3](./docs/ltx2.md)
|
||||
- [🔥Z-Image](./docs/z_image.md)
|
||||
- [Ovis-Image](./docs/ovis_image.md)
|
||||
- [Anima](./docs/anima.md)
|
||||
- [ERNIE-Image](./docs/ernie_image.md)
|
||||
- [HiDream-O1-Image](./docs/hidream_o1_image.md)
|
||||
- [Lens](./docs/lens.md)
|
||||
- [LongCat Image / LongCat Image Edit](./docs/longcat_image.md)
|
||||
- [RPC](./docs/rpc.md)
|
||||
- [LoRA](./docs/lora.md)
|
||||
- [LCM/LCM-LoRA](./docs/lcm.md)
|
||||
- [Using PhotoMaker to personalize image generation](./docs/photo_maker.md)
|
||||
- [Using ESRGAN to upscale results](./docs/esrgan.md)
|
||||
- [Using TAESD to faster decoding](./docs/taesd.md)
|
||||
- [Docker](./docs/docker.md)
|
||||
- [Quantization and GGUF](./docs/quantization_and_gguf.md)
|
||||
- [Inference acceleration via caching](./docs/caching.md)
|
||||
@@ -187,23 +181,3 @@ These projects use `stable-diffusion.cpp` as a backend for their image generatio
|
||||
Thank you to all the people who have already contributed to stable-diffusion.cpp!
|
||||
|
||||
[](https://github.com/leejet/stable-diffusion.cpp/graphs/contributors)
|
||||
|
||||
## Star History
|
||||
|
||||
[](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)
|
||||
|
||||
BIN
assets/animatediff/img2video_demo.gif
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/animatediff/v2_coast.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/animatediff/v2_house.gif
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/animatediff/v2_man.gif
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/animatediff/v2_rabbit.gif
Normal file
|
After Width: | Height: | Size: 1002 KiB |
BIN
assets/animatediff/v3_coast.gif
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/animatediff/v3_house.gif
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/animatediff/v3_man.gif
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/animatediff/v3_rabbit.gif
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/animatediff/v3_rabbit_domain_lora.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/boogu/edit_example.png
Normal file
|
After Width: | Height: | Size: 477 KiB |
BIN
assets/boogu/example.png
Normal file
|
After Width: | Height: | Size: 489 KiB |
BIN
assets/huanyuan_video/hy1.5_t2v.mp4
Normal file
BIN
assets/hunyuan_video/hy1.5_t2v.mp4
Normal file
BIN
assets/ideogram4/example.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
assets/krea2/example.png
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
assets/mage_flow/edit_example.png
Normal file
|
After Width: | Height: | Size: 466 KiB |
BIN
assets/mage_flow/example.png
Normal file
|
After Width: | Height: | Size: 399 KiB |
BIN
assets/sefi_image/example.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
37
cmake/stable-diffusion-config.cmake.in
Normal file
@@ -0,0 +1,37 @@
|
||||
set(SD_VERSION "@SD_INSTALL_VERSION@")
|
||||
set(SD_BUILD_COMMIT "@SD_INSTALL_COMMIT@")
|
||||
set(SD_SHARED_LIB @SD_SHARED_LIB@)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(SD_INCLUDE_DIR "@PACKAGE_SD_INCLUDE_INSTALL_DIR@")
|
||||
set_and_check(SD_LIB_DIR "@PACKAGE_SD_LIB_INSTALL_DIR@")
|
||||
set(SD_BIN_DIR "@PACKAGE_SD_BIN_INSTALL_DIR@")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(ggml REQUIRED HINTS "${SD_LIB_DIR}/cmake")
|
||||
|
||||
if(NOT TARGET stable-diffusion)
|
||||
find_library(stable-diffusion_LIBRARY stable-diffusion
|
||||
REQUIRED
|
||||
HINTS "${SD_LIB_DIR}"
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
|
||||
add_library(stable-diffusion UNKNOWN IMPORTED)
|
||||
set_target_properties(stable-diffusion
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${SD_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "ggml::ggml"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${stable-diffusion_LIBRARY}"
|
||||
INTERFACE_COMPILE_FEATURES "c_std_11;cxx_std_17"
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(SD_SHARED_LIB)
|
||||
target_compile_definitions(stable-diffusion
|
||||
INTERFACE SD_BUILD_SHARED_LIB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
check_required_components(stable-diffusion)
|
||||
11
cmake/stable-diffusion.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: stable-diffusion
|
||||
Description: Diffusion model(SD,Flux,Wan,Qwen Image,Z-Image,...) inference in pure C/C++
|
||||
Version: @SDCPP_BUILD_VERSION@
|
||||
Libs: -L${libdir} -lstable-diffusion
|
||||
Libs.private: -lggml -lggml-base
|
||||
Cflags: -I${includedir}
|
||||
43
docker/Dockerfile
Normal file
@@ -0,0 +1,43 @@
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS build
|
||||
|
||||
# sd-server embeds the web UI at build time, so the build image needs Node/pnpm.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git cmake ca-certificates curl gnupg && \
|
||||
mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \
|
||||
gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \
|
||||
rm /tmp/nodesource-repo.gpg.key && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g pnpm@10.15.1 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cmake . -B ./build \
|
||||
-DSD_BUILD_SHARED_LIBS=ON \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DSD_BUILD_SHARED_GGML_LIB=ON \
|
||||
-DGGML_BACKEND_DL=ON \
|
||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DCMAKE_INSTALL_RPATH='$ORIGIN'
|
||||
RUN cmake --build ./build --config Release --parallel
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin /sd.cpp/bin
|
||||
RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \
|
||||
printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \
|
||||
chmod +x /sd-cli /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
60
docker/Dockerfile.cuda
Normal file
@@ -0,0 +1,60 @@
|
||||
ARG CUDA_VERSION=12.6.3
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM nvidia/cuda:${CUDA_VERSION}-cudnn-devel-ubuntu${UBUNTU_VERSION} AS build
|
||||
|
||||
# sd-server embeds the web UI at build time, so the build image needs Node/pnpm.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git ccache cmake ca-certificates curl gnupg && \
|
||||
mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \
|
||||
gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \
|
||||
rm /tmp/nodesource-repo.gpg.key && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g pnpm@10.15.1 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG CUDACXX=/usr/local/cuda/bin/nvcc
|
||||
ARG CUDA_ARCHITECTURES=""
|
||||
ARG GGML_CUDA_FA_ALL_QUANTS=""
|
||||
ARG GGML_CUDA_ENABLE_DYNAMIC_CPU_BACKENDS=ON
|
||||
|
||||
RUN set -- \
|
||||
-DSD_CUDA=ON; \
|
||||
if [ "${GGML_CUDA_ENABLE_DYNAMIC_CPU_BACKENDS}" = "ON" ]; then \
|
||||
set -- "$@" \
|
||||
-DSD_BUILD_SHARED_LIBS=ON \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DSD_BUILD_SHARED_GGML_LIB=ON \
|
||||
-DGGML_BACKEND_DL=ON \
|
||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
"-DCMAKE_INSTALL_RPATH=\$ORIGIN"; \
|
||||
fi; \
|
||||
if [ -n "${CUDA_ARCHITECTURES}" ]; then \
|
||||
set -- "$@" "-DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHITECTURES}"; \
|
||||
fi; \
|
||||
if [ -n "${GGML_CUDA_FA_ALL_QUANTS}" ]; then \
|
||||
set -- "$@" "-DGGML_CUDA_FA_ALL_QUANTS=${GGML_CUDA_FA_ALL_QUANTS}"; \
|
||||
fi; \
|
||||
cmake . -B ./build "$@"
|
||||
RUN cmake --build ./build --config Release -j$(nproc)
|
||||
|
||||
FROM nvidia/cuda:${CUDA_VERSION}-cudnn-runtime-ubuntu${UBUNTU_VERSION} AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin /sd.cpp/bin
|
||||
RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \
|
||||
printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \
|
||||
chmod +x /sd-cli /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
45
docker/Dockerfile.musa
Normal file
@@ -0,0 +1,45 @@
|
||||
ARG MUSA_VERSION=rc4.2.0
|
||||
ARG UBUNTU_VERSION=22.04
|
||||
|
||||
FROM mthreads/musa:${MUSA_VERSION}-devel-ubuntu${UBUNTU_VERSION}-amd64 as build
|
||||
|
||||
# sd-server embeds the web UI at build time, so the build image needs Node/pnpm.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends ccache cmake git ca-certificates curl gnupg && \
|
||||
mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \
|
||||
gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \
|
||||
rm /tmp/nodesource-repo.gpg.key && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g pnpm@10.15.1 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mkdir build && cd build && \
|
||||
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
|
||||
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
|
||||
-DSD_MUSA=ON \
|
||||
-DSD_BUILD_SHARED_LIBS=ON \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DSD_BUILD_SHARED_GGML_LIB=ON \
|
||||
-DGGML_BACKEND_DL=ON \
|
||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DCMAKE_INSTALL_RPATH='$ORIGIN' \
|
||||
-DCMAKE_BUILD_TYPE=Release && \
|
||||
cmake --build . --config Release
|
||||
|
||||
FROM mthreads/musa:${MUSA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}-amd64 as runtime
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin /sd.cpp/bin
|
||||
RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \
|
||||
printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \
|
||||
chmod +x /sd-cli /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
32
docker/Dockerfile.sycl
Normal file
@@ -0,0 +1,32 @@
|
||||
# ggml SYCL hardware detection uses BMG G31/WCL architecture enums added in oneAPI 2025.3.
|
||||
ARG SYCL_VERSION=2025.3.2-0
|
||||
|
||||
FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS build
|
||||
|
||||
# sd-server embeds the web UI at build time, so the build image needs Node/pnpm.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends cmake ca-certificates curl gnupg && \
|
||||
mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \
|
||||
gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \
|
||||
rm /tmp/nodesource-repo.gpg.key && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g pnpm@10.15.1 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN mkdir build && cd build && \
|
||||
cmake .. -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DSD_SYCL=ON -DCMAKE_BUILD_TYPE=Release && \
|
||||
cmake --build . --config Release -j$(nproc)
|
||||
|
||||
FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS runtime
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
|
||||
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
44
docker/Dockerfile.vulkan
Normal file
@@ -0,0 +1,44 @@
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS build
|
||||
|
||||
# sd-server embeds the web UI at build time, so the build image needs Node/pnpm.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential git cmake libvulkan-dev glslc spirv-headers ca-certificates curl gnupg && \
|
||||
mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /tmp/nodesource-repo.gpg.key && \
|
||||
gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource-repo.gpg.key && \
|
||||
rm /tmp/nodesource-repo.gpg.key && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g pnpm@10.15.1 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /sd.cpp
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cmake . -B ./build \
|
||||
-DSD_VULKAN=ON \
|
||||
-DSD_BUILD_SHARED_LIBS=ON \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DSD_BUILD_SHARED_GGML_LIB=ON \
|
||||
-DGGML_BACKEND_DL=ON \
|
||||
-DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DCMAKE_INSTALL_RPATH='$ORIGIN'
|
||||
RUN cmake --build ./build --config Release -j$(nproc)
|
||||
|
||||
FROM ubuntu:$UBUNTU_VERSION AS runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --yes --no-install-recommends libgomp1 libvulkan1 mesa-vulkan-drivers libglvnd0 libgl1 libglx0 libegl1 libgles2 && \
|
||||
apt-get clean
|
||||
|
||||
COPY --from=build /sd.cpp/build/bin /sd.cpp/bin
|
||||
RUN printf '#!/bin/sh\nexec /sd.cpp/bin/sd-cli "$@"\n' > /sd-cli && \
|
||||
printf '#!/bin/sh\nexec /sd.cpp/bin/sd-server "$@"\n' > /sd-server && \
|
||||
chmod +x /sd-cli /sd-server
|
||||
|
||||
ENTRYPOINT [ "/sd-cli" ]
|
||||
110
docs/adetailer.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# ADetailer
|
||||
|
||||
`sd-cli` can run a YOLOv8 object detector on an existing or newly generated
|
||||
image and perform a cropped inpaint pass for every detected object. The first
|
||||
implementation supports YOLOv8 detection checkpoints. YOLOv8 segmentation and
|
||||
MediaPipe models are not supported yet.
|
||||
|
||||
## Convert a detector
|
||||
|
||||
Ultralytics checkpoints must be converted before use. The converter fuses
|
||||
BatchNorm into convolution layers and writes a safetensors file with the weight
|
||||
names expected by the native GGML implementation.
|
||||
|
||||
```bash
|
||||
python scripts/convert_yolov8_to_safetensors.py face_yolov8n.pt face_yolov8n.safetensors
|
||||
```
|
||||
|
||||
The converter requires Python packages `ultralytics`, `torch`, and
|
||||
`safetensors`.
|
||||
Only YOLOv8 detection checkpoints are accepted.
|
||||
PyTorch checkpoints use pickle internally, so only convert `.pt` files from a
|
||||
trusted source.
|
||||
|
||||
## Repair an existing image
|
||||
|
||||
Use the dedicated `adetailer` mode to detect and repair objects in an existing
|
||||
image:
|
||||
|
||||
```bash
|
||||
./bin/sd-cli \
|
||||
-M adetailer \
|
||||
-m model.safetensors \
|
||||
-i input.png \
|
||||
-o repaired.png \
|
||||
-p "detailed portrait photo" \
|
||||
--negative-prompt "deformed face" \
|
||||
--steps 24 \
|
||||
--cfg-scale 6 \
|
||||
--strength 0.4 \
|
||||
--sampling-method dpm++2m \
|
||||
--scheduler karras \
|
||||
--ad-model face_yolov8n.safetensors \
|
||||
--extra-ad-args "confidence=0.3,inpaint_padding=32,mask_blur=4"
|
||||
```
|
||||
|
||||
This mode reuses the normal image-generation options for the detail pass:
|
||||
|
||||
- `--init-img`, `--output`, `--prompt`, and `--negative-prompt`
|
||||
- `--steps`, `--cfg-scale`, `--sampling-method`, and `--scheduler`
|
||||
- `--strength`, `--seed`, LoRA settings, VAE tiling, and backend assignments
|
||||
- `--width` and `--height`, which also resize the input when specified
|
||||
|
||||
`--ad-prompt` and `--ad-negative-prompt` optionally override the normal prompts.
|
||||
Values provided in `--extra-ad-args`, such as `steps`, `cfg_scale`,
|
||||
`denoising_strength`, or `inpaint_width`, take precedence over inherited values.
|
||||
|
||||
## Repair generated images
|
||||
|
||||
ADetailer can also run automatically after normal image generation:
|
||||
|
||||
```bash
|
||||
./bin/sd-cli \
|
||||
-m model.safetensors \
|
||||
-p "portrait photo" \
|
||||
--ad-model face_yolov8n.safetensors \
|
||||
--ad-prompt "[PROMPT], detailed face" \
|
||||
--ad-negative-prompt "" \
|
||||
--extra-ad-args "confidence=0.3,denoising_strength=0.4,inpaint_width=512,inpaint_height=512"
|
||||
```
|
||||
|
||||
An empty ADetailer prompt inherits the main prompt. `[PROMPT]` inserts the main
|
||||
prompt, `[SEP]` assigns different prompts to consecutive masks, and `[SKIP]`
|
||||
skips the corresponding mask.
|
||||
|
||||
All settings other than the detector path and prompts are passed through
|
||||
`--extra-ad-args` as a comma-separated `key=value` list:
|
||||
|
||||
| Key | Default | Description |
|
||||
| --- | ---: | --- |
|
||||
| `input_size` | `640` | Square YOLO input size; must be a multiple of 32 |
|
||||
| `confidence` | `0.3` | Detection confidence threshold |
|
||||
| `nms` | `0.45` | NMS IoU threshold |
|
||||
| `max_detections` | `100` | Maximum detections retained after NMS |
|
||||
| `mask_k_largest` | `0` | Keep only the largest K masks; zero keeps all |
|
||||
| `mask_min_ratio` | `0` | Minimum bbox area relative to the image |
|
||||
| `mask_max_ratio` | `1` | Maximum bbox area relative to the image |
|
||||
| `dilate_erode` | `4` | Positive values dilate; negative values erode |
|
||||
| `x_offset`, `y_offset` | `0` | Mask offset in pixels; positive Y moves upward |
|
||||
| `mask_mode` | `none` | `none`, `merge`, or `merge_invert` |
|
||||
| `merge_masks`, `invert_mask` | `false` | Boolean alternatives to `mask_mode` |
|
||||
| `mask_blur` | `4` | Final composite feather radius |
|
||||
| `inpaint_padding` | `32` | Padding around the detected region |
|
||||
| `inpaint_width`, `inpaint_height` | mode-specific | `512x512` after generation; input/output size in `adetailer` mode |
|
||||
| `denoising_strength` | mode-specific | `0.4` after generation; inherits `--strength` in `adetailer` mode |
|
||||
| `steps` | `0` | Detail steps; zero inherits the main generation |
|
||||
| `cfg_scale` | `-1` | Detail CFG; a negative value inherits the main generation |
|
||||
| `sample_method` | inherited | Detail sampler name |
|
||||
| `scheduler` | inherited | Detail scheduler name |
|
||||
| `sort_by` | `none` | `none`, `left_to_right`, `center_to_edge`, or `area` |
|
||||
|
||||
Multiple masks are processed serially. Each completed inpaint becomes the input
|
||||
for the next mask, and the seed is incremented by the mask index. Use
|
||||
`mask_mode=merge` to process all detections in one inpaint pass.
|
||||
|
||||
The detector uses the `detector` backend module. For example, keep detection on
|
||||
the CPU while diffusion runs on CUDA:
|
||||
|
||||
```bash
|
||||
--backend "diffusion=cuda0,detector=cpu"
|
||||
```
|
||||
@@ -15,7 +15,7 @@
|
||||
## Examples
|
||||
|
||||
```sh
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="anima image example" src="../assets/anima/example.png" />
|
||||
|
||||
171
docs/animatediff.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# AnimateDiff (SD 1.5)
|
||||
|
||||
AnimateDiff adds motion to a frozen Stable Diffusion 1.5 checkpoint by
|
||||
injecting a temporal-attention module at 20 UNet slots. The base SD 1.5
|
||||
model, VAE, and text encoder are unchanged; only the motion module produces
|
||||
the temporal residual that turns a batch of independent frames into a
|
||||
coherent animation. Reference: Guo et al., "AnimateDiff: Animate Your
|
||||
Personalized Text-to-Image Diffusion Models without Specific Tuning"
|
||||
(https://arxiv.org/abs/2307.04725).
|
||||
|
||||
## Download weights
|
||||
|
||||
- Motion module (v3, recommended)
|
||||
- fp16 safetensors: https://huggingface.co/conrevo/AnimateDiff-A1111/resolve/main/motion_module/mm_sd15_v3.safetensors
|
||||
- original checkpoint: https://huggingface.co/guoyww/animatediff/resolve/main/v3_sd15_mm.ckpt
|
||||
- SD 1.5 base model
|
||||
- any SD 1.5 checkpoint works. `realisticVisionV60B1` and `toonyou_beta3`
|
||||
are the ones used in guoyww's reference configs.
|
||||
- Domain Adapter LoRA (optional, v3 only, sharpens the base UNet's output
|
||||
toward the motion module's trained distribution)
|
||||
- ckpt: https://huggingface.co/guoyww/animatediff/resolve/main/v3_sd15_adapter.ckpt
|
||||
- place under your `--lora-model-dir` and reference in the prompt as
|
||||
`<lora:v3_sd15_adapter:1.0>`.
|
||||
|
||||
The motion module is `~836 MB` and loads alongside the SD 1.5 UNet via
|
||||
`--motion-module`.
|
||||
|
||||
## Motion module versions
|
||||
|
||||
Per [animatediff.net/models](https://animatediff.net/models):
|
||||
|
||||
| Module | Base | Native res | Character |
|
||||
|---------------------|------|------------|-----------|
|
||||
| `mm_sd_v14.ckpt` | 1.5 | 256x256 | earliest, more jittery |
|
||||
| `mm_sd_v15.ckpt` | 1.5 | 256x256 | improved stability over v1.4 |
|
||||
| `mm_sd_v15_v2.ckpt` | 1.5 | 384x384 | significantly better motion dynamics |
|
||||
| `v3_sd15_mm.ckpt` | 1.5 | 512x512 | smoothest, highest quality; pairs with a Domain Adapter LoRA |
|
||||
| `mm_sdxl_v10_beta` | SDXL | 512x512 | experimental, not yet supported here |
|
||||
|
||||
Match your `-H -W` to the module's native resolution for best results. v3 is
|
||||
trained at 512x512 - going smaller (e.g. 384x384) still works but the motion
|
||||
character is closer to v2.
|
||||
|
||||
## Examples
|
||||
|
||||
Generate an 8-frame animation at 512x512, seed 42, 20 steps. The sampler /
|
||||
scheduler / CFG values below match what mm_sd15_v3 was trained with; using
|
||||
SD 1.5 defaults (euler_a, low CFG) produces noise-like output.
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -M vid_gen \
|
||||
--model ..\models\checkpoints\realisticVisionV60B1.safetensors \
|
||||
--motion-module ..\models\animatediff\mm_sd15_v3.safetensors \
|
||||
--offload-to-cpu --diffusion-fa \
|
||||
-p "a red apple on a wooden table" \
|
||||
--cfg-scale 8.0 --sampling-method euler --scheduler discrete \
|
||||
-H 512 -W 512 --video-frames 8 --fps 8 --steps 20 -s 42 \
|
||||
-o out.avi
|
||||
```
|
||||
|
||||
Generate at the motion module's native 16-frame context (recommended for
|
||||
best temporal quality). Needs more VRAM at 512x512, so drop to 384x384 or
|
||||
use layer streaming:
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -M vid_gen \
|
||||
--model ..\models\checkpoints\realisticVisionV60B1.safetensors \
|
||||
--motion-module ..\models\animatediff\mm_sd15_v3.safetensors \
|
||||
--offload-to-cpu --diffusion-fa \
|
||||
-p "photo of coastline, rocks, storm weather, wind, waves, lightning" \
|
||||
--cfg-scale 8.0 --sampling-method euler --scheduler discrete \
|
||||
-H 384 -W 384 --video-frames 16 --fps 8 --steps 20 -s 42 \
|
||||
-o out.avi
|
||||
```
|
||||
|
||||
Low-VRAM streaming (verified with a 2 GiB cap on RTX 3060):
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -M vid_gen \
|
||||
--model ..\models\checkpoints\realisticVisionV60B1.safetensors \
|
||||
--motion-module ..\models\animatediff\mm_sd15_v3.safetensors \
|
||||
--max-vram 2.0 --stream-layers --diffusion-fa \
|
||||
-p "photo of coastline, rocks, storm weather, wind, waves, lightning" \
|
||||
--cfg-scale 8.0 --sampling-method euler --scheduler discrete \
|
||||
-H 384 -W 384 --video-frames 8 --fps 8 --steps 20 -s 42 \
|
||||
-o out.avi
|
||||
```
|
||||
|
||||
## Reference-quality reproduction
|
||||
|
||||
Using guoyww's official reference configs on this impl (RealisticVision v6.0
|
||||
base + `mm_sd15_v3` or `mm_sd_v15_v2` + native resolution + 16 frames + euler
|
||||
+ 25 steps + CFG 8 + linear beta schedule) reproduces the reference
|
||||
AnimateDiff output style.
|
||||
|
||||
### v3 (512x512, `mm_sd15_v3`)
|
||||
|
||||
| Prompt | Sample |
|
||||
|---------------------------------------|--------|
|
||||
| B&W man on stormy coastline | <img src="../assets/animatediff/v3_man.gif" width="256"/> |
|
||||
| Close-up rabbit macro shot | <img src="../assets/animatediff/v3_rabbit.gif" width="256"/> |
|
||||
| Coastline, storm, waves, lightning | <img src="../assets/animatediff/v3_coast.gif" width="256"/> |
|
||||
| Old house, storm, forest, night | <img src="../assets/animatediff/v3_house.gif" width="256"/> |
|
||||
|
||||
### v2 (384x384, `mm_sd_v15_v2.ckpt`)
|
||||
|
||||
| Prompt | Sample |
|
||||
|---------------------------------------|--------|
|
||||
| B&W man on stormy coastline | <img src="../assets/animatediff/v2_man.gif" width="256"/> |
|
||||
| Close-up rabbit macro shot | <img src="../assets/animatediff/v2_rabbit.gif" width="256"/> |
|
||||
| Coastline, storm, waves, lightning | <img src="../assets/animatediff/v2_coast.gif" width="256"/> |
|
||||
| Old house, storm, forest, night | <img src="../assets/animatediff/v2_house.gif" width="256"/> |
|
||||
|
||||
Motion is strong for scenes with motion cues in the prompt (storm/waves/wind)
|
||||
and subtle for static subjects (close-up macro), matching reference behavior.
|
||||
v2 has an additional motion module at the UNet middle block that v3 dropped;
|
||||
this impl auto-detects the topology from the checkpoint.
|
||||
|
||||
### v3 + Domain Adapter LoRA
|
||||
|
||||
Attaching the `v3_sd15_adapter` LoRA sharpens the base UNet output toward
|
||||
the training distribution the motion module was fine-tuned against. Same
|
||||
prompt, seed, config as above:
|
||||
|
||||
<img src="../assets/animatediff/v3_rabbit_domain_lora.gif" width="256"/>
|
||||
|
||||
Individual fur strands, glowing inner-ear, and richer forest detail become
|
||||
visible compared to the no-LoRA rendering.
|
||||
|
||||
```
|
||||
sd-cli -M vid_gen --model realisticVisionV60B1.safetensors \
|
||||
--motion-module mm_sd15_v3.safetensors \
|
||||
--lora-model-dir ./loras \
|
||||
-p "close up photo of a rabbit ...<lora:v3_sd15_adapter:1.0>" ...
|
||||
```
|
||||
|
||||
## img2video
|
||||
|
||||
Pass a pre-rendered image via `-i / --init-img` to animate FROM it. All N output frames start from the encoded init latent, then per-frame noise is added at `--strength`. Character identity, composition, and quality are anchored by the init image; the motion module adds subtle motion on top.
|
||||
|
||||
Left: init image rendered with `-M img_gen`. Right: 8-frame vid_gen output.
|
||||
|
||||
<img src="../assets/animatediff/img2video_demo.gif" width="512"/>
|
||||
|
||||
```
|
||||
sd-cli -M img_gen ... -o init.png # any high-quality still
|
||||
sd-cli -M vid_gen --motion-module mm_sd15_v3.safetensors \
|
||||
-i init.png --strength 0.75 \
|
||||
--cfg-scale 7.0 --sampling-method euler --scheduler karras \
|
||||
-H 512 -W 512 --video-frames 8 --steps 25 -s 42 \
|
||||
-p "..." -o out.avi
|
||||
```
|
||||
|
||||
`--strength` controls how far the motion module is allowed to deviate from the init image (higher = more motion, lower = more static).
|
||||
|
||||
## Notes
|
||||
|
||||
- The motion module was trained at `video_length=16`. Running with
|
||||
`--video-frames 16` gives the best coherence; F=8 works but shows a shorter
|
||||
motion arc. Frame counts up to 32 are supported by the positional encoding
|
||||
but exceed the trained regime and produce more static output.
|
||||
- At `--video-frames 1` the motion module is skipped entirely and the output
|
||||
is bit-identical to `-M img_gen`. This avoids the single-token
|
||||
temporal-attention degeneracy that would otherwise emit an untrained-magnitude
|
||||
residual on a single-frame sample.
|
||||
- The base UNet is frozen, so character identity and style follow the SD 1.5
|
||||
checkpoint you pass to `--model`. LoRAs and prompt weighting attach to the
|
||||
base model in the usual way.
|
||||
- No mid_block motion module in v3. `mm_sdxl_v10_beta` (SDXL variant) is not
|
||||
supported yet.
|
||||
- Output is written as MJPEG AVI. Use `--fps` to set playback speed.
|
||||
136
docs/backend.md
@@ -3,7 +3,7 @@
|
||||
`stable-diffusion.cpp` has two backend assignments:
|
||||
|
||||
- `--backend` selects the runtime backend used to execute model graphs.
|
||||
- `--params-backend` selects the backend used to allocate model parameters.
|
||||
- `--params-backend` selects where model parameters are kept.
|
||||
|
||||
If `--params-backend` is not set, parameters use the same backend as their module runtime backend.
|
||||
|
||||
@@ -29,6 +29,20 @@ The same syntax is used for parameter placement:
|
||||
sd-cli -m model.safetensors -p "a cat" --backend cuda0 --params-backend te=cpu,vae=cpu
|
||||
```
|
||||
|
||||
`--params-backend` also accepts the special value `disk`:
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --backend cuda0 --params-backend disk
|
||||
```
|
||||
|
||||
`--max-vram` can target resolved backend/device names:
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --backend diffusion=cuda0,vae=vulkan0 --max-vram cuda0=6,vulkan0=2
|
||||
```
|
||||
|
||||
The budget applies to every module running on that backend.
|
||||
|
||||
Module names are case-insensitive. Hyphens and underscores in module names are ignored, so `clip_vision`, `clip-vision`, and `clipvision` are equivalent.
|
||||
|
||||
`all=`, `default=`, and `*=` can be used to set the default backend inside a mixed assignment:
|
||||
@@ -37,6 +51,97 @@ Module names are case-insensitive. Hyphens and underscores in module names are i
|
||||
sd-cli -m model.safetensors -p "a cat" --backend all=cuda0,te=cpu
|
||||
```
|
||||
|
||||
## Multiple devices per module (layer split)
|
||||
|
||||
A `--backend` module assignment can list several devices separated by `&`:
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --backend "diffusion=cuda0&cuda1"
|
||||
```
|
||||
|
||||
The module's transformer blocks are then distributed across the listed devices
|
||||
in contiguous ranges sized proportionally to each device's free memory (minus a
|
||||
compute-buffer headroom of about 2 GiB per device), and the
|
||||
module's graphs are executed with a `ggml_backend_sched` that runs each block
|
||||
on the device holding its weights, copying the residual stream at the range
|
||||
boundaries. The first device in the list is the module's main device: it also
|
||||
holds the non-block tensors (embeddings, final norms, small sub-runners such as
|
||||
CLIP models or projectors) and the graph inputs/outputs.
|
||||
|
||||
Layer split is supported for the `diffusion` and `te` modules. For `te` it
|
||||
applies to the dominant text encoder (`t5xxl` or the LLM); other modules accept
|
||||
only a single device. If the module has no recognizable transformer blocks, the
|
||||
assignment falls back to the first listed device.
|
||||
|
||||
`--params-backend` accepts no device lists. If the module has no explicit
|
||||
params assignment, each block range's parameters are loaded directly to (and,
|
||||
with `--params-backend diffusion=disk`, released directly from) its own device;
|
||||
an explicit assignment such as `te=cpu` keeps the parameters on that backend
|
||||
and stages each range to its device on demand.
|
||||
|
||||
Layer split cannot be combined with `--max-vram` graph-cut segmentation or
|
||||
`--stream-layers` for the split module; those are single-device mechanisms and
|
||||
are disabled for it.
|
||||
|
||||
Use `--list-devices` to see the device names available on the system.
|
||||
|
||||
### Row split (`--split-mode row`)
|
||||
|
||||
`--split-mode` selects how a multi-device module distributes its weights:
|
||||
`layer` (the default, described above) or `row`. It accepts a single mode or
|
||||
per-module assignments:
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --backend "diffusion=cuda0&cuda1" --split-mode row
|
||||
sd-cli -m model.safetensors -p "a cat" --backend "diffusion=cuda0&cuda1,te=cuda0&cuda1" --split-mode diffusion=row,te=layer
|
||||
```
|
||||
|
||||
In row mode the module keeps executing on its main (first listed) device, but
|
||||
its transformer-block matmul weights are allocated in the backend's row-split
|
||||
buffer type, which slices each weight's rows across the listed devices in
|
||||
proportion to free memory and runs those matmuls on all devices in parallel.
|
||||
Compared to a layer split this uses all GPUs within every layer (instead of
|
||||
sequentially device by device) at the cost of a cross-device reduction per
|
||||
matmul - usually the faster option when the devices have fast interconnect.
|
||||
|
||||
Row split requires backend support for split buffers and is currently
|
||||
available on CUDA only; on other backends (or when the listed devices belong
|
||||
to different backend registries) the module falls back to a layer split.
|
||||
Embeddings, normalization weights, biases and other non-block tensors stay in
|
||||
regular buffers on the main device.
|
||||
|
||||
Direct ("immediately") LoRA application cannot patch row-split tensors; with
|
||||
`--split-mode row` the automatic LoRA mode selects runtime application, and an
|
||||
explicit `--lora-apply-mode immediately` skips the split tensors with a
|
||||
warning.
|
||||
|
||||
## Automatic placement (`--auto-fit`)
|
||||
|
||||
`--auto-fit` derives the `diffusion` / `te` / `vae` placements from the model
|
||||
metadata and the per-device memory budgets, then feeds them into the same
|
||||
backend assignment mechanism described above (the chosen specs are printed).
|
||||
`--backend` and `--params-backend` are ignored while auto-fit is enabled.
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --auto-fit
|
||||
sd-cli -m model.safetensors -p "a cat" --auto-fit --max-vram cuda0=8,cuda1=14
|
||||
sd-cli -m model.safetensors -p "a cat" --auto-fit --split-mode row
|
||||
```
|
||||
|
||||
Budgets reuse `--max-vram`: a positive per-device value caps what auto-fit
|
||||
plans with on that device, a negative value means "free memory minus that many
|
||||
GiB", and with no budget set each device's free memory minus a 512 MiB margin
|
||||
is used. (The same values still drive graph-cut segmented execution for
|
||||
modules that end up on a single device.)
|
||||
|
||||
When everything fits resident, components are simply spread across the
|
||||
available GPUs. When it does not, auto-fit switches to time-share mode: the
|
||||
heavy components get `disk` params residency (loaded for their phase, freed
|
||||
after), and a component too large for any single device is split across all
|
||||
GPUs with the layer/row split mechanism (`--split-mode` selects which, layer
|
||||
by default). Components that fit nowhere fall back to the CPU. If a VAE decode
|
||||
still runs out of memory, tiling is enabled and the decode retried once.
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Purpose | Accepted names |
|
||||
@@ -48,6 +153,7 @@ sd-cli -m model.safetensors -p "a cat" --backend all=cuda0,te=cpu
|
||||
| `controlnet` | ControlNet | `controlnet`, `control` |
|
||||
| `photomaker` | PhotoMaker ID encoder and PhotoMaker LoRA | `photomaker`, `photomakerid`, `pmid`, `photo` |
|
||||
| `upscaler` | ESRGAN upscaler | `upscaler`, `esrgan`, `hires` |
|
||||
| `detector` | ADetailer YOLOv8 detector | `detector`, `adetailer`, `yolo` |
|
||||
|
||||
`te` is the preferred module name for text encoders. `clip` is kept as an accepted alias because many existing commands and model names use CLIP terminology.
|
||||
|
||||
@@ -64,9 +170,11 @@ The special values `auto`, `default`, and an empty backend name select the defau
|
||||
|
||||
The special value `gpu` selects the first GPU backend, falling back to the first integrated GPU backend.
|
||||
|
||||
The special value `disk` is accepted only by `--params-backend`. `--backend disk` is invalid because `disk` is a parameter residency mode, not a runtime compute backend.
|
||||
|
||||
## Runtime backend vs. parameter backend
|
||||
|
||||
The runtime backend controls where graph execution runs. The parameter backend controls where model weights are allocated.
|
||||
The runtime backend controls where graph execution runs. The parameter backend controls where model weights are allocated or whether they are reloaded from disk on demand.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -76,6 +184,16 @@ sd-cli -m model.safetensors -p "a cat" --backend cuda0 --params-backend cpu
|
||||
|
||||
This runs all modules on `cuda0`, but stores parameters in CPU RAM. During execution, parameters are moved to the runtime backend as needed.
|
||||
|
||||
For example:
|
||||
|
||||
```shell
|
||||
sd-cli -m model.safetensors -p "a cat" --backend cuda0 --params-backend disk
|
||||
```
|
||||
|
||||
This runs all modules on `cuda0`, reloads parameters from the model file as needed, and releases those parameter buffers after use.
|
||||
|
||||
`disk` is never selected implicitly. If `--params-backend` is not set, parameters use the runtime backend.
|
||||
|
||||
Per-module assignments can be mixed:
|
||||
|
||||
```shell
|
||||
@@ -100,23 +218,27 @@ uses one shared CPU backend for both `te` and `vae` runtime execution.
|
||||
|
||||
Runtime and parameter assignments also share the same backend cache. If `--backend diffusion=cuda0` and `--params-backend diffusion=cuda0` resolve to the same device, both use the same backend instance.
|
||||
|
||||
`--params-backend disk` does not create a separate backend instance. Parameters are loaded lazily using the module runtime backend.
|
||||
|
||||
`SDBackendManager` owns the backend instances and frees them when the context or upscaler is destroyed. Model runners receive non-owning runtime and parameter backend pointers and do not free them.
|
||||
|
||||
## Compatibility flags
|
||||
|
||||
The older CPU placement flags are still supported:
|
||||
The example CLI/server still accepts these older CPU placement flags as compatibility aliases:
|
||||
|
||||
- `--clip-on-cpu`
|
||||
- `--vae-on-cpu`
|
||||
- `--control-net-cpu`
|
||||
- `--offload-to-cpu`
|
||||
|
||||
`--clip-on-cpu`, `--vae-on-cpu`, and `--control-net-cpu` affect runtime backend assignment only when `--backend` is not set. They map to `te=cpu`, `vae=cpu`, and `controlnet=cpu`.
|
||||
`--clip-on-cpu`, `--vae-on-cpu`, and `--control-net-cpu` are deprecated. The example argument layer prepends `te=cpu`, `vae=cpu`, and `controlnet=cpu` to `--backend` before creating the context.
|
||||
|
||||
`--offload-to-cpu` affects parameter backend assignment only when `--params-backend` is not set. It is equivalent to:
|
||||
`--offload-to-cpu` prepends a CPU default to the parameter assignment in the caller before creating the context:
|
||||
|
||||
```shell
|
||||
--params-backend cpu
|
||||
--params-backend '*=cpu'
|
||||
```
|
||||
|
||||
Explicit `--backend` and `--params-backend` assignments are preferred for new commands.
|
||||
Because this default is inserted first, later explicit `--params-backend` entries can still override it, for example `--offload-to-cpu --params-backend te=disk` keeps non-TE parameters on CPU and reloads TE parameters from disk.
|
||||
|
||||
Library callers should set `backend` and `params_backend` directly. The old CPU/offload fields are no longer part of the C API. Explicit `--backend` and `--params-backend` assignments are preferred for new commands.
|
||||
|
||||
31
docs/boogu_image.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# How to Use
|
||||
|
||||
Boogu Image uses a Boogu diffusion transformer, the FLUX VAE, and Qwen3-VL as the LLM text and vision encoder.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Boogu Image
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Boogu-Image/tree/main/diffusion_models
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/black-forest-labs/FLUX.1-dev/blob/main/ae.safetensors
|
||||
- Download Qwen3-VL 8B
|
||||
- gguf: https://huggingface.co/unsloth/Qwen3-VL-8B-Instruct-GGUF/tree/main
|
||||
- For image editing with GGUF text encoders, also download the matching mmproj file and pass it with `--llm_vision`.
|
||||
|
||||
## Examples
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
<img width="256" alt="Boogu Image Base example" src="../assets/boogu/example.png" />
|
||||
|
||||
### 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'"
|
||||
```
|
||||
|
||||
<img width="256" alt="Boogu Image Edit example" src="../assets/boogu/edit_example.png" />
|
||||
@@ -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.
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
## Run
|
||||
@@ -24,10 +24,9 @@ You can download the preconverted gguf weights from [silveroxides/Chroma-GGUF](h
|
||||
For example:
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe --diffusion-model ..\models\chroma-unlocked-v40-q8_0.gguf --vae ..\models\ae.sft --t5xxl ..\models\t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'chroma.cpp'" --cfg-scale 4.0 --sampling-method euler -v --chroma-disable-dit-mask --clip-on-cpu
|
||||
.\bin\Release\sd-cli.exe --diffusion-model ..\models\chroma-unlocked-v40-q8_0.gguf --vae ..\models\ae.sft --t5xxl ..\models\t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'chroma.cpp'" --cfg-scale 4.0 --sampling-method euler -v --model-args chroma_use_dit_mask=false --clip-on-cpu
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
## Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="Chroma1-Radiance" src="../assets/flux/chroma1-radiance.png" />
|
||||
|
||||
@@ -19,7 +19,7 @@ docker run --rm --init -v /path/to/models:/models -v /path/to/output/:/output -p
|
||||
## Building using Docker
|
||||
|
||||
```shell
|
||||
docker build -t sd .
|
||||
docker build -f docker/Dockerfile -t sd .
|
||||
```
|
||||
|
||||
## Building variants using Docker
|
||||
@@ -27,7 +27,7 @@ docker build -t sd .
|
||||
Vulkan:
|
||||
|
||||
```shell
|
||||
docker build -f Dockerfile.vulkan -t sd .
|
||||
docker build -f docker/Dockerfile.vulkan -t sd .
|
||||
```
|
||||
|
||||
## Run locally built image's CLI
|
||||
|
||||
96
docs/edit.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Image Editing
|
||||
|
||||
Image editing in `stable-diffusion.cpp` allows you to use reference images to guide the generation process, enabling tasks like identity preservation, style transfer, or layout modification.
|
||||
|
||||
|
||||
## Supported Models
|
||||
|
||||
Depending on the architecture, different models handle reference images differently.
|
||||
|
||||
| Model | Default Preset |
|
||||
| :--- | :--- |
|
||||
| [**FLUX.1-Kontext-dev**](./kontext.md) | `flux_kontext` |
|
||||
| [**LongCat Image Edit**](./longcat_image.md) | `longcat` |
|
||||
| [**Qwen Image Edit**](./qwen_image_edit.md) | `qwen` |
|
||||
| **Qwen Image LAYERED** | `qwen_layered` |
|
||||
| [**Flux.2 [Dev] / Flux.2 [Klein]**](./flux2.md) | `flux2` |
|
||||
| [**Boogu Image Edit**](./boogu_image.md) | `z_image_omni` |
|
||||
| **Krea2 (Community Edit LoRAs)** | `krea2_ostris_edit` |
|
||||
| [**Mage-Flow-Edit**](./mage_flow.md#image-editing) | `mage_flow` |
|
||||
| **Anima (Community Edit LoRAs)** | `cosmos_reference` |
|
||||
|
||||
Stable-diffusion.spp also supports basic Unet-based editing models like instruct-pix2pix or CosXL-Edit. This document is not about those.
|
||||
|
||||
---
|
||||
|
||||
## Configuring Reference Modes (`--ref-image-args`)
|
||||
|
||||
Different DiT-based editing models require different configurations to process reference images correctly (e.g., whether to use a Vision Language Model (VLM) encoder or pass VAE-encoded images directly to the DiT).
|
||||
|
||||
To simplify this, we provide **Presets**. By default, the system automatically selects the best preset based on the model architecture. However, you can override this using the `--ref-image-args` argument.
|
||||
|
||||
### Usage
|
||||
The `--ref-image-args` argument accepts a comma-separated list of key-value pairs:
|
||||
|
||||
**Using a preset:**
|
||||
`--ref-image-args "preset=qwen_layered"`
|
||||
|
||||
**Using a preset with a specific override:**
|
||||
`--ref-image-args "preset=krea2_edit,force_ref_timestep_zero=true"`
|
||||
|
||||
### Available Presets
|
||||
|
||||
| Preset | Primary Use Case |
|
||||
| :--- | :--- |
|
||||
| `flux_kontext` | FLUX.1 Kontext |
|
||||
| `longcat` | LongCat Image Edit |
|
||||
| `flux2` | FLUX.2 models |
|
||||
| `qwen` | Qwen Image Edit |
|
||||
| `qwen_layered` | Qwen Image Layered |
|
||||
| `z_image_omni` | Boogu, Z-Image Omni |
|
||||
| `krea2_ostris_edit` | Most Krea2 Community edit LoRAs (trained with Ostris script) |
|
||||
| `mage_flow` | Mage-Flow-Edit |
|
||||
| `krea2_edit` | Specifically for [lbouaraba/krea2edit](https://huggingface.co/conradlocke/krea2-identity-edit). (or similar) |
|
||||
| `cosmos_reference` | For Anima |
|
||||
| `default` | Uses the automatic detection based on model architecture. |
|
||||
|
||||
---
|
||||
|
||||
## Advanced Parameter Reference
|
||||
|
||||
If presets are insufficient, you can manually configure the following parameters via `--ref-image-args`:
|
||||
|
||||
| Key | Type | Description | Allowed Values |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `preset` | string | Overrides the automatic preset. | (See the Presets table above) |
|
||||
| `pass_to_vlm` | bool | Whether reference images are passed to the VLM encoder. | `true`, `false` |
|
||||
| `pass_to_dit` | bool | Whether VAE-encoded references are passed directly to the DiT. | `true`, `false` |
|
||||
| `ref_index_mode` | string | Behavior of the RoPE index. | `fixed`, `increase`, `decrease` |
|
||||
| `force_ref_timestep_zero` | bool | Forces timestep=0 for reference tokens. | `true`, `false` (Krea2 only) |
|
||||
| `resize_before_vae` | bool | Whether reference images are resized before VAE encoding. | `true`, `false` |
|
||||
| `vae_input_max_pixels` | int | Maximum pixel area for VAE reference inputs. | Integer |
|
||||
| `vlm_resize_mode` | string | How to resize VLM reference inputs. | `longest_side`, `area`, `none` |
|
||||
| `vlm_max_size` | int | Maximum VLM input size; interpreted according to `vlm_resize_mode`. | Integer |
|
||||
| `vlm_min_size` | int | Minimum VLM input size; interpreted according to `vlm_resize_mode`. | Integer |
|
||||
| `vlm_size` | int | Shortcut to set both VLM min and max size to the same value. | Integer |
|
||||
|
||||
### Preset Default Values
|
||||
|
||||
For a technical overview of how each preset is configured, see the table below.
|
||||
|
||||
| Preset | VLM | RoPE Index | Cond Resize | Special Notes |
|
||||
| :--- | :---: | :---: | :---: | :--- |
|
||||
| `flux_kontext` | No | `fixed` | `none` | |
|
||||
| `longcat` | Yes | `fixed` | `area` | |
|
||||
| `flux2` | No | `increase` | `none` | |
|
||||
| `qwen` | Yes | `increase` | `area` | |
|
||||
| `qwen_layered` | Yes | `decrease` | `area` | |
|
||||
| `mage_flow` | Yes | `increase` | `longest` | `vlm_max_size = 384`, VAE input resized to target |
|
||||
| `z_image_omni` | Yes | `fixed` | `area` | |
|
||||
| `krea2_ostris_edit`| Yes | `increase` | `area` | `force_ref_timestep_zero = true` |
|
||||
| `krea2_edit` | Yes | `increase` | `longest` | `vlm_size = 768` |
|
||||
| `cosmos_reference` | No | `fixed` | `none` | `resize_before_vae = false` |
|
||||
|
||||
**Additional Default Notes:**
|
||||
- **VLM Input Sizes:** For most presets, `vlm_max_size` and `vlm_min_size` are set to `-1`, meaning the values are model-dependent and handled automatically. In `area` mode they represent pixel area; in `longest_side` mode they represent a side length in pixels.
|
||||
- **VAE Input Size:** `vae_input_max_pixels` defaults to $1024 \times 1024$ pixels (`1048576`).
|
||||
@@ -21,7 +21,7 @@ You can run ERNIE-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — o
|
||||
### ERNIE-Image-Turbo
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img width="256" alt="ERNIE-Image example" src="../assets/ernie_image/example.png" />
|
||||
|
||||
@@ -17,7 +17,7 @@ You can download the preconverted gguf weights from [FLUX.1-dev-gguf](https://hu
|
||||
|
||||
For example:
|
||||
```
|
||||
.\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
|
||||
.\bin\Release\sd-cli.exe -M convert -m ..\models\unet\flux1-dev.sft -o ..\models\flux1-dev-q8_0.gguf -v --type q8_0
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
### Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2 example" src="../assets/flux2/example.png" />
|
||||
@@ -42,19 +42,19 @@
|
||||
### Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-4b" src="../assets/flux2/flux2-klein-4b.png" />
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-4b-edit" src="../assets/flux2/flux2-klein-4b-edit.png" />
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-base-4b" src="../assets/flux2/flux2-klein-base-4b.png" />
|
||||
@@ -78,19 +78,19 @@
|
||||
### Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-9b" src="../assets/flux2/flux2-klein-9b.png" />
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-9b-edit" src="../assets/flux2/flux2-klein-9b-edit.png" />
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="flux2-klein-base-9b" src="../assets/flux2/flux2-klein-base-9b.png" />
|
||||
@@ -12,7 +12,7 @@
|
||||
### HiDream-O1-Image-Dev
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -m ..\..\ComfyUI\models\diffusion_models\hidream_o1_image_dev_bf16.safetensors -p "a lovely cat holding a sign says
|
||||
.\bin\Release\sd-cli.exe -m ..\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
|
||||
```
|
||||
|
||||
|
||||
24
docs/hunyuan_video.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# HunyuanVideo 1.5
|
||||
|
||||
HunyuanVideo 1.5 uses a HunyuanVideo diffusion transformer, a causal video VAE, Qwen2.5-VL 7B for the main text conditioning,
|
||||
and ByT5 Small GlyphXL for glyph-aware text conditioning.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download HunyuanVideo 1.5
|
||||
- safetensors: https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/tree/main/split_files/diffusion_models
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/tree/main/split_files/vae
|
||||
- Download qwen_2.5_vl 7b
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/tree/main/split_files/text_encoders
|
||||
- gguf: https://huggingface.co/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/tree/main
|
||||
- Download byt5 small glyphxl
|
||||
- safetensros: https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/tree/main/split_files/text_encoders
|
||||
|
||||
## Text-to-video example
|
||||
|
||||
```shell
|
||||
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\hunyuanvideo1.5_720p_t2v_fp16.safetensors --vae ..\models\vae\hunyuanvideo15_vae_fp16.safetensors --llm ..\models\text_encoders\qwen_2.5_vl_7b.safetensors --t5xxl ..\models\text_encoders\byt5_small_glyphxl_fp16.safetensors -p "a lovely cat" --cfg-scale 6.0 --sampling-method euler -v -W 1280 -H 720 --offload-to-cpu --diffusion-fa --video-frames 33 --vae-tiling
|
||||
```
|
||||
|
||||
<video src=../assets/hunyuan_video/hy1.5_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
40
docs/ideogram4.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# How to Use
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Ideogram4
|
||||
- safetensors: https://huggingface.co/ideogram-ai/ideogram-4-fp8/tree/main/transformer
|
||||
- Download Ideogram4 uncond
|
||||
- safetensors: https://huggingface.co/ideogram-ai/ideogram-4-fp8/tree/main/unconditional_transformer
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/black-forest-labs/FLUX.2-dev/tree/main
|
||||
- Download Qwen3-VL-8B-Instruct
|
||||
- gguf: https://huggingface.co/unsloth/Qwen3-VL-8B-Instruct-GGUF/tree/main
|
||||
|
||||
## Convert weights
|
||||
|
||||
fp8 scale -> bf16
|
||||
|
||||
```
|
||||
python .\convert_fp8_scale_to_bf16.py --input .\ideogram4_fp8.safetensors --output ideogram4_bf16.safetensors
|
||||
python .\convert_fp8_scale_to_bf16.py --input .\ideogram4_uncond_fp8.safetensors --output ideogram4_uncond_bf16.safetensors
|
||||
```
|
||||
|
||||
bf16 -> q8
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -M convert -m ideogram4_bf16.safetensors -o ideogram4-Q8_0.gguf --tensor-type-rules "^layers.*adaln_modulation.*weight=q8_0,layers.*attention.o.*weight=q8_0,layers.*attention.qkv.*weight=q8_0,layers.*feed_forward.*weight=q8_0" -v
|
||||
|
||||
.\bin\Release\sd-cli.exe -M convert -m ideogram4_uncond_bf16.safetensors -o ideogram4_uncond-Q8_0.gguf --tensor-type-rules "^layers.*adaln_modulation.*weight=q8_0,layers.*attention.o.*weight=q8_0,layers.*attention.qkv.*weight=q8_0,layers.*feed_forward.*weight=q8_0" -v
|
||||
```
|
||||
|
||||
If you want lower VRAM usage, you can change the quantization from q8_0 to a lower-level quantization, such as q4_0.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
<img alt="ideogram4 image example" src="../assets/ideogram4/example.png" />
|
||||
59
docs/imatrix.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Importance Matrix (imatrix) Quantization
|
||||
|
||||
## What is an Importance Matrix?
|
||||
|
||||
Quantization reduces the precision of a model's weights, decreasing its size and computational requirements. However, this can lead to a loss of quality. An importance matrix helps mitigate this by identifying which weights are *most* important for the model's performance. During quantization, these important weights are preserved with higher precision, while less important weights are quantized more aggressively. This allows for better overall quality at a given quantization level.
|
||||
|
||||
This originates from work done with language models in [llama.cpp](https://github.com/ggml-org/llama.cpp/blob/master/tools/imatrix/README.md).
|
||||
|
||||
## Usage
|
||||
|
||||
The imatrix feature involves two main steps: *training* the matrix and *using* it during quantization.
|
||||
|
||||
### Training the Importance Matrix
|
||||
|
||||
To generate an imatrix, run stable-diffusion.cpp with the `--imat-out` flag, specifying the output filename. This process runs alongside normal image generation.
|
||||
|
||||
```bash
|
||||
sd.exe [same exact parameters as normal generation] --imat-out imatrix.dat
|
||||
```
|
||||
|
||||
* **`[same exact parameters as normal generation]`**: Use the same command-line arguments you would normally use for image generation (e.g., prompt, dimensions, sampling method, etc.).
|
||||
* **`--imat-out imatrix.dat`**: Specifies the output file for the generated imatrix.
|
||||
|
||||
You can generate multiple images at once using the `-b` flag to speed up the training process.
|
||||
|
||||
### Continuing Training an Existing Matrix
|
||||
|
||||
If you want to refine an existing imatrix, use the `--imat-in` flag *in addition* to `--imat-out`. This will load the existing matrix and continue training it.
|
||||
|
||||
```bash
|
||||
sd.exe [same exact parameters as normal generation] --imat-out imatrix.dat --imat-in imatrix.dat
|
||||
```
|
||||
With that, you can train and refine the imatrix while generating images like you'd normally do.
|
||||
|
||||
### Using Multiple Matrices
|
||||
|
||||
You can load and merge multiple imatrices together:
|
||||
|
||||
```bash
|
||||
sd.exe [same exact parameters as normal generation] --imat-out imatrix.dat --imat-in imatrix.dat --imat-in imatrix2.dat
|
||||
```
|
||||
|
||||
### Quantizing with an Importance Matrix
|
||||
|
||||
To quantize a model using a trained imatrix, use the `-M convert` option (or equivalent quantization command) and the `--imat-in` flag, specifying the imatrix file.
|
||||
|
||||
```bash
|
||||
sd.exe -M convert [same exact parameters as normal quantization] --imat-in imatrix.dat
|
||||
```
|
||||
|
||||
* **`[same exact parameters as normal quantization]`**: Use the same command-line arguments you would normally use for quantization (e.g., target quantization method, input/output filenames).
|
||||
* **`--imat-in imatrix.dat`**: Specifies the imatrix file to use during quantization. You can specify multiple `--imat-in` flags to combine multiple matrices.
|
||||
|
||||
## Important Considerations
|
||||
|
||||
* The quality of the imatrix depends on the prompts and settings used during training. Use prompts and settings representative of the types of images you intend to generate for the best results.
|
||||
* Experiment with different training parameters (e.g., number of images, prompt variations) to optimize the imatrix for your specific use case.
|
||||
* The performance impact of training an imatrix during image generation or using an imatrix for quantization is negligible.
|
||||
* Using already quantized models to train the imatrix seems to be working fine.
|
||||
@@ -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.
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
27
docs/krea2.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# How to Use
|
||||
|
||||
Krea2 uses a Krea2 diffusion transformer, the Wan2.1 VAE, and Qwen3-VL 4B as the LLM text encoder.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Krea2 Raw
|
||||
- safetensors: https://huggingface.co/krea/Krea-2-Raw/tree/main
|
||||
- gguf: https://huggingface.co/realrebelai/KREA-2_GGUFs/tree/main/BASE
|
||||
- Download Krea2 Turbo
|
||||
- safetensors: https://huggingface.co/krea/Krea-2-Turbo/tree/main
|
||||
- gguf: https://huggingface.co/realrebelai/KREA-2_GGUFs/tree/main/TURBO
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/blob/main/split_files/vae/wan_2.1_vae.safetensors
|
||||
- Download Qwen3-VL 4B
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Krea-2/tree/main/text_encoders
|
||||
- gguf: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct-GGUF/tree/main
|
||||
|
||||
## Examples
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
<img width="256" alt="Krea2 Raw example" src="../assets/krea2/example.png" />
|
||||
@@ -18,7 +18,7 @@ Lens uses a Lens diffusion transformer, the FLUX.2 VAE, and GPT-OSS-20B as the L
|
||||
### Lens
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img width="256" alt="Lens Turbo example" src="../assets/lens/turbo_example.png" />
|
||||
|
||||
32
docs/lingbot_video.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# How to Use
|
||||
|
||||
Lingbot Video uses a Lingbot diffusion transformer, the Wan2.1 VAE, and Qwen3-VL 4B as the LLM text encoder.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download lingbot-video-dense-1.3b
|
||||
- safetensors: https://huggingface.co/robbyant/lingbot-video-dense-1.3b/tree/main/transformer
|
||||
- Download lingbot-video-moe-30b-a3b
|
||||
- safetensors: https://huggingface.co/robbyant/lingbot-video-moe-30b-a3b/tree/main/transformer
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/blob/main/split_files/vae/wan_2.1_vae.safetensors
|
||||
- Download Qwen3-VL 4B
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Krea-2/tree/main/text_encoders
|
||||
- gguf: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct-GGUF/tree/main
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `-M vid_gen`.
|
||||
- T2V uses the text prompt only.
|
||||
- I2V uses `-i` as the first video frame. The same image is also passed to the
|
||||
Qwen3-VL prompt enhancer when vision weights are available.
|
||||
- Video frames are aligned to Wan-style temporal compression, so use frame counts
|
||||
like 33, 49, or 81.
|
||||
|
||||
## Examples
|
||||
|
||||
### LingBot-Video T2V
|
||||
|
||||
```sh
|
||||
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\lingbot-video-dens-1.3b.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\wan_2.1_vae.safetensors -p '{"caption":{"comprehensive_description":"A lovely cat sits comfortably on a soft cushion near a sunlit window, looking calm, gentle, and adorable. The cat has soft fluffy fur, bright expressive eyes, small rounded ears, delicate whiskers, and a relaxed posture. Warm daylight falls across the cat from one side, creating soft highlights on the fur and a cozy glow around the scene. The background is softly blurred, showing hints of a peaceful indoor home environment with warm tones and gentle natural light. The overall atmosphere is cute, tender, serene, and photorealistic, emphasizing the cat''s charming appearance, soft texture, and affectionate presence.","camera_info":{"color":"Warm","frame_size":"Close Up","shot_type_angle":"Eye level","lens_size":"Medium Lens","composition":"Centered balanced","lighting":"Soft light","lighting_type":"Daylight"},"world_knowledge":[],"prominent_elements":[{"name":"lovely cat","description":"A cute and gentle domestic cat with soft fluffy fur, expressive eyes, and a calm relaxed presence.","location":"center of the frame","relative_size":"large","shape_and_color":"Small animal body with rounded face, triangular ears, bright eyes, and soft fur in warm natural tones","texture":"soft, fluffy, silky","appearance_details":"The cat has clean well-groomed fur, delicate whiskers, small ears, a cute nose, and bright attentive eyes. Its expression appears calm, affectionate, and slightly curious.","relationship":"Acts as the main subject and emotional focal point of the scene.","orientation":"facing the camera","pose":"sitting comfortably with a relaxed posture","expression":"gentle, adorable, calm, slightly curious","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"cat eyes","description":"Bright expressive eyes that give the cat a sweet and affectionate appearance.","location":"upper center of the cat face","relative_size":"small","shape_and_color":"Round almond-like eyes with glossy reflections","texture":"clear, glossy, reflective","appearance_details":"The eyes catch the soft daylight, creating small natural highlights that make the cat look vivid and alive.","relationship":"Enhance the emotional charm and cuteness of the cat.","orientation":"looking toward the camera","pose":"","expression":"soft and attentive","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"soft cushion","description":"A comfortable cushion or blanket where the cat is resting.","location":"bottom portion of the frame","relative_size":"medium","shape_and_color":"Soft rounded fabric surface in light warm neutral tones","texture":"plush, fabric, cozy","appearance_details":"The cushion gently supports the cat and adds a comfortable home-like feeling to the scene.","relationship":"Provides a cozy resting place for the cat.","orientation":"horizontal","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":""},{"name":"sunlit indoor background","description":"A softly blurred indoor background with warm daylight and peaceful home atmosphere.","location":"behind the cat, filling the upper and side areas of the frame","relative_size":"large","shape_and_color":"Soft abstract shapes in warm beige, cream, and pale golden tones","texture":"soft, blurry, bokeh-like","appearance_details":"The background is intentionally out of focus, keeping attention on the cat while creating a cozy and serene mood.","relationship":"Provides a warm and gentle environment that supports the cute domestic scene.","orientation":"upright","pose":"","expression":"","clothing":"","gender":"","skin_tone_and_texture":"","is_cluster":true,"number_of_objects":"numerous"}]}}' -n '{"universal_negative":{"visual_quality":["low quality","worst quality","blurry","pixelated","jpeg artifacts","low resolution","unstable color","color flicker","underexposed","overexposed","invisible subject","subject hidden in darkness"],"artistic_style":["painting","illustration","drawing","cartoon","3d render","cgi","sketch","digital art"],"composition_and_content":["text","watermark","signature","logo","subtitles","pillarboxed","side bars","portrait image in landscape frame"],"temporal_and_motion_stability":["flickering","jittery","motion blur","temporal inconsistency","warping","morphing","incoherent motion","unnatural movement","static object with sudden jump","frame-to-frame inconsistency"],"material_and_structure":["plastic-like glass","unrealistic texture","deformed bottle","liquid freezing improperly","distorted reflections"]}}' --diffusion-fa --offload-to-cpu --cfg-scale 3 --video-frames 33 -v
|
||||
```
|
||||
@@ -24,7 +24,7 @@ LongCat uses quoted text for character-level text rendering. Put target text ins
|
||||
### LongCat Image
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="longcat example" src="../assets/longcat/example.png" />
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
### LTX-2.3 dev T2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video
|
||||
@@ -33,7 +33,7 @@
|
||||
### LTX-2.3 dev I2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video
|
||||
@@ -45,7 +45,7 @@
|
||||
### LTX-2.3 dev FLF2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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`.
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
45
docs/mage_flow.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Mage-Flow
|
||||
|
||||
[Mage-Flow](https://github.com/microsoft/Mage) uses a 4B native-resolution multimodal diffusion transformer, Qwen3-VL for text and image conditioning, and the 128-channel Mage-VAE. Both text-to-image and instruction-based image editing checkpoints are supported.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Mage-Flow
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow/tree/main/transformer
|
||||
- Download Mage-Flow-Base
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow-Base/tree/main/transformer
|
||||
- Download Mage-Flow-Turbo
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow-Turbo/tree/main/transformer
|
||||
- Download Mage-Flow-Edit
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow-Edit/tree/main/transformer
|
||||
- Download Mage-Flow-Edit-Turbo
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow-Edit-Turbo/tree/main/transformer
|
||||
- Download Mage-Flow-Edit-Base
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow-Edit-Base/tree/main/transformer
|
||||
- Download Mage-Flow vae
|
||||
- safetensors: https://huggingface.co/microsoft/Mage-Flow/tree/main/vae
|
||||
- Download Qwen3-VL 4B
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Krea-2/tree/main/text_encoders
|
||||
- gguf: https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct-GGUF/tree/main
|
||||
|
||||
## Text-to-image
|
||||
|
||||
Use 30 steps for Base models and 4 steps with `--cfg-scale 1` for Turbo models. Image dimensions must be multiples of 16; the official checkpoints are trained for native resolutions from 512 to 2048 pixels.
|
||||
|
||||
```bash
|
||||
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Mage-Flow-Turbo.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\mage_vae.safetensors -p "a lovely cat holding a sign says 'mage.cpp'" --cfg-scale 1.0 --steps 4 --diffusion-fa -v --offload-to-cpu
|
||||
```
|
||||
|
||||
<img width="256" alt="Mage-Flow example" src="../assets/mage_flow/example.png" />
|
||||
|
||||
## Image editing
|
||||
|
||||
Mage-Flow-Edit accepts one or more reference images. The default `mage_flow` reference preset sends each image to both Qwen3-VL and the diffusion transformer, caps the VLM copy's longest edge at 384 pixels, and keeps the VAE copy at the requested output resolution.
|
||||
|
||||
For the Turbo edit checkpoint, use 4 steps and `--cfg-scale 1`.
|
||||
|
||||
```bash
|
||||
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\Mage-Flow-Edit.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --llm_vision ..\models\text_encoders\Qwen3-VL-4B-Instruct-mmproj-BF16.gguf --vae ..\models\vae\mage_vae.safetensors -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'mage.cpp'" --cfg-scale 4.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu
|
||||
```
|
||||
|
||||
<img width="256" alt="Mage-Flow-Edit example" src="../assets/mage_flow/edit_example.png" />
|
||||
48
docs/minit2i.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# How to Use
|
||||
|
||||
MiniT2I uses a MiniT2I diffusion transformer and `google/flan-t5-large` as the text encoder.
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download MiniT2I diffusion model
|
||||
- safetensors: https://huggingface.co/MiniT2I/MiniT2I/tree/main/minit2i-b-16/transformer (`diffusion_pytorch_model.safetensors`)
|
||||
- Download flan-t5-large text encoder
|
||||
- safetensors: https://huggingface.co/google/flan-t5-large/tree/main (`model.safetensors`)
|
||||
|
||||
## Examples
|
||||
|
||||
### Mac Metal
|
||||
|
||||
```
|
||||
./bin/sd-cli \
|
||||
--backend metal \
|
||||
--diffusion-model ../models/minit2i/diffusion_pytorch_model.safetensors \
|
||||
--t5xxl ../models/flan-t5-large/model.safetensors \
|
||||
--prompt "a cat" \
|
||||
--steps 100 \
|
||||
--cfg-scale 6 \
|
||||
--width 512 \
|
||||
--height 512 \
|
||||
--seed 42 \
|
||||
--sampling-method euler \
|
||||
--rng cpu \
|
||||
--output minit2i_metal.png \
|
||||
--threads 8
|
||||
```
|
||||
|
||||
### CUDA with diffusion flash attention
|
||||
|
||||
```
|
||||
./bin/sd-cli \
|
||||
--diffusion-model ../models/minit2i/diffusion_pytorch_model.safetensors \
|
||||
--t5xxl ../models/flan-t5-large/model.safetensors \
|
||||
--prompt "a cat" \
|
||||
--steps 100 \
|
||||
--cfg-scale 6 \
|
||||
--width 512 \
|
||||
--height 512 \
|
||||
--seed 42 \
|
||||
--sampling-method euler \
|
||||
--diffusion-fa \
|
||||
--output minit2i_cuda.png
|
||||
```
|
||||
118
docs/model_config.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Model Configuration Conventions
|
||||
|
||||
This document describes the conventions for model configuration structs and
|
||||
weight-based configuration detection.
|
||||
|
||||
## Config Types
|
||||
|
||||
Model configuration should live in a model-specific `*Config` struct.
|
||||
|
||||
Examples:
|
||||
|
||||
- `ZImageConfig`
|
||||
- `UNetConfig`
|
||||
- `MMDiTConfig`
|
||||
- `LLMConfig`
|
||||
|
||||
Preserve established acronym casing in type names, such as `UNet`, `MMDiT`,
|
||||
`LLM`, `VAE`, and `T5`.
|
||||
|
||||
Place the config struct near the top of the model header, before the main model
|
||||
blocks and runner types that consume it.
|
||||
|
||||
## Config Variables
|
||||
|
||||
Variables and members that hold a config should be named `config`.
|
||||
|
||||
Examples:
|
||||
|
||||
```cpp
|
||||
UNetConfig config;
|
||||
UnetModelBlock unet;
|
||||
|
||||
MMDiTRunner(...)
|
||||
: DiffusionModelRunner(backend, params_backend, prefix),
|
||||
config(MMDiTConfig::detect_from_weights(tensor_storage_map, prefix)),
|
||||
mmdit(config) {
|
||||
}
|
||||
```
|
||||
|
||||
Avoid alternate names such as `params`, `params_cfg`, `model_params`, or
|
||||
model-specific aliases unless an existing public API requires them.
|
||||
|
||||
## Weight Detection
|
||||
|
||||
If a model can derive configuration from loaded weight metadata, expose that
|
||||
logic as a static method on the config type:
|
||||
|
||||
```cpp
|
||||
static XxxConfig detect_from_weights(const String2TensorStorage& tensor_storage_map,
|
||||
const std::string& prefix);
|
||||
```
|
||||
|
||||
Additional selector arguments are allowed when required by an existing model
|
||||
family, for example `SDVersion version` or an architecture enum:
|
||||
|
||||
```cpp
|
||||
static UNetConfig detect_from_weights(const String2TensorStorage& tensor_storage_map,
|
||||
const std::string& prefix,
|
||||
SDVersion version = VERSION_SD1);
|
||||
```
|
||||
|
||||
Use `TensorStorage` metadata, especially `n_dims` and `ne`, to infer shapes.
|
||||
Do not load or parse tensor data for config detection.
|
||||
|
||||
Detection should respect `prefix`. For nested weights, construct full names from
|
||||
`prefix + "." + suffix` or filter entries with `starts_with(name, prefix)`.
|
||||
|
||||
Do not add persistent config fields such as `inferred_from_weights` only to
|
||||
record whether detection happened. If the function needs to decide whether to
|
||||
print a debug line, keep that as local control flow inside `detect_from_weights`.
|
||||
|
||||
## Logging
|
||||
|
||||
When config values are inferred from weights, print one `LOG_DEBUG` line at the
|
||||
end of `detect_from_weights`.
|
||||
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
LOG_DEBUG("llm: num_layers = %" PRId64 ", vocab_size = %" PRId64 ", hidden_size = %" PRId64 ", intermediate_size = %" PRId64,
|
||||
config.num_layers,
|
||||
config.vocab_size,
|
||||
config.hidden_size,
|
||||
config.intermediate_size);
|
||||
```
|
||||
|
||||
Only print the config detection log when the function actually inferred values
|
||||
from weights. Do not duplicate the same config summary in runner constructors or
|
||||
model loading code.
|
||||
|
||||
Use the correct format specifiers for field types, such as `%" PRId64 "` for
|
||||
`int64_t` and `%d` for `int`.
|
||||
|
||||
## Runner And Model Responsibilities
|
||||
|
||||
Runners should detect the config once and pass it into the model block:
|
||||
|
||||
```cpp
|
||||
struct XxxRunner : public DiffusionModelRunner {
|
||||
XxxConfig config;
|
||||
XxxModel model;
|
||||
|
||||
XxxRunner(..., const String2TensorStorage& tensor_storage_map, const std::string prefix)
|
||||
: DiffusionModelRunner(backend, params_backend, prefix),
|
||||
config(XxxConfig::detect_from_weights(tensor_storage_map, prefix)),
|
||||
model(config) {
|
||||
model.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Model blocks should consume `config` directly instead of re-scanning weights in
|
||||
their constructors. Keep config-derived behavior centralized in the config
|
||||
struct.
|
||||
|
||||
If a model has no weight-derived config today, it may still provide
|
||||
`detect_from_weights` for API consistency, but it should not print a config
|
||||
detection log unless it actually derives values from weights.
|
||||
@@ -13,7 +13,7 @@
|
||||
## Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="ovis image example" src="../assets/ovis_image/example.png" />
|
||||
@@ -21,6 +21,58 @@ and the compute buffer shrink in the debug log:
|
||||
|
||||
Using `--offload-to-cpu` allows you to offload weights to the CPU, saving VRAM without reducing generation speed.
|
||||
|
||||
## Use params backend to reduce VRAM or RAM usage.
|
||||
|
||||
`--params-backend` controls where model parameters are kept. If it is not set, parameters use the same backend as `--backend`, so a GPU runtime backend also keeps parameters in VRAM.
|
||||
|
||||
Use CPU params to reduce VRAM usage:
|
||||
|
||||
```shell
|
||||
--backend cuda0 --params-backend cpu
|
||||
```
|
||||
|
||||
This keeps model weights in system RAM and moves them to the runtime backend when needed. In the example CLI/server, `--offload-to-cpu` is a compatibility shortcut that prepends `*=cpu` to `--params-backend` before creating the context, so explicit module assignments can still override it:
|
||||
|
||||
```shell
|
||||
--offload-to-cpu --params-backend te=disk
|
||||
```
|
||||
|
||||
Use disk params to reduce both VRAM and RAM usage:
|
||||
|
||||
```shell
|
||||
--backend cuda0 --params-backend disk
|
||||
```
|
||||
|
||||
This reloads parameters from the model file on demand and releases them after use. It has the lowest memory residency, but can be slower because weights must be read again. `disk` is never selected implicitly; set it explicitly when RAM usage matters more than reload cost.
|
||||
|
||||
Per-module assignments can target only the largest modules:
|
||||
|
||||
```shell
|
||||
--backend cuda0 --params-backend diffusion=disk,te=cpu,vae=cpu
|
||||
```
|
||||
|
||||
See [backend selection](./backend.md) for full syntax.
|
||||
|
||||
## Run models that don't fit in VRAM (CPU streaming).
|
||||
|
||||
`--offload-to-cpu` alone keeps every parameter in system RAM and stages it to the runtime backend on first use, then leaves it resident there. If the diffusion model is larger than the runtime backend's free memory (e.g. Flux dev at bf16 on an 8 GiB GPU), that residency stops fitting during the sampling loop and generation fails. Two additional flags make it fit by trading a small amount of speed for room:
|
||||
|
||||
- `--max-vram <GiB>` sets a VRAM budget the graph-cut segmenter respects. It cuts each forward pass into segments sized to fit the budget, running them in sequence and freeing intermediate activations between them. Negative values auto-detect free VRAM and spare the given amount (`--max-vram -1` uses most of the free VRAM and keeps ~1 GiB headroom), a positive value caps the budget, `0` disables segmentation.
|
||||
- `--stream-layers` streams the diffusion model's transformer blocks one at a time. Each block's parameters are copied from the CPU to the runtime backend just before it runs and evicted when the residency budget is reached. Prefetching hides most of the copy latency behind compute. This flag only takes effect when the diffusion params backend is CPU, so it must be combined with `--offload-to-cpu` (or an explicit `--params-backend diffusion=cpu`); a warning is logged and the flag is ignored otherwise.
|
||||
|
||||
The three flags stack. The recommended shape for "biggest model my card can host":
|
||||
|
||||
```shell
|
||||
sd-cli --diffusion-model flux1-dev.safetensors ... \
|
||||
--offload-to-cpu --max-vram -1 --stream-layers
|
||||
```
|
||||
|
||||
- `--offload-to-cpu`: params in RAM, staged as needed.
|
||||
- `--max-vram -1`: use most of the free VRAM as the compute budget, spare 1 GiB headroom, let the graph-cut segmenter split each forward pass to fit.
|
||||
- `--stream-layers`: on top of the segmenter, stream individual transformer blocks so their weights don't all need to be resident at once.
|
||||
|
||||
Ordered from fastest to smallest-VRAM: no flags → `--offload-to-cpu` → `--offload-to-cpu --max-vram <N>` → `--offload-to-cpu --max-vram <N> --stream-layers`. Each step down costs a few percent of throughput to buy more room; combined they can run models roughly 3-4x larger than the raw VRAM would allow.
|
||||
|
||||
## Use quantization to reduce memory usage.
|
||||
|
||||
[quantization](./quantization_and_gguf.md)
|
||||
[quantization](./quantization_and_gguf.md)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# How to Use
|
||||
|
||||
PiD is NVIDIA's Pixel Diffusion Decoder. It replaces the usual VAE decode or decode-then-upscale path with a pixel-space diffusion decoder conditioned on a
|
||||
source latent and text prompt.
|
||||
source latent and text prompt. Both the original PiD checkpoints and PiD 1.5 are supported.
|
||||
|
||||
In stable-diffusion.cpp, PiD currently runs as an image edit pipeline: provide a reference image with `-r`/`--ref-image`, encode that image with a matching VAE, then let the PiD diffusion model decode/upscale directly to RGB.
|
||||
|
||||
@@ -16,13 +16,14 @@ In stable-diffusion.cpp, PiD currently runs as an image edit pipeline: provide a
|
||||
- Flux / Z-Image PiD: use the Flux VAE and pass `--vae-format flux`
|
||||
- SD3 PiD: use the SD3 VAE and pass `--vae-format sd3`
|
||||
- Flux.2 PiD: use the Flux.2 VAE and pass `--vae-format flux2`
|
||||
- Qwen-Image PiD: use the Qwen-Image 2D VAE and pass `--vae-format wan`
|
||||
|
||||
The official PiD model card should be checked before use. At the time of the initial PiD release, the official weights are under the NSCLv1 non-commercial license.
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
Before:
|
||||
|
||||
196
docs/pulid.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# PuLID-Flux face-identity preservation
|
||||
|
||||
stable-diffusion.cpp supports the [PuLID-Flux](https://github.com/ToTheBeginning/PuLID)
|
||||
identity-injection technique on top of Flux.1 (schnell or dev) models.
|
||||
Given a single source portrait, PuLID-Flux produces new generations that
|
||||
preserve the source person's face across arbitrary scenes, poses, and
|
||||
prompts.
|
||||
|
||||
Unlike PhotoMaker (which extracts the identity inside the inference
|
||||
process from a directory of images), PuLID-Flux's identity extractor is
|
||||
a heavy stack (insightface ArcFace + EVA-CLIP-L + IDFormer encoder) that
|
||||
is impractical to port to C++/ggml. To keep this implementation small and
|
||||
cross-vendor, **stable-diffusion.cpp consumes a precomputed identity
|
||||
embedding** produced by an external Python tool that runs once per source
|
||||
portrait. Everything downstream of that one-shot extraction is C++ and
|
||||
runs on any backend (Vulkan, CUDA, Metal, ROCm, CPU).
|
||||
|
||||
## Architecture summary
|
||||
|
||||
The PuLID-Flux contribution to the Flux denoise loop is a stack of 20
|
||||
small cross-attention modules (`PerceiverAttentionCA`) inserted between
|
||||
the Flux transformer blocks:
|
||||
|
||||
- After every 2nd of the 19 double-stream blocks (10 hook points)
|
||||
- After every 4th of the 38 single-stream blocks (10 hook points)
|
||||
|
||||
Each cross-attention layer takes the current image tokens as query, the
|
||||
32-token / 2048-dim identity embedding as key+value, and adds its output
|
||||
(scaled by `id_weight`, typically 1.0) back to the image tokens.
|
||||
|
||||
## Required weights
|
||||
|
||||
Three files in addition to the standard Flux weight set:
|
||||
|
||||
1. **Flux base** (transformer + VAE + clip_l + t5xxl) -- exactly as
|
||||
[docs/flux.md](flux.md) describes.
|
||||
2. **PuLID weights** -- download from
|
||||
[guozinan/PuLID](https://huggingface.co/guozinan/PuLID):
|
||||
- `pulid_flux_v0.9.0.safetensors` or `pulid_flux_v0.9.1.safetensors`
|
||||
(recommended; this implementation is verified against v0.9.1)
|
||||
- **v1.1 (`pulid_v1.1.safetensors`) is NOT yet supported** -- it uses
|
||||
renamed keys (`id_adapter_attn_layers.*` instead of `pulid_ca.*`)
|
||||
and possibly different module structure. Future PR.
|
||||
3. **Identity embedding (.pulidembd)** -- produced by the precompute
|
||||
tool below.
|
||||
|
||||
## Precompute the identity embedding
|
||||
|
||||
The precompute tool runs the PyTorch identity-extraction stack on a
|
||||
single portrait image and writes the resulting `(32, 2048)` embedding
|
||||
to a `.pulidembd` binary file (about 131 KB). Run it once per source
|
||||
person; the same file is reused for any number of generations.
|
||||
|
||||
A reference Python script is provided alongside this docs file at
|
||||
[`scripts/pulid_extract_id.py`](../scripts/pulid_extract_id.py). It
|
||||
requires:
|
||||
- A working CUDA / CPU PyTorch stack
|
||||
- `insightface`, `facexlib`, `eva-clip`, `torchvision`, `opencv-python`,
|
||||
`huggingface_hub`, `gguf`
|
||||
- The PuLID weights file (same one stable-diffusion.cpp will load below)
|
||||
- The ToTheBeginning/PuLID repo's `pulid/` package (including
|
||||
`pulid/pipeline_flux.py`) and `eva_clip/` package on `PYTHONPATH`; `flux/`
|
||||
is not needed for embedding extraction
|
||||
|
||||
Run it as:
|
||||
|
||||
```
|
||||
python pulid_extract_id.py \
|
||||
--portrait /path/to/source-photo.jpg \
|
||||
--pulid-weights /path/to/pulid_flux_v0.9.1.safetensors \
|
||||
--out /path/to/source.pulidembd
|
||||
```
|
||||
|
||||
## Format (gguf)
|
||||
|
||||
The embedding is a standard **gguf** container holding a single tensor:
|
||||
|
||||
```
|
||||
tensor name : "pulid_id"
|
||||
shape : [token_dim, num_tokens] (ggml order; typically [2048, 32])
|
||||
type : F16 (also accepts F32 / BF16)
|
||||
metadata : general.architecture = "pulid", pulid.version = 1
|
||||
```
|
||||
|
||||
stable-diffusion.cpp loads it with the normal gguf reader
|
||||
(`gguf_init_from_file`) and converts to fp32 at load time -- no bespoke
|
||||
parser. Total file size for the typical (32, 2048, fp16) case is ~131 KB.
|
||||
|
||||
## Command-line usage
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe \
|
||||
--diffusion-model models\flux1-schnell-Q4_K_S.gguf \
|
||||
--vae models\ae.safetensors \
|
||||
--clip_l models\clip_l.safetensors \
|
||||
--t5xxl models\t5xxl_fp16.safetensors \
|
||||
--pulid-weights models\pulid_flux_v0.9.1.safetensors \
|
||||
--pulid-id-embedding source.pulidembd \
|
||||
--pulid-id-weight 1.0 \
|
||||
-p "candid photograph of a young woman on a beach at sunset" \
|
||||
--cfg-scale 1.0 --sampling-method euler --steps 4 -W 512 -H 512 \
|
||||
--seed 42 --clip-on-cpu \
|
||||
-o out.png
|
||||
```
|
||||
|
||||
For Flux Dev (instead of Schnell), add `--guidance 3.5` and `--steps 20`.
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Purpose |
|
||||
|----------------------------|-------------------------------------------------------------------|
|
||||
| `--pulid-weights <path>` | Path to `pulid_flux_v0.9.x.safetensors`. Loaded with the model. |
|
||||
| `--pulid-id-embedding <p>` | Path to a `.pulidembd` binary produced by the precompute tool. |
|
||||
| `--pulid-id-weight <f>` | Identity-injection strength. Typical 0.7-1.2; default 1.0. |
|
||||
|
||||
All three flags must be set together to activate PuLID. Setting only
|
||||
`--pulid-weights` (no embedding) loads the weights but disables injection
|
||||
at runtime. Setting `--pulid-id-weight 0` zeros out the contribution
|
||||
(useful for falsification testing: outputs should be byte-identical to
|
||||
a no-PuLID run with the same seed).
|
||||
|
||||
## Memory budget
|
||||
|
||||
At 512x512, 4 steps (Schnell), the 20 cross-attention layers add roughly
|
||||
10% to denoise time and almost nothing to peak VRAM. Tested on a 12 GB
|
||||
consumer card alongside Flux Schnell Q4 GGUF + CPU-offloaded clip_l and
|
||||
t5xxl + GPU-resident VAE.
|
||||
|
||||
At 1024x1024 with Flux Dev Q4 + 20 steps + PuLID, the VAE decode compute
|
||||
buffer doesn't fit on a 12 GB card even with `--vae-on-cpu`. Workaround:
|
||||
explicitly route VAE to the CPU backend instead of the offload flag:
|
||||
|
||||
```
|
||||
--backend "diffusion=vulkan0,vae=cpu"
|
||||
```
|
||||
|
||||
The `--vae-on-cpu` flag offloads VAE weights but leaves the compute graph
|
||||
on the default backend; this is existing stable-diffusion.cpp behavior,
|
||||
not a PuLID-specific issue. Documented here because anyone running PuLID
|
||||
at 1024 will hit it.
|
||||
|
||||
## Backend selection
|
||||
|
||||
The standard `--backend` flag works as documented. Common patterns:
|
||||
|
||||
```
|
||||
# AMD Vulkan
|
||||
--backend "diffusion=vulkan0,vae=cpu"
|
||||
|
||||
# NVIDIA Vulkan
|
||||
--backend "diffusion=vulkan1,vae=cpu"
|
||||
|
||||
# CUDA
|
||||
--backend "diffusion=cuda0,vae=cpu"
|
||||
```
|
||||
|
||||
The PuLID cross-attention layers run on the same backend as the main
|
||||
diffusion model. They have not yet been independently profiled on every
|
||||
backend; only Vulkan and CPU have been tested by the original contributor.
|
||||
|
||||
## Verification
|
||||
|
||||
A three-way SHA-256 check is the recommended sanity test when bringing up
|
||||
a new combination of model + backend + hardware:
|
||||
|
||||
| Run | Expected hash relation |
|
||||
|----------------------------------------------|------------------------------------|
|
||||
| A: no `--pulid-*` flags | baseline |
|
||||
| B: PuLID flags, `--pulid-id-weight 0.0` | **byte-identical to A** |
|
||||
| C: PuLID flags, `--pulid-id-weight 1.0` | **different from A,B**, preserves source identity |
|
||||
|
||||
If A and C differ but A and B differ too, the injection is allocating
|
||||
or computing something even at zero weight -- likely a bug.
|
||||
|
||||
## Limitations / not yet supported
|
||||
|
||||
- **`--skip-layers` (skip-layer-guidance / SLG) combined with PuLID** is not
|
||||
supported. The `pulid_ca` index advances per non-skipped block, so a
|
||||
skipped block silently misaligns the cross-attention weight assignment
|
||||
vs. the trained intervals. The reference PyTorch implementation does
|
||||
not have SLG either, so there is no well-defined behavior to emulate.
|
||||
Use either feature alone.
|
||||
- **PuLID v1.1 weights** (`pulid_v1.1.safetensors`, renamed key layout).
|
||||
- **Multiple ID images.** The reference PyTorch implementation can fuse
|
||||
several portraits into one embedding for stronger identity. This
|
||||
implementation accepts a single embedding produced from one or more
|
||||
images by the external precompute tool.
|
||||
- **Negative-prompt branch of CFG.** PuLID only injects on the positive
|
||||
conditioning path in the published reference, and the implementation
|
||||
here follows that. Flux's distilled guidance doesn't run a separate
|
||||
uncond branch in normal use, so this matters only for `--true-cfg`
|
||||
workflows that aren't standard for Flux.
|
||||
- **Backends other than Vulkan and CPU** are untested by the original
|
||||
contributor. The implementation is pure-ggml and should work on CUDA,
|
||||
ROCm, and Metal, but verification by users on those backends is
|
||||
welcomed.
|
||||
@@ -14,7 +14,7 @@
|
||||
## Examples
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="qwen example" src="../assets/qwen/example.png" />
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
### Qwen Image Edit
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" />
|
||||
@@ -32,17 +32,17 @@
|
||||
### 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'"
|
||||
.\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'"
|
||||
```
|
||||
|
||||
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" />
|
||||
|
||||
### Qwen Image Edit 2511
|
||||
|
||||
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, `--model-args qwen_image_zero_cond_t=true` must be enabled; otherwise, image editing quality will degrade significantly.
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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'" --model-args qwen_image_zero_cond_t=true
|
||||
```
|
||||
|
||||
<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" />
|
||||
|
||||
220
docs/rpc.md
Normal file
@@ -0,0 +1,220 @@
|
||||
# Building and Using the RPC Server with `stable-diffusion.cpp`
|
||||
|
||||
This guide covers how to build a version of [the RPC server from `llama.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/tools/rpc/README.md) that is compatible with your version of `stable-diffusion.cpp` to manage multi-backends setups. RPC allows you to offload specific model components to a remote server.
|
||||
|
||||
> **Note on Model Location:** The model files (e.g., `.safetensors` or `.gguf`) remain on the **Client** machine. The client parses the file and transmits the necessary tensor data and computational graphs to the server. The server does not need to store the model files locally.
|
||||
|
||||
## 1. Building `stable-diffusion.cpp` with RPC client
|
||||
|
||||
First, you should build the client application from source. It requires `SD_RPC=ON` to include the RPC backend to your client.
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. \
|
||||
-DSD_RPC=ON \
|
||||
# Add other build flags here (e.g., -DSD_VULKAN=ON)
|
||||
cmake --build . --config Release -j $(nproc)
|
||||
```
|
||||
|
||||
> **Note:** Ensure you add the other flags you would normally use (e.g., `-DSD_VULKAN=ON`, `-DSD_CUDA=ON`, `-DSD_HIPBLAS=ON`, or `-DGGML_METAL=ON`), for more information about building `stable-diffusion.cpp` from source, please refer to the [build.md](build.md) documentation.
|
||||
|
||||
## 2. Ensure `llama.cpp` is at the correct commit
|
||||
|
||||
`stable-diffusion.cpp`'s RPC client is designed to work with a specific version of `llama.cpp` (compatible with the `ggml` submodule) to ensure API compatibility. The commit hash for `llama.cpp` is stored in `ggml/scripts/sync-llama.last`.
|
||||
|
||||
> **Start from Root:** Perform these steps from the root of your `stable-diffusion.cpp` directory.
|
||||
|
||||
1. Read the target commit hash from the submodule tracker:
|
||||
|
||||
```bash
|
||||
# Linux / WSL / MacOS
|
||||
HASH=$(cat ggml/scripts/sync-llama.last)
|
||||
|
||||
# Windows (PowerShell)
|
||||
$HASH = Get-Content -Path "ggml\scripts\sync-llama.last"
|
||||
```
|
||||
|
||||
2. Clone `llama.cpp` at the target commit .
|
||||
```bash
|
||||
git clone https://github.com/ggml-org/llama.cpp.git
|
||||
cd llama.cpp
|
||||
git checkout $HASH
|
||||
```
|
||||
To save on download time and storage, you can use a shallow clone to download only the target commit:
|
||||
```bash
|
||||
mkdir -p llama.cpp
|
||||
cd llama.cpp
|
||||
git init
|
||||
git remote add origin https://github.com/ggml-org/llama.cpp.git
|
||||
git fetch --depth 1 origin $HASH
|
||||
git checkout FETCH_HEAD
|
||||
```
|
||||
|
||||
## 3. Build `llama.cpp` (RPC Server)
|
||||
|
||||
The RPC server acts as the worker. You must explicitly enable the **backend** (the hardware interface, such as CUDA for Nvidia, Metal for Apple Silicon, or Vulkan) when building, otherwise the server will default to using only the CPU.
|
||||
|
||||
To find the correct flags for your system, refer to the official documentation for the [`llama.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/docs/build.md) repository.
|
||||
|
||||
> **Crucial:** You must include the compiler flags required to satisfy the API compatibility with `stable-diffusion.cpp` (`-DGGML_MAX_NAME=128`). Without this flag, `GGML_MAX_NAME` will default to `64` for the server, and data transfers between the client and server will fail. Of course, `-DGGML_RPC` must also be enabled.
|
||||
>
|
||||
> I recommend disabling the `LLAMA_CURL` flag to avoid unnecessary dependencies, and disabling shared library builds to avoid potential conflicts.
|
||||
|
||||
> **Build Target:** We are specifically building the `rpc-server` target. This prevents the build system from compiling the entire `llama.cpp` suite (like `llama-server`), making the build significantly faster.
|
||||
|
||||
### Linux / WSL (Vulkan)
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DGGML_RPC=ON \
|
||||
-DGGML_VULKAN=ON \ # Ensure backend is enabled
|
||||
-DGGML_BUILD_SHARED_LIBS=OFF \
|
||||
-DLLAMA_CURL=OFF \
|
||||
-DCMAKE_C_FLAGS=-DGGML_MAX_NAME=128 \
|
||||
-DCMAKE_CXX_FLAGS=-DGGML_MAX_NAME=128
|
||||
cmake --build . --config Release --target rpc-server -j $(nproc)
|
||||
```
|
||||
|
||||
### macOS (Metal)
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DGGML_RPC=ON \
|
||||
-DGGML_METAL=ON \
|
||||
-DGGML_BUILD_SHARED_LIBS=OFF \
|
||||
-DLLAMA_CURL=OFF \
|
||||
-DCMAKE_C_FLAGS=-DGGML_MAX_NAME=128 \
|
||||
-DCMAKE_CXX_FLAGS=-DGGML_MAX_NAME=128
|
||||
cmake --build . --config Release --target rpc-server
|
||||
```
|
||||
|
||||
### Windows (Visual Studio 2022, Vulkan)
|
||||
|
||||
```powershell
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 17 2022" -A x64 `
|
||||
-DGGML_RPC=ON `
|
||||
-DGGML_VULKAN=ON `
|
||||
-DGGML_BUILD_SHARED_LIBS=OFF `
|
||||
-DLLAMA_CURL=OFF `
|
||||
-DCMAKE_C_FLAGS=-DGGML_MAX_NAME=128 `
|
||||
-DCMAKE_CXX_FLAGS=-DGGML_MAX_NAME=128
|
||||
cmake --build . --config Release --target rpc-server
|
||||
```
|
||||
|
||||
## 4. Usage
|
||||
|
||||
Once both applications are built, you can run the server and the client to manage your GPU allocation.
|
||||
|
||||
### Step A: Run the RPC Server
|
||||
|
||||
Start the server. It listens for connections on the default address (usually `localhost:50052`). If your server is on a different machine, ensure the server binds to the correct interface and your firewall allows the connection.
|
||||
|
||||
**On the Server :**
|
||||
If running on the same machine, you can use the default address:
|
||||
|
||||
```bash
|
||||
./rpc-server
|
||||
```
|
||||
|
||||
If you want to allow connections from other machines on the network:
|
||||
|
||||
```bash
|
||||
./rpc-server --host 0.0.0.0
|
||||
```
|
||||
|
||||
> **Security Warning:** The RPC server does not currently support authentication or encryption. **Only run the server on trusted local networks**. Never expose the RPC server directly to the open internet.
|
||||
|
||||
> **Drivers & Hardware:** Ensure the Server machine has the necessary drivers installed and functional (e.g., Nvidia Drivers for CUDA, Vulkan SDK, or Metal). If no devices are found, the server will simply fallback to CPU usage.
|
||||
|
||||
<!-- ### Step B: Check if the client is able to connect to the server and see the available devices
|
||||
|
||||
We're assuming the server is running on your local machine, and listening on the default port `50052`. If it's running on a different machine, you can replace `localhost` with the IP address of the server.
|
||||
|
||||
**On the Client:**
|
||||
|
||||
```bash
|
||||
./sd-cli --rpc-servers localhost:50052 --list-devices
|
||||
```
|
||||
|
||||
If the server is running and the client is able to connect, you should see `RPC0 localhost:50052` in the list of devices.
|
||||
|
||||
Example output:
|
||||
(Client built without GPU acceleration, two GPUs available on the server)
|
||||
|
||||
```
|
||||
List of available GGML devices:
|
||||
Name Description
|
||||
-------------------
|
||||
CPU AMD Ryzen 9 5900X 12-Core Processor
|
||||
RPC0 localhost:50052
|
||||
RPC1 localhost:50052
|
||||
``` -->
|
||||
|
||||
### Step B: Run with RPC device
|
||||
|
||||
If everything is working correctly, you can now run the client while offloading some or all of the work to the RPC server.
|
||||
|
||||
Example: Setting the main backend to the RPC0 device for doing all the work on the server.
|
||||
|
||||
```bash
|
||||
./sd-cli -m models/sd1.5.safetensors -p "A cat" --rpc-servers localhost:50052 --backend RPC0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Scaling: Multiple RPC Servers
|
||||
|
||||
You can connect the client to multiple RPC servers simultaneously to scale out your hardware usage.
|
||||
|
||||
Example: A main machine (192.168.1.10) with 3 GPUs, with one GPU running CUDA and the other two running Vulkan, and a second machine (192.168.1.11) only one GPU.
|
||||
|
||||
**On the first machine (Running two server instances):**
|
||||
|
||||
**Terminal 1 (CUDA):**
|
||||
|
||||
```bash
|
||||
# Linux / WSL
|
||||
export CUDA_VISIBLE_DEVICES=0
|
||||
cd ./build_cuda/bin/Release
|
||||
./rpc-server --host 0.0.0.0
|
||||
|
||||
# Windows PowerShell
|
||||
$env:CUDA_VISIBLE_DEVICES="0"
|
||||
cd .\build_cuda\bin\Release
|
||||
./rpc-server --host 0.0.0.0
|
||||
```
|
||||
|
||||
**Terminal 2 (Vulkan):**
|
||||
|
||||
```bash
|
||||
cd ./build_vulkan/bin/Release
|
||||
# ignore the first GPU (used by CUDA server)
|
||||
./rpc-server --host 0.0.0.0 --port 50053 -d Vulkan1,Vulkan2
|
||||
```
|
||||
|
||||
**On the second machine:**
|
||||
|
||||
```bash
|
||||
cd ./build/bin/Release
|
||||
./rpc-server --host 0.0.0.0
|
||||
```
|
||||
|
||||
**On the Client:**
|
||||
Pass multiple server addresses separated by commas.
|
||||
|
||||
```bash
|
||||
./sd-cli --rpc-servers 192.168.1.10:50052,192.168.1.10:50053,192.168.1.11:50052 [...]
|
||||
```
|
||||
|
||||
The client will map these servers to sequential device IDs (e.g., RPC0 from the first server, RPC2, RPC3 from the second, and RPC4 from the third). With this setup, you could for example use RPC0 for the main backend, RPC1 and RPC2 for the text encoders, and RPC3 for the VAE.
|
||||
|
||||
---
|
||||
|
||||
## 6. Performance Considerations
|
||||
|
||||
RPC performance is heavily dependent on network bandwidth, as large weights and activations must be transferred back and forth over the network, especially for large models, or when using high resolutions. For best results, ensure your network connection is stable and has sufficient bandwidth (>1Gbps recommended). This shoumd not be a concern if you are running the server and client on the same machine, as the data transfer will happen over the loopback interface.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
- download original weights(.ckpt or .safetensors). For example
|
||||
- Stable Diffusion v1.4 from https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
|
||||
- Stable Diffusion v1.5 from https://huggingface.co/runwayml/stable-diffusion-v1-5
|
||||
- Stable Diffuison v2.1 from https://huggingface.co/stabilityai/stable-diffusion-2-1
|
||||
- Stable Diffusion v1.5 from https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5
|
||||
- Stable Diffuison v2.1 from https://huggingface.co/Manojb/stable-diffusion-2-1-base
|
||||
- Stable Diffusion 3 2B from https://huggingface.co/stabilityai/stable-diffusion-3-medium
|
||||
|
||||
### txt2img example
|
||||
@@ -34,4 +34,4 @@ Using formats of different precisions will yield results of varying quality.
|
||||
|
||||
<p align="center">
|
||||
<img src="../assets/img2img_output.png" width="256x">
|
||||
</p>
|
||||
</p>
|
||||
|
||||
50
docs/sefi_image.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# How to Use
|
||||
|
||||
SeFi-Image uses a Flux2-style dual-time transformer (semantic + texture streams), the standard Flux2 VAE, and Qwen3-VL as the LLM text encoder. Tech report: [arXiv:2606.22568](https://arxiv.org/abs/2606.22568).
|
||||
|
||||
## Download weights
|
||||
|
||||
The SeFi-Image family ships in three scales (1B / 2B / 5B) and three families (Base / RL / turbo), all gated on Hugging Face under https://huggingface.co/SeFi-Image.
|
||||
|
||||
- 1B and 2B variants pair with Qwen3-VL-2B-Instruct.
|
||||
- 5B variants pair with Qwen3-VL-4B-Instruct.
|
||||
- All variants use the standard Flux2 VAE (`flux2_ae.safetensors` from https://huggingface.co/black-forest-labs/FLUX.2-dev).
|
||||
|
||||
Convert the transformer and text encoder to sd.cpp safetensors:
|
||||
|
||||
```bash
|
||||
python3 scripts/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
|
||||
```
|
||||
|
||||
## Variant defaults
|
||||
|
||||
| Family | timestep_shift_alpha | steps | cfg-scale |
|
||||
|---|---|---|---|
|
||||
| Base | 0.3 | 50 | 4.0 |
|
||||
| RL | 0.3 | 50 | 4.0 |
|
||||
| turbo | 1.0 | 4 | 1.0 |
|
||||
|
||||
The dispatcher picks `alpha` from the filename (`turbo` substring => 1.0, otherwise 0.3). Override via `--extra-sample-args sefi_alpha=<value>` or `sefi_delta_t=<value>`.
|
||||
|
||||
## Examples
|
||||
|
||||
### 1B / 2B turbo
|
||||
|
||||
```
|
||||
./build/bin/sd-cli --diffusion-model /path/to/sefi_1b_turbo.safetensors --vae /path/to/flux2_ae.safetensors --llm /path/to/qwen3_vl_2b.safetensors -p "a photograph of an orange tabby cat sitting on a couch" --cfg-scale 1.0 --steps 4 -W 1024 -H 1024 -s 42 --diffusion-fa --offload-to-cpu -o out.png
|
||||
```
|
||||
|
||||
### 1B / 2B base
|
||||
|
||||
```
|
||||
./build/bin/sd-cli --diffusion-model /path/to/sefi_1b_base.safetensors --vae /path/to/flux2_ae.safetensors --llm /path/to/qwen3_vl_2b.safetensors -p "a photograph of an orange tabby cat sitting on a couch" --cfg-scale 4.0 --steps 50 -W 1024 -H 1024 -s 42 --diffusion-fa --offload-to-cpu -o out.png
|
||||
```
|
||||
|
||||
### 5B (needs streaming on 12 GiB VRAM)
|
||||
|
||||
```
|
||||
./build/bin/sd-cli --diffusion-model /path/to/sefi_5b_turbo.safetensors --vae /path/to/flux2_ae.safetensors --llm /path/to/qwen3_vl_4b.safetensors -p "a photograph of an orange tabby cat sitting on a couch" --cfg-scale 1.0 --steps 4 -W 1024 -H 1024 -s 42 --diffusion-fa --max-vram 8 --stream-layers --offload-to-cpu -o out.png
|
||||
```
|
||||
|
||||
<img alt="SeFi-Image 5B turbo example" src="../assets/sefi_image/example.png" />
|
||||
34
docs/wan.md
@@ -55,7 +55,7 @@
|
||||
### Wan2.1 T2V 1.3B
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.2_14B_t2v_lora.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
@@ -117,7 +117,7 @@
|
||||
#### T2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.2_5B_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
@@ -125,7 +125,7 @@
|
||||
#### I2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
### Wan2.2 FLF2V 14B
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.2_14B_flf2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
@@ -152,7 +152,7 @@
|
||||
#### T2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.1_1.3B_vace_t2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
@@ -161,7 +161,7 @@
|
||||
#### R2V
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
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 ..\..\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.1_14B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
|
||||
@@ -21,7 +21,7 @@ You can run Z-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — or ev
|
||||
### Z-Image-Turbo
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<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
|
||||
|
||||
```
|
||||
.\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
|
||||
.\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
|
||||
```
|
||||
|
||||
<img width="256" alt="z-image example" src="../assets/z_image/base_bf16.png" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(cli)
|
||||
add_subdirectory(server)
|
||||
add_subdirectory(server)
|
||||
|
||||
@@ -1,203 +1,13 @@
|
||||
# Run
|
||||
# Usage
|
||||
|
||||
For detailed command-line arguments, run:
|
||||
|
||||
```bash
|
||||
./bin/sd-cli -h
|
||||
```
|
||||
usage: ./bin/sd-cli [options]
|
||||
|
||||
CLI Options:
|
||||
-o, --output <string> path to write result image to. you can use printf-style %d format specifiers for image
|
||||
sequences (default: ./output.png) (eg. output_%03d.png). Single-file video outputs
|
||||
support .avi, .webm, and animated .webp
|
||||
--image <string> path to the image to inspect (for metadata mode)
|
||||
--metadata-format <string> metadata output format, one of [text, json] (default: text)
|
||||
--preview-path <string> path to write preview image to (default: ./preview.png). Multi-frame previews support
|
||||
.avi, .webm, and animated .webp
|
||||
--preview-interval <int> interval in denoising steps between consecutive updates of the image preview file
|
||||
(default is 1, meaning updating at every step)
|
||||
--output-begin-idx <int> starting index for output image sequence, must be non-negative (default 0 if specified
|
||||
%d in output path, 1 otherwise)
|
||||
--canny apply canny preprocessor (edge detection)
|
||||
--convert-name convert tensor name (for convert mode)
|
||||
-v, --verbose print extra info
|
||||
--color colors the logging tags according to level
|
||||
--taesd-preview-only prevents usage of taesd for decoding the final image. (for use with --preview tae)
|
||||
--preview-noisy enables previewing noisy inputs of the models rather than the denoised outputs
|
||||
--metadata-raw include raw hex previews for unparsed metadata payloads
|
||||
--metadata-brief truncate long metadata text values in text output
|
||||
--metadata-all include structural/container entries such as IHDR, IDAT, and non-metadata JPEG segments
|
||||
-M, --mode run mode, one of [img_gen, vid_gen, upscale, convert, metadata], default: img_gen
|
||||
--preview preview method. must be one of the following [none, proj, tae, vae] (default is none)
|
||||
-h, --help show this help message and exit
|
||||
|
||||
Context Options:
|
||||
-m, --model <string> path to full model
|
||||
--clip_l <string> path to the clip-l text encoder
|
||||
--clip_g <string> path to the clip-g text encoder
|
||||
--clip_vision <string> path to the clip-vision encoder
|
||||
--t5xxl <string> path to the t5xxl text encoder
|
||||
--llm <string> path to the llm text encoder. For example: (qwenvl2.5 for qwen-image,
|
||||
mistral-small3.2 for flux2, ...)
|
||||
--llm_vision <string> path to the llm vit
|
||||
--qwen2vl <string> alias of --llm. Deprecated.
|
||||
--qwen2vl_vision <string> alias of --llm_vision. Deprecated.
|
||||
--diffusion-model <string> path to the standalone diffusion model
|
||||
--high-noise-diffusion-model <string> path to the standalone high noise diffusion model
|
||||
--vae <string> path to standalone vae model
|
||||
--taesd <string> path to taesd. Using Tiny AutoEncoder for fast decoding (low quality)
|
||||
--tae <string> alias of --taesd
|
||||
--control-net <string> path to control net model
|
||||
--embd-dir <string> embeddings directory
|
||||
--lora-model-dir <string> lora model directory
|
||||
--hires-upscalers-dir <string> highres fix upscaler model directory
|
||||
--tensor-type-rules <string> weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
||||
--photo-maker <string> path to PHOTOMAKER model
|
||||
--upscale-model <string> path to esrgan model.
|
||||
-t, --threads <int> number of threads to use during computation (default: -1). If threads <= 0,
|
||||
then threads will be set to the number of CPU physical cores
|
||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
||||
--max-vram <float> maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables
|
||||
graph splitting; a negative value auto-detects free VRAM, sparing the
|
||||
specified value (e.g. -0.5 will keep at least 0.5 GiB free)
|
||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
||||
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM
|
||||
when needed
|
||||
--mmap whether to memory-map model
|
||||
--control-net-cpu keep controlnet in cpu (for low vram)
|
||||
--clip-on-cpu keep clip in cpu (for low vram)
|
||||
--vae-on-cpu keep vae in cpu (for low vram)
|
||||
--fa use flash attention
|
||||
--diffusion-fa use flash attention in the diffusion model only
|
||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||
--circular enable circular padding for convolutions
|
||||
--circularx enable circular RoPE wrapping on x-axis (width) only
|
||||
--circulary enable circular RoPE wrapping on y-axis (height) only
|
||||
--chroma-disable-dit-mask disable dit mask for chroma
|
||||
--qwen-image-zero-cond-t enable zero_cond_t for qwen image
|
||||
--chroma-enable-t5-mask enable t5 mask for chroma
|
||||
--type weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K,
|
||||
q4_K). If not specified, the default is the type of the weight file
|
||||
--rng RNG, one of [std_default, cuda, cpu], default: cuda(sd-webui), cpu(comfyui)
|
||||
--sampler-rng sampler RNG, one of [std_default, cuda, cpu]. If not specified, use --rng
|
||||
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow,
|
||||
flux2_flow]
|
||||
--lora-apply-mode the way to apply LoRA, one of [auto, immediately, at_runtime], default is
|
||||
auto. In auto mode, if the model weights contain any quantized parameters,
|
||||
the at_runtime mode will be used; otherwise, immediately will be used.The
|
||||
immediately mode may have precision and compatibility issues with quantized
|
||||
parameters, but it usually offers faster inference speed and, in some cases,
|
||||
lower memory usage. The at_runtime mode, on the other hand, is exactly the
|
||||
opposite.
|
||||
|
||||
Generation Options:
|
||||
-p, --prompt <string> the prompt to render
|
||||
-n, --negative-prompt <string> the negative prompt (default: "")
|
||||
-i, --init-img <string> path to the init image
|
||||
--end-img <string> path to the end image, required by flf2v
|
||||
--mask <string> path to the mask image
|
||||
--control-image <string> path to control image, control net
|
||||
--control-video <string> path to control video frames, It must be a directory path. The video frames
|
||||
inside should be stored as images in lexicographical (character) order. For
|
||||
example, if the control video path is `frames`, the directory contain images
|
||||
such as 00.png, 01.png, ... etc.
|
||||
--pm-id-images-dir <string> path to PHOTOMAKER input id images dir
|
||||
--pm-id-embed-path <string> path to PHOTOMAKER v2 id embed
|
||||
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
||||
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
||||
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
||||
--extra-sample-args <string> extra sampler/scheduler/guidance args, key=value list. APG supports apg_eta,
|
||||
apg_momentum, apg_norm_threshold, apg_norm_threshold_smoothing; SLG supports
|
||||
slg_uncond; lcm supports noise_clip_std, noise_scale_start, noise_scale_end;
|
||||
ltx2 supports max_shift, base_shift, stretch, terminal; euler_ge supports gamma
|
||||
--extra-tiling-args <string> extra VAE tiling args, key=value list. LTX video VAE supports
|
||||
temporal_tile_frames (default: 4), temporal_tile_overlap (default: 1)
|
||||
-H, --height <int> image height, in pixel space (default: 512)
|
||||
-W, --width <int> image width, in pixel space (default: 512)
|
||||
--steps <int> number of sample steps (default: 20)
|
||||
--high-noise-steps <int> (high noise) number of sample steps (default: -1 = auto)
|
||||
--clip-skip <int> ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer
|
||||
(default: -1). <= 0 represents unspecified, will be 1 for SD1.x, 2 for SD2.x
|
||||
-b, --batch-count <int> batch count
|
||||
--video-frames <int> video frames (default: 1)
|
||||
--fps <int> fps (default: 24)
|
||||
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for
|
||||
NitroSD-Realism around 250 and 500 for NitroSD-Vibrant
|
||||
--upscale-repeats <int> Run the ESRGAN upscaler this many times (default: 1)
|
||||
--upscale-tile-size <int> tile size for ESRGAN upscaling (default: 128)
|
||||
--hires-width <int> highres fix target width, 0 to use --hires-scale (default: 0)
|
||||
--hires-height <int> highres fix target height, 0 to use --hires-scale (default: 0)
|
||||
--hires-steps <int> highres fix second pass sample steps, 0 to reuse --steps (default: 0)
|
||||
--hires-upscale-tile-size <int> highres fix upscaler tile size, reserved for model-backed upscalers (default:
|
||||
128)
|
||||
--cfg-scale <float> unconditional guidance scale: (default: 7.0)
|
||||
--img-cfg-scale <float> image guidance scale for inpaint or image edit models: (default: same as
|
||||
--cfg-scale)
|
||||
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--slg-scale <float> skip layer guidance (SLG) scale, only for DiT models: (default: 0). 0 means
|
||||
disabled, a value of 2.5 is nice for sd3.5 medium
|
||||
--skip-layer-start <float> SLG enabling point (default: 0.01)
|
||||
--skip-layer-end <float> SLG disabling point (default: 0.2)
|
||||
--eta <float> noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and
|
||||
res_2s; 1 for euler_a, er_sde and dpm++2s_a)
|
||||
--flow-shift <float> shift value for Flow models like SD3.x or WAN (default: auto)
|
||||
--high-noise-cfg-scale <float> (high noise) unconditional guidance scale: (default: 7.0)
|
||||
--high-noise-img-cfg-scale <float> (high noise) image guidance scale for inpaint or image edit models (default:
|
||||
same as --cfg-scale)
|
||||
--high-noise-guidance <float> (high noise) distilled guidance scale for models with guidance input
|
||||
(default: 3.5)
|
||||
--high-noise-slg-scale <float> (high noise) skip layer guidance (SLG) scale, only for DiT models: (default:
|
||||
0)
|
||||
--high-noise-skip-layer-start <float> (high noise) SLG enabling point (default: 0.01)
|
||||
--high-noise-skip-layer-end <float> (high noise) SLG disabling point (default: 0.2)
|
||||
--high-noise-eta <float> (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)
|
||||
--strength <float> strength for noising/unnoising (default: 0.75)
|
||||
--pm-style-strength <float>
|
||||
--control-strength <float> strength to apply Control Net (default: 0.9). 1.0 corresponds to full
|
||||
destruction of information in init image
|
||||
--moe-boundary <float> timestep boundary for Wan2.2 MoE model. (default: 0.875). Only enabled if
|
||||
`--high-noise-steps` is set to -1
|
||||
--vace-strength <float> wan vace strength
|
||||
--vae-tile-overlap <float> tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
||||
--hires-scale <float> highres fix scale when target size is not set (default: 2.0)
|
||||
--hires-denoising-strength <float> highres fix second pass denoising strength (default: 0.7)
|
||||
--increase-ref-index automatically increase the indices of references images based on the order
|
||||
they are listed (starting with 1).
|
||||
--disable-auto-resize-ref-image disable auto resize of ref images
|
||||
--disable-image-metadata do not embed generation metadata on image files
|
||||
--vae-tiling process vae in tiles to reduce memory usage
|
||||
--temporal-tiling enable temporal tiling for LTX video VAE decode
|
||||
--hires enable highres fix
|
||||
-s, --seed RNG seed (default: 42, use random seed for < 0)
|
||||
--sampling-method 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)
|
||||
--high-noise-sampling-method (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
|
||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
||||
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent, ltx2], default:
|
||||
model-specific
|
||||
--sigmas custom sigma values for the sampler, comma-separated (e.g.,
|
||||
"14.61,7.8,3.5,0.0").
|
||||
--hires-sigmas custom sigma values for the highres fix second pass, comma-separated (e.g.,
|
||||
"0.85,0.725,0.421875,0.0").
|
||||
--skip-layers layers to skip for SLG steps (default: [7,8,9])
|
||||
--high-noise-skip-layers (high noise) layers to skip for SLG steps (default: [7,8,9])
|
||||
-r, --ref-image reference image for Flux Kontext models (can be used multiple times)
|
||||
--cache-mode caching method: 'easycache' (DiT), 'ucache' (UNET),
|
||||
'dbcache'/'taylorseer'/'cache-dit' (DiT block-level), 'spectrum' (UNET/DiT
|
||||
Chebyshev+Taylor forecasting)
|
||||
--cache-option named cache params (key=value format, comma-separated). easycache/ucache:
|
||||
threshold=,start=,end=,decay=,relative=,reset=; dbcache/taylorseer/cache-dit:
|
||||
Fn=,Bn=,threshold=,warmup=; spectrum: w=,m=,lam=,window=,flex=,warmup=,stop=.
|
||||
Examples: "threshold=0.25" or "threshold=1.5,reset=0"
|
||||
--scm-mask SCM steps mask for cache-dit: comma-separated 0/1 (e.g.,
|
||||
"1,1,1,0,0,1,0,0,1,0") - 1=compute, 0=can cache
|
||||
--scm-policy SCM policy: 'dynamic' (default) or 'static'
|
||||
--vae-tile-size tile size for vae tiling, format [X]x[Y] (default: 32x32)
|
||||
--vae-relative-tile-size relative tile size for vae tiling, format [X]x[Y], in fraction of image size
|
||||
if < 1, in number of tiles per dim if >=1 (overrides --vae-tile-size)
|
||||
```
|
||||
For direct image repair or automatic post-generation YOLOv8 detection followed by cropped inpainting, see
|
||||
[ADetailer](../../docs/adetailer.md).
|
||||
|
||||
Metadata mode inspects PNG/JPEG container metadata without loading any model:
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
@@ -53,6 +54,9 @@ struct SDCliParams {
|
||||
bool metadata_brief = false;
|
||||
bool metadata_all = false;
|
||||
|
||||
std::string imatrix_out;
|
||||
std::vector<std::string> imatrix_in;
|
||||
|
||||
bool normal_exit = false;
|
||||
|
||||
ArgOptions get_options() {
|
||||
@@ -62,19 +66,28 @@ struct SDCliParams {
|
||||
{"-o",
|
||||
"--output",
|
||||
"path to write result image to. you can use printf-style %d format specifiers for image sequences (default: ./output.png) (eg. output_%03d.png). Single-file video outputs support .avi, .webm, and animated .webp",
|
||||
0,
|
||||
&output_path},
|
||||
{"",
|
||||
"--image",
|
||||
"path to the image to inspect (for metadata mode)",
|
||||
0,
|
||||
&image_path},
|
||||
{"",
|
||||
"--metadata-format",
|
||||
"metadata output format, one of [text, json] (default: text)",
|
||||
0,
|
||||
&metadata_format},
|
||||
{"",
|
||||
"--preview-path",
|
||||
"path to write preview image to (default: ./preview.png). Multi-frame previews support .avi, .webm, and animated .webp",
|
||||
0,
|
||||
&preview_path},
|
||||
{"",
|
||||
"--imat-out",
|
||||
"compute the imatrix for this run and save it to the provided path",
|
||||
0,
|
||||
&imatrix_out},
|
||||
};
|
||||
|
||||
options.int_options = {
|
||||
@@ -169,15 +182,24 @@ struct SDCliParams {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_help_arg = [&](int argc, const char** argv, int index) {
|
||||
auto on_help_arg = [&](int argc, const char** argv, int index, bool& valid) {
|
||||
normal_exit = true;
|
||||
valid = true;
|
||||
return -1;
|
||||
};
|
||||
|
||||
auto on_imatrix_in_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
}
|
||||
imatrix_in.push_back(argv[index]);
|
||||
return 1;
|
||||
};
|
||||
|
||||
options.manual_options = {
|
||||
{"-M",
|
||||
"--mode",
|
||||
"run mode, one of [img_gen, vid_gen, upscale, convert, metadata], default: img_gen",
|
||||
"run mode, one of [img_gen, adetailer, vid_gen, upscale, convert, metadata], default: img_gen",
|
||||
on_mode_arg},
|
||||
{"",
|
||||
"--preview",
|
||||
@@ -187,6 +209,10 @@ struct SDCliParams {
|
||||
"--help",
|
||||
"show this help message and exit",
|
||||
on_help_arg},
|
||||
{"",
|
||||
"--imat-in",
|
||||
"load an imatrix file for quantization or continued collection; can be specified multiple times",
|
||||
on_imatrix_in_arg},
|
||||
};
|
||||
|
||||
return options;
|
||||
@@ -248,6 +274,7 @@ struct SDCliParams {
|
||||
<< " preview_fps: " << preview_fps << ",\n"
|
||||
<< " taesd_preview: " << (taesd_preview ? "true" : "false") << ",\n"
|
||||
<< " preview_noisy: " << (preview_noisy ? "true" : "false") << ",\n"
|
||||
<< " imatrix_out: \"" << imatrix_out << "\",\n"
|
||||
<< " metadata_raw: " << (metadata_raw ? "true" : "false") << ",\n"
|
||||
<< " metadata_brief: " << (metadata_brief ? "true" : "false") << ",\n"
|
||||
<< " metadata_all: " << (metadata_all ? "true" : "false") << "\n"
|
||||
@@ -454,7 +481,8 @@ bool save_results(const SDCliParams& cli_params,
|
||||
if (!img.data)
|
||||
return false;
|
||||
|
||||
const int64_t metadata_seed = cli_params.mode == VID_GEN ? gen_params.seed : gen_params.seed + idx;
|
||||
int images_per_batch = gen_params.batch_count > 0 ? std::max(1, num_results / gen_params.batch_count) : 1;
|
||||
const int64_t metadata_seed = cli_params.mode == VID_GEN ? gen_params.seed : gen_params.seed + idx / images_per_batch;
|
||||
std::string params = gen_params.embed_image_metadata
|
||||
? get_image_params(ctx_params, gen_params, metadata_seed, cli_params.mode)
|
||||
: "";
|
||||
@@ -538,6 +566,65 @@ bool save_results(const SDCliParams& cli_params,
|
||||
return sucessful_reults != 0;
|
||||
}
|
||||
|
||||
static bool apply_adetailer(sd_ctx_t* sd_ctx,
|
||||
const sd_ctx_params_t& sd_ctx_params,
|
||||
const SDContextParams& ctx_params,
|
||||
const SDGenerationParams& gen_params,
|
||||
const sd_img_gen_params_t& img_gen_params,
|
||||
SDMode mode,
|
||||
SDImageVec& results,
|
||||
int num_results) {
|
||||
if (gen_params.ad_model_path.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sd_adetailer_params_t ad_params{};
|
||||
ad_params.prompt = gen_params.ad_prompt.empty() ? nullptr : gen_params.ad_prompt.c_str();
|
||||
ad_params.negative_prompt = gen_params.ad_negative_prompt.empty() ? nullptr : gen_params.ad_negative_prompt.c_str();
|
||||
ad_params.extra_ad_args = gen_params.extra_ad_args.c_str();
|
||||
|
||||
ADetailerCtxPtr ad_ctx(new_adetailer_ctx(gen_params.ad_model_path.c_str(),
|
||||
ctx_params.n_threads,
|
||||
sd_ctx_params.backend,
|
||||
sd_ctx_params.params_backend));
|
||||
if (ad_ctx == nullptr) {
|
||||
LOG_ERROR("new_adetailer_ctx failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_results; ++i) {
|
||||
if (results[i].data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
sd_img_gen_params_t ad_generation_params = img_gen_params;
|
||||
ad_generation_params.seed = img_gen_params.seed + i;
|
||||
if (mode == IMG_GEN) {
|
||||
ad_generation_params.width = 512;
|
||||
ad_generation_params.height = 512;
|
||||
ad_generation_params.strength = 0.4f;
|
||||
}
|
||||
sd_image_t* detailed_images = nullptr;
|
||||
int detailed_count = 0;
|
||||
if (!adetail_image(ad_ctx.get(),
|
||||
sd_ctx,
|
||||
results[i],
|
||||
&ad_params,
|
||||
&ad_generation_params,
|
||||
&detailed_images,
|
||||
&detailed_count) ||
|
||||
detailed_count <= 0 || detailed_images == nullptr || detailed_images[0].data == nullptr) {
|
||||
free_sd_images(detailed_images, detailed_count);
|
||||
LOG_ERROR("ADetailer failed for image %d", i + 1);
|
||||
return false;
|
||||
}
|
||||
free(results[i].data);
|
||||
results[i] = detailed_images[0];
|
||||
detailed_images[0] = {0, 0, 0, nullptr};
|
||||
free_sd_images(detailed_images, detailed_count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc > 1 && std::string(argv[1]) == "--version") {
|
||||
std::cout << version_string() << "\n";
|
||||
@@ -570,6 +657,11 @@ int main(int argc, const char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!gen_params.ad_model_path.empty() && cli_params.mode != IMG_GEN && cli_params.mode != ADETAILER) {
|
||||
LOG_ERROR("--ad-model is only supported in image generation and adetailer modes");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (gen_params.video_frames > 4) {
|
||||
size_t last_dot_pos = cli_params.preview_path.find_last_of(".");
|
||||
std::string base_path = cli_params.preview_path;
|
||||
@@ -600,13 +692,33 @@ int main(int argc, const char* argv[]) {
|
||||
LOG_DEBUG("%s", ctx_params.to_string().c_str());
|
||||
LOG_DEBUG("%s", gen_params.to_string().c_str());
|
||||
|
||||
if (!cli_params.imatrix_out.empty()) {
|
||||
if (fs::exists(cli_params.imatrix_out) &&
|
||||
std::find(cli_params.imatrix_in.begin(), cli_params.imatrix_in.end(), cli_params.imatrix_out) == cli_params.imatrix_in.end()) {
|
||||
LOG_WARN("imatrix file '%s' already exists and will be overwritten", cli_params.imatrix_out.c_str());
|
||||
}
|
||||
enable_imatrix_collection();
|
||||
}
|
||||
|
||||
for (const auto& in_file : cli_params.imatrix_in) {
|
||||
LOG_INFO("loading imatrix from '%s'", in_file.c_str());
|
||||
if (!load_imatrix(in_file.c_str())) {
|
||||
LOG_WARN("failed to load imatrix from '%s'", in_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_params.mode == CONVERT) {
|
||||
bool success = convert(ctx_params.model_path.c_str(),
|
||||
ctx_params.vae_path.c_str(),
|
||||
cli_params.output_path.c_str(),
|
||||
ctx_params.wtype,
|
||||
ctx_params.tensor_type_rules.c_str(),
|
||||
cli_params.convert_name);
|
||||
bool success = convert_with_components(ctx_params.model_path.c_str(),
|
||||
ctx_params.clip_l_path.c_str(),
|
||||
ctx_params.clip_g_path.c_str(),
|
||||
ctx_params.t5xxl_path.c_str(),
|
||||
ctx_params.diffusion_model_path.c_str(),
|
||||
ctx_params.vae_path.c_str(),
|
||||
cli_params.output_path.c_str(),
|
||||
ctx_params.wtype,
|
||||
ctx_params.tensor_type_rules.c_str(),
|
||||
cli_params.convert_name,
|
||||
ctx_params.n_threads);
|
||||
if (!success) {
|
||||
LOG_ERROR("convert '%s'/'%s' to '%s' failed",
|
||||
ctx_params.model_path.c_str(),
|
||||
@@ -622,8 +734,6 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
bool vae_decode_only = true;
|
||||
|
||||
auto load_image_and_update_size = [&](const std::string& path,
|
||||
SDImageOwner& image,
|
||||
bool resize_image = true,
|
||||
@@ -645,21 +755,18 @@ int main(int argc, const char* argv[]) {
|
||||
};
|
||||
|
||||
if (gen_params.init_image_path.size() > 0) {
|
||||
vae_decode_only = false;
|
||||
if (!load_image_and_update_size(gen_params.init_image_path, gen_params.init_image)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (gen_params.end_image_path.size() > 0) {
|
||||
vae_decode_only = false;
|
||||
if (!load_image_and_update_size(gen_params.end_image_path, gen_params.end_image)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (gen_params.ref_image_paths.size() > 0) {
|
||||
vae_decode_only = false;
|
||||
gen_params.ref_images.clear();
|
||||
for (auto& path : gen_params.ref_image_paths) {
|
||||
SDImageOwner ref_image({0, 0, 3, nullptr});
|
||||
@@ -734,18 +841,7 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_params.mode == VID_GEN) {
|
||||
vae_decode_only = false;
|
||||
}
|
||||
|
||||
if (gen_params.hires_enabled &&
|
||||
(gen_params.resolved_hires_upscaler == SD_HIRES_UPSCALER_MODEL ||
|
||||
gen_params.resolved_hires_upscaler == SD_HIRES_UPSCALER_LANCZOS ||
|
||||
gen_params.resolved_hires_upscaler == SD_HIRES_UPSCALER_NEAREST)) {
|
||||
vae_decode_only = false;
|
||||
}
|
||||
|
||||
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(vae_decode_only, true, cli_params.taesd_preview);
|
||||
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(cli_params.taesd_preview);
|
||||
|
||||
SDImageVec results;
|
||||
int num_results = 0;
|
||||
@@ -774,11 +870,22 @@ int main(int argc, const char* argv[]) {
|
||||
gen_params.sample_params.scheduler = sd_get_default_scheduler(sd_ctx.get(), gen_params.sample_params.sample_method);
|
||||
}
|
||||
|
||||
if (cli_params.mode == IMG_GEN) {
|
||||
sd_img_gen_params_t img_gen_params = gen_params.to_sd_img_gen_params_t();
|
||||
sd_img_gen_params_t img_gen_params{};
|
||||
const bool use_img_gen_params = cli_params.mode == IMG_GEN || cli_params.mode == ADETAILER;
|
||||
if (use_img_gen_params) {
|
||||
img_gen_params = gen_params.to_sd_img_gen_params_t();
|
||||
}
|
||||
|
||||
num_results = gen_params.batch_count;
|
||||
results.adopt(generate_image(sd_ctx.get(), &img_gen_params), num_results);
|
||||
if (cli_params.mode == IMG_GEN) {
|
||||
sd_image_t* generated_images = nullptr;
|
||||
if (!generate_image(sd_ctx.get(), &img_gen_params, &generated_images, &num_results)) {
|
||||
generated_images = nullptr;
|
||||
num_results = 0;
|
||||
}
|
||||
results.adopt(generated_images, num_results);
|
||||
} else if (cli_params.mode == ADETAILER) {
|
||||
num_results = 1;
|
||||
results.push_back(gen_params.init_image.release());
|
||||
} else if (cli_params.mode == VID_GEN) {
|
||||
sd_vid_gen_params_t vid_gen_params = gen_params.to_sd_vid_gen_params_t();
|
||||
sd_image_t* generated_video = nullptr;
|
||||
@@ -792,17 +899,28 @@ int main(int argc, const char* argv[]) {
|
||||
LOG_ERROR("generate failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (use_img_gen_params &&
|
||||
!apply_adetailer(sd_ctx.get(),
|
||||
sd_ctx_params,
|
||||
ctx_params,
|
||||
gen_params,
|
||||
img_gen_params,
|
||||
cli_params.mode,
|
||||
results,
|
||||
num_results)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int upscale_factor = 4; // unused for RealESRGAN_x4plus_anime_6B.pth
|
||||
if (ctx_params.esrgan_path.size() > 0 && gen_params.upscale_repeats > 0) {
|
||||
UpscalerCtxPtr upscaler_ctx(new_upscaler_ctx(ctx_params.esrgan_path.c_str(),
|
||||
ctx_params.offload_params_to_cpu,
|
||||
ctx_params.diffusion_conv_direct,
|
||||
ctx_params.n_threads,
|
||||
gen_params.upscale_tile_size,
|
||||
ctx_params.backend.c_str(),
|
||||
ctx_params.params_backend.c_str()));
|
||||
sd_ctx_params.backend,
|
||||
sd_ctx_params.params_backend));
|
||||
|
||||
if (upscaler_ctx == nullptr) {
|
||||
LOG_ERROR("new_upscaler_ctx failed");
|
||||
@@ -814,12 +932,22 @@ int main(int argc, const char* argv[]) {
|
||||
SDImageOwner current_image(results[i]);
|
||||
results[i] = {0, 0, 0, nullptr};
|
||||
for (int u = 0; u < gen_params.upscale_repeats; ++u) {
|
||||
SDImageOwner upscaled_image(upscale(upscaler_ctx.get(), current_image.get(), upscale_factor));
|
||||
if (upscaled_image.get().data == nullptr) {
|
||||
sd_image_t* upscaled_images = nullptr;
|
||||
int upscaled_count = 0;
|
||||
bool upscale_ok = upscale(upscaler_ctx.get(),
|
||||
current_image.get(),
|
||||
upscale_factor,
|
||||
&upscaled_images,
|
||||
&upscaled_count);
|
||||
if (!upscale_ok || upscaled_count <= 0 || upscaled_images[0].data == nullptr) {
|
||||
free_sd_images(upscaled_images, upscaled_count);
|
||||
LOG_ERROR("upscale failed");
|
||||
break;
|
||||
}
|
||||
current_image = std::move(upscaled_image);
|
||||
sd_image_t upscaled_image = upscaled_images[0];
|
||||
upscaled_images[0] = {0, 0, 0, nullptr};
|
||||
free_sd_images(upscaled_images, upscaled_count);
|
||||
current_image.reset(upscaled_image);
|
||||
}
|
||||
results[i] = current_image.release(); // Set the final upscaled image as the result
|
||||
}
|
||||
@@ -831,6 +959,11 @@ int main(int argc, const char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!cli_params.imatrix_out.empty()) {
|
||||
LOG_INFO("saving imatrix to '%s'", cli_params.imatrix_out.c_str());
|
||||
save_imatrix(cli_params.imatrix_out.c_str());
|
||||
}
|
||||
|
||||
free_sd_audio(generated_audio);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
#define BOOL_STR(b) ((b) ? "true" : "false")
|
||||
|
||||
extern const char* const modes_str[];
|
||||
#define SD_ALL_MODES_STR "img_gen, vid_gen, convert, upscale, metadata"
|
||||
#define SD_ALL_MODES_STR "img_gen, adetailer, vid_gen, convert, upscale, metadata"
|
||||
|
||||
enum SDMode {
|
||||
IMG_GEN,
|
||||
ADETAILER,
|
||||
VID_GEN,
|
||||
CONVERT,
|
||||
UPSCALE,
|
||||
@@ -31,6 +32,7 @@ struct StringOption {
|
||||
std::string short_name;
|
||||
std::string long_name;
|
||||
std::string desc;
|
||||
int concat;
|
||||
std::string* target;
|
||||
};
|
||||
|
||||
@@ -56,11 +58,42 @@ struct BoolOption {
|
||||
bool* target;
|
||||
};
|
||||
|
||||
struct ManualFunction {
|
||||
std::function<int(int, const char**, int, bool&)> _func;
|
||||
|
||||
ManualFunction() = default;
|
||||
|
||||
ManualFunction(std::function<int(int argc, const char** argv, int index, bool& valid)> func)
|
||||
: _func(std::move(func)) {
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
ManualFunction(F func)
|
||||
: _func(make_function(func)) {
|
||||
}
|
||||
|
||||
int operator()(int argc, const char** argv, int index, bool& valid) const {
|
||||
return _func(argc, argv, index, valid);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename F>
|
||||
static std::function<int(int, const char**, int, bool&)> make_function(F func) {
|
||||
if constexpr (std::is_invocable_v<F, int, const char**, int, bool&>) {
|
||||
return func;
|
||||
} else {
|
||||
return [func](int argc, const char** argv, int index, bool&) {
|
||||
return func(argc, argv, index);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ManualOption {
|
||||
std::string short_name;
|
||||
std::string long_name;
|
||||
std::string desc;
|
||||
std::function<int(int argc, const char** argv, int index)> cb;
|
||||
ManualFunction cb;
|
||||
};
|
||||
|
||||
struct ArgOptions {
|
||||
@@ -92,6 +125,7 @@ struct SDContextParams {
|
||||
std::string llm_vision_path;
|
||||
std::string diffusion_model_path;
|
||||
std::string high_noise_diffusion_model_path;
|
||||
std::string uncond_diffusion_model_path;
|
||||
std::string embeddings_connectors_path;
|
||||
std::string vae_path;
|
||||
std::string vae_format = "auto";
|
||||
@@ -99,8 +133,10 @@ struct SDContextParams {
|
||||
std::string taesd_path;
|
||||
std::string esrgan_path;
|
||||
std::string control_net_path;
|
||||
std::string motion_module_path;
|
||||
std::string embedding_dir;
|
||||
std::string photo_maker_path;
|
||||
std::string pulid_weights_path;
|
||||
sd_type_t wtype = SD_TYPE_COUNT;
|
||||
std::string tensor_type_rules;
|
||||
std::string lora_model_dir = ".";
|
||||
@@ -112,9 +148,17 @@ struct SDContextParams {
|
||||
rng_type_t rng_type = CUDA_RNG;
|
||||
rng_type_t sampler_rng_type = RNG_TYPE_COUNT;
|
||||
bool offload_params_to_cpu = false;
|
||||
float max_vram = 0.f;
|
||||
std::string max_vram = "0";
|
||||
bool stream_layers = false;
|
||||
bool eager_load = false;
|
||||
std::string backend;
|
||||
std::string params_backend;
|
||||
std::string split_mode;
|
||||
std::string model_args;
|
||||
bool auto_fit = false;
|
||||
std::string rpc_servers;
|
||||
std::string effective_backend;
|
||||
std::string effective_params_backend;
|
||||
bool enable_mmap = false;
|
||||
bool control_net_cpu = false;
|
||||
bool clip_on_cpu = false;
|
||||
@@ -124,16 +168,6 @@ struct SDContextParams {
|
||||
bool diffusion_conv_direct = false;
|
||||
bool vae_conv_direct = false;
|
||||
|
||||
bool circular = false;
|
||||
bool circular_x = false;
|
||||
bool circular_y = false;
|
||||
|
||||
bool chroma_use_dit_mask = true;
|
||||
bool chroma_use_t5_mask = false;
|
||||
int chroma_t5_mask_pad = 1;
|
||||
|
||||
bool qwen_image_zero_cond_t = false;
|
||||
|
||||
prediction_t prediction = PREDICTION_COUNT;
|
||||
lora_apply_mode_t lora_apply_mode = LORA_APPLY_AUTO;
|
||||
|
||||
@@ -142,21 +176,27 @@ struct SDContextParams {
|
||||
float flow_shift = INFINITY;
|
||||
ArgOptions get_options();
|
||||
void build_embedding_map();
|
||||
void prepare_backend_assignments();
|
||||
bool resolve(SDMode mode);
|
||||
bool validate(SDMode mode);
|
||||
bool resolve_and_validate(SDMode mode);
|
||||
std::string to_string() const;
|
||||
sd_ctx_params_t to_sd_ctx_params_t(bool vae_decode_only, bool free_params_immediately, bool taesd_preview);
|
||||
sd_ctx_params_t to_sd_ctx_params_t(bool taesd_preview);
|
||||
};
|
||||
|
||||
struct SDGenerationParams {
|
||||
// User-facing input fields.
|
||||
std::string prompt;
|
||||
std::string negative_prompt;
|
||||
std::string ad_model_path;
|
||||
std::string ad_prompt;
|
||||
std::string ad_negative_prompt;
|
||||
std::string extra_ad_args;
|
||||
int clip_skip = -1; // <= 0 represents unspecified
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
int batch_count = 1;
|
||||
int qwen_image_layers = 3;
|
||||
int64_t seed = 42;
|
||||
float strength = 0.75f;
|
||||
float control_strength = 0.9f;
|
||||
@@ -193,13 +233,22 @@ struct SDGenerationParams {
|
||||
sd_tiling_params_t vae_tiling_params = {false, false, 0, 0, 0.5f, 0.0f, 0.0f, nullptr};
|
||||
std::string extra_tiling_args;
|
||||
|
||||
std::string ref_image_args;
|
||||
|
||||
std::string pm_id_images_dir;
|
||||
std::string pm_id_embed_path;
|
||||
float pm_style_strength = 20.f;
|
||||
|
||||
std::string pulid_id_embedding_path;
|
||||
float pulid_id_weight = 1.0f;
|
||||
|
||||
int upscale_repeats = 1;
|
||||
int upscale_tile_size = 128;
|
||||
|
||||
bool circular = false;
|
||||
bool circular_x = false;
|
||||
bool circular_y = false;
|
||||
|
||||
bool hires_enabled = false;
|
||||
std::string hires_upscaler = "Latent";
|
||||
std::string hires_upscaler_model_path;
|
||||
|
||||
@@ -40,12 +40,21 @@ struct UpscalerCtxDeleter {
|
||||
}
|
||||
};
|
||||
|
||||
struct ADetailerCtxDeleter {
|
||||
void operator()(adetailer_ctx_t* ctx) const {
|
||||
if (ctx != nullptr) {
|
||||
free_adetailer_ctx(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using FreeUniquePtr = std::unique_ptr<T, FreeDeleter>;
|
||||
|
||||
using FilePtr = std::unique_ptr<FILE, FileCloser>;
|
||||
using SDCtxPtr = std::unique_ptr<sd_ctx_t, SDCtxDeleter>;
|
||||
using UpscalerCtxPtr = std::unique_ptr<upscaler_ctx_t, UpscalerCtxDeleter>;
|
||||
using FilePtr = std::unique_ptr<FILE, FileCloser>;
|
||||
using SDCtxPtr = std::unique_ptr<sd_ctx_t, SDCtxDeleter>;
|
||||
using UpscalerCtxPtr = std::unique_ptr<upscaler_ctx_t, UpscalerCtxDeleter>;
|
||||
using ADetailerCtxPtr = std::unique_ptr<adetailer_ctx_t, ADetailerCtxDeleter>;
|
||||
|
||||
class SDImageOwner {
|
||||
private:
|
||||
|
||||
@@ -117,186 +117,10 @@ In this case, the server will load and serve the specified `index.html` file ins
|
||||
* using a custom UI
|
||||
* avoiding rebuilding the binary after frontend modifications
|
||||
|
||||
# Run
|
||||
# Usage
|
||||
|
||||
```
|
||||
usage: ./bin/sd-server [options]
|
||||
|
||||
Svr Options:
|
||||
-l, --listen-ip <string> server listen ip (default: 127.0.0.1)
|
||||
--serve-html-path <string> path to HTML file to serve at root (optional)
|
||||
--listen-port <int> server listen port (default: 1234)
|
||||
-v, --verbose print extra info
|
||||
--color colors the logging tags according to level
|
||||
-h, --help show this help message and exit
|
||||
|
||||
Context Options:
|
||||
-m, --model <string> path to full model
|
||||
--clip_l <string> path to the clip-l text encoder
|
||||
--clip_g <string> path to the clip-g text encoder
|
||||
--clip_vision <string> path to the clip-vision encoder
|
||||
--t5xxl <string> path to the t5xxl text encoder
|
||||
--llm <string> path to the llm text encoder. For example: (qwenvl2.5 for qwen-image,
|
||||
mistral-small3.2 for flux2, ...)
|
||||
--llm_vision <string> path to the llm vit
|
||||
--qwen2vl <string> alias of --llm. Deprecated.
|
||||
--qwen2vl_vision <string> alias of --llm_vision. Deprecated.
|
||||
--diffusion-model <string> path to the standalone diffusion model
|
||||
--high-noise-diffusion-model <string> path to the standalone high noise diffusion model
|
||||
--vae <string> path to standalone vae model
|
||||
--taesd <string> path to taesd. Using Tiny AutoEncoder for fast decoding (low quality)
|
||||
--tae <string> alias of --taesd
|
||||
--control-net <string> path to control net model
|
||||
--embd-dir <string> embeddings directory
|
||||
--lora-model-dir <string> lora model directory
|
||||
--hires-upscalers-dir <string> highres fix upscaler model directory
|
||||
--tensor-type-rules <string> weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
||||
--photo-maker <string> path to PHOTOMAKER model
|
||||
--upscale-model <string> path to esrgan model.
|
||||
-t, --threads <int> number of threads to use during computation (default: -1). If threads <= 0,
|
||||
then threads will be set to the number of CPU physical cores
|
||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
||||
--max-vram <float> maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables
|
||||
graph splitting; a negative value auto-detects free VRAM, sparing the
|
||||
specified value (e.g. -0.5 will keep at least 0.5 GiB free)
|
||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
||||
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM
|
||||
when needed
|
||||
--mmap whether to memory-map model
|
||||
--control-net-cpu keep controlnet in cpu (for low vram)
|
||||
--clip-on-cpu keep clip in cpu (for low vram)
|
||||
--vae-on-cpu keep vae in cpu (for low vram)
|
||||
--fa use flash attention
|
||||
--diffusion-fa use flash attention in the diffusion model only
|
||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||
--circular enable circular padding for convolutions
|
||||
--circularx enable circular RoPE wrapping on x-axis (width) only
|
||||
--circulary enable circular RoPE wrapping on y-axis (height) only
|
||||
--chroma-disable-dit-mask disable dit mask for chroma
|
||||
--qwen-image-zero-cond-t enable zero_cond_t for qwen image
|
||||
--chroma-enable-t5-mask enable t5 mask for chroma
|
||||
--type weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K,
|
||||
q4_K). If not specified, the default is the type of the weight file
|
||||
--rng RNG, one of [std_default, cuda, cpu], default: cuda(sd-webui), cpu(comfyui)
|
||||
--sampler-rng sampler RNG, one of [std_default, cuda, cpu]. If not specified, use --rng
|
||||
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow,
|
||||
flux2_flow]
|
||||
--lora-apply-mode the way to apply LoRA, one of [auto, immediately, at_runtime], default is
|
||||
auto. In auto mode, if the model weights contain any quantized parameters,
|
||||
the at_runtime mode will be used; otherwise, immediately will be used.The
|
||||
immediately mode may have precision and compatibility issues with quantized
|
||||
parameters, but it usually offers faster inference speed and, in some cases,
|
||||
lower memory usage. The at_runtime mode, on the other hand, is exactly the
|
||||
opposite.
|
||||
|
||||
Default Generation Options:
|
||||
-p, --prompt <string> the prompt to render
|
||||
-n, --negative-prompt <string> the negative prompt (default: "")
|
||||
-i, --init-img <string> path to the init image
|
||||
--end-img <string> path to the end image, required by flf2v
|
||||
--mask <string> path to the mask image
|
||||
--control-image <string> path to control image, control net
|
||||
--control-video <string> path to control video frames, It must be a directory path. The video frames
|
||||
inside should be stored as images in lexicographical (character) order. For
|
||||
example, if the control video path is `frames`, the directory contain images
|
||||
such as 00.png, 01.png, ... etc.
|
||||
--pm-id-images-dir <string> path to PHOTOMAKER input id images dir
|
||||
--pm-id-embed-path <string> path to PHOTOMAKER v2 id embed
|
||||
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
||||
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
||||
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
||||
--extra-sample-args <string> extra sampler/scheduler/guidance args, key=value list. APG supports apg_eta,
|
||||
apg_momentum, apg_norm_threshold, apg_norm_threshold_smoothing; SLG supports
|
||||
slg_uncond; lcm supports noise_clip_std, noise_scale_start, noise_scale_end;
|
||||
ltx2 supports max_shift, base_shift, stretch, terminal; euler_ge supports gamma
|
||||
--extra-tiling-args <string> extra VAE tiling args, key=value list. LTX video VAE supports
|
||||
temporal_tile_frames (default: 4), temporal_tile_overlap (default: 1)
|
||||
-H, --height <int> image height, in pixel space (default: 512)
|
||||
-W, --width <int> image width, in pixel space (default: 512)
|
||||
--steps <int> number of sample steps (default: 20)
|
||||
--high-noise-steps <int> (high noise) number of sample steps (default: -1 = auto)
|
||||
--clip-skip <int> ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer
|
||||
(default: -1). <= 0 represents unspecified, will be 1 for SD1.x, 2 for SD2.x
|
||||
-b, --batch-count <int> batch count
|
||||
--video-frames <int> video frames (default: 1)
|
||||
--fps <int> fps (default: 24)
|
||||
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for
|
||||
NitroSD-Realism around 250 and 500 for NitroSD-Vibrant
|
||||
--upscale-repeats <int> Run the ESRGAN upscaler this many times (default: 1)
|
||||
--upscale-tile-size <int> tile size for ESRGAN upscaling (default: 128)
|
||||
--hires-width <int> highres fix target width, 0 to use --hires-scale (default: 0)
|
||||
--hires-height <int> highres fix target height, 0 to use --hires-scale (default: 0)
|
||||
--hires-steps <int> highres fix second pass sample steps, 0 to reuse --steps (default: 0)
|
||||
--hires-upscale-tile-size <int> highres fix upscaler tile size, reserved for model-backed upscalers (default:
|
||||
128)
|
||||
--cfg-scale <float> unconditional guidance scale: (default: 7.0)
|
||||
--img-cfg-scale <float> image guidance scale for inpaint or image edit models: (default: same as
|
||||
--cfg-scale)
|
||||
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--slg-scale <float> skip layer guidance (SLG) scale, only for DiT models: (default: 0). 0 means
|
||||
disabled, a value of 2.5 is nice for sd3.5 medium
|
||||
--skip-layer-start <float> SLG enabling point (default: 0.01)
|
||||
--skip-layer-end <float> SLG disabling point (default: 0.2)
|
||||
--eta <float> noise multiplier (default: 0 for ddim_trailing, tcd, res_multistep and
|
||||
res_2s; 1 for euler_a, er_sde and dpm++2s_a)
|
||||
--flow-shift <float> shift value for Flow models like SD3.x or WAN (default: auto)
|
||||
--high-noise-cfg-scale <float> (high noise) unconditional guidance scale: (default: 7.0)
|
||||
--high-noise-img-cfg-scale <float> (high noise) image guidance scale for inpaint or image edit models (default:
|
||||
same as --cfg-scale)
|
||||
--high-noise-guidance <float> (high noise) distilled guidance scale for models with guidance input
|
||||
(default: 3.5)
|
||||
--high-noise-slg-scale <float> (high noise) skip layer guidance (SLG) scale, only for DiT models: (default:
|
||||
0)
|
||||
--high-noise-skip-layer-start <float> (high noise) SLG enabling point (default: 0.01)
|
||||
--high-noise-skip-layer-end <float> (high noise) SLG disabling point (default: 0.2)
|
||||
--high-noise-eta <float> (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)
|
||||
--strength <float> strength for noising/unnoising (default: 0.75)
|
||||
--pm-style-strength <float>
|
||||
--control-strength <float> strength to apply Control Net (default: 0.9). 1.0 corresponds to full
|
||||
destruction of information in init image
|
||||
--moe-boundary <float> timestep boundary for Wan2.2 MoE model. (default: 0.875). Only enabled if
|
||||
`--high-noise-steps` is set to -1
|
||||
--vace-strength <float> wan vace strength
|
||||
--vae-tile-overlap <float> tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
||||
--hires-scale <float> highres fix scale when target size is not set (default: 2.0)
|
||||
--hires-denoising-strength <float> highres fix second pass denoising strength (default: 0.7)
|
||||
--increase-ref-index automatically increase the indices of references images based on the order
|
||||
they are listed (starting with 1).
|
||||
--disable-auto-resize-ref-image disable auto resize of ref images
|
||||
--disable-image-metadata do not embed generation metadata on image files
|
||||
--vae-tiling process vae in tiles to reduce memory usage
|
||||
--temporal-tiling enable temporal tiling for LTX video VAE decode
|
||||
--hires enable highres fix
|
||||
-s, --seed RNG seed (default: 42, use random seed for < 0)
|
||||
--sampling-method 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)
|
||||
--high-noise-sampling-method (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
|
||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
||||
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent, ltx2], default:
|
||||
model-specific
|
||||
--sigmas custom sigma values for the sampler, comma-separated (e.g.,
|
||||
"14.61,7.8,3.5,0.0").
|
||||
--hires-sigmas custom sigma values for the highres fix second pass, comma-separated (e.g.,
|
||||
"0.85,0.725,0.421875,0.0").
|
||||
--skip-layers layers to skip for SLG steps (default: [7,8,9])
|
||||
--high-noise-skip-layers (high noise) layers to skip for SLG steps (default: [7,8,9])
|
||||
-r, --ref-image reference image for Flux Kontext models (can be used multiple times)
|
||||
--cache-mode caching method: 'easycache' (DiT), 'ucache' (UNET),
|
||||
'dbcache'/'taylorseer'/'cache-dit' (DiT block-level), 'spectrum' (UNET/DiT
|
||||
Chebyshev+Taylor forecasting)
|
||||
--cache-option named cache params (key=value format, comma-separated). easycache/ucache:
|
||||
threshold=,start=,end=,decay=,relative=,reset=; dbcache/taylorseer/cache-dit:
|
||||
Fn=,Bn=,threshold=,warmup=; spectrum: w=,m=,lam=,window=,flex=,warmup=,stop=.
|
||||
Examples: "threshold=0.25" or "threshold=1.5,reset=0"
|
||||
--scm-mask SCM steps mask for cache-dit: comma-separated 0/1 (e.g.,
|
||||
"1,1,1,0,0,1,0,0,1,0") - 1=compute, 0=can cache
|
||||
--scm-policy SCM policy: 'dynamic' (default) or 'static'
|
||||
--vae-tile-size tile size for vae tiling, format [X]x[Y] (default: 32x32)
|
||||
--vae-relative-tile-size relative tile size for vae tiling, format [X]x[Y], in fraction of image size
|
||||
if < 1, in number of tiles per dim if >=1 (overrides --vae-tile-size)
|
||||
For detailed command-line arguments, run:
|
||||
|
||||
```bash
|
||||
./bin/sd-server -h
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "async_jobs.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
@@ -173,8 +174,13 @@ bool execute_img_gen_job(ServerRuntime& runtime,
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*runtime.sd_ctx_mutex);
|
||||
sd_image_t* raw_results = generate_image(runtime.sd_ctx, ¶ms);
|
||||
results.adopt(raw_results, params.batch_count);
|
||||
sd_image_t* raw_results = nullptr;
|
||||
int num_results = 0;
|
||||
if (!generate_image(runtime.sd_ctx, ¶ms, &raw_results, &num_results)) {
|
||||
raw_results = nullptr;
|
||||
num_results = 0;
|
||||
}
|
||||
results.adopt(raw_results, num_results);
|
||||
}
|
||||
|
||||
const int num_results = results.count();
|
||||
@@ -190,6 +196,8 @@ bool execute_img_gen_job(ServerRuntime& runtime,
|
||||
encoded_format = EncodedImageFormat::WEBP;
|
||||
}
|
||||
|
||||
int batch_count = job.img_gen.gen_params.batch_count;
|
||||
int images_per_batch = batch_count > 0 ? std::max(1, num_results / batch_count) : 1;
|
||||
for (int i = 0; i < num_results; ++i) {
|
||||
if (results[i].data == nullptr) {
|
||||
continue;
|
||||
@@ -198,7 +206,7 @@ bool execute_img_gen_job(ServerRuntime& runtime,
|
||||
const std::string metadata = job.img_gen.gen_params.embed_image_metadata
|
||||
? get_image_params(*runtime.ctx_params,
|
||||
job.img_gen.gen_params,
|
||||
job.img_gen.gen_params.seed + i)
|
||||
job.img_gen.gen_params.seed + i / images_per_batch)
|
||||
: "";
|
||||
auto image_bytes = encode_image_to_vector(encoded_format,
|
||||
results[i].data,
|
||||
|
||||
@@ -85,7 +85,7 @@ int main(int argc, const char** argv) {
|
||||
LOG_DEBUG("%s", ctx_params.to_string().c_str());
|
||||
LOG_DEBUG("%s", default_gen_params.to_string().c_str());
|
||||
|
||||
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(false, false, false);
|
||||
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(false);
|
||||
SDCtxPtr sd_ctx(new_sd_ctx(&sd_ctx_params));
|
||||
|
||||
if (sd_ctx == nullptr) {
|
||||
|
||||
@@ -229,8 +229,11 @@ static bool execute_sync_img_gen_request(ServerRuntime& runtime,
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*runtime.sd_ctx_mutex);
|
||||
sd_image_t* raw_results = generate_image(runtime.sd_ctx, &img_gen_params);
|
||||
num_results = request.gen_params.batch_count;
|
||||
sd_image_t* raw_results = nullptr;
|
||||
if (!generate_image(runtime.sd_ctx, &img_gen_params, &raw_results, &num_results)) {
|
||||
raw_results = nullptr;
|
||||
num_results = 0;
|
||||
}
|
||||
results.adopt(raw_results, num_results);
|
||||
}
|
||||
|
||||
@@ -281,14 +284,16 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
out["data"] = json::array();
|
||||
out["output_format"] = request.output_format;
|
||||
|
||||
for (int i = 0; i < request.gen_params.batch_count; ++i) {
|
||||
int result_count = results.count();
|
||||
int images_per_batch = request.gen_params.batch_count > 0 ? std::max(1, result_count / request.gen_params.batch_count) : 1;
|
||||
for (int i = 0; i < result_count; ++i) {
|
||||
if (results[i].data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
std::string params = request.gen_params.embed_image_metadata
|
||||
? get_image_params(*runtime->ctx_params,
|
||||
request.gen_params,
|
||||
request.gen_params.seed + i)
|
||||
request.gen_params.seed + i / images_per_batch)
|
||||
: "";
|
||||
auto image_bytes = encode_image_to_vector(request.output_format == "jpeg"
|
||||
? EncodedImageFormat::JPEG
|
||||
@@ -353,14 +358,16 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
out["data"] = json::array();
|
||||
out["output_format"] = request.output_format;
|
||||
|
||||
for (int i = 0; i < request.gen_params.batch_count; ++i) {
|
||||
int result_count = results.count();
|
||||
int images_per_batch = request.gen_params.batch_count > 0 ? std::max(1, result_count / request.gen_params.batch_count) : 1;
|
||||
for (int i = 0; i < result_count; ++i) {
|
||||
if (results[i].data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
std::string params = request.gen_params.embed_image_metadata
|
||||
? get_image_params(*runtime->ctx_params,
|
||||
request.gen_params,
|
||||
request.gen_params.seed + i)
|
||||
request.gen_params.seed + i / images_per_batch)
|
||||
: "";
|
||||
auto image_bytes = encode_image_to_vector(request.output_format == "jpeg" ? EncodedImageFormat::JPEG : EncodedImageFormat::PNG,
|
||||
results[i].data,
|
||||
|
||||
@@ -63,6 +63,10 @@ static enum sample_method_t get_sdapi_sample_method(std::string name) {
|
||||
{"ddim", DDIM_TRAILING_SAMPLE_METHOD},
|
||||
{"dpm++ 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},
|
||||
{"k_res_multistep", RES_MULTISTEP_SAMPLE_METHOD},
|
||||
{"res 2s", RES_2S_SAMPLE_METHOD},
|
||||
@@ -259,6 +263,48 @@ static bool build_sdapi_img_gen_request(const json& j,
|
||||
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) {
|
||||
ServerRuntime* runtime = &rt;
|
||||
|
||||
@@ -292,8 +338,11 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*runtime->sd_ctx_mutex);
|
||||
sd_image_t* raw_results = generate_image(runtime->sd_ctx, &img_gen_params);
|
||||
num_results = request.gen_params.batch_count;
|
||||
sd_image_t* raw_results = nullptr;
|
||||
if (!generate_image(runtime->sd_ctx, &img_gen_params, &raw_results, &num_results)) {
|
||||
raw_results = nullptr;
|
||||
num_results = 0;
|
||||
}
|
||||
results.adopt(raw_results, num_results);
|
||||
}
|
||||
|
||||
@@ -306,24 +355,26 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
json out;
|
||||
out["images"] = json::array();
|
||||
out["parameters"] = j;
|
||||
out["info"] = "";
|
||||
json jsoninfo = prepare_info_field(*runtime->ctx_params, request.gen_params, img2img);
|
||||
|
||||
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) {
|
||||
if (results[i].data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string params = request.gen_params.embed_image_metadata
|
||||
? get_image_params(*runtime->ctx_params,
|
||||
request.gen_params,
|
||||
request.gen_params.seed + i)
|
||||
: "";
|
||||
auto image_bytes = encode_image_to_vector(EncodedImageFormat::PNG,
|
||||
results[i].data,
|
||||
results[i].width,
|
||||
results[i].height,
|
||||
results[i].channel,
|
||||
params);
|
||||
bool embed_meta = request.gen_params.embed_image_metadata;
|
||||
|
||||
std::string params = get_image_params(*runtime->ctx_params,
|
||||
request.gen_params,
|
||||
request.gen_params.seed + i / images_per_batch);
|
||||
|
||||
auto image_bytes = encode_image_to_vector(EncodedImageFormat::PNG,
|
||||
results[i].data,
|
||||
results[i].width,
|
||||
results[i].height,
|
||||
results[i].channel,
|
||||
embed_meta ? params : "");
|
||||
|
||||
if (image_bytes.empty()) {
|
||||
LOG_ERROR("write image to mem failed");
|
||||
@@ -331,8 +382,16 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
}
|
||||
|
||||
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.status = 200;
|
||||
|
||||
@@ -438,6 +497,9 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
||||
scheduler_names.push_back("default");
|
||||
for (int i = 0; i < SCHEDULER_COUNT; i++) {
|
||||
scheduler_names.push_back(sd_scheduler_name((scheduler_t)i));
|
||||
if (i == DISCRETE_SCHEDULER) {
|
||||
scheduler_names.push_back("normal");
|
||||
}
|
||||
}
|
||||
json r = json::array();
|
||||
for (auto name : scheduler_names) {
|
||||
|
||||
@@ -126,6 +126,7 @@ static json make_img_gen_defaults_json(const SDGenerationParams& defaults, const
|
||||
{"strength", defaults.strength},
|
||||
{"seed", defaults.seed},
|
||||
{"batch_count", defaults.batch_count},
|
||||
{"qwen_image_layers", defaults.qwen_image_layers},
|
||||
{"auto_resize_ref_image", defaults.auto_resize_ref_image},
|
||||
{"increase_ref_index", defaults.increase_ref_index},
|
||||
{"control_strength", defaults.control_strength},
|
||||
@@ -219,6 +220,9 @@ static json make_capabilities_json(ServerRuntime& runtime) {
|
||||
|
||||
for (int i = 0; i < SCHEDULER_COUNT; ++i) {
|
||||
schedulers.push_back(sd_scheduler_name((scheduler_t)i));
|
||||
if (i == DISCRETE_SCHEDULER) {
|
||||
schedulers.push_back("normal");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -190,8 +190,8 @@ ArgOptions SDSvrParams::get_options() {
|
||||
ArgOptions options;
|
||||
|
||||
options.string_options = {
|
||||
{"-l", "--listen-ip", "server listen ip (default: 127.0.0.1)", &listen_ip},
|
||||
{"", "--serve-html-path", "path to HTML file to serve at root (optional)", &serve_html_path},
|
||||
{"-l", "--listen-ip", "server listen ip (default: 127.0.0.1)", 0, &listen_ip},
|
||||
{"", "--serve-html-path", "path to HTML file to serve at root (optional)", 0, &serve_html_path},
|
||||
};
|
||||
|
||||
options.int_options = {
|
||||
@@ -203,8 +203,9 @@ ArgOptions SDSvrParams::get_options() {
|
||||
{"", "--color", "colors the logging tags according to level", true, &color},
|
||||
};
|
||||
|
||||
auto on_help_arg = [&](int, const char**, int) {
|
||||
auto on_help_arg = [&](int, const char**, int, bool& valid) {
|
||||
normal_exit = true;
|
||||
valid = true;
|
||||
return -1;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
for f in src/*.cpp src/*.h src/*.hpp src/tokenizers/*.h src/tokenizers/*.cpp src/tokenizers/vocab/*.h src/tokenizers/vocab/*.cpp \
|
||||
src/model_io/*.h src/model_io/*.cpp examples/cli/*.cpp examples/cli/*.h examples/server/*.cpp \
|
||||
examples/common/*.hpp examples/common/*.h examples/common/*.cpp; do
|
||||
[[ "$f" == vocab* ]] && continue
|
||||
echo "formatting '$f'"
|
||||
# if [ "$f" != "stable-diffusion.h" ]; then
|
||||
# clang-tidy -fix -p build_linux/ "$f"
|
||||
# fi
|
||||
clang-format -style=file -i "$f"
|
||||
done
|
||||
2
ggml
@@ -54,6 +54,8 @@ enum sample_method_t {
|
||||
EULER_CFG_PP_SAMPLE_METHOD,
|
||||
EULER_A_CFG_PP_SAMPLE_METHOD,
|
||||
EULER_GE_SAMPLE_METHOD,
|
||||
DPMPP2M_SDE_SAMPLE_METHOD,
|
||||
DPMPP2M_SDE_BT_SAMPLE_METHOD,
|
||||
SAMPLE_METHOD_COUNT
|
||||
};
|
||||
|
||||
@@ -70,6 +72,10 @@ enum scheduler_t {
|
||||
LCM_SCHEDULER,
|
||||
BONG_TANGENT_SCHEDULER,
|
||||
LTX2_SCHEDULER,
|
||||
LOGIT_NORMAL_SCHEDULER,
|
||||
FLUX2_SCHEDULER,
|
||||
FLUX_SCHEDULER,
|
||||
BETA_SCHEDULER,
|
||||
SCHEDULER_COUNT
|
||||
};
|
||||
|
||||
@@ -79,7 +85,8 @@ enum prediction_t {
|
||||
EDM_V_PRED,
|
||||
FLOW_PRED,
|
||||
FLUX_FLOW_PRED,
|
||||
FLUX2_FLOW_PRED,
|
||||
SEFI_FLOW_PRED,
|
||||
MINIT2I_FLOW_PRED,
|
||||
PREDICTION_COUNT
|
||||
};
|
||||
|
||||
@@ -173,6 +180,7 @@ enum sd_vae_format_t {
|
||||
SD_VAE_FORMAT_FLUX,
|
||||
SD_VAE_FORMAT_SD3,
|
||||
SD_VAE_FORMAT_FLUX2,
|
||||
SD_VAE_FORMAT_WAN,
|
||||
SD_VAE_FORMAT_COUNT,
|
||||
};
|
||||
|
||||
@@ -186,44 +194,41 @@ typedef struct {
|
||||
const char* llm_vision_path;
|
||||
const char* diffusion_model_path;
|
||||
const char* high_noise_diffusion_model_path;
|
||||
const char* uncond_diffusion_model_path;
|
||||
const char* embeddings_connectors_path;
|
||||
const char* vae_path;
|
||||
const char* audio_vae_path;
|
||||
const char* taesd_path;
|
||||
const char* control_net_path;
|
||||
const char* motion_module_path;
|
||||
const sd_embedding_t* embeddings;
|
||||
uint32_t embedding_count;
|
||||
const char* photo_maker_path;
|
||||
const char* pulid_weights_path;
|
||||
const char* tensor_type_rules;
|
||||
bool vae_decode_only;
|
||||
bool free_params_immediately;
|
||||
int n_threads;
|
||||
enum sd_type_t wtype;
|
||||
enum rng_type_t rng_type;
|
||||
enum rng_type_t sampler_rng_type;
|
||||
enum prediction_t prediction;
|
||||
enum lora_apply_mode_t lora_apply_mode;
|
||||
bool offload_params_to_cpu;
|
||||
bool enable_mmap;
|
||||
bool keep_clip_on_cpu;
|
||||
bool keep_control_net_on_cpu;
|
||||
bool keep_vae_on_cpu;
|
||||
bool flash_attn;
|
||||
bool diffusion_flash_attn;
|
||||
bool tae_preview_only;
|
||||
bool diffusion_conv_direct;
|
||||
bool vae_conv_direct;
|
||||
bool circular_x;
|
||||
bool circular_y;
|
||||
bool force_sdxl_vae_conv_scale;
|
||||
bool chroma_use_dit_mask;
|
||||
bool chroma_use_t5_mask;
|
||||
int chroma_t5_mask_pad;
|
||||
bool qwen_image_zero_cond_t;
|
||||
enum sd_vae_format_t vae_format;
|
||||
float max_vram; // GiB budget for graph-cut segmented param offload (0 = disabled, -1 = auto free VRAM minus 1 GiB)
|
||||
const char* max_vram; // GiB budget or backend assignment spec for graph-cut segmented param offload (0 = disabled, -1 = auto)
|
||||
bool stream_layers; // Enable residency+prefetch streaming on top of --max-vram (no effect without --max-vram)
|
||||
bool eager_load; // Load all params into the params backend at model-load time instead of lazily on first use
|
||||
const char* backend;
|
||||
const char* params_backend;
|
||||
const char* split_mode; // weight distribution for multi-device modules: layer (default) or row, or per-module assignments e.g. "diffusion=row"
|
||||
bool auto_fit;
|
||||
const char* rpc_servers;
|
||||
const char* model_args;
|
||||
} sd_ctx_params_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -275,6 +280,11 @@ typedef struct {
|
||||
float style_strength;
|
||||
} sd_pm_params_t; // photo maker
|
||||
|
||||
typedef struct {
|
||||
const char* id_embedding_path;
|
||||
float id_weight;
|
||||
} sd_pulid_params_t;
|
||||
|
||||
enum sd_cache_mode_t {
|
||||
SD_CACHE_DISABLED = 0,
|
||||
SD_CACHE_EASYCACHE,
|
||||
@@ -355,8 +365,7 @@ typedef struct {
|
||||
sd_image_t init_image;
|
||||
sd_image_t* ref_images;
|
||||
int ref_images_count;
|
||||
bool auto_resize_ref_image;
|
||||
bool increase_ref_index;
|
||||
const char* ref_image_args;
|
||||
sd_image_t mask_image;
|
||||
int width;
|
||||
int height;
|
||||
@@ -367,9 +376,13 @@ typedef struct {
|
||||
sd_image_t control_image;
|
||||
float control_strength;
|
||||
sd_pm_params_t pm_params;
|
||||
sd_pulid_params_t pulid_params;
|
||||
sd_tiling_params_t vae_tiling_params;
|
||||
sd_cache_params_t cache;
|
||||
sd_hires_params_t hires;
|
||||
int qwen_image_layers;
|
||||
bool circular_x;
|
||||
bool circular_y;
|
||||
} sd_img_gen_params_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -395,22 +408,32 @@ typedef struct {
|
||||
sd_tiling_params_t vae_tiling_params;
|
||||
sd_cache_params_t cache;
|
||||
sd_hires_params_t hires;
|
||||
bool circular_x;
|
||||
bool circular_y;
|
||||
} sd_vid_gen_params_t;
|
||||
|
||||
typedef struct sd_ctx_t sd_ctx_t;
|
||||
struct ggml_tensor;
|
||||
|
||||
typedef void (*sd_log_cb_t)(enum sd_log_level_t level, const char* text, void* data);
|
||||
typedef void (*sd_progress_cb_t)(int step, int steps, float time, void* data);
|
||||
typedef void (*sd_preview_cb_t)(int step, int frame_count, sd_image_t* frames, bool is_noisy, void* data);
|
||||
typedef bool (*sd_graph_eval_callback_t)(struct ggml_tensor* t, bool ask, void* user_data);
|
||||
|
||||
SD_API void sd_set_log_callback(sd_log_cb_t sd_log_cb, void* data);
|
||||
SD_API void sd_set_progress_callback(sd_progress_cb_t cb, void* data);
|
||||
SD_API void sd_set_preview_callback(sd_preview_cb_t cb, enum preview_t mode, int interval, bool denoised, bool noisy, void* data);
|
||||
SD_API void sd_set_backend_eval_callback(sd_graph_eval_callback_t cb, void* data);
|
||||
SD_API int32_t sd_get_num_physical_cores();
|
||||
SD_API const char* sd_get_system_info();
|
||||
SD_API bool sd_ctx_supports_image_generation(const sd_ctx_t* sd_ctx);
|
||||
SD_API bool sd_ctx_supports_video_generation(const sd_ctx_t* sd_ctx);
|
||||
|
||||
// ControlNet hot-swap APIs are not safe to call while generation is in flight.
|
||||
SD_API bool sd_ctx_load_control_net(sd_ctx_t* sd_ctx, const char* path);
|
||||
SD_API bool sd_ctx_unload_control_net(sd_ctx_t* sd_ctx);
|
||||
SD_API bool sd_ctx_has_control_net(const sd_ctx_t* sd_ctx);
|
||||
|
||||
SD_API const char* sd_type_name(enum sd_type_t type);
|
||||
SD_API enum sd_type_t str_to_sd_type(const char* str);
|
||||
SD_API const char* sd_rng_type_name(enum rng_type_t rng_type);
|
||||
@@ -446,7 +469,21 @@ SD_API enum scheduler_t sd_get_default_scheduler(const sd_ctx_t* sd_ctx, enum sa
|
||||
|
||||
SD_API void sd_img_gen_params_init(sd_img_gen_params_t* sd_img_gen_params);
|
||||
SD_API char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params);
|
||||
SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* sd_img_gen_params);
|
||||
SD_API bool generate_image(sd_ctx_t* sd_ctx,
|
||||
const sd_img_gen_params_t* sd_img_gen_params,
|
||||
sd_image_t** images_out,
|
||||
int* num_images_out);
|
||||
|
||||
enum sd_cancel_mode_t {
|
||||
// Stop the current generation as soon as possible.
|
||||
SD_CANCEL_ALL,
|
||||
// Finish the current image sample, then skip additional batch latents and return completed images.
|
||||
SD_CANCEL_NEW_LATENTS,
|
||||
// Clear a pending cancellation request.
|
||||
SD_CANCEL_RESET
|
||||
};
|
||||
|
||||
SD_API void sd_cancel_generation(sd_ctx_t* sd_ctx, enum sd_cancel_mode_t mode);
|
||||
|
||||
SD_API void sd_vid_gen_params_init(sd_vid_gen_params_t* sd_vid_gen_params);
|
||||
SD_API bool generate_video(sd_ctx_t* sd_ctx,
|
||||
@@ -458,7 +495,6 @@ SD_API bool generate_video(sd_ctx_t* sd_ctx,
|
||||
typedef struct upscaler_ctx_t upscaler_ctx_t;
|
||||
|
||||
SD_API upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path,
|
||||
bool offload_params_to_cpu,
|
||||
bool direct,
|
||||
int n_threads,
|
||||
int tile_size,
|
||||
@@ -466,12 +502,35 @@ SD_API upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path,
|
||||
const char* params_backend);
|
||||
SD_API void free_upscaler_ctx(upscaler_ctx_t* upscaler_ctx);
|
||||
|
||||
SD_API sd_image_t upscale(upscaler_ctx_t* upscaler_ctx,
|
||||
sd_image_t input_image,
|
||||
uint32_t upscale_factor);
|
||||
SD_API bool upscale(upscaler_ctx_t* upscaler_ctx,
|
||||
sd_image_t input_image,
|
||||
uint32_t upscale_factor,
|
||||
sd_image_t** images_out,
|
||||
int* num_images_out);
|
||||
|
||||
SD_API int get_upscale_factor(upscaler_ctx_t* upscaler_ctx);
|
||||
|
||||
typedef struct adetailer_ctx_t adetailer_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
const char* prompt;
|
||||
const char* negative_prompt;
|
||||
const char* extra_ad_args;
|
||||
} sd_adetailer_params_t;
|
||||
|
||||
SD_API adetailer_ctx_t* new_adetailer_ctx(const char* detector_path,
|
||||
int n_threads,
|
||||
const char* backend,
|
||||
const char* params_backend);
|
||||
SD_API void free_adetailer_ctx(adetailer_ctx_t* adetailer_ctx);
|
||||
SD_API bool adetail_image(adetailer_ctx_t* adetailer_ctx,
|
||||
sd_ctx_t* sd_ctx,
|
||||
sd_image_t input_image,
|
||||
const sd_adetailer_params_t* adetailer_params,
|
||||
const sd_img_gen_params_t* inpaint_params,
|
||||
sd_image_t** images_out,
|
||||
int* num_images_out);
|
||||
|
||||
SD_API bool convert(const char* input_path,
|
||||
const char* vae_path,
|
||||
const char* output_path,
|
||||
@@ -479,6 +538,18 @@ SD_API bool convert(const char* input_path,
|
||||
const char* tensor_type_rules,
|
||||
bool convert_name);
|
||||
|
||||
SD_API bool convert_with_components(const char* model_path,
|
||||
const char* clip_l_path,
|
||||
const char* clip_g_path,
|
||||
const char* t5xxl_path,
|
||||
const char* diffusion_model_path,
|
||||
const char* vae_path,
|
||||
const char* output_path,
|
||||
enum sd_type_t output_type,
|
||||
const char* tensor_type_rules,
|
||||
bool convert_name,
|
||||
int n_threads);
|
||||
|
||||
SD_API bool preprocess_canny(sd_image_t image,
|
||||
float high_threshold,
|
||||
float low_threshold,
|
||||
@@ -486,9 +557,24 @@ SD_API bool preprocess_canny(sd_image_t image,
|
||||
float strong,
|
||||
bool inverse);
|
||||
|
||||
SD_API bool load_imatrix(const char* imatrix_path);
|
||||
SD_API void save_imatrix(const char* imatrix_path);
|
||||
SD_API void enable_imatrix_collection(void);
|
||||
SD_API void disable_imatrix_collection(void);
|
||||
|
||||
SD_API const char* sd_commit(void);
|
||||
SD_API const char* sd_version(void);
|
||||
|
||||
// List available ggml backend devices, one `name<TAB>description` per line.
|
||||
// The names are the device names accepted by the --backend / --params-backend
|
||||
// assignment specs. Returns the number of bytes required, excluding the null
|
||||
// terminator. Passing nullptr or buffer_size 0 only queries the required size.
|
||||
SD_API size_t sd_list_devices(char* buffer, size_t buffer_size);
|
||||
|
||||
// for C API, caller needs to call free_sd_images to free the memory after use
|
||||
// This helps avoid CRT problems on Windows when memory is allocated in the library but freed in the caller, which may use a different CRT.
|
||||
SD_API void free_sd_images(sd_image_t* result_images, int num_images);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
283
scripts/convert_fp8_scale_to_bf16.py
Normal file
@@ -0,0 +1,283 @@
|
||||
#!/usr/bin/env python
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import struct
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
from safetensors import safe_open
|
||||
|
||||
|
||||
FLOAT_DTYPES = {
|
||||
"BF16",
|
||||
"F16",
|
||||
"F32",
|
||||
"F64",
|
||||
"F8_E4M3",
|
||||
"F8_E4M3FN",
|
||||
"F8_E5M2",
|
||||
}
|
||||
|
||||
FP8_DTYPES = {
|
||||
"F8_E4M3",
|
||||
"F8_E4M3FN",
|
||||
"F8_E5M2",
|
||||
}
|
||||
|
||||
DTYPE_SIZES = {
|
||||
"BOOL": 1,
|
||||
"U8": 1,
|
||||
"I8": 1,
|
||||
"F8_E4M3": 1,
|
||||
"F8_E4M3FN": 1,
|
||||
"F8_E5M2": 1,
|
||||
"U16": 2,
|
||||
"I16": 2,
|
||||
"F16": 2,
|
||||
"BF16": 2,
|
||||
"U32": 4,
|
||||
"I32": 4,
|
||||
"F32": 4,
|
||||
"U64": 8,
|
||||
"I64": 8,
|
||||
"F64": 8,
|
||||
}
|
||||
|
||||
|
||||
def read_safetensors_header(path: Path):
|
||||
with path.open("rb") as f:
|
||||
header_len = struct.unpack("<Q", f.read(8))[0]
|
||||
header = f.read(header_len).decode("utf-8").rstrip()
|
||||
return json.loads(header)
|
||||
|
||||
|
||||
def numel(shape):
|
||||
return math.prod(shape) if shape else 1
|
||||
|
||||
|
||||
def scale_key_for_weight(name: str):
|
||||
if name.endswith(".weight"):
|
||||
return name[:-len(".weight")] + ".weight_scale"
|
||||
if name.endswith("weight"):
|
||||
return name + "_scale"
|
||||
return None
|
||||
|
||||
|
||||
def tensor_nbytes(dtype: str, shape):
|
||||
return numel(shape) * DTYPE_SIZES[dtype]
|
||||
|
||||
|
||||
def build_output_plan(header):
|
||||
entries = {k: v for k, v in header.items() if k != "__metadata__"}
|
||||
paired_scale_keys = set()
|
||||
plan = []
|
||||
|
||||
for name, info in entries.items():
|
||||
scale_key = scale_key_for_weight(name)
|
||||
if info["dtype"] in FP8_DTYPES and scale_key in entries:
|
||||
paired_scale_keys.add(scale_key)
|
||||
|
||||
for name, info in entries.items():
|
||||
if name in paired_scale_keys:
|
||||
continue
|
||||
|
||||
dtype = info["dtype"]
|
||||
shape = info["shape"]
|
||||
scale_key = scale_key_for_weight(name)
|
||||
|
||||
if dtype in FP8_DTYPES and scale_key in entries:
|
||||
scale_info = entries[scale_key]
|
||||
plan.append(
|
||||
{
|
||||
"name": name,
|
||||
"source_dtype": dtype,
|
||||
"output_dtype": "BF16",
|
||||
"shape": shape,
|
||||
"mode": "fp8_scaled_weight",
|
||||
"scale_key": scale_key,
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
if dtype in FLOAT_DTYPES:
|
||||
plan.append(
|
||||
{
|
||||
"name": name,
|
||||
"source_dtype": dtype,
|
||||
"output_dtype": "BF16",
|
||||
"shape": shape,
|
||||
"mode": "float_to_bf16",
|
||||
}
|
||||
)
|
||||
else:
|
||||
plan.append(
|
||||
{
|
||||
"name": name,
|
||||
"source_dtype": dtype,
|
||||
"output_dtype": dtype,
|
||||
"shape": shape,
|
||||
"mode": "copy",
|
||||
}
|
||||
)
|
||||
|
||||
metadata = dict(header.get("__metadata__", {}) or {})
|
||||
metadata["format"] = "pt"
|
||||
metadata["conversion"] = "fp8_weight_scale_to_bf16"
|
||||
|
||||
output_header = {"__metadata__": metadata}
|
||||
offset = 0
|
||||
for item in plan:
|
||||
size = tensor_nbytes(item["output_dtype"], item["shape"])
|
||||
output_header[item["name"]] = {
|
||||
"dtype": item["output_dtype"],
|
||||
"shape": item["shape"],
|
||||
"data_offsets": [offset, offset + size],
|
||||
}
|
||||
offset += size
|
||||
|
||||
return plan, output_header, offset
|
||||
|
||||
|
||||
def write_tensor_bytes(out, tensor):
|
||||
tensor = tensor.detach().cpu().contiguous()
|
||||
if tensor.numel() == 0:
|
||||
return
|
||||
if tensor.dtype == torch.bfloat16:
|
||||
tensor.view(torch.uint16).numpy().tofile(out)
|
||||
elif tensor.dtype in (getattr(torch, "float8_e4m3fn", None), getattr(torch, "float8_e5m2", None)):
|
||||
tensor.view(torch.uint8).numpy().tofile(out)
|
||||
else:
|
||||
tensor.numpy().tofile(out)
|
||||
|
||||
|
||||
def scale_view_for_chunk(scale, chunk, first_dim_start=0, first_dim_end=None):
|
||||
scale = scale.to(torch.float32)
|
||||
|
||||
if scale.numel() == 1:
|
||||
return scale.reshape((1,) * chunk.ndim)
|
||||
|
||||
if chunk.ndim > 0 and scale.ndim == 1:
|
||||
if first_dim_end is not None and scale.shape[0] >= first_dim_end:
|
||||
scale = scale[first_dim_start:first_dim_end]
|
||||
if scale.shape[0] == chunk.shape[0]:
|
||||
return scale.reshape((scale.shape[0],) + (1,) * (chunk.ndim - 1))
|
||||
|
||||
return scale
|
||||
|
||||
|
||||
def write_scaled_fp8_weight(out, weight, scale, chunk_rows):
|
||||
if weight.ndim == 0:
|
||||
result = weight.to(torch.float32) * scale_view_for_chunk(scale, weight)
|
||||
write_tensor_bytes(out, result.to(torch.bfloat16))
|
||||
return
|
||||
|
||||
rows = weight.shape[0]
|
||||
for start in range(0, rows, chunk_rows):
|
||||
end = min(start + chunk_rows, rows)
|
||||
chunk = weight[start:end].to(torch.float32)
|
||||
scale_view = scale_view_for_chunk(scale, chunk, start, end)
|
||||
result = chunk * scale_view
|
||||
write_tensor_bytes(out, result.to(torch.bfloat16))
|
||||
|
||||
|
||||
def write_float_as_bf16(out, tensor, chunk_rows):
|
||||
if tensor.dtype == torch.bfloat16:
|
||||
write_tensor_bytes(out, tensor)
|
||||
return
|
||||
|
||||
if tensor.ndim == 0:
|
||||
write_tensor_bytes(out, tensor.to(torch.bfloat16))
|
||||
return
|
||||
|
||||
rows = tensor.shape[0]
|
||||
for start in range(0, rows, chunk_rows):
|
||||
end = min(start + chunk_rows, rows)
|
||||
write_tensor_bytes(out, tensor[start:end].to(torch.bfloat16))
|
||||
|
||||
|
||||
def convert(input_path: Path, output_path: Path, chunk_rows: int, dry_run: bool):
|
||||
header = read_safetensors_header(input_path)
|
||||
plan, output_header, data_size = build_output_plan(header)
|
||||
|
||||
source_counts = Counter(item["source_dtype"] for item in plan)
|
||||
output_counts = Counter(item["output_dtype"] for item in plan)
|
||||
scaled_count = sum(item["mode"] == "fp8_scaled_weight" for item in plan)
|
||||
dropped_scales = sum(item["mode"] == "fp8_scaled_weight" for item in plan)
|
||||
header_bytes = json.dumps(output_header, separators=(",", ":")).encode("utf-8")
|
||||
expected_size = 8 + len(header_bytes) + data_size
|
||||
|
||||
print(f"input: {input_path}")
|
||||
print(f"output: {output_path}")
|
||||
print(f"tensors written: {len(plan)}")
|
||||
print(f"scaled fp8 weights dequantized: {scaled_count}")
|
||||
print(f"weight_scale tensors dropped: {dropped_scales}")
|
||||
print(f"source dtypes: {dict(sorted(source_counts.items()))}")
|
||||
print(f"output dtypes: {dict(sorted(output_counts.items()))}")
|
||||
print(f"expected output size: {expected_size / (1024 ** 3):.2f} GiB")
|
||||
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
if output_path.exists():
|
||||
raise FileExistsError(f"{output_path} already exists; pass --overwrite to replace it")
|
||||
|
||||
tmp_path = output_path.with_suffix(output_path.suffix + ".tmp")
|
||||
if tmp_path.exists():
|
||||
raise FileExistsError(f"{tmp_path} already exists; remove it or choose another output")
|
||||
|
||||
with safe_open(str(input_path), framework="pt", device="cpu") as sf, tmp_path.open("wb") as out:
|
||||
out.write(struct.pack("<Q", len(header_bytes)))
|
||||
out.write(header_bytes)
|
||||
|
||||
for index, item in enumerate(plan, 1):
|
||||
name = item["name"]
|
||||
print(f"[{index:04d}/{len(plan):04d}] {name} -> {item['output_dtype']}")
|
||||
|
||||
tensor = sf.get_tensor(name)
|
||||
if item["mode"] == "fp8_scaled_weight":
|
||||
scale = sf.get_tensor(item["scale_key"])
|
||||
write_scaled_fp8_weight(out, tensor, scale, chunk_rows)
|
||||
elif item["mode"] == "float_to_bf16":
|
||||
write_float_as_bf16(out, tensor, chunk_rows)
|
||||
else:
|
||||
write_tensor_bytes(out, tensor)
|
||||
|
||||
actual_size = out.tell()
|
||||
|
||||
if actual_size != expected_size:
|
||||
tmp_path.unlink(missing_ok=True)
|
||||
raise RuntimeError(f"wrote {actual_size} bytes, expected {expected_size} bytes")
|
||||
|
||||
tmp_path.replace(output_path)
|
||||
print("done")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert an fp8 safetensors checkpoint with weight_scale tensors to bf16."
|
||||
)
|
||||
parser.add_argument("--input", default="ideogram4_fp8.safetensors", type=Path)
|
||||
parser.add_argument("--output", default="ideogram4_bf16.safetensors", type=Path)
|
||||
parser.add_argument("--chunk-rows", default=1024, type=int)
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
parser.add_argument("--overwrite", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
input_path = args.input.resolve()
|
||||
output_path = args.output.resolve()
|
||||
|
||||
if args.chunk_rows < 1:
|
||||
raise ValueError("--chunk-rows must be >= 1")
|
||||
if not input_path.exists():
|
||||
raise FileNotFoundError(input_path)
|
||||
if args.overwrite and output_path.exists():
|
||||
output_path.unlink()
|
||||
|
||||
convert(input_path, output_path, args.chunk_rows, args.dry_run)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
112
scripts/convert_qwen3_vl.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert a Qwen3-VL HF safetensors checkpoint into a sd.cpp-loadable form.
|
||||
|
||||
The HF dump prefixes text-tower keys with ``model.language_model.`` and
|
||||
vision-tower keys with ``model.visual.``. sd.cpp expects ``model.<rest>`` for
|
||||
the text side; the vision side is converted by sd.cpp's own
|
||||
``convert_qwen3_vl_vision_name`` and is left as-is here.
|
||||
|
||||
Operates on raw safetensors bytes so any dtype (BF16/F16/F32) is preserved.
|
||||
|
||||
Usage:
|
||||
python3 scripts/convert_qwen3_vl.py <hf_qwen3_vl_dir_or_safetensors> <output.safetensors>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def rewrite_key(key: str) -> str:
|
||||
if key.startswith("model.language_model."):
|
||||
return "model." + key[len("model.language_model."):]
|
||||
return key
|
||||
|
||||
|
||||
def read_safetensors_header(path: str):
|
||||
with open(path, "rb") as f:
|
||||
hdr_len = struct.unpack("<Q", f.read(8))[0]
|
||||
hdr_bytes = f.read(hdr_len)
|
||||
return json.loads(hdr_bytes), 8 + hdr_len
|
||||
|
||||
|
||||
def collect_shard_paths(path: str):
|
||||
if os.path.isdir(path):
|
||||
index_path = os.path.join(path, "model.safetensors.index.json")
|
||||
if os.path.isfile(index_path):
|
||||
with open(index_path) as f:
|
||||
idx = json.load(f)
|
||||
return sorted({os.path.join(path, n) for n in idx["weight_map"].values()})
|
||||
single = os.path.join(path, "model.safetensors")
|
||||
if os.path.isfile(single):
|
||||
return [single]
|
||||
raise FileNotFoundError(f"No Qwen3-VL safetensors in {path}")
|
||||
if os.path.isfile(path):
|
||||
return [path]
|
||||
raise FileNotFoundError(path)
|
||||
|
||||
|
||||
def stage_tensors(input_path: str):
|
||||
entries = []
|
||||
for shard_path in collect_shard_paths(input_path):
|
||||
hdr, data_off = read_safetensors_header(shard_path)
|
||||
for key, info in hdr.items():
|
||||
if key == "__metadata__":
|
||||
continue
|
||||
entries.append((rewrite_key(key), shard_path, data_off, info))
|
||||
return entries
|
||||
|
||||
|
||||
def write_consolidated(out_path: str, entries):
|
||||
entries = sorted(entries, key=lambda e: e[0])
|
||||
|
||||
new_header = {}
|
||||
cur_offset = 0
|
||||
for new_key, shard_path, data_off, info in entries:
|
||||
start, end = info["data_offsets"]
|
||||
size = end - start
|
||||
new_header[new_key] = {
|
||||
"dtype": info["dtype"],
|
||||
"shape": info["shape"],
|
||||
"data_offsets": [cur_offset, cur_offset + size],
|
||||
}
|
||||
cur_offset += size
|
||||
|
||||
header_json = json.dumps(new_header, separators=(",", ":")).encode("utf-8")
|
||||
pad = (-len(header_json)) % 8
|
||||
header_json = header_json + (b" " * pad)
|
||||
|
||||
with open(out_path, "wb") as out:
|
||||
out.write(struct.pack("<Q", len(header_json)))
|
||||
out.write(header_json)
|
||||
for new_key, shard_path, data_off, info in entries:
|
||||
start, end = info["data_offsets"]
|
||||
with open(shard_path, "rb") as src:
|
||||
src.seek(data_off + start)
|
||||
remaining = end - start
|
||||
while remaining > 0:
|
||||
chunk = src.read(min(8 * 1024 * 1024, remaining))
|
||||
if not chunk:
|
||||
raise IOError(f"Truncated tensor in {shard_path}")
|
||||
out.write(chunk)
|
||||
remaining -= len(chunk)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("input", help="HF Qwen3-VL directory or single safetensors file")
|
||||
parser.add_argument("output", help="Output single safetensors path")
|
||||
args = parser.parse_args()
|
||||
|
||||
entries = stage_tensors(args.input)
|
||||
print(f"Tensors: {len(entries)}")
|
||||
print(f"Writing -> {args.output}")
|
||||
os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True)
|
||||
write_consolidated(args.output, entries)
|
||||
print(f"Done. Output size: {os.path.getsize(args.output) / 1e9:.2f} GB")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
279
scripts/convert_sefi.py
Normal file
@@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert a SeFi-Image diffusers checkpoint into a single sd.cpp-compatible safetensors.
|
||||
|
||||
Operates on raw safetensors bytes so any dtype (BF16, F32, ...) is preserved exactly.
|
||||
No numpy or torch dependency required.
|
||||
|
||||
Usage:
|
||||
python3 scripts/convert_sefi.py <sefi_diffusers_dir> <output.safetensors>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
_LINEAR_TO_LIN = re.compile(r"\.linear\.")
|
||||
_SHARED_MOD_PREFIXES = (
|
||||
"double_stream_modulation_img",
|
||||
"double_stream_modulation_txt",
|
||||
"single_stream_modulation",
|
||||
)
|
||||
|
||||
|
||||
def rewrite_transformer_key(key: str) -> str:
|
||||
if key.startswith("backbone."):
|
||||
key = key[len("backbone."):]
|
||||
elif key.startswith("dual_time_embed."):
|
||||
return key
|
||||
|
||||
if any(key.startswith(prefix + ".") for prefix in _SHARED_MOD_PREFIXES):
|
||||
key = _LINEAR_TO_LIN.sub(".lin.", key, count=1)
|
||||
|
||||
if key == "context_embedder.weight":
|
||||
return "txt_in.weight"
|
||||
if key == "context_embedder.bias":
|
||||
return "txt_in.bias"
|
||||
if key == "x_embedder.weight":
|
||||
return "img_in.weight"
|
||||
if key == "x_embedder.bias":
|
||||
return "img_in.bias"
|
||||
|
||||
if key == "proj_out.weight":
|
||||
return "final_layer.linear.weight"
|
||||
if key == "proj_out.bias":
|
||||
return "final_layer.linear.bias"
|
||||
if key == "norm_out.linear.weight":
|
||||
return "final_layer.adaLN_modulation.1.weight"
|
||||
if key == "norm_out.linear.bias":
|
||||
return "final_layer.adaLN_modulation.1.bias"
|
||||
|
||||
m = re.match(r"transformer_blocks\.(\d+)\.(.*)$", key)
|
||||
if m:
|
||||
return _rewrite_double_stream(m.group(1), m.group(2))
|
||||
m = re.match(r"single_transformer_blocks\.(\d+)\.(.*)$", key)
|
||||
if m:
|
||||
return _rewrite_single_stream(m.group(1), m.group(2))
|
||||
|
||||
return key
|
||||
|
||||
|
||||
def _rewrite_double_stream(idx: str, tail: str) -> str:
|
||||
dst = f"double_blocks.{idx}."
|
||||
mapping = {
|
||||
"norm1.linear.weight": "img_mod.lin.weight",
|
||||
"norm1_context.linear.weight": "txt_mod.lin.weight",
|
||||
"attn.norm_q.weight": "img_attn.norm.query_norm.scale",
|
||||
"attn.norm_k.weight": "img_attn.norm.key_norm.scale",
|
||||
"attn.norm_added_q.weight": "txt_attn.norm.query_norm.scale",
|
||||
"attn.norm_added_k.weight": "txt_attn.norm.key_norm.scale",
|
||||
"attn.to_out.0.weight": "img_attn.proj.weight",
|
||||
"attn.to_add_out.weight": "txt_attn.proj.weight",
|
||||
"ff.net.0.proj.weight": "img_mlp.0.weight",
|
||||
"ff.net.2.weight": "img_mlp.2.weight",
|
||||
"ff_context.net.0.proj.weight": "txt_mlp.0.weight",
|
||||
"ff_context.net.2.weight": "txt_mlp.2.weight",
|
||||
"ff.linear_in.weight": "img_mlp.0.weight",
|
||||
"ff.linear_out.weight": "img_mlp.2.weight",
|
||||
"ff_context.linear_in.weight": "txt_mlp.0.weight",
|
||||
"ff_context.linear_out.weight": "txt_mlp.2.weight",
|
||||
}
|
||||
return dst + mapping.get(tail, tail)
|
||||
|
||||
|
||||
# QKV triplets to fuse on output: source tails -> target fused tail.
|
||||
# Each tuple is (q_tail, k_tail, v_tail, fused_target_tail).
|
||||
QKV_DOUBLE_TRIPLETS = [
|
||||
("attn.to_q.weight", "attn.to_k.weight", "attn.to_v.weight", "img_attn.qkv.weight"),
|
||||
("attn.add_q_proj.weight", "attn.add_k_proj.weight", "attn.add_v_proj.weight", "txt_attn.qkv.weight"),
|
||||
]
|
||||
|
||||
|
||||
def _rewrite_single_stream(idx: str, tail: str) -> str:
|
||||
dst = f"single_blocks.{idx}."
|
||||
mapping = {
|
||||
"norm.linear.weight": "modulation.lin.weight",
|
||||
"attn.norm_q.weight": "norm.query_norm.scale",
|
||||
"attn.norm_k.weight": "norm.key_norm.scale",
|
||||
"attn.to_qkv_mlp_proj.weight": "linear1.weight",
|
||||
"attn.to_out.weight": "linear2.weight",
|
||||
}
|
||||
return dst + mapping.get(tail, tail)
|
||||
|
||||
|
||||
|
||||
|
||||
def read_safetensors_header(path: str):
|
||||
"""Return (header dict, data start byte offset)."""
|
||||
with open(path, "rb") as f:
|
||||
hdr_len = struct.unpack("<Q", f.read(8))[0]
|
||||
hdr_bytes = f.read(hdr_len)
|
||||
return json.loads(hdr_bytes), 8 + hdr_len
|
||||
|
||||
|
||||
def collect_shard_paths(directory: str, weight_pattern: str):
|
||||
index_path = os.path.join(directory, f"{weight_pattern}.safetensors.index.json")
|
||||
if os.path.isfile(index_path):
|
||||
with open(index_path) as f:
|
||||
idx = json.load(f)
|
||||
return sorted({os.path.join(directory, n) for n in idx["weight_map"].values()})
|
||||
single = os.path.join(directory, f"{weight_pattern}.safetensors")
|
||||
if not os.path.isfile(single):
|
||||
raise FileNotFoundError(f"No checkpoint at {directory}: missing {weight_pattern}")
|
||||
return [single]
|
||||
|
||||
|
||||
def stage_tensors_for_section(section_dir: str, rewrite_fn):
|
||||
"""Return a list of (new_key, shard_path, data_start_offset, info_dict) entries.
|
||||
|
||||
A "qkv_fuse" pseudo-entry with three source descriptors is emitted when a
|
||||
transformer_blocks.* split q/k/v triplet is found, so the writer can fuse
|
||||
them into a single output tensor.
|
||||
"""
|
||||
entries = []
|
||||
# First, index all raw keys per shard so we can detect qkv triplets.
|
||||
raw_by_block = {} # block_idx -> {tail: (key, shard_path, data_off, info)}
|
||||
raw_others = []
|
||||
for shard_path in collect_shard_paths(section_dir, "diffusion_pytorch_model"):
|
||||
hdr, data_off = read_safetensors_header(shard_path)
|
||||
for key, info in hdr.items():
|
||||
if key == "__metadata__":
|
||||
continue
|
||||
m = re.match(r"backbone\.transformer_blocks\.(\d+)\.(.*)$", key)
|
||||
if m and any(m.group(2) in trip[:3] for trip in QKV_DOUBLE_TRIPLETS):
|
||||
idx = m.group(1)
|
||||
raw_by_block.setdefault(idx, {})[m.group(2)] = (key, shard_path, data_off, info)
|
||||
else:
|
||||
raw_others.append((key, shard_path, data_off, info))
|
||||
|
||||
for key, shard_path, data_off, info in raw_others:
|
||||
new_key = rewrite_fn(key)
|
||||
# Swap the (scale, shift) halves to (shift, scale) at conversion time so
|
||||
# the on-disk weight matches BFL flux ordering and the runtime stays
|
||||
# version-agnostic. norm_out.linear weight shape is [2*dim, dim] and bias
|
||||
# is [2*dim]; both split along axis 0 (outermost == row-major outer).
|
||||
if new_key in ("final_layer.adaLN_modulation.1.weight",
|
||||
"final_layer.adaLN_modulation.1.bias"):
|
||||
info = dict(info)
|
||||
info["_chunk_swap_halves"] = True
|
||||
entries.append((new_key, shard_path, data_off, info))
|
||||
|
||||
for block_idx, tails in raw_by_block.items():
|
||||
for q_tail, k_tail, v_tail, fused_tail in QKV_DOUBLE_TRIPLETS:
|
||||
if q_tail in tails and k_tail in tails and v_tail in tails:
|
||||
q = tails[q_tail]; k = tails[k_tail]; v = tails[v_tail]
|
||||
# Validate shapes match.
|
||||
q_shape = q[3]["shape"]; k_shape = k[3]["shape"]; v_shape = v[3]["shape"]
|
||||
if q_shape != k_shape or q_shape != v_shape:
|
||||
raise ValueError(f"qkv shape mismatch at block {block_idx} {q_tail}: q={q_shape} k={k_shape} v={v_shape}")
|
||||
fused_shape = [q_shape[0] * 3] + list(q_shape[1:])
|
||||
fused_info = {
|
||||
"dtype": q[3]["dtype"],
|
||||
"shape": fused_shape,
|
||||
"_qkv_sources": [q, k, v], # pseudo field consumed by writer
|
||||
}
|
||||
entries.append((f"double_blocks.{block_idx}.{fused_tail}",
|
||||
None, None, fused_info))
|
||||
del tails[q_tail]; del tails[k_tail]; del tails[v_tail]
|
||||
# Anything left in tails was an unmatched single - pass through.
|
||||
for tail, payload in tails.items():
|
||||
entries.append((rewrite_fn(payload[0]),) + payload[1:])
|
||||
return entries
|
||||
|
||||
|
||||
_DTYPE_BYTES = {
|
||||
"BF16": 2, "F16": 2, "F32": 4, "F64": 8,
|
||||
"U8": 1, "I8": 1, "I16": 2, "I32": 4, "I64": 8,
|
||||
"BOOL": 1,
|
||||
}
|
||||
|
||||
|
||||
def _total_bytes(info: dict) -> int:
|
||||
if "_qkv_sources" in info:
|
||||
elems = 1
|
||||
for d in info["shape"]:
|
||||
elems *= d
|
||||
return elems * _DTYPE_BYTES[info["dtype"]]
|
||||
start, end = info["data_offsets"]
|
||||
return end - start
|
||||
|
||||
|
||||
def write_consolidated(out_path: str, entries):
|
||||
"""Write a single safetensors file by streaming raw bytes from each shard.
|
||||
|
||||
For qkv-fused entries, q/k/v are concatenated along axis 0 (row-major), so a
|
||||
simple byte-level concatenation produces the correct fused layout for any
|
||||
standard dtype.
|
||||
"""
|
||||
entries = sorted(entries, key=lambda e: e[0])
|
||||
|
||||
new_header = {}
|
||||
cur_offset = 0
|
||||
for new_key, shard_path, data_off, info in entries:
|
||||
size = _total_bytes(info)
|
||||
new_header[new_key] = {
|
||||
"dtype": info["dtype"],
|
||||
"shape": info["shape"],
|
||||
"data_offsets": [cur_offset, cur_offset + size],
|
||||
}
|
||||
cur_offset += size
|
||||
|
||||
header_json = json.dumps(new_header, separators=(",", ":")).encode("utf-8")
|
||||
pad = (-len(header_json)) % 8
|
||||
header_json = header_json + (b" " * pad)
|
||||
|
||||
def copy_range(src_path, src_data_off, src_info, out, byte_range=None):
|
||||
start, end = src_info["data_offsets"]
|
||||
if byte_range is not None:
|
||||
sub_start, sub_end = byte_range
|
||||
start, end = start + sub_start, start + sub_end
|
||||
with open(src_path, "rb") as src:
|
||||
src.seek(src_data_off + start)
|
||||
remaining = end - start
|
||||
while remaining > 0:
|
||||
chunk = src.read(min(8 * 1024 * 1024, remaining))
|
||||
if not chunk:
|
||||
raise IOError(f"Truncated tensor in {src_path}")
|
||||
out.write(chunk)
|
||||
remaining -= len(chunk)
|
||||
|
||||
with open(out_path, "wb") as out:
|
||||
out.write(struct.pack("<Q", len(header_json)))
|
||||
out.write(header_json)
|
||||
for new_key, shard_path, data_off, info in entries:
|
||||
if "_qkv_sources" in info:
|
||||
for q_entry in info["_qkv_sources"]:
|
||||
_, src_path, src_data_off, src_info = q_entry
|
||||
copy_range(src_path, src_data_off, src_info, out)
|
||||
elif info.get("_chunk_swap_halves"):
|
||||
size = _total_bytes(info)
|
||||
half = size // 2
|
||||
if size != half * 2:
|
||||
raise ValueError(f"{new_key}: odd byte size {size} cannot be split into halves")
|
||||
copy_range(shard_path, data_off, info, out, byte_range=(half, size))
|
||||
copy_range(shard_path, data_off, info, out, byte_range=(0, half))
|
||||
else:
|
||||
copy_range(shard_path, data_off, info, out)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("input_dir", help="SeFi diffusers checkpoint directory")
|
||||
parser.add_argument("output", help="Output transformer safetensors path (load via --diffusion-model)")
|
||||
args = parser.parse_args()
|
||||
|
||||
transformer_entries = stage_tensors_for_section(
|
||||
os.path.join(args.input_dir, "transformer"), rewrite_transformer_key)
|
||||
|
||||
print(f"Transformer tensors: {len(transformer_entries)}")
|
||||
print(f"Writing {len(transformer_entries)} tensors -> {args.output}")
|
||||
os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True)
|
||||
write_consolidated(args.output, transformer_entries)
|
||||
print(f"Done. Output size: {os.path.getsize(args.output) / 1e9:.2f} GB")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
86
scripts/convert_yolov8_to_safetensors.py
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert an Ultralytics YOLOv8 detection checkpoint for sd.cpp ADetailer."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert an Ultralytics YOLOv8 detection .pt checkpoint to safetensors."
|
||||
)
|
||||
parser.add_argument("input", type=Path, help="input YOLOv8 detection checkpoint")
|
||||
parser.add_argument("output", type=Path, help="output safetensors path")
|
||||
parser.add_argument(
|
||||
"--input-size", type=int, default=640, help="detector input size metadata (default: 640)"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
if args.input_size < 32 or args.input_size % 32 != 0:
|
||||
raise ValueError("--input-size must be a positive multiple of 32")
|
||||
if args.output.suffix.lower() != ".safetensors":
|
||||
raise ValueError("output path must use the .safetensors extension")
|
||||
|
||||
try:
|
||||
import torch
|
||||
from safetensors.torch import save_file
|
||||
from ultralytics import YOLO
|
||||
from ultralytics.nn.modules.head import Detect
|
||||
except ImportError as exc:
|
||||
raise SystemExit("conversion requires ultralytics, torch, and safetensors") from exc
|
||||
|
||||
torch_load = torch.load
|
||||
|
||||
def load_trusted_checkpoint(*load_args, **load_kwargs):
|
||||
load_kwargs.setdefault("weights_only", False)
|
||||
return torch_load(*load_args, **load_kwargs)
|
||||
|
||||
torch.load = load_trusted_checkpoint
|
||||
try:
|
||||
yolo = YOLO(str(args.input))
|
||||
finally:
|
||||
torch.load = torch_load
|
||||
network = yolo.model
|
||||
if not isinstance(network.model[-1], Detect) or network.model[-1].__class__.__name__ != "Detect":
|
||||
raise ValueError("only YOLOv8 detection checkpoints are supported; segmentation is not yet supported")
|
||||
|
||||
network.eval()
|
||||
network.fuse()
|
||||
state_dict = network.state_dict()
|
||||
required = {
|
||||
"model.0.conv.weight",
|
||||
"model.22.cv2.0.2.weight",
|
||||
"model.22.cv3.0.2.weight",
|
||||
}
|
||||
missing = sorted(required.difference(state_dict))
|
||||
if missing:
|
||||
raise ValueError(f"checkpoint does not match the supported YOLOv8 layout; missing {missing}")
|
||||
|
||||
tensors = {}
|
||||
for name, tensor in state_dict.items():
|
||||
if not name.startswith("model.") or ".bn." in name or name.endswith("dfl.conv.weight"):
|
||||
continue
|
||||
if not (name.endswith(".weight") or name.endswith(".bias")):
|
||||
continue
|
||||
dtype = torch.float16 if name.endswith(".weight") else torch.float32
|
||||
tensors[name] = tensor.detach().to(device="cpu", dtype=dtype).contiguous()
|
||||
|
||||
metadata = {
|
||||
"format": "pt",
|
||||
"yolov8.variant": "detect",
|
||||
"yolov8.input_size": str(args.input_size),
|
||||
"yolov8.num_classes": str(int(network.model[-1].nc)),
|
||||
"yolov8.reg_max": str(int(network.model[-1].reg_max)),
|
||||
"yolov8.names": json.dumps(yolo.names, ensure_ascii=False),
|
||||
}
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
save_file(tensors, str(args.output), metadata=metadata)
|
||||
print(f"wrote {args.output}: {len(tensors)} tensors")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
60
scripts/format-code.ps1
Normal file
@@ -0,0 +1,60 @@
|
||||
$patterns = @(
|
||||
"src/*.cpp"
|
||||
"src/*.h"
|
||||
"src/*.hpp"
|
||||
"src/conditioning/*.cpp"
|
||||
"src/conditioning/*.h"
|
||||
"src/conditioning/*.hpp"
|
||||
"src/core/*.cpp"
|
||||
"src/core/*.h"
|
||||
"src/core/*.hpp"
|
||||
"src/extensions/*.cpp"
|
||||
"src/extensions/*.h"
|
||||
"src/extensions/*.hpp"
|
||||
"src/runtime/*.cpp"
|
||||
"src/runtime/*.h"
|
||||
"src/runtime/*.hpp"
|
||||
"src/model/*/*.cpp"
|
||||
"src/model/*/*.h"
|
||||
"src/model/*/*.hpp"
|
||||
"src/tokenizers/*.h"
|
||||
"src/tokenizers/*.cpp"
|
||||
"src/tokenizers/vocab/*.h"
|
||||
"src/tokenizers/vocab/*.cpp"
|
||||
"src/model_io/*.h"
|
||||
"src/model_io/*.cpp"
|
||||
"examples/cli/*.cpp"
|
||||
"examples/cli/*.h"
|
||||
"examples/server/*.cpp"
|
||||
"examples/common/*.hpp"
|
||||
"examples/common/*.h"
|
||||
"examples/common/*.cpp"
|
||||
)
|
||||
|
||||
Push-Location (Join-Path $PSScriptRoot "..")
|
||||
|
||||
try {
|
||||
$root = (Get-Location).Path
|
||||
|
||||
foreach ($pattern in $patterns) {
|
||||
$files = Get-ChildItem -Path $pattern -File -ErrorAction SilentlyContinue | Sort-Object FullName
|
||||
|
||||
foreach ($file in $files) {
|
||||
$relativePath = $file.FullName.Substring($root.Length).TrimStart('\', '/') -replace '\\', '/'
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
24
scripts/format-code.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$repo_root"
|
||||
|
||||
for f in src/*.cpp src/*.h src/*.hpp \
|
||||
src/conditioning/*.cpp src/conditioning/*.h src/conditioning/*.hpp \
|
||||
src/core/*.cpp src/core/*.h src/core/*.hpp \
|
||||
src/extensions/*.cpp src/extensions/*.h src/extensions/*.hpp \
|
||||
src/runtime/*.cpp src/runtime/*.h src/runtime/*.hpp \
|
||||
src/model/*/*.cpp src/model/*/*.h src/model/*/*.hpp \
|
||||
src/tokenizers/*.h src/tokenizers/*.cpp src/tokenizers/vocab/*.h src/tokenizers/vocab/*.cpp \
|
||||
src/model_io/*.h src/model_io/*.cpp examples/cli/*.cpp examples/cli/*.h examples/server/*.cpp \
|
||||
examples/common/*.hpp examples/common/*.h examples/common/*.cpp; do
|
||||
[[ -e "$f" ]] || continue
|
||||
[[ "$f" == vocab* ]] && continue
|
||||
echo "formatting '$f'"
|
||||
# if [ "$f" != "stable-diffusion.h" ]; then
|
||||
# clang-tidy -fix -p build_linux/ "$f"
|
||||
# fi
|
||||
clang-format -style=file -i "$f"
|
||||
done
|
||||
134
scripts/pulid_extract_id.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
Precompute a PuLID-Flux identity embedding from a single source portrait.
|
||||
|
||||
Writes a gguf file (a single tensor `pulid_id`) that stable-diffusion.cpp's
|
||||
`--pulid-id-embedding` flag consumes.
|
||||
|
||||
Dependencies (recommended: vendor rather than pip-install due to upstream
|
||||
packaging quirks):
|
||||
- torch + safetensors
|
||||
- The ToTheBeginning/PuLID repository's `pulid/` package and `eva_clip/`.
|
||||
Put them on PYTHONPATH or sys.path before running this script.
|
||||
- insightface, facexlib, torchvision, opencv-python, huggingface_hub, gguf
|
||||
- numpy, Pillow
|
||||
|
||||
Usage:
|
||||
python scripts/pulid_extract_id.py \\
|
||||
--portrait /path/to/source-photo.jpg \\
|
||||
--pulid-weights /path/to/pulid_flux_v0.9.1.safetensors \\
|
||||
--out /path/to/source.pulidembd
|
||||
|
||||
The portrait must contain a clearly visible face. insightface's antelopev2
|
||||
detector will be auto-downloaded on first run.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
def extract(portrait_path: str, pulid_weights: str) -> "torch.Tensor":
|
||||
import numpy as np
|
||||
import torch
|
||||
from PIL import Image
|
||||
from pulid.pipeline_flux import PuLIDPipeline
|
||||
|
||||
if torch.cuda.is_available():
|
||||
device, onnx_provider = "cuda", "gpu"
|
||||
else:
|
||||
device, onnx_provider = "cpu", "cpu"
|
||||
|
||||
print(f"device={device}", flush=True)
|
||||
|
||||
# PuLIDPipeline only attaches pulid_ca attributes to `dit` during
|
||||
# construction; get_id_embedding() never runs Flux, so a dummy object is
|
||||
# enough and avoids importing/building a Flux skeleton.
|
||||
print("instantiating PuLIDPipeline with a dummy Flux object", flush=True)
|
||||
dit = SimpleNamespace()
|
||||
pulid = PuLIDPipeline(dit=dit,
|
||||
device=device,
|
||||
weight_dtype=torch.bfloat16,
|
||||
onnx_provider=onnx_provider)
|
||||
|
||||
print(f"loading PuLID weights from {pulid_weights}", flush=True)
|
||||
pulid.load_pretrain(pretrain_path=pulid_weights, version="v0.9.1")
|
||||
|
||||
print(f"extracting ID embedding from {portrait_path}", flush=True)
|
||||
face_img = np.array(Image.open(portrait_path).convert("RGB"))
|
||||
id_embedding, _ = pulid.get_id_embedding(face_img)
|
||||
print(f"id embedding shape={tuple(id_embedding.shape)} dtype={id_embedding.dtype}",
|
||||
flush=True)
|
||||
|
||||
if id_embedding.ndim == 3 and id_embedding.shape[0] == 1:
|
||||
id_embedding = id_embedding[0]
|
||||
return id_embedding
|
||||
|
||||
|
||||
def write_embd(tensor, out_path: str, dtype_choice: str) -> None:
|
||||
import gguf
|
||||
import torch
|
||||
|
||||
if tensor.ndim != 2:
|
||||
raise ValueError(f"expected (num_tokens, token_dim); got {tuple(tensor.shape)}")
|
||||
num_tokens, token_dim = tensor.shape
|
||||
|
||||
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
|
||||
|
||||
writer = gguf.GGUFWriter(out_path, arch="pulid")
|
||||
writer.add_uint32("pulid.version", 1)
|
||||
|
||||
if dtype_choice == "fp16":
|
||||
arr = tensor.to(torch.float16).contiguous().cpu().numpy()
|
||||
writer.add_tensor("pulid_id", arr)
|
||||
elif dtype_choice == "fp32":
|
||||
arr = tensor.to(torch.float32).contiguous().cpu().numpy()
|
||||
writer.add_tensor("pulid_id", arr)
|
||||
elif dtype_choice == "bf16":
|
||||
raw = tensor.to(torch.bfloat16).contiguous().view(torch.uint16).cpu().numpy()
|
||||
writer.add_tensor("pulid_id", raw,
|
||||
raw_shape=(int(num_tokens), int(token_dim)),
|
||||
raw_dtype=gguf.GGMLQuantizationType.BF16)
|
||||
else:
|
||||
raise ValueError(f"unknown --dtype {dtype_choice}")
|
||||
|
||||
writer.write_header_to_file()
|
||||
writer.write_kv_data_to_file()
|
||||
writer.write_tensors_to_file()
|
||||
writer.close()
|
||||
|
||||
print(f"wrote {out_path}: gguf, tensor pulid_id [{token_dim}, {num_tokens}] {dtype_choice}",
|
||||
flush=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--portrait", required=True,
|
||||
help="Path to the source portrait image (JPG/PNG).")
|
||||
ap.add_argument("--pulid-weights", required=True,
|
||||
help="Path to pulid_flux_v0.9.x.safetensors.")
|
||||
ap.add_argument("--out", required=True,
|
||||
help="Output path for the .pulidembd binary.")
|
||||
ap.add_argument("--dtype", default="fp16",
|
||||
choices=["fp16", "bf16", "fp32"],
|
||||
help="Storage dtype (default fp16; produces ~131 KB).")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not os.path.exists(args.portrait):
|
||||
print(f"ERROR: portrait not found at {args.portrait}", file=sys.stderr)
|
||||
return 2
|
||||
if not os.path.exists(args.pulid_weights):
|
||||
print(f"ERROR: PuLID weights not found at {args.pulid_weights}", file=sys.stderr)
|
||||
return 3
|
||||
|
||||
embedding = extract(args.portrait, args.pulid_weights)
|
||||
write_embd(embedding, args.out, args.dtype)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||