mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-06-25 07:36:38 +00:00
Compare commits
No commits in common. "22d9a8374b252a8181283519b8b820e93c4b2bd0" and "77380738d8801cb76e026ddbb92bf9d41ca38666" have entirely different histories.
22d9a8374b
...
77380738d8
15
.github/pull_request_template.md
vendored
15
.github/pull_request_template.md
vendored
@ -1,15 +0,0 @@
|
|||||||
## Summary
|
|
||||||
|
|
||||||
<!-- Describe what changed and why. Keep the PR focused on one clear change. -->
|
|
||||||
|
|
||||||
## Related Issue / Discussion
|
|
||||||
|
|
||||||
<!-- Link related issues, discussions, or previous PRs if applicable. -->
|
|
||||||
|
|
||||||
## Additional Information
|
|
||||||
|
|
||||||
<!-- Add verification notes, screenshots, sample output, or other context when applicable. -->
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
- [ ] I have read and confirmed this PR follows the [contribution guidelines](https://github.com/leejet/stable-diffusion.cpp/blob/master/CONTRIBUTING.md).
|
|
||||||
@ -13,9 +13,7 @@ if (MSVC)
|
|||||||
add_compile_definitions(_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
|
add_compile_definitions(_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
$<$<COMPILE_LANGUAGE:C>:/MP>
|
$<$<COMPILE_LANGUAGE:C>:/MP>
|
||||||
$<$<COMPILE_LANGUAGE:C>:/utf-8>
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:/MP>
|
$<$<COMPILE_LANGUAGE:CXX>:/MP>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:/utf-8>
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -71,12 +69,6 @@ option(SD_BUILD_SHARED_GGML_LIB "sd: build ggml as a separate shared lib" O
|
|||||||
option(SD_USE_SYSTEM_GGML "sd: use system-installed GGML library" OFF)
|
option(SD_USE_SYSTEM_GGML "sd: use system-installed GGML library" OFF)
|
||||||
#option(SD_BUILD_SERVER "sd: build server example" ON)
|
#option(SD_BUILD_SERVER "sd: build server example" ON)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
|
||||||
set(CMAKE_C_STANDARD_REQUIRED true)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
|
||||||
|
|
||||||
if(SD_CUDA)
|
if(SD_CUDA)
|
||||||
message("-- Use CUDA as backend stable-diffusion")
|
message("-- Use CUDA as backend stable-diffusion")
|
||||||
set(GGML_CUDA ON)
|
set(GGML_CUDA ON)
|
||||||
@ -114,8 +106,7 @@ if(SD_WEBP)
|
|||||||
"Or link against system library:\n cmake (...) -DSD_USE_SYSTEM_WEBP=ON")
|
"Or link against system library:\n cmake (...) -DSD_USE_SYSTEM_WEBP=ON")
|
||||||
endif()
|
endif()
|
||||||
if(SD_USE_SYSTEM_WEBP)
|
if(SD_USE_SYSTEM_WEBP)
|
||||||
find_package(WebP)
|
find_package(WebP REQUIRED)
|
||||||
if(WebP_FOUND)
|
|
||||||
add_library(webp ALIAS WebP::webp)
|
add_library(webp ALIAS WebP::webp)
|
||||||
# libwebp CMake target naming is not consistent across versions/distros.
|
# libwebp CMake target naming is not consistent across versions/distros.
|
||||||
# Some export WebP::libwebpmux, others export WebP::webpmux.
|
# Some export WebP::libwebpmux, others export WebP::webpmux.
|
||||||
@ -129,14 +120,6 @@ if(SD_WEBP)
|
|||||||
"Expected WebP::libwebpmux or WebP::webpmux."
|
"Expected WebP::libwebpmux or WebP::webpmux."
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(WebP REQUIRED IMPORTED_TARGET GLOBAL libwebp)
|
|
||||||
pkg_check_modules(WebPMux REQUIRED IMPORTED_TARGET GLOBAL libwebpmux)
|
|
||||||
link_libraries(PkgConfig::WebP)
|
|
||||||
link_libraries(PkgConfig::WebPMux)
|
|
||||||
add_library(libwebpmux ALIAS PkgConfig::WebPMux)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -150,13 +133,6 @@ if(SD_WEBM)
|
|||||||
"Or link against system library:\n cmake (...) -DSD_USE_SYSTEM_WEBM=ON")
|
"Or link against system library:\n cmake (...) -DSD_USE_SYSTEM_WEBM=ON")
|
||||||
endif()
|
endif()
|
||||||
if(SD_USE_SYSTEM_WEBM)
|
if(SD_USE_SYSTEM_WEBM)
|
||||||
find_package(PkgConfig)
|
|
||||||
if(PkgConfig_FOUND)
|
|
||||||
pkg_check_modules(WebM REQUIRED IMPORTED_TARGET GLOBAL libwebm)
|
|
||||||
endif()
|
|
||||||
if(PkgConfig_FOUND AND WebM_FOUND)
|
|
||||||
link_libraries(PkgConfig::WebM)
|
|
||||||
else()
|
|
||||||
find_path(WEBM_INCLUDE_DIR
|
find_path(WEBM_INCLUDE_DIR
|
||||||
NAMES mkvmuxer/mkvmuxer.h mkvparser/mkvparser.h common/webmids.h
|
NAMES mkvmuxer/mkvmuxer.h mkvparser/mkvparser.h common/webmids.h
|
||||||
PATH_SUFFIXES webm
|
PATH_SUFFIXES webm
|
||||||
@ -171,7 +147,6 @@ if(SD_WEBM)
|
|||||||
INTERFACE_INCLUDE_DIRECTORIES "${WEBM_INCLUDE_DIR}")
|
INTERFACE_INCLUDE_DIRECTORIES "${WEBM_INCLUDE_DIR}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
|
||||||
|
|
||||||
set(SD_LIB stable-diffusion)
|
set(SD_LIB stable-diffusion)
|
||||||
|
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
This document collects general contribution conventions for this repository.
|
|
||||||
|
|
||||||
## Before You Start
|
|
||||||
|
|
||||||
Before opening a PR, please search existing PRs to avoid duplicating ongoing work.
|
|
||||||
|
|
||||||
For large-scale refactors or changes with broad impact, please open an issue first to discuss the approach before submitting a PR.
|
|
||||||
|
|
||||||
If you want to update a third-party dependency, please open an issue first instead of submitting a direct PR. See [Dependency Updates](#dependency-updates) for details.
|
|
||||||
|
|
||||||
## Pull Requests
|
|
||||||
|
|
||||||
Keep each PR focused on one clear change. Large or overly complex PRs are harder to review and may not be merged.
|
|
||||||
|
|
||||||
Follow Conventional Commit-style subjects seen in history: `feat:`, `fix:`, `refactor:`, `ci:`, `docs:`, `chore:`. Keep subjects imperative and scoped.
|
|
||||||
|
|
||||||
PRs should include:
|
|
||||||
|
|
||||||
- What changed and why (short problem/solution summary).
|
|
||||||
- Verification evidence when applicable (commands and key outputs).
|
|
||||||
- Linked issue/PR context when applicable.
|
|
||||||
- Screenshots or sample outputs for UI/visual behavior changes.
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Naming conventions:
|
|
||||||
|
|
||||||
- Use `PascalCase` for class/struct/type names.
|
|
||||||
- In `PascalCase` names, preserve common abbreviations in uppercase, for example `SD`, `API`, `HTTP`, `JSON`, `RGB`, `VAE`, `TAE`, `LoRA`, and `WebP`.
|
|
||||||
- Use `snake_case` for functions, methods, variables, and file names unless an existing API requires a different style.
|
|
||||||
- Use a trailing underscore for private data member names, for example `hidden_size_` or `tokenizer_`.
|
|
||||||
- Use `.h` for C and C++ header files. Do not introduce new `.hpp` headers.
|
|
||||||
- Use macro-based header include guards instead of `#pragma once`.
|
|
||||||
- Format header include guards as `__SD_{PATH}__`, where `{PATH}` is the header path in uppercase snake case without the file extension. For example, `src/sample.h` should use `__SD_SAMPLE_H__`.
|
|
||||||
- Do not introduce anonymous namespaces in new or modified code; prefer `static` file-local functions/variables or an explicit named namespace when scoping is needed.
|
|
||||||
- In `class`/`struct` definitions, place data members before member functions unless an existing type already clearly follows a different pattern.
|
|
||||||
- Keep `test_*.cpp` / `test_*.py` naming for tests.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## AI-Assisted Contributions
|
|
||||||
|
|
||||||
AI tools may be used to assist development, but contributors are responsible for the quality and correctness of the submitted code.
|
|
||||||
|
|
||||||
If any part of a contribution was generated with AI assistance, the contributor must perform a thorough human review before submitting the PR and understand every changed line.
|
|
||||||
|
|
||||||
Do not list AI tools as co-authors. The human contributor is the sole responsible author of the submitted code.
|
|
||||||
|
|
||||||
Please do not submit AI-generated code that you do not understand, and do not include meaningless experiments, temporary test code, or unrelated generated output in a PR.
|
|
||||||
|
|
||||||
## Dependency Updates
|
|
||||||
|
|
||||||
Do not submit PRs that update `ggml`. `ggml` updates are performed only after local validation by the maintainer.
|
|
||||||
|
|
||||||
Other third-party dependencies are not updated unless necessary. If you want to update a dependency, please open an issue first instead of submitting a direct PR.
|
|
||||||
|
|
||||||
## Security & Configuration
|
|
||||||
|
|
||||||
Do not commit model weights, secrets, or local absolute paths. Keep large binaries out of git unless intentionally tracked release assets.
|
|
||||||
@ -58,7 +58,6 @@ API and command-line option may change frequently.***
|
|||||||
- [Ovis-Image](./docs/ovis_image.md)
|
- [Ovis-Image](./docs/ovis_image.md)
|
||||||
- [Anima](./docs/anima.md)
|
- [Anima](./docs/anima.md)
|
||||||
- [ERNIE-Image](./docs/ernie_image.md)
|
- [ERNIE-Image](./docs/ernie_image.md)
|
||||||
- [HiDream-O1-Image](./docs/hidream_o1_image.md)
|
|
||||||
- Image Edit Models
|
- Image Edit Models
|
||||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||||
- [Qwen Image Edit series](./docs/qwen_image_edit.md)
|
- [Qwen Image Edit series](./docs/qwen_image_edit.md)
|
||||||
@ -149,7 +148,6 @@ If you want to improve performance or reduce VRAM/RAM usage, please refer to [pe
|
|||||||
- [Ovis-Image](./docs/ovis_image.md)
|
- [Ovis-Image](./docs/ovis_image.md)
|
||||||
- [Anima](./docs/anima.md)
|
- [Anima](./docs/anima.md)
|
||||||
- [ERNIE-Image](./docs/ernie_image.md)
|
- [ERNIE-Image](./docs/ernie_image.md)
|
||||||
- [HiDream-O1-Image](./docs/hidream_o1_image.md)
|
|
||||||
- [LoRA](./docs/lora.md)
|
- [LoRA](./docs/lora.md)
|
||||||
- [LCM/LCM-LoRA](./docs/lcm.md)
|
- [LCM/LCM-LoRA](./docs/lcm.md)
|
||||||
- [Using PhotoMaker to personalize image generation](./docs/photo_maker.md)
|
- [Using PhotoMaker to personalize image generation](./docs/photo_maker.md)
|
||||||
@ -165,7 +163,6 @@ These projects wrap `stable-diffusion.cpp` for easier use in other languages/fra
|
|||||||
|
|
||||||
* Golang (non-cgo): [seasonjs/stable-diffusion](https://github.com/seasonjs/stable-diffusion)
|
* Golang (non-cgo): [seasonjs/stable-diffusion](https://github.com/seasonjs/stable-diffusion)
|
||||||
* Golang (cgo): [Binozo/GoStableDiffusion](https://github.com/Binozo/GoStableDiffusion)
|
* Golang (cgo): [Binozo/GoStableDiffusion](https://github.com/Binozo/GoStableDiffusion)
|
||||||
* Golang (non-cgo): [l8bloom/gosd](https://github.com/l8bloom/gosd)
|
|
||||||
* C#: [DarthAffe/StableDiffusion.NET](https://github.com/DarthAffe/StableDiffusion.NET)
|
* C#: [DarthAffe/StableDiffusion.NET](https://github.com/DarthAffe/StableDiffusion.NET)
|
||||||
* Python: [william-murray1204/stable-diffusion-cpp-python](https://github.com/william-murray1204/stable-diffusion-cpp-python)
|
* Python: [william-murray1204/stable-diffusion-cpp-python](https://github.com/william-murray1204/stable-diffusion-cpp-python)
|
||||||
* Rust: [newfla/diffusion-rs](https://github.com/newfla/diffusion-rs)
|
* Rust: [newfla/diffusion-rs](https://github.com/newfla/diffusion-rs)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 MiB |
@ -1,20 +0,0 @@
|
|||||||
# How to Use
|
|
||||||
|
|
||||||
## Download weights
|
|
||||||
|
|
||||||
- Download HiDream-O1-Image-Dev
|
|
||||||
- safetensors: https://huggingface.co/Comfy-Org/HiDream-O1-Image/tree/main/checkpoints
|
|
||||||
- Download HiDream-O1-Image
|
|
||||||
- safetensors: https://huggingface.co/Comfy-Org/HiDream-O1-Image/tree/main/checkpoints
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### 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
|
|
||||||
'hidream o1 cpp'" --cfg-scale 1.0 -v -H 1024 -W 1024
|
|
||||||
```
|
|
||||||
|
|
||||||
<img width="256" alt="HiDream-O1-Image-Dev example" src="../assets/hidream-o1/dev_example.png" />
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ Context Options:
|
|||||||
then threads will be set to the number of CPU physical cores
|
then threads will be set to the number of CPU physical cores
|
||||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
--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
|
--max-vram <float> maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables
|
||||||
graph splitting; -1 auto-detects free VRAM minus 1 GiB
|
graph splitting
|
||||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
--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
|
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM
|
||||||
when needed
|
when needed
|
||||||
@ -103,8 +103,6 @@ Generation Options:
|
|||||||
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
||||||
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
||||||
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
||||||
--extra-sample-args <string> extra sampler args, key=value list. Currently lcm supports noise_clip_std,
|
|
||||||
noise_scale_start, noise_scale_end
|
|
||||||
-H, --height <int> image height, in pixel space (default: 512)
|
-H, --height <int> image height, in pixel space (default: 512)
|
||||||
-W, --width <int> image width, in pixel space (default: 512)
|
-W, --width <int> image width, in pixel space (default: 512)
|
||||||
--steps <int> number of sample steps (default: 20)
|
--steps <int> number of sample steps (default: 20)
|
||||||
@ -165,10 +163,10 @@ Generation Options:
|
|||||||
-s, --seed RNG seed (default: 42, use random seed for < 0)
|
-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,
|
--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,
|
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)
|
er_sde] (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,
|
--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,
|
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
|
res_2s, er_sde] default: euler for Flux/SD3/Wan, euler_a otherwise
|
||||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
||||||
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent], default:
|
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent], default:
|
||||||
discrete
|
discrete
|
||||||
|
|||||||
@ -405,7 +405,7 @@ ArgOptions SDContextParams::get_options() {
|
|||||||
options.float_options = {
|
options.float_options = {
|
||||||
{"",
|
{"",
|
||||||
"--max-vram",
|
"--max-vram",
|
||||||
"maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables graph splitting; -1 auto-detects free VRAM minus 1 GiB",
|
"maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables graph splitting",
|
||||||
&max_vram},
|
&max_vram},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -819,10 +819,6 @@ ArgOptions SDGenerationParams::get_options() {
|
|||||||
"Latent (antialiased), Latent (bicubic), Latent (bicubic antialiased), or a model name "
|
"Latent (antialiased), Latent (bicubic), Latent (bicubic antialiased), or a model name "
|
||||||
"under --hires-upscalers-dir (default: Latent)",
|
"under --hires-upscalers-dir (default: Latent)",
|
||||||
&hires_upscaler},
|
&hires_upscaler},
|
||||||
{"",
|
|
||||||
"--extra-sample-args",
|
|
||||||
"extra sampler args, key=value list. Currently lcm supports noise_clip_std, noise_scale_start, noise_scale_end",
|
|
||||||
&extra_sample_args},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.int_options = {
|
options.int_options = {
|
||||||
@ -1265,12 +1261,12 @@ ArgOptions SDGenerationParams::get_options() {
|
|||||||
on_seed_arg},
|
on_seed_arg},
|
||||||
{"",
|
{"",
|
||||||
"--sampling-method",
|
"--sampling-method",
|
||||||
"sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]"
|
"sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde] "
|
||||||
"(default: euler for Flux/SD3/Wan, euler_a otherwise)",
|
"(default: euler for Flux/SD3/Wan, euler_a otherwise)",
|
||||||
on_sample_method_arg},
|
on_sample_method_arg},
|
||||||
{"",
|
{"",
|
||||||
"--high-noise-sampling-method",
|
"--high-noise-sampling-method",
|
||||||
"(high noise) sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde, euler_cfg_pp, euler_a_cfg_pp]"
|
"(high noise) sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd, res_multistep, res_2s, er_sde]"
|
||||||
" default: euler for Flux/SD3/Wan, euler_a otherwise",
|
" default: euler for Flux/SD3/Wan, euler_a otherwise",
|
||||||
on_high_noise_sample_method_arg},
|
on_high_noise_sample_method_arg},
|
||||||
{"",
|
{"",
|
||||||
@ -1628,7 +1624,6 @@ bool SDGenerationParams::from_json_str(
|
|||||||
|
|
||||||
auto parse_sample_params_json = [&](const json& sample_json,
|
auto parse_sample_params_json = [&](const json& sample_json,
|
||||||
sd_sample_params_t& target_params,
|
sd_sample_params_t& target_params,
|
||||||
std::string& target_extra_sample_args,
|
|
||||||
std::vector<int>& target_skip_layers,
|
std::vector<int>& target_skip_layers,
|
||||||
std::vector<float>* target_custom_sigmas) {
|
std::vector<float>* target_custom_sigmas) {
|
||||||
if (sample_json.contains("sample_steps") && sample_json["sample_steps"].is_number_integer()) {
|
if (sample_json.contains("sample_steps") && sample_json["sample_steps"].is_number_integer()) {
|
||||||
@ -1643,9 +1638,6 @@ bool SDGenerationParams::from_json_str(
|
|||||||
if (sample_json.contains("flow_shift") && sample_json["flow_shift"].is_number()) {
|
if (sample_json.contains("flow_shift") && sample_json["flow_shift"].is_number()) {
|
||||||
target_params.flow_shift = sample_json["flow_shift"];
|
target_params.flow_shift = sample_json["flow_shift"];
|
||||||
}
|
}
|
||||||
if (sample_json.contains("extra_sample_args") && sample_json["extra_sample_args"].is_string()) {
|
|
||||||
target_extra_sample_args = sample_json["extra_sample_args"].get<std::string>();
|
|
||||||
}
|
|
||||||
if (target_custom_sigmas != nullptr &&
|
if (target_custom_sigmas != nullptr &&
|
||||||
sample_json.contains("custom_sigmas") &&
|
sample_json.contains("custom_sigmas") &&
|
||||||
sample_json["custom_sigmas"].is_array()) {
|
sample_json["custom_sigmas"].is_array()) {
|
||||||
@ -1693,12 +1685,11 @@ bool SDGenerationParams::from_json_str(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (j.contains("sample_params") && j["sample_params"].is_object()) {
|
if (j.contains("sample_params") && j["sample_params"].is_object()) {
|
||||||
parse_sample_params_json(j["sample_params"], sample_params, extra_sample_args, skip_layers, &custom_sigmas);
|
parse_sample_params_json(j["sample_params"], sample_params, skip_layers, &custom_sigmas);
|
||||||
}
|
}
|
||||||
if (j.contains("high_noise_sample_params") && j["high_noise_sample_params"].is_object()) {
|
if (j.contains("high_noise_sample_params") && j["high_noise_sample_params"].is_object()) {
|
||||||
parse_sample_params_json(j["high_noise_sample_params"],
|
parse_sample_params_json(j["high_noise_sample_params"],
|
||||||
high_noise_sample_params,
|
high_noise_sample_params,
|
||||||
high_noise_extra_sample_args,
|
|
||||||
high_noise_skip_layers,
|
high_noise_skip_layers,
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
@ -2128,8 +2119,6 @@ sd_img_gen_params_t SDGenerationParams::to_sd_img_gen_params_t() {
|
|||||||
high_noise_sample_params.guidance.slg.layer_count = high_noise_skip_layers.size();
|
high_noise_sample_params.guidance.slg.layer_count = high_noise_skip_layers.size();
|
||||||
sample_params.custom_sigmas = custom_sigmas.empty() ? nullptr : custom_sigmas.data();
|
sample_params.custom_sigmas = custom_sigmas.empty() ? nullptr : custom_sigmas.data();
|
||||||
sample_params.custom_sigmas_count = static_cast<int>(custom_sigmas.size());
|
sample_params.custom_sigmas_count = static_cast<int>(custom_sigmas.size());
|
||||||
sample_params.extra_sample_args = extra_sample_args.empty() ? nullptr : extra_sample_args.c_str();
|
|
||||||
high_noise_sample_params.extra_sample_args = high_noise_extra_sample_args.empty() ? nullptr : high_noise_extra_sample_args.c_str();
|
|
||||||
cache_params.scm_mask = scm_mask.empty() ? nullptr : scm_mask.c_str();
|
cache_params.scm_mask = scm_mask.empty() ? nullptr : scm_mask.c_str();
|
||||||
|
|
||||||
sd_pm_params_t pm_params = {
|
sd_pm_params_t pm_params = {
|
||||||
@ -2199,8 +2188,6 @@ sd_vid_gen_params_t SDGenerationParams::to_sd_vid_gen_params_t() {
|
|||||||
high_noise_sample_params.guidance.slg.layer_count = high_noise_skip_layers.size();
|
high_noise_sample_params.guidance.slg.layer_count = high_noise_skip_layers.size();
|
||||||
sample_params.custom_sigmas = custom_sigmas.empty() ? nullptr : custom_sigmas.data();
|
sample_params.custom_sigmas = custom_sigmas.empty() ? nullptr : custom_sigmas.data();
|
||||||
sample_params.custom_sigmas_count = static_cast<int>(custom_sigmas.size());
|
sample_params.custom_sigmas_count = static_cast<int>(custom_sigmas.size());
|
||||||
sample_params.extra_sample_args = extra_sample_args.empty() ? nullptr : extra_sample_args.c_str();
|
|
||||||
high_noise_sample_params.extra_sample_args = high_noise_extra_sample_args.empty() ? nullptr : high_noise_extra_sample_args.c_str();
|
|
||||||
cache_params.scm_mask = scm_mask.empty() ? nullptr : scm_mask.c_str();
|
cache_params.scm_mask = scm_mask.empty() ? nullptr : scm_mask.c_str();
|
||||||
|
|
||||||
params.loras = lora_vec.empty() ? nullptr : lora_vec.data();
|
params.loras = lora_vec.empty() ? nullptr : lora_vec.data();
|
||||||
@ -2341,7 +2328,6 @@ static json build_sampling_metadata_json(const sd_sample_params_t& sample_params
|
|||||||
{"eta", sample_params.eta},
|
{"eta", sample_params.eta},
|
||||||
{"shifted_timestep", sample_params.shifted_timestep},
|
{"shifted_timestep", sample_params.shifted_timestep},
|
||||||
{"flow_shift", sample_params.flow_shift},
|
{"flow_shift", sample_params.flow_shift},
|
||||||
{"extra_sample_args", safe_json_string(sample_params.extra_sample_args)},
|
|
||||||
{"guidance",
|
{"guidance",
|
||||||
{
|
{
|
||||||
{"txt_cfg", sample_params.guidance.txt_cfg},
|
{"txt_cfg", sample_params.guidance.txt_cfg},
|
||||||
@ -2533,9 +2519,6 @@ std::string get_image_params(const SDContextParams& ctx_params,
|
|||||||
}
|
}
|
||||||
parameter_string += "Guidance: " + std::to_string(gen_params.sample_params.guidance.distilled_guidance) + ", ";
|
parameter_string += "Guidance: " + std::to_string(gen_params.sample_params.guidance.distilled_guidance) + ", ";
|
||||||
parameter_string += "Eta: " + std::to_string(gen_params.sample_params.eta) + ", ";
|
parameter_string += "Eta: " + std::to_string(gen_params.sample_params.eta) + ", ";
|
||||||
if (!gen_params.extra_sample_args.empty()) {
|
|
||||||
parameter_string += "Extra sample args: " + gen_params.extra_sample_args + ", ";
|
|
||||||
}
|
|
||||||
parameter_string += "Seed: " + std::to_string(seed) + ", ";
|
parameter_string += "Seed: " + std::to_string(seed) + ", ";
|
||||||
parameter_string += "Size: " + std::to_string(gen_params.get_resolved_width()) + "x" + std::to_string(gen_params.get_resolved_height()) + ", ";
|
parameter_string += "Size: " + std::to_string(gen_params.get_resolved_width()) + "x" + std::to_string(gen_params.get_resolved_height()) + ", ";
|
||||||
parameter_string += "Model: " + sd_basename(ctx_params.model_path) + ", ";
|
parameter_string += "Model: " + sd_basename(ctx_params.model_path) + ", ";
|
||||||
|
|||||||
@ -170,8 +170,6 @@ struct SDGenerationParams {
|
|||||||
|
|
||||||
sd_sample_params_t sample_params;
|
sd_sample_params_t sample_params;
|
||||||
sd_sample_params_t high_noise_sample_params;
|
sd_sample_params_t high_noise_sample_params;
|
||||||
std::string extra_sample_args;
|
|
||||||
std::string high_noise_extra_sample_args;
|
|
||||||
std::vector<int> skip_layers = {7, 8, 9};
|
std::vector<int> skip_layers = {7, 8, 9};
|
||||||
std::vector<int> high_noise_skip_layers = {7, 8, 9};
|
std::vector<int> high_noise_skip_layers = {7, 8, 9};
|
||||||
|
|
||||||
|
|||||||
@ -157,7 +157,7 @@ Context Options:
|
|||||||
then threads will be set to the number of CPU physical cores
|
then threads will be set to the number of CPU physical cores
|
||||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
--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
|
--max-vram <float> maximum VRAM budget in GiB for graph-cut segmented execution. 0 disables
|
||||||
graph splitting; -1 auto-detects free VRAM minus 1 GiB
|
graph splitting
|
||||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
--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
|
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM
|
||||||
when needed
|
when needed
|
||||||
@ -205,8 +205,6 @@ Default Generation Options:
|
|||||||
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
--hires-upscaler <string> highres fix upscaler, Lanczos, Nearest, Latent, Latent (nearest), Latent
|
||||||
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
(nearest-exact), Latent (antialiased), Latent (bicubic), Latent (bicubic
|
||||||
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
antialiased), or a model name under --hires-upscalers-dir (default: Latent)
|
||||||
--extra-sample-args <string> extra sampler args, key=value list. Currently lcm supports noise_clip_std,
|
|
||||||
noise_scale_start, noise_scale_end
|
|
||||||
-H, --height <int> image height, in pixel space (default: 512)
|
-H, --height <int> image height, in pixel space (default: 512)
|
||||||
-W, --width <int> image width, in pixel space (default: 512)
|
-W, --width <int> image width, in pixel space (default: 512)
|
||||||
--steps <int> number of sample steps (default: 20)
|
--steps <int> number of sample steps (default: 20)
|
||||||
@ -266,10 +264,10 @@ Default Generation Options:
|
|||||||
-s, --seed RNG seed (default: 42, use random seed for < 0)
|
-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,
|
--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,
|
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)
|
er_sde] (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,
|
--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,
|
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
|
res_2s, er_sde] default: euler for Flux/SD3/Wan, euler_a otherwise
|
||||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits,
|
||||||
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent], default:
|
smoothstep, sgm_uniform, simple, kl_optimal, lcm, bong_tangent], default:
|
||||||
discrete
|
discrete
|
||||||
|
|||||||
@ -145,7 +145,7 @@ int main(int argc, const char** argv) {
|
|||||||
register_sdapi_endpoints(svr, runtime);
|
register_sdapi_endpoints(svr, runtime);
|
||||||
register_sdcpp_api_endpoints(svr, runtime);
|
register_sdcpp_api_endpoints(svr, runtime);
|
||||||
|
|
||||||
LOG_INFO("listening on: http://%s:%d\n", svr_params.listen_ip.c_str(), svr_params.listen_port);
|
LOG_INFO("listening on: %s:%d\n", svr_params.listen_ip.c_str(), svr_params.listen_port);
|
||||||
svr.listen(svr_params.listen_ip, svr_params.listen_port);
|
svr.listen(svr_params.listen_ip, svr_params.listen_port);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -67,10 +67,6 @@ static enum sample_method_t get_sdapi_sample_method(std::string name) {
|
|||||||
{"k_res_multistep", RES_MULTISTEP_SAMPLE_METHOD},
|
{"k_res_multistep", RES_MULTISTEP_SAMPLE_METHOD},
|
||||||
{"res 2s", RES_2S_SAMPLE_METHOD},
|
{"res 2s", RES_2S_SAMPLE_METHOD},
|
||||||
{"k_res_2s", RES_2S_SAMPLE_METHOD},
|
{"k_res_2s", RES_2S_SAMPLE_METHOD},
|
||||||
{"euler_cfg_pp", EULER_CFG_PP_SAMPLE_METHOD},
|
|
||||||
{"k_euler_cfg_pp", EULER_CFG_PP_SAMPLE_METHOD},
|
|
||||||
{"euler_a_cfg_pp", EULER_CFG_PP_SAMPLE_METHOD},
|
|
||||||
{"k_euler_a_cfg_pp", EULER_CFG_PP_SAMPLE_METHOD},
|
|
||||||
};
|
};
|
||||||
auto it = hardcoded.find(name);
|
auto it = hardcoded.find(name);
|
||||||
return it != hardcoded.end() ? it->second : SAMPLE_METHOD_COUNT;
|
return it != hardcoded.end() ? it->second : SAMPLE_METHOD_COUNT;
|
||||||
|
|||||||
@ -51,8 +51,6 @@ enum sample_method_t {
|
|||||||
RES_MULTISTEP_SAMPLE_METHOD,
|
RES_MULTISTEP_SAMPLE_METHOD,
|
||||||
RES_2S_SAMPLE_METHOD,
|
RES_2S_SAMPLE_METHOD,
|
||||||
ER_SDE_SAMPLE_METHOD,
|
ER_SDE_SAMPLE_METHOD,
|
||||||
EULER_CFG_PP_SAMPLE_METHOD,
|
|
||||||
EULER_A_CFG_PP_SAMPLE_METHOD,
|
|
||||||
SAMPLE_METHOD_COUNT
|
SAMPLE_METHOD_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -208,7 +206,7 @@ typedef struct {
|
|||||||
bool chroma_use_t5_mask;
|
bool chroma_use_t5_mask;
|
||||||
int chroma_t5_mask_pad;
|
int chroma_t5_mask_pad;
|
||||||
bool qwen_image_zero_cond_t;
|
bool qwen_image_zero_cond_t;
|
||||||
float max_vram; // GiB budget for graph-cut segmented param offload (0 = disabled, -1 = auto free VRAM minus 1 GiB)
|
float max_vram;
|
||||||
} sd_ctx_params_t;
|
} sd_ctx_params_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -250,7 +248,6 @@ typedef struct {
|
|||||||
float* custom_sigmas;
|
float* custom_sigmas;
|
||||||
int custom_sigmas_count;
|
int custom_sigmas_count;
|
||||||
float flow_shift;
|
float flow_shift;
|
||||||
const char* extra_sample_args;
|
|
||||||
} sd_sample_params_t;
|
} sd_sample_params_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@ -16,12 +16,6 @@ struct SDCondition {
|
|||||||
sd::Tensor<float> c_concat;
|
sd::Tensor<float> c_concat;
|
||||||
sd::Tensor<int32_t> c_t5_ids;
|
sd::Tensor<int32_t> c_t5_ids;
|
||||||
sd::Tensor<float> c_t5_weights;
|
sd::Tensor<float> c_t5_weights;
|
||||||
sd::Tensor<int32_t> c_input_ids;
|
|
||||||
sd::Tensor<int32_t> c_position_ids;
|
|
||||||
sd::Tensor<int32_t> c_token_types;
|
|
||||||
sd::Tensor<int32_t> c_vinput_mask;
|
|
||||||
std::vector<std::pair<int, sd::Tensor<float>>> c_image_embeds;
|
|
||||||
std::vector<sd::Tensor<float>> c_ref_images;
|
|
||||||
|
|
||||||
std::vector<sd::Tensor<float>> extra_c_crossattns;
|
std::vector<sd::Tensor<float>> extra_c_crossattns;
|
||||||
|
|
||||||
@ -34,24 +28,10 @@ struct SDCondition {
|
|||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
if (!c_crossattn.empty() || !c_vector.empty() || !c_concat.empty() ||
|
if (!c_crossattn.empty() || !c_vector.empty() || !c_concat.empty() ||
|
||||||
!c_t5_ids.empty() || !c_t5_weights.empty() ||
|
!c_t5_ids.empty() || !c_t5_weights.empty()) {
|
||||||
!c_input_ids.empty() || !c_position_ids.empty() ||
|
|
||||||
!c_token_types.empty() || !c_vinput_mask.empty()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& image_embed : c_image_embeds) {
|
|
||||||
if (!image_embed.second.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& tensor : c_ref_images) {
|
|
||||||
if (!tensor.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& tensor : extra_c_crossattns) {
|
for (const auto& tensor : extra_c_crossattns) {
|
||||||
if (!tensor.empty()) {
|
if (!tensor.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
311
src/denoiser.hpp
311
src/denoiser.hpp
@ -2,7 +2,6 @@
|
|||||||
#define __DENOISER_HPP__
|
#define __DENOISER_HPP__
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "ggml_extend.hpp"
|
#include "ggml_extend.hpp"
|
||||||
@ -753,7 +752,7 @@ struct Flux2FlowDenoiser : public FluxFlowDenoiser {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<sd::Tensor<float>(const sd::Tensor<float>&, float, int, sd::Tensor<float>*)> denoise_cb_t;
|
typedef std::function<sd::Tensor<float>(const sd::Tensor<float>&, float, int)> denoise_cb_t;
|
||||||
|
|
||||||
static std::pair<float, float> get_ancestral_step(float sigma_from,
|
static std::pair<float, float> get_ancestral_step(float sigma_from,
|
||||||
float sigma_to,
|
float sigma_to,
|
||||||
@ -824,34 +823,46 @@ static std::tuple<float, float, float> get_ancestral_step(float sigma_from,
|
|||||||
static sd::Tensor<float> sample_euler_ancestral(denoise_cb_t model,
|
static sd::Tensor<float> sample_euler_ancestral(denoise_cb_t model,
|
||||||
sd::Tensor<float> x,
|
sd::Tensor<float> x,
|
||||||
const std::vector<float>& sigmas,
|
const std::vector<float>& sigmas,
|
||||||
std::shared_ptr<RNG> rng = nullptr,
|
std::shared_ptr<RNG> rng,
|
||||||
bool is_flow_denoiser = false,
|
float eta) {
|
||||||
float eta = 0.f) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
float sigma_to = sigmas[i + 1];
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
auto denoised_opt = model(x, sigma, i + 1, nullptr);
|
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
if (sigma_to == 0.f) {
|
sd::Tensor<float> d = (x - denoised) / sigma;
|
||||||
x = denoised;
|
auto [sigma_down, sigma_up] = get_ancestral_step(sigmas[i], sigmas[i + 1], eta);
|
||||||
} else if (eta == 0.f) {
|
x += d * (sigma_down - sigmas[i]);
|
||||||
float sigma_ratio = sigma_to / sigma;
|
if (sigmas[i + 1] > 0) {
|
||||||
x = sigma_ratio * x + (1.0 - sigma_ratio) * denoised;
|
|
||||||
} else {
|
|
||||||
auto [sigma_down, sigma_up, alpha_scale] = get_ancestral_step(sigma, sigma_to, eta, is_flow_denoiser);
|
|
||||||
float sigma_ratio = sigma_down / sigma;
|
|
||||||
x = sigma_ratio * x + (1.0f - sigma_ratio) * denoised;
|
|
||||||
if (sigma_up > 0.f) {
|
|
||||||
if (is_flow_denoiser) {
|
|
||||||
x *= alpha_scale;
|
|
||||||
}
|
|
||||||
x += sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
x += sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sd::Tensor<float> sample_euler_flow(denoise_cb_t model,
|
||||||
|
sd::Tensor<float> x,
|
||||||
|
const std::vector<float>& sigmas,
|
||||||
|
std::shared_ptr<RNG> rng,
|
||||||
|
float eta) {
|
||||||
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
float sigma = sigmas[i];
|
||||||
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
|
if (denoised_opt.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
|
auto [sigma_down, sigma_up, alpha_scale] = get_ancestral_step_flow(sigma, sigmas[i + 1], eta);
|
||||||
|
float sigma_ratio = sigma_down / sigma;
|
||||||
|
x = sigma_ratio * x + (1.0f - sigma_ratio) * denoised;
|
||||||
|
|
||||||
|
if (sigma_up > 0.0f) {
|
||||||
|
x = alpha_scale * x + sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
@ -862,7 +873,7 @@ static sd::Tensor<float> sample_euler(denoise_cb_t model,
|
|||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
auto denoised_opt = model(x, sigma, i + 1, nullptr);
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -878,7 +889,7 @@ static sd::Tensor<float> sample_heun(denoise_cb_t model,
|
|||||||
const std::vector<float>& sigmas) {
|
const std::vector<float>& sigmas) {
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1), nullptr);
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -889,7 +900,7 @@ static sd::Tensor<float> sample_heun(denoise_cb_t model,
|
|||||||
x += d * dt;
|
x += d * dt;
|
||||||
} else {
|
} else {
|
||||||
sd::Tensor<float> x2 = x + d * dt;
|
sd::Tensor<float> x2 = x + d * dt;
|
||||||
auto denoised2_opt = model(x2, sigmas[i + 1], i + 1, nullptr);
|
auto denoised2_opt = model(x2, sigmas[i + 1], i + 1);
|
||||||
if (denoised2_opt.empty()) {
|
if (denoised2_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -906,7 +917,7 @@ static sd::Tensor<float> sample_dpm2(denoise_cb_t model,
|
|||||||
const std::vector<float>& sigmas) {
|
const std::vector<float>& sigmas) {
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1), nullptr);
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -919,7 +930,7 @@ static sd::Tensor<float> sample_dpm2(denoise_cb_t model,
|
|||||||
float dt_1 = sigma_mid - sigmas[i];
|
float dt_1 = sigma_mid - sigmas[i];
|
||||||
float dt_2 = sigmas[i + 1] - sigmas[i];
|
float dt_2 = sigmas[i + 1] - sigmas[i];
|
||||||
sd::Tensor<float> x2 = x + d * dt_1;
|
sd::Tensor<float> x2 = x + d * dt_1;
|
||||||
auto denoised2_opt = model(x2, sigma_mid, i + 1, nullptr);
|
auto denoised2_opt = model(x2, sigma_mid, i + 1);
|
||||||
if (denoised2_opt.empty()) {
|
if (denoised2_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -940,7 +951,7 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral(denoise_cb_t model,
|
|||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1), nullptr);
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -956,7 +967,7 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral(denoise_cb_t model,
|
|||||||
float s = t + 0.5f * h;
|
float s = t + 0.5f * h;
|
||||||
float sigma_s = sigma_fn(s);
|
float sigma_s = sigma_fn(s);
|
||||||
sd::Tensor<float> x2 = (sigma_s / sigma_fn(t)) * x - (exp(-h * 0.5f) - 1) * denoised;
|
sd::Tensor<float> x2 = (sigma_s / sigma_fn(t)) * x - (exp(-h * 0.5f) - 1) * denoised;
|
||||||
auto denoised2_opt = model(x2, sigma_s, i + 1, nullptr);
|
auto denoised2_opt = model(x2, sigma_s, i + 1);
|
||||||
if (denoised2_opt.empty()) {
|
if (denoised2_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -983,7 +994,7 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral_flow(denoise_cb_t model,
|
|||||||
|
|
||||||
bool opt_first_step = (1.0 - sigma < 1e-6);
|
bool opt_first_step = (1.0 - sigma < 1e-6);
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, (opt_first_step ? 1 : -1) * (i + 1), nullptr);
|
auto denoised_opt = model(x, sigma, (opt_first_step ? 1 : -1) * (i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1012,8 +1023,8 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral_flow(denoise_cb_t model,
|
|||||||
// so sigma_s = 1 = sigma, and sigma_s_i_ratio = sigma_s / sigma = 1
|
// so sigma_s = 1 = sigma, and sigma_s_i_ratio = sigma_s / sigma = 1
|
||||||
// u = (x*sigma_s_i_ratio)+(denoised*(1.0f-sigma_s_i_ratio))
|
// u = (x*sigma_s_i_ratio)+(denoised*(1.0f-sigma_s_i_ratio))
|
||||||
// = (x*1)+(denoised*0) = x
|
// = (x*1)+(denoised*0) = x
|
||||||
// so D_i = model(u, sigma_s, i + 1, nullptr)
|
// so D_i = model(u, sigma_s, i + 1)
|
||||||
// = model(x, sigma, i + 1, nullptr)
|
// = model(x, sigma, i + 1)
|
||||||
// = denoised
|
// = denoised
|
||||||
D_i = denoised;
|
D_i = denoised;
|
||||||
|
|
||||||
@ -1046,7 +1057,7 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral_flow(denoise_cb_t model,
|
|||||||
float sigma_s_i_ratio = sigma_s / sigma;
|
float sigma_s_i_ratio = sigma_s / sigma;
|
||||||
sd::Tensor<float> u = (x * sigma_s_i_ratio) + (denoised * (1.0f - sigma_s_i_ratio));
|
sd::Tensor<float> u = (x * sigma_s_i_ratio) + (denoised * (1.0f - sigma_s_i_ratio));
|
||||||
|
|
||||||
auto denoised2_opt = model(u, sigma_s, i + 1, nullptr);
|
auto denoised2_opt = model(u, sigma_s, i + 1);
|
||||||
if (denoised2_opt.empty()) {
|
if (denoised2_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1073,7 +1084,7 @@ static sd::Tensor<float> sample_dpmpp_2m(denoise_cb_t model,
|
|||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1, nullptr);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1105,7 +1116,7 @@ static sd::Tensor<float> sample_dpmpp_2m_v2(denoise_cb_t model,
|
|||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1, nullptr);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1137,83 +1148,10 @@ static sd::Tensor<float> sample_lcm(denoise_cb_t model,
|
|||||||
sd::Tensor<float> x,
|
sd::Tensor<float> x,
|
||||||
const std::vector<float>& sigmas,
|
const std::vector<float>& sigmas,
|
||||||
std::shared_ptr<RNG> rng,
|
std::shared_ptr<RNG> rng,
|
||||||
bool is_flow_denoiser,
|
bool is_flow_denoiser) {
|
||||||
const char* extra_sample_args = nullptr) {
|
|
||||||
struct LCMSampleArgs {
|
|
||||||
float noise_clip_std = 0.0f;
|
|
||||||
float noise_scale_start = 1.0f;
|
|
||||||
float noise_scale_end = 1.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto trim = [](std::string value) -> std::string {
|
|
||||||
const char* whitespace = " \t\r\n";
|
|
||||||
size_t begin = value.find_first_not_of(whitespace);
|
|
||||||
if (begin == std::string::npos) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
size_t end = value.find_last_not_of(whitespace);
|
|
||||||
return value.substr(begin, end - begin + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
LCMSampleArgs args;
|
|
||||||
if (extra_sample_args != nullptr && extra_sample_args[0] != '\0') {
|
|
||||||
std::string raw(extra_sample_args);
|
|
||||||
size_t start = 0;
|
|
||||||
bool noise_scale_end_was_set = false;
|
|
||||||
bool noise_scale_start_was_set = false;
|
|
||||||
auto parse_arg = [&](const std::string& item) {
|
|
||||||
std::string token = trim(item);
|
|
||||||
if (token.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t eq = token.find('=');
|
|
||||||
if (eq == std::string::npos) {
|
|
||||||
LOG_WARN("ignoring invalid lcm extra sample arg '%s'", token.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string key = trim(token.substr(0, eq));
|
|
||||||
std::string value = trim(token.substr(eq + 1));
|
|
||||||
float parsed = 0.0f;
|
|
||||||
try {
|
|
||||||
size_t consumed = 0;
|
|
||||||
parsed = std::stof(value, &consumed);
|
|
||||||
if (trim(value.substr(consumed)).size() != 0) {
|
|
||||||
LOG_WARN("ignoring invalid lcm extra sample arg '%s'", token.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (const std::exception&) {
|
|
||||||
LOG_WARN("ignoring invalid lcm extra sample arg '%s'", token.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "noise_clip_std") {
|
|
||||||
args.noise_clip_std = parsed;
|
|
||||||
} else if (key == "noise_scale_start") {
|
|
||||||
args.noise_scale_start = parsed;
|
|
||||||
noise_scale_start_was_set = true;
|
|
||||||
} else if (key == "noise_scale_end") {
|
|
||||||
args.noise_scale_end = parsed;
|
|
||||||
noise_scale_end_was_set = true;
|
|
||||||
} else {
|
|
||||||
LOG_WARN("ignoring unknown lcm extra sample arg '%s'", key.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t pos = 0; pos <= raw.size(); ++pos) {
|
|
||||||
if (pos == raw.size() || raw[pos] == ',' || raw[pos] == ';') {
|
|
||||||
parse_arg(raw.substr(start, pos - start));
|
|
||||||
start = pos + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (noise_scale_start_was_set && !noise_scale_end_was_set) {
|
|
||||||
args.noise_scale_end = args.noise_scale_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1, nullptr);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1222,27 +1160,7 @@ static sd::Tensor<float> sample_lcm(denoise_cb_t model,
|
|||||||
if (is_flow_denoiser) {
|
if (is_flow_denoiser) {
|
||||||
x *= (1 - sigmas[i + 1]);
|
x *= (1 - sigmas[i + 1]);
|
||||||
}
|
}
|
||||||
auto noise = sd::Tensor<float>::randn_like(x, rng);
|
x += sd::Tensor<float>::randn_like(x, rng) * sigmas[i + 1];
|
||||||
if (args.noise_clip_std > 0.0f && noise.numel() > 0) {
|
|
||||||
double mean = 0.0;
|
|
||||||
for (int64_t j = 0; j < noise.numel(); ++j) {
|
|
||||||
mean += static_cast<double>(noise[j]);
|
|
||||||
}
|
|
||||||
mean /= static_cast<double>(noise.numel());
|
|
||||||
|
|
||||||
double variance = 0.0;
|
|
||||||
for (int64_t j = 0; j < noise.numel(); ++j) {
|
|
||||||
double centered = static_cast<double>(noise[j]) - mean;
|
|
||||||
variance += centered * centered;
|
|
||||||
}
|
|
||||||
variance /= static_cast<double>(noise.numel());
|
|
||||||
|
|
||||||
float clip_val = args.noise_clip_std * static_cast<float>(std::sqrt(variance));
|
|
||||||
noise = sd::ops::clamp(noise, -clip_val, clip_val);
|
|
||||||
}
|
|
||||||
float t = steps > 1 ? static_cast<float>(i) / static_cast<float>(steps - 1) : 0.0f;
|
|
||||||
float noise_scale = args.noise_scale_start + (args.noise_scale_end - args.noise_scale_start) * t;
|
|
||||||
x += noise * (sigmas[i + 1] * noise_scale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
@ -1259,7 +1177,7 @@ static sd::Tensor<float> sample_ipndm(denoise_cb_t model,
|
|||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
float sigma_next = sigmas[i + 1];
|
float sigma_next = sigmas[i + 1];
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, i + 1, nullptr);
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1303,7 +1221,7 @@ static sd::Tensor<float> sample_ipndm_v(denoise_cb_t model,
|
|||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
float t_next = sigmas[i + 1];
|
float t_next = sigmas[i + 1];
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, i + 1, nullptr);
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1365,7 +1283,7 @@ static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1, nullptr);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1442,7 +1360,7 @@ static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|||||||
float sigma_from = sigmas[i];
|
float sigma_from = sigmas[i];
|
||||||
float sigma_to = sigmas[i + 1];
|
float sigma_to = sigmas[i + 1];
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma_from, -(i + 1), nullptr);
|
auto denoised_opt = model(x, sigma_from, -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1468,7 +1386,7 @@ static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|||||||
sd::Tensor<float> eps1 = denoised - x0;
|
sd::Tensor<float> eps1 = denoised - x0;
|
||||||
sd::Tensor<float> x2 = x0 + eps1 * (h * a21);
|
sd::Tensor<float> x2 = x0 + eps1 * (h * a21);
|
||||||
|
|
||||||
auto denoised2_opt = model(x2, sigma_c2, i + 1, nullptr);
|
auto denoised2_opt = model(x2, sigma_c2, i + 1);
|
||||||
if (denoised2_opt.empty()) {
|
if (denoised2_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1545,7 +1463,7 @@ static sd::Tensor<float> sample_er_sde(denoise_cb_t model,
|
|||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
sd::Tensor<float> denoised = model(x, sigmas[i], i + 1, nullptr);
|
sd::Tensor<float> denoised = model(x, sigmas[i], i + 1);
|
||||||
if (denoised.empty()) {
|
if (denoised.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1621,6 +1539,46 @@ static sd::Tensor<float> sample_er_sde(denoise_cb_t model,
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sd::Tensor<float> sample_ddim_trailing(denoise_cb_t model,
|
||||||
|
sd::Tensor<float> x,
|
||||||
|
const std::vector<float>& sigmas,
|
||||||
|
std::shared_ptr<RNG> rng,
|
||||||
|
float eta) {
|
||||||
|
int steps = static_cast<int>(sigmas.size()) - 1;
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
float sigma = sigmas[i];
|
||||||
|
float sigma_to = sigmas[i + 1];
|
||||||
|
|
||||||
|
auto model_output_opt = model(x, sigma, i + 1);
|
||||||
|
if (model_output_opt.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
sd::Tensor<float> model_output = std::move(model_output_opt);
|
||||||
|
model_output = (x - model_output) * (1.0f / sigma);
|
||||||
|
|
||||||
|
float alpha_prod_t = 1.0f / (sigma * sigma + 1.0f);
|
||||||
|
float alpha_prod_t_prev = 1.0f / (sigma_to * sigma_to + 1.0f);
|
||||||
|
float beta_prod_t = 1.0f - alpha_prod_t;
|
||||||
|
|
||||||
|
sd::Tensor<float> pred_original_sample = ((x / std::sqrt(sigma * sigma + 1)) -
|
||||||
|
std::sqrt(beta_prod_t) * model_output) *
|
||||||
|
(1.0f / std::sqrt(alpha_prod_t));
|
||||||
|
|
||||||
|
float beta_prod_t_prev = 1.0f - alpha_prod_t_prev;
|
||||||
|
float variance = (beta_prod_t_prev / beta_prod_t) *
|
||||||
|
(1.0f - alpha_prod_t / alpha_prod_t_prev);
|
||||||
|
float std_dev_t = eta * std::sqrt(variance);
|
||||||
|
|
||||||
|
x = pred_original_sample +
|
||||||
|
std::sqrt((1.0f - alpha_prod_t_prev - std::pow(std_dev_t, 2)) / alpha_prod_t_prev) * model_output;
|
||||||
|
|
||||||
|
if (eta > 0) {
|
||||||
|
x += std_dev_t / std::sqrt(alpha_prod_t_prev) * sd::Tensor<float>::randn_like(x, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
||||||
sd::Tensor<float> x,
|
sd::Tensor<float> x,
|
||||||
const std::vector<float>& sigmas,
|
const std::vector<float>& sigmas,
|
||||||
@ -1663,12 +1621,12 @@ static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|||||||
int timestep_s = (int)floor((1 - eta) * prev_timestep);
|
int timestep_s = (int)floor((1 - eta) * prev_timestep);
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, i + 1, nullptr);
|
auto model_output_opt = model(x, sigma, i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (model_output_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> model_output = std::move(model_output_opt);
|
||||||
sd::Tensor<float> d = (x - denoised) / sigma;
|
model_output = (x - model_output) * (1.0f / sigma);
|
||||||
|
|
||||||
float alpha_prod_t = 1.0f / (sigma * sigma + 1.0f);
|
float alpha_prod_t = 1.0f / (sigma * sigma + 1.0f);
|
||||||
float beta_prod_t = 1.0f - alpha_prod_t;
|
float beta_prod_t = 1.0f - alpha_prod_t;
|
||||||
@ -1676,8 +1634,12 @@ static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|||||||
float alpha_prod_s = static_cast<float>(alphas_cumprod[timestep_s]);
|
float alpha_prod_s = static_cast<float>(alphas_cumprod[timestep_s]);
|
||||||
float beta_prod_s = 1.0f - alpha_prod_s;
|
float beta_prod_s = 1.0f - alpha_prod_s;
|
||||||
|
|
||||||
x = std::sqrt(alpha_prod_s / alpha_prod_t_prev) * denoised +
|
sd::Tensor<float> pred_original_sample = ((x / std::sqrt(sigma * sigma + 1)) -
|
||||||
std::sqrt(beta_prod_s / alpha_prod_t_prev) * d;
|
std::sqrt(beta_prod_t) * model_output) *
|
||||||
|
(1.0f / std::sqrt(alpha_prod_t));
|
||||||
|
|
||||||
|
x = std::sqrt(alpha_prod_s / alpha_prod_t_prev) * pred_original_sample +
|
||||||
|
std::sqrt(beta_prod_s / alpha_prod_t_prev) * model_output;
|
||||||
|
|
||||||
if (eta > 0 && sigma_to > 0.0f) {
|
if (eta > 0 && sigma_to > 0.0f) {
|
||||||
x = std::sqrt(alpha_prod_t_prev / alpha_prod_s) * x +
|
x = std::sqrt(alpha_prod_t_prev / alpha_prod_s) * x +
|
||||||
@ -1687,56 +1649,6 @@ static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static sd::Tensor<float> sample_euler_cfg_pp(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
|
||||||
float sigma = sigmas[i];
|
|
||||||
sd::Tensor<float> uncond_denoised;
|
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, i + 1, &uncond_denoised);
|
|
||||||
if (denoised_opt.empty() || uncond_denoised.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
|
||||||
sd::Tensor<float> d = (x - uncond_denoised) / sigma;
|
|
||||||
|
|
||||||
x = denoised + d * sigmas[i + 1];
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sd::Tensor<float> sample_euler_ancestral_cfg_pp(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
|
||||||
float sigma = sigmas[i];
|
|
||||||
sd::Tensor<float> uncond_denoised;
|
|
||||||
|
|
||||||
auto denoised_opt = model(x, sigma, i + 1, &uncond_denoised);
|
|
||||||
if (denoised_opt.empty() || uncond_denoised.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
|
||||||
sd::Tensor<float> d = (x - uncond_denoised) / sigma;
|
|
||||||
|
|
||||||
auto [sigma_down, sigma_up] = get_ancestral_step(sigmas[i], sigmas[i + 1], eta);
|
|
||||||
|
|
||||||
x = denoised + d * sigma_down;
|
|
||||||
|
|
||||||
if (sigmas[i + 1] > 0) {
|
|
||||||
x += sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// k diffusion reverse ODE: dx = (x - D(x;\sigma)) / \sigma dt; \sigma(t) = t
|
// k diffusion reverse ODE: dx = (x - D(x;\sigma)) / \sigma dt; \sigma(t) = t
|
||||||
static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
||||||
denoise_cb_t model,
|
denoise_cb_t model,
|
||||||
@ -1744,11 +1656,13 @@ static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
|||||||
std::vector<float> sigmas,
|
std::vector<float> sigmas,
|
||||||
std::shared_ptr<RNG> rng,
|
std::shared_ptr<RNG> rng,
|
||||||
float eta,
|
float eta,
|
||||||
bool is_flow_denoiser,
|
bool is_flow_denoiser) {
|
||||||
const char* extra_sample_args) {
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case EULER_A_SAMPLE_METHOD:
|
case EULER_A_SAMPLE_METHOD:
|
||||||
return sample_euler_ancestral(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
|
if (is_flow_denoiser)
|
||||||
|
return sample_euler_flow(model, std::move(x), sigmas, rng, eta);
|
||||||
|
else
|
||||||
|
return sample_euler_ancestral(model, std::move(x), sigmas, rng, eta);
|
||||||
case EULER_SAMPLE_METHOD:
|
case EULER_SAMPLE_METHOD:
|
||||||
return sample_euler(model, std::move(x), sigmas);
|
return sample_euler(model, std::move(x), sigmas);
|
||||||
case HEUN_SAMPLE_METHOD:
|
case HEUN_SAMPLE_METHOD:
|
||||||
@ -1765,7 +1679,7 @@ static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
|||||||
case DPMPP2Mv2_SAMPLE_METHOD:
|
case DPMPP2Mv2_SAMPLE_METHOD:
|
||||||
return sample_dpmpp_2m_v2(model, std::move(x), sigmas);
|
return sample_dpmpp_2m_v2(model, std::move(x), sigmas);
|
||||||
case LCM_SAMPLE_METHOD:
|
case LCM_SAMPLE_METHOD:
|
||||||
return sample_lcm(model, std::move(x), sigmas, rng, is_flow_denoiser, extra_sample_args);
|
return sample_lcm(model, std::move(x), sigmas, rng, is_flow_denoiser);
|
||||||
case IPNDM_SAMPLE_METHOD:
|
case IPNDM_SAMPLE_METHOD:
|
||||||
return sample_ipndm(model, std::move(x), sigmas);
|
return sample_ipndm(model, std::move(x), sigmas);
|
||||||
case IPNDM_V_SAMPLE_METHOD:
|
case IPNDM_V_SAMPLE_METHOD:
|
||||||
@ -1777,14 +1691,9 @@ static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
|||||||
case ER_SDE_SAMPLE_METHOD:
|
case ER_SDE_SAMPLE_METHOD:
|
||||||
return sample_er_sde(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
|
return sample_er_sde(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
|
||||||
case DDIM_TRAILING_SAMPLE_METHOD:
|
case DDIM_TRAILING_SAMPLE_METHOD:
|
||||||
// DDIM is equivalent to Euler Ancestral with the Simple scheduler
|
return sample_ddim_trailing(model, std::move(x), sigmas, rng, eta);
|
||||||
return sample_euler_ancestral(model, std::move(x), sigmas, rng, is_flow_denoiser, eta);
|
|
||||||
case TCD_SAMPLE_METHOD:
|
case TCD_SAMPLE_METHOD:
|
||||||
return sample_tcd(model, std::move(x), sigmas, rng, eta);
|
return sample_tcd(model, std::move(x), sigmas, rng, eta);
|
||||||
case EULER_CFG_PP_SAMPLE_METHOD:
|
|
||||||
return sample_euler_cfg_pp(model, std::move(x), sigmas);
|
|
||||||
case EULER_A_CFG_PP_SAMPLE_METHOD:
|
|
||||||
return sample_euler_ancestral_cfg_pp(model, std::move(x), sigmas, rng, eta);
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
#include "anima.hpp"
|
#include "anima.hpp"
|
||||||
#include "ernie_image.hpp"
|
#include "ernie_image.hpp"
|
||||||
#include "flux.hpp"
|
#include "flux.hpp"
|
||||||
#include "hidream_o1.hpp"
|
|
||||||
#include "ltxv.hpp"
|
#include "ltxv.hpp"
|
||||||
#include "mmdit.hpp"
|
#include "mmdit.hpp"
|
||||||
#include "qwen_image.hpp"
|
#include "qwen_image.hpp"
|
||||||
@ -16,8 +15,8 @@
|
|||||||
|
|
||||||
struct DiffusionParams {
|
struct DiffusionParams {
|
||||||
const sd::Tensor<float>* x = nullptr;
|
const sd::Tensor<float>* x = nullptr;
|
||||||
const sd::Tensor<float>* timesteps = nullptr;
|
|
||||||
const sd::Tensor<float>* audio_x = nullptr;
|
const sd::Tensor<float>* audio_x = nullptr;
|
||||||
|
const sd::Tensor<float>* timesteps = nullptr;
|
||||||
const sd::Tensor<float>* audio_timesteps = nullptr;
|
const sd::Tensor<float>* audio_timesteps = nullptr;
|
||||||
const sd::Tensor<float>* context = nullptr;
|
const sd::Tensor<float>* context = nullptr;
|
||||||
const sd::Tensor<float>* c_concat = nullptr;
|
const sd::Tensor<float>* c_concat = nullptr;
|
||||||
@ -26,12 +25,6 @@ struct DiffusionParams {
|
|||||||
const sd::Tensor<float>* t5_weights = nullptr;
|
const sd::Tensor<float>* t5_weights = nullptr;
|
||||||
const sd::Tensor<float>* guidance = nullptr;
|
const sd::Tensor<float>* guidance = nullptr;
|
||||||
const std::vector<sd::Tensor<float>>* ref_latents = nullptr;
|
const std::vector<sd::Tensor<float>>* ref_latents = nullptr;
|
||||||
const sd::Tensor<int32_t>* input_ids = nullptr;
|
|
||||||
const sd::Tensor<int32_t>* input_pos = nullptr;
|
|
||||||
const sd::Tensor<int32_t>* token_types = nullptr;
|
|
||||||
const sd::Tensor<int32_t>* vinput_mask = nullptr;
|
|
||||||
const std::vector<sd::Tensor<float>>* vlm_images = nullptr;
|
|
||||||
const std::vector<std::pair<int, sd::Tensor<float>>>* image_embeds = nullptr;
|
|
||||||
bool increase_ref_index = false;
|
bool increase_ref_index = false;
|
||||||
int num_video_frames = -1;
|
int num_video_frames = -1;
|
||||||
const std::vector<sd::Tensor<float>>* controls = nullptr;
|
const std::vector<sd::Tensor<float>>* controls = nullptr;
|
||||||
@ -487,82 +480,6 @@ struct QwenImageModel : public DiffusionModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HiDreamO1Model : public DiffusionModel {
|
|
||||||
std::string prefix;
|
|
||||||
HiDreamO1::HiDreamO1Runner hidream_o1;
|
|
||||||
|
|
||||||
HiDreamO1Model(ggml_backend_t backend,
|
|
||||||
bool offload_params_to_cpu,
|
|
||||||
const String2TensorStorage& tensor_storage_map = {},
|
|
||||||
const std::string& prefix = "model")
|
|
||||||
: prefix(prefix), hidream_o1(backend, offload_params_to_cpu, tensor_storage_map, prefix) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_desc() override {
|
|
||||||
return hidream_o1.get_desc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void alloc_params_buffer() override {
|
|
||||||
hidream_o1.alloc_params_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_params_buffer() override {
|
|
||||||
hidream_o1.free_params_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_compute_buffer() override {
|
|
||||||
hidream_o1.free_compute_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, ggml_tensor*>& tensors) override {
|
|
||||||
hidream_o1.get_param_tensors(tensors, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_params_buffer_size() override {
|
|
||||||
return hidream_o1.get_params_buffer_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
|
||||||
hidream_o1.set_weight_adapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t get_adm_in_channels() override {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_flash_attention_enabled(bool enabled) {
|
|
||||||
hidream_o1.set_flash_attention_enabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_max_graph_vram_bytes(size_t max_vram_bytes) override {
|
|
||||||
hidream_o1.set_max_graph_vram_bytes(max_vram_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_circular_axes(bool circular_x, bool circular_y) override {
|
|
||||||
hidream_o1.set_circular_axes(circular_x, circular_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<float> compute(int n_threads,
|
|
||||||
const DiffusionParams& diffusion_params) override {
|
|
||||||
GGML_ASSERT(diffusion_params.x != nullptr);
|
|
||||||
GGML_ASSERT(diffusion_params.timesteps != nullptr);
|
|
||||||
GGML_ASSERT(diffusion_params.input_ids != nullptr);
|
|
||||||
GGML_ASSERT(diffusion_params.input_pos != nullptr);
|
|
||||||
GGML_ASSERT(diffusion_params.token_types != nullptr);
|
|
||||||
static const std::vector<sd::Tensor<float>> empty_images;
|
|
||||||
static const std::vector<std::pair<int, sd::Tensor<float>>> empty_image_embeds;
|
|
||||||
return hidream_o1.compute(n_threads,
|
|
||||||
*diffusion_params.x,
|
|
||||||
*diffusion_params.timesteps,
|
|
||||||
*diffusion_params.input_ids,
|
|
||||||
*diffusion_params.input_pos,
|
|
||||||
*diffusion_params.token_types,
|
|
||||||
tensor_or_empty(diffusion_params.vinput_mask),
|
|
||||||
diffusion_params.image_embeds ? *diffusion_params.image_embeds : empty_image_embeds,
|
|
||||||
diffusion_params.ref_latents ? *diffusion_params.ref_latents : empty_images);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ZImageModel : public DiffusionModel {
|
struct ZImageModel : public DiffusionModel {
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
ZImage::ZImageRunner z_image;
|
ZImage::ZImageRunner z_image;
|
||||||
|
|||||||
@ -280,9 +280,6 @@ __STATIC_INLINE__ void print_sd_tensor(const sd::Tensor<T>& tensor, bool shape_o
|
|||||||
if (shape_only) {
|
if (shape_only) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tensor.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int range = 3;
|
int range = 3;
|
||||||
std::vector<int64_t> shape = tensor.shape();
|
std::vector<int64_t> shape = tensor.shape();
|
||||||
while (shape.size() < 4) {
|
while (shape.size() < 4) {
|
||||||
@ -1716,7 +1713,10 @@ struct GGMLRunnerContext {
|
|||||||
if (debug_tensors == nullptr || tensor == nullptr) {
|
if (debug_tensors == nullptr || tensor == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ggml_tensor* snapshot = ggml_cont(ggml_ctx, tensor);
|
ggml_tensor* snapshot = tensor;
|
||||||
|
if (!ggml_is_contiguous(snapshot) || snapshot->view_src != nullptr) {
|
||||||
|
snapshot = ggml_cont(ggml_ctx, snapshot);
|
||||||
|
}
|
||||||
ggml_tensor* dst = ggml_dup_tensor(ggml_ctx, snapshot);
|
ggml_tensor* dst = ggml_dup_tensor(ggml_ctx, snapshot);
|
||||||
snapshot = ggml_cpy(ggml_ctx, snapshot, dst);
|
snapshot = ggml_cpy(ggml_ctx, snapshot, dst);
|
||||||
ggml_set_output(snapshot);
|
ggml_set_output(snapshot);
|
||||||
@ -2024,13 +2024,9 @@ protected:
|
|||||||
ggml_backend_buffer_t src_buf = sd::ggml_graph_cut::tensor_buffer(src);
|
ggml_backend_buffer_t src_buf = sd::ggml_graph_cut::tensor_buffer(src);
|
||||||
ggml_backend_buffer_t dst_buf = sd::ggml_graph_cut::tensor_buffer(dst);
|
ggml_backend_buffer_t dst_buf = sd::ggml_graph_cut::tensor_buffer(dst);
|
||||||
if (src_buf == nullptr || dst_buf == nullptr) {
|
if (src_buf == nullptr || dst_buf == nullptr) {
|
||||||
LOG_ERROR("%s cache copy tensor buffer missing: name=%s op=%s src0=%p src0_name=%s src0_buffer=%p src_buffer=%p src_view_src=%p src_view_src_buffer=%p dst_buffer=%p",
|
LOG_ERROR("%s cache copy tensor buffer missing: name=%s src_buffer=%p src_view_src=%p src_view_src_buffer=%p dst_buffer=%p",
|
||||||
get_desc().c_str(),
|
get_desc().c_str(),
|
||||||
src && src->name[0] != '\0' ? src->name : "<unnamed>",
|
src && src->name[0] != '\0' ? src->name : "<unnamed>",
|
||||||
src ? ggml_op_name(src->op) : "<null>",
|
|
||||||
src ? src->src[0] : nullptr,
|
|
||||||
(src && src->src[0] && src->src[0]->name[0] != '\0') ? src->src[0]->name : "<unnamed>",
|
|
||||||
(src && src->src[0]) ? sd::ggml_graph_cut::tensor_buffer(src->src[0]) : nullptr,
|
|
||||||
src ? src->buffer : nullptr,
|
src ? src->buffer : nullptr,
|
||||||
src ? src->view_src : nullptr,
|
src ? src->view_src : nullptr,
|
||||||
(src && src->view_src) ? src->view_src->buffer : nullptr,
|
(src && src->view_src) ? src->view_src->buffer : nullptr,
|
||||||
@ -2062,42 +2058,6 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::optional<sd::Tensor<T>> read_graph_tensor(ggml_tensor* tensor, const char* label) {
|
|
||||||
if (tensor == nullptr) {
|
|
||||||
LOG_ERROR("%s %s tensor is null", get_desc().c_str(), label);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
if (tensor->type != sd::GGMLTypeTraits<T>::type) {
|
|
||||||
LOG_ERROR("%s %s tensor type mismatch: got %s",
|
|
||||||
get_desc().c_str(),
|
|
||||||
label,
|
|
||||||
ggml_type_name(tensor->type));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
ggml_backend_buffer_t buf = sd::ggml_graph_cut::tensor_buffer(tensor);
|
|
||||||
if (buf == nullptr) {
|
|
||||||
LOG_ERROR("%s %s tensor buffer missing: name=%s op=%s buffer=%p view_src=%p view_src_buffer=%p data=%p",
|
|
||||||
get_desc().c_str(),
|
|
||||||
label,
|
|
||||||
tensor->name[0] != '\0' ? tensor->name : "<unnamed>",
|
|
||||||
ggml_op_name(tensor->op),
|
|
||||||
tensor->buffer,
|
|
||||||
tensor->view_src,
|
|
||||||
tensor->view_src ? tensor->view_src->buffer : nullptr,
|
|
||||||
tensor->data);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<T> result(sd::shape_from_ggml(tensor));
|
|
||||||
if (tensor->view_src != nullptr || !ggml_is_contiguous(tensor) || tensor->buffer == nullptr) {
|
|
||||||
ggml_backend_tensor_get(tensor, result.data(), 0, ggml_nbytes(tensor));
|
|
||||||
} else {
|
|
||||||
ggml_backend_tensor_get(tensor, result.data(), 0, ggml_nbytes(tensor));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_data_to_backend_tensor(ggml_cgraph* gf, bool clear_after_copy = true) {
|
void copy_data_to_backend_tensor(ggml_cgraph* gf, bool clear_after_copy = true) {
|
||||||
GGML_ASSERT(gf != nullptr);
|
GGML_ASSERT(gf != nullptr);
|
||||||
std::unordered_set<const ggml_tensor*> graph_tensor_set;
|
std::unordered_set<const ggml_tensor*> graph_tensor_set;
|
||||||
@ -2118,9 +2078,6 @@ protected:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const char* name = ggml_get_name(tensor);
|
const char* name = ggml_get_name(tensor);
|
||||||
if (graph_tensor_set.find(tensor) == graph_tensor_set.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (tensor->buffer == nullptr) {
|
if (tensor->buffer == nullptr) {
|
||||||
LOG_WARN("%s skip backend tensor copy: tensor buffer not set, name='%s', ne=[%lld,%lld,%lld,%lld], type=%s",
|
LOG_WARN("%s skip backend tensor copy: tensor buffer not set, name='%s', ne=[%lld,%lld,%lld,%lld], type=%s",
|
||||||
get_desc().c_str(),
|
get_desc().c_str(),
|
||||||
@ -2133,6 +2090,10 @@ protected:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (graph_tensor_set.find(tensor) == graph_tensor_set.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer;
|
ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer;
|
||||||
if (buf == nullptr) {
|
if (buf == nullptr) {
|
||||||
LOG_WARN("%s graph exec skip tensor copy: name=%s op=%s reason=buffer_not_set data=%p view_src=%p view_src_buffer=%p",
|
LOG_WARN("%s graph exec skip tensor copy: name=%s op=%s reason=buffer_not_set data=%p view_src=%p view_src_buffer=%p",
|
||||||
@ -2518,32 +2479,11 @@ protected:
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<const ggml_tensor*> debug_graph_tensor_set;
|
|
||||||
const int n_debug_leafs = sd::ggml_graph_cut::leaf_count(gf);
|
|
||||||
const int n_debug_nodes = ggml_graph_n_nodes(gf);
|
|
||||||
debug_graph_tensor_set.reserve(static_cast<size_t>(n_debug_leafs + n_debug_nodes));
|
|
||||||
for (int i = 0; i < n_debug_leafs; ++i) {
|
|
||||||
debug_graph_tensor_set.insert(sd::ggml_graph_cut::leaf_tensor(gf, i));
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n_debug_nodes; ++i) {
|
|
||||||
debug_graph_tensor_set.insert(ggml_graph_node(gf, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& entry : debug_tensors) {
|
for (const auto& entry : debug_tensors) {
|
||||||
auto tensor = entry.first;
|
auto tensor = entry.first;
|
||||||
if (tensor == nullptr) {
|
if (tensor == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (debug_graph_tensor_set.find(tensor) == debug_graph_tensor_set.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ggml_backend_buffer_t tensor_buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer;
|
|
||||||
if (tensor_buf == nullptr) {
|
|
||||||
LOG_WARN("%s skip debug tensor '%s': tensor buffer not set",
|
|
||||||
get_desc().c_str(),
|
|
||||||
entry.second.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (tensor->type != GGML_TYPE_F32) {
|
if (tensor->type != GGML_TYPE_F32) {
|
||||||
LOG_WARN("%s skip debug tensor '%s': only GGML_TYPE_F32 is supported, got %s",
|
LOG_WARN("%s skip debug tensor '%s': only GGML_TYPE_F32 is supported, got %s",
|
||||||
get_desc().c_str(),
|
get_desc().c_str(),
|
||||||
@ -2568,15 +2508,7 @@ protected:
|
|||||||
auto result = ggml_get_tensor(compute_ctx, final_result_name.c_str());
|
auto result = ggml_get_tensor(compute_ctx, final_result_name.c_str());
|
||||||
std::optional<sd::Tensor<T>> output;
|
std::optional<sd::Tensor<T>> output;
|
||||||
if (!no_return) {
|
if (!no_return) {
|
||||||
output = read_graph_tensor<T>(result, "output");
|
output = sd::make_sd_tensor_from_ggml<T>(result);
|
||||||
if (!output.has_value()) {
|
|
||||||
if (free_compute_buffer_immediately) {
|
|
||||||
free_compute_buffer();
|
|
||||||
} else if (use_partial_param_offload) {
|
|
||||||
restore_partial_params();
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
output = sd::Tensor<T>();
|
output = sd::Tensor<T>();
|
||||||
}
|
}
|
||||||
@ -2716,26 +2648,6 @@ public:
|
|||||||
|
|
||||||
bool alloc_params_buffer() {
|
bool alloc_params_buffer() {
|
||||||
size_t num_tensors = ggml_tensor_num(params_ctx);
|
size_t num_tensors = ggml_tensor_num(params_ctx);
|
||||||
if (num_tensors > 0) {
|
|
||||||
// ggml_backend_alloc_ctx_tensors fails when all tensors are already allocated
|
|
||||||
// (typical for memory-mapped weights). See ggml-alloc.c n_buffers==0 branch.
|
|
||||||
bool all_have_data = true;
|
|
||||||
for (ggml_tensor* t = ggml_get_first_tensor(params_ctx); t != nullptr; t = ggml_get_next_tensor(params_ctx, t)) {
|
|
||||||
if (t->data == nullptr) {
|
|
||||||
all_have_data = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (all_have_data) {
|
|
||||||
LOG_DEBUG("%s all params already mmap-allocated (no separate buffer needed)", get_desc().c_str());
|
|
||||||
params_buffer = nullptr;
|
|
||||||
rebuild_params_tensor_set();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("%s skipping params allocation (no tensors)", get_desc().c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
params_buffer = ggml_backend_alloc_ctx_tensors(params_ctx, params_backend);
|
params_buffer = ggml_backend_alloc_ctx_tensors(params_ctx, params_backend);
|
||||||
if (params_buffer == nullptr) {
|
if (params_buffer == nullptr) {
|
||||||
LOG_ERROR("%s alloc params backend buffer failed, num_tensors = %i",
|
LOG_ERROR("%s alloc params backend buffer failed, num_tensors = %i",
|
||||||
|
|||||||
@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
namespace sd::ggml_graph_cut {
|
namespace sd::ggml_graph_cut {
|
||||||
|
|
||||||
static constexpr double MAX_VRAM_BYTES_PER_GIB = 1024.0 * 1024.0 * 1024.0;
|
|
||||||
static constexpr size_t MAX_VRAM_AUTO_RESERVE_BYTES = 1024ULL * 1024ULL * 1024ULL;
|
|
||||||
|
|
||||||
static std::string graph_cut_tensor_display_name(const ggml_tensor* tensor) {
|
static std::string graph_cut_tensor_display_name(const ggml_tensor* tensor) {
|
||||||
if (tensor == nullptr) {
|
if (tensor == nullptr) {
|
||||||
return "<null>";
|
return "<null>";
|
||||||
@ -48,21 +45,6 @@ namespace sd::ggml_graph_cut {
|
|||||||
return params_tensor_set.find(tensor) != params_tensor_set.end();
|
return params_tensor_set.find(tensor) != params_tensor_set.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int graph_node_index_by_name(ggml_cgraph* gf, const char* name) {
|
|
||||||
GGML_ASSERT(gf != nullptr);
|
|
||||||
if (name == nullptr || name[0] == '\0') {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
const int n_nodes = ggml_graph_n_nodes(gf);
|
|
||||||
for (int i = 0; i < n_nodes; ++i) {
|
|
||||||
ggml_tensor* node = ggml_graph_node(gf, i);
|
|
||||||
if (node != nullptr && std::strcmp(node->name, name) == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Plan::InputShape input_shape(const ggml_tensor* tensor) {
|
static Plan::InputShape input_shape(const ggml_tensor* tensor) {
|
||||||
Plan::InputShape shape;
|
Plan::InputShape shape;
|
||||||
if (tensor == nullptr) {
|
if (tensor == nullptr) {
|
||||||
@ -82,58 +64,6 @@ namespace sd::ggml_graph_cut {
|
|||||||
segment.output_bytes;
|
segment.output_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t max_vram_gib_to_bytes(float max_vram) {
|
|
||||||
if (max_vram <= 0.f) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return static_cast<size_t>(static_cast<double>(max_vram) * MAX_VRAM_BYTES_PER_GIB);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float max_vram_bytes_to_gib(size_t max_vram_bytes) {
|
|
||||||
return static_cast<float>(static_cast<double>(max_vram_bytes) / MAX_VRAM_BYTES_PER_GIB);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t resolve_auto_max_vram_bytes(ggml_backend_t backend) {
|
|
||||||
if (backend == nullptr) {
|
|
||||||
LOG_WARN("--max-vram -1 requested, but no backend is available; disabling graph splitting");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_backend_dev_t dev = ggml_backend_get_device(backend);
|
|
||||||
if (dev == nullptr) {
|
|
||||||
LOG_WARN("--max-vram -1 requested, but no backend device is available; disabling graph splitting");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (ggml_backend_dev_type(dev) == GGML_BACKEND_DEVICE_TYPE_CPU) {
|
|
||||||
LOG_WARN("--max-vram -1 requested, but the main backend is CPU; disabling graph splitting");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t free_vram = 0;
|
|
||||||
size_t total_vram = 0;
|
|
||||||
ggml_backend_dev_memory(dev, &free_vram, &total_vram);
|
|
||||||
|
|
||||||
if (free_vram <= MAX_VRAM_AUTO_RESERVE_BYTES) {
|
|
||||||
LOG_WARN("--max-vram -1 requested, but free VRAM is %.2f GiB; reserving 1.00 GiB leaves no graph budget",
|
|
||||||
free_vram / MAX_VRAM_BYTES_PER_GIB);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t max_vram_bytes = free_vram - MAX_VRAM_AUTO_RESERVE_BYTES;
|
|
||||||
LOG_INFO("--max-vram -1 auto-detected %.2f GiB free VRAM (%.2f GiB total), reserving 1.00 GiB; using %.2f GiB",
|
|
||||||
free_vram / MAX_VRAM_BYTES_PER_GIB,
|
|
||||||
total_vram / MAX_VRAM_BYTES_PER_GIB,
|
|
||||||
max_vram_bytes / MAX_VRAM_BYTES_PER_GIB);
|
|
||||||
return max_vram_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
float resolve_max_vram_gib(float max_vram, ggml_backend_t backend) {
|
|
||||||
if (max_vram != -1.f) {
|
|
||||||
return max_vram;
|
|
||||||
}
|
|
||||||
return max_vram_bytes_to_gib(resolve_auto_max_vram_bytes(backend));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Segment make_segment_seed(const Plan& plan,
|
static Segment make_segment_seed(const Plan& plan,
|
||||||
size_t start_segment_index,
|
size_t start_segment_index,
|
||||||
size_t end_segment_index) {
|
size_t end_segment_index) {
|
||||||
@ -314,11 +244,6 @@ namespace sd::ggml_graph_cut {
|
|||||||
if (tensor == nullptr) {
|
if (tensor == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (tensor_buffer(tensor) == nullptr && tensor->src[0] != nullptr &&
|
|
||||||
ggml_nelements(tensor->src[0]) == ggml_nelements(tensor) &&
|
|
||||||
ggml_nbytes(tensor->src[0]) == ggml_nbytes(tensor)) {
|
|
||||||
return cache_source_tensor(tensor->src[0]);
|
|
||||||
}
|
|
||||||
return tensor->view_src ? tensor->view_src : tensor;
|
return tensor->view_src ? tensor->view_src : tensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,15 +503,11 @@ namespace sd::ggml_graph_cut {
|
|||||||
log_desc);
|
log_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int final_output_index = graph_node_index_by_name(gf, "ggml_runner_final_result_tensor");
|
ggml_tensor* final_output = ggml_graph_node(gf, -1);
|
||||||
if (final_output_index < 0) {
|
if (final_output != nullptr && available_cut_output_node_indices.find(n_nodes - 1) == available_cut_output_node_indices.end()) {
|
||||||
final_output_index = n_nodes - 1;
|
|
||||||
}
|
|
||||||
ggml_tensor* final_output = final_output_index >= 0 ? ggml_graph_node(gf, final_output_index) : nullptr;
|
|
||||||
if (final_output != nullptr && available_cut_output_node_indices.find(final_output_index) == available_cut_output_node_indices.end()) {
|
|
||||||
Segment final_segment;
|
Segment final_segment;
|
||||||
final_segment.group_name = "ggml_runner.final";
|
final_segment.group_name = "ggml_runner.final";
|
||||||
final_segment.output_node_indices.push_back(final_output_index);
|
final_segment.output_node_indices.push_back(n_nodes - 1);
|
||||||
build_segment(gf,
|
build_segment(gf,
|
||||||
plan,
|
plan,
|
||||||
final_segment,
|
final_segment,
|
||||||
|
|||||||
@ -83,8 +83,6 @@ namespace sd::ggml_graph_cut {
|
|||||||
ggml_cgraph* gf,
|
ggml_cgraph* gf,
|
||||||
const Segment& segment,
|
const Segment& segment,
|
||||||
const char* log_desc);
|
const char* log_desc);
|
||||||
size_t max_vram_gib_to_bytes(float max_vram);
|
|
||||||
float resolve_max_vram_gib(float max_vram, ggml_backend_t backend);
|
|
||||||
Plan build_plan(ggml_backend_t backend,
|
Plan build_plan(ggml_backend_t backend,
|
||||||
ggml_cgraph* gf,
|
ggml_cgraph* gf,
|
||||||
const std::unordered_set<const ggml_tensor*>& params_tensor_set,
|
const std::unordered_set<const ggml_tensor*>& params_tensor_set,
|
||||||
|
|||||||
@ -1,653 +0,0 @@
|
|||||||
#ifndef __SD_HIDREAM_O1_H__
|
|
||||||
#define __SD_HIDREAM_O1_H__
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common_dit.hpp"
|
|
||||||
#include "conditioner.hpp"
|
|
||||||
#include "llm.hpp"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
namespace HiDreamO1 {
|
|
||||||
constexpr int HIDREAM_O1_GRAPH_SIZE = 32768;
|
|
||||||
constexpr int PATCH_SIZE = 32;
|
|
||||||
constexpr int TIMESTEP_TOKEN_NUM = 1;
|
|
||||||
constexpr int IMAGE_TOKEN_ID = 151655;
|
|
||||||
constexpr int VISION_START_TOKEN_ID = 151652;
|
|
||||||
|
|
||||||
static inline std::string repeat_special_token(const std::string& token, int64_t count) {
|
|
||||||
std::string out;
|
|
||||||
out.reserve(static_cast<size_t>(count) * token.size());
|
|
||||||
for (int64_t i = 0; i < count; ++i) {
|
|
||||||
out += token;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<int, int> calculate_dimensions(int max_size, double ratio) {
|
|
||||||
int width = static_cast<int>(std::sqrt(max_size * max_size * ratio));
|
|
||||||
int height = static_cast<int>(width / ratio);
|
|
||||||
width = (width / PATCH_SIZE) * PATCH_SIZE;
|
|
||||||
height = (height / PATCH_SIZE) * PATCH_SIZE;
|
|
||||||
width = std::max(width, PATCH_SIZE);
|
|
||||||
height = std::max(height, PATCH_SIZE);
|
|
||||||
return {width, height};
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline sd::Tensor<float> resize_to_area(const sd::Tensor<float>& image, int image_size) {
|
|
||||||
int64_t width = image.shape()[0];
|
|
||||||
int64_t height = image.shape()[1];
|
|
||||||
int64_t s_max = static_cast<int64_t>(image_size) * image_size;
|
|
||||||
double scale = std::sqrt(static_cast<double>(s_max) / static_cast<double>(width * height));
|
|
||||||
|
|
||||||
std::vector<std::pair<int64_t, int64_t>> sizes = {
|
|
||||||
{(static_cast<int64_t>(std::llround(width * scale)) / PATCH_SIZE) * PATCH_SIZE, (static_cast<int64_t>(std::llround(height * scale)) / PATCH_SIZE) * PATCH_SIZE},
|
|
||||||
{(static_cast<int64_t>(std::llround(width * scale)) / PATCH_SIZE) * PATCH_SIZE, (static_cast<int64_t>(std::floor(height * scale)) / PATCH_SIZE) * PATCH_SIZE},
|
|
||||||
{(static_cast<int64_t>(std::floor(width * scale)) / PATCH_SIZE) * PATCH_SIZE, (static_cast<int64_t>(std::llround(height * scale)) / PATCH_SIZE) * PATCH_SIZE},
|
|
||||||
{(static_cast<int64_t>(std::floor(width * scale)) / PATCH_SIZE) * PATCH_SIZE, (static_cast<int64_t>(std::floor(height * scale)) / PATCH_SIZE) * PATCH_SIZE},
|
|
||||||
};
|
|
||||||
std::sort(sizes.begin(), sizes.end(), [](const auto& a, const auto& b) {
|
|
||||||
return a.first * a.second > b.first * b.second;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::pair<int64_t, int64_t> new_size = sizes.back();
|
|
||||||
for (const auto& size : sizes) {
|
|
||||||
if (size.first > 0 && size.second > 0 && size.first * size.second <= s_max) {
|
|
||||||
new_size = size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double s1 = static_cast<double>(width) / static_cast<double>(new_size.first);
|
|
||||||
double s2 = static_cast<double>(height) / static_cast<double>(new_size.second);
|
|
||||||
sd::Tensor<float> resized;
|
|
||||||
if (s1 < s2) {
|
|
||||||
int64_t resized_h = static_cast<int64_t>(std::llround(height / s1));
|
|
||||||
resized = sd::ops::interpolate(image,
|
|
||||||
{new_size.first, resized_h, image.shape()[2], image.shape()[3]},
|
|
||||||
sd::ops::InterpolateMode::Bicubic);
|
|
||||||
int64_t top = (resized_h - new_size.second) / 2;
|
|
||||||
resized = sd::ops::slice(resized, 1, top, top + new_size.second);
|
|
||||||
} else {
|
|
||||||
int64_t resized_w = static_cast<int64_t>(std::llround(width / s2));
|
|
||||||
resized = sd::ops::interpolate(image,
|
|
||||||
{resized_w, new_size.second, image.shape()[2], image.shape()[3]},
|
|
||||||
sd::ops::InterpolateMode::Bicubic);
|
|
||||||
int64_t left = (resized_w - new_size.first) / 2;
|
|
||||||
resized = sd::ops::slice(resized, 0, left, left + new_size.first);
|
|
||||||
}
|
|
||||||
return resized;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::vector<int32_t> build_position_ids(const std::vector<int32_t>& input_ids,
|
|
||||||
const std::vector<std::array<int32_t, 3>>& image_grids,
|
|
||||||
const std::vector<int32_t>& skip_vision_start_token) {
|
|
||||||
std::vector<int32_t> position_ids(4 * input_ids.size(), 0);
|
|
||||||
int image_index = 0;
|
|
||||||
int st = 0;
|
|
||||||
int fix_point = 4096;
|
|
||||||
std::vector<int32_t> out_t;
|
|
||||||
std::vector<int32_t> out_h;
|
|
||||||
std::vector<int32_t> out_w;
|
|
||||||
|
|
||||||
while (st < static_cast<int>(input_ids.size())) {
|
|
||||||
int ed = st;
|
|
||||||
while (ed < static_cast<int>(input_ids.size()) && input_ids[ed] != IMAGE_TOKEN_ID) {
|
|
||||||
ed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ed >= static_cast<int>(input_ids.size())) {
|
|
||||||
int st_idx = out_t.empty() ? 0 : (*std::max_element(out_t.begin(), out_t.end()) + 1);
|
|
||||||
for (int i = 0; i < static_cast<int>(input_ids.size()) - st; ++i) {
|
|
||||||
out_t.push_back(st_idx + i);
|
|
||||||
out_h.push_back(st_idx + i);
|
|
||||||
out_w.push_back(st_idx + i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int text_len = std::max(0, ed - st - skip_vision_start_token[image_index]);
|
|
||||||
int st_idx = out_t.empty() ? 0 : (*std::max_element(out_t.begin(), out_t.end()) + 1);
|
|
||||||
for (int i = 0; i < text_len; ++i) {
|
|
||||||
out_t.push_back(st_idx + i);
|
|
||||||
out_h.push_back(st_idx + i);
|
|
||||||
out_w.push_back(st_idx + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto grid = image_grids[image_index];
|
|
||||||
int base;
|
|
||||||
if (skip_vision_start_token[image_index]) {
|
|
||||||
if (fix_point > 0) {
|
|
||||||
base = fix_point;
|
|
||||||
fix_point = 0;
|
|
||||||
} else {
|
|
||||||
base = st_idx;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
base = text_len + st_idx;
|
|
||||||
}
|
|
||||||
for (int32_t ti = 0; ti < grid[0]; ++ti) {
|
|
||||||
for (int32_t hi = 0; hi < grid[1]; ++hi) {
|
|
||||||
for (int32_t wi = 0; wi < grid[2]; ++wi) {
|
|
||||||
out_t.push_back(base + ti);
|
|
||||||
out_h.push_back(base + hi);
|
|
||||||
out_w.push_back(base + wi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
st = ed + grid[0] * grid[1] * grid[2];
|
|
||||||
image_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
GGML_ASSERT(out_t.size() == input_ids.size());
|
|
||||||
for (size_t i = 0; i < input_ids.size(); ++i) {
|
|
||||||
// ggml IMROPE consumes 4 flattened position streams:
|
|
||||||
// [t, h, w, e]
|
|
||||||
// llama.cpp's generic Qwen-VL fallback expands text positions as
|
|
||||||
// [pos, pos, pos, 0]. Keep the extra stream zeroed here too.
|
|
||||||
position_ids[i] = out_t[i];
|
|
||||||
position_ids[input_ids.size() + i] = out_h[i];
|
|
||||||
position_ids[input_ids.size() * 2 + i] = out_w[i];
|
|
||||||
position_ids[input_ids.size() * 3 + i] = 0;
|
|
||||||
}
|
|
||||||
return position_ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TimestepEmbedder : public GGMLBlock {
|
|
||||||
int frequency_embedding_size = 256;
|
|
||||||
|
|
||||||
TimestepEmbedder(int64_t hidden_size) {
|
|
||||||
blocks["mlp.0"] = std::make_shared<Linear>(frequency_embedding_size, hidden_size, true);
|
|
||||||
blocks["mlp.2"] = std::make_shared<Linear>(hidden_size, hidden_size, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* t) {
|
|
||||||
auto mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["mlp.0"]);
|
|
||||||
auto mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["mlp.2"]);
|
|
||||||
auto emb = ggml_ext_timestep_embedding(ctx->ggml_ctx, t, frequency_embedding_size, 10000, 1000.0f);
|
|
||||||
emb = mlp_0->forward(ctx, emb);
|
|
||||||
emb = ggml_silu_inplace(ctx->ggml_ctx, emb);
|
|
||||||
emb = mlp_2->forward(ctx, emb);
|
|
||||||
return emb;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BottleneckPatchEmbed : public GGMLBlock {
|
|
||||||
BottleneckPatchEmbed(int64_t in_dim, int64_t pca_dim, int64_t embed_dim) {
|
|
||||||
blocks["proj1"] = std::make_shared<Linear>(in_dim, pca_dim, false);
|
|
||||||
blocks["proj2"] = std::make_shared<Linear>(pca_dim, embed_dim, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x) {
|
|
||||||
auto proj1 = std::dynamic_pointer_cast<Linear>(blocks["proj1"]);
|
|
||||||
auto proj2 = std::dynamic_pointer_cast<Linear>(blocks["proj2"]);
|
|
||||||
return proj2->forward(ctx, proj1->forward(ctx, x));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FinalLayer : public GGMLBlock {
|
|
||||||
FinalLayer(int64_t hidden_size, int64_t out_dim) {
|
|
||||||
blocks["linear"] = std::make_shared<Linear>(hidden_size, out_dim, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x) {
|
|
||||||
auto linear = std::dynamic_pointer_cast<Linear>(blocks["linear"]);
|
|
||||||
return linear->forward(ctx, x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HiDreamO1Params {
|
|
||||||
LLM::LLMParams llm;
|
|
||||||
int patch_size = PATCH_SIZE;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline HiDreamO1Params make_hidream_o1_params() {
|
|
||||||
HiDreamO1Params params;
|
|
||||||
params.llm.arch = LLM::LLMArch::QWEN3_VL;
|
|
||||||
params.llm.hidden_size = 4096;
|
|
||||||
params.llm.intermediate_size = 12288;
|
|
||||||
params.llm.num_layers = 36;
|
|
||||||
params.llm.num_heads = 32;
|
|
||||||
params.llm.num_kv_heads = 8;
|
|
||||||
params.llm.head_dim = 128;
|
|
||||||
params.llm.qkv_bias = false;
|
|
||||||
params.llm.qk_norm = true;
|
|
||||||
params.llm.vocab_size = 151936;
|
|
||||||
params.llm.rms_norm_eps = 1e-6f;
|
|
||||||
params.llm.vision.arch = LLM::LLMVisionArch::QWEN3_VL;
|
|
||||||
params.llm.vision.num_layers = 27;
|
|
||||||
params.llm.vision.hidden_size = 1152;
|
|
||||||
params.llm.vision.intermediate_size = 4304;
|
|
||||||
params.llm.vision.num_heads = 16;
|
|
||||||
params.llm.vision.out_hidden_size = 4096;
|
|
||||||
params.llm.vision.patch_size = 16;
|
|
||||||
params.llm.vision.spatial_merge_size = 2;
|
|
||||||
params.llm.vision.temporal_patch_size = 2;
|
|
||||||
params.llm.vision.num_position_embeddings = 2304;
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HiDreamO1Model : public GGMLBlock {
|
|
||||||
HiDreamO1Params params;
|
|
||||||
|
|
||||||
HiDreamO1Model() = default;
|
|
||||||
explicit HiDreamO1Model(HiDreamO1Params params)
|
|
||||||
: params(std::move(params)) {
|
|
||||||
blocks["language_model"] = std::make_shared<LLM::TextModel>(this->params.llm);
|
|
||||||
blocks["t_embedder1"] = std::make_shared<TimestepEmbedder>(this->params.llm.hidden_size);
|
|
||||||
blocks["x_embedder"] = std::make_shared<BottleneckPatchEmbed>(this->params.patch_size * this->params.patch_size * 3,
|
|
||||||
this->params.llm.hidden_size / 4,
|
|
||||||
this->params.llm.hidden_size);
|
|
||||||
blocks["final_layer2"] = std::make_shared<FinalLayer>(this->params.llm.hidden_size,
|
|
||||||
this->params.patch_size * this->params.patch_size * 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<LLM::TextModel> text_model() {
|
|
||||||
return std::dynamic_pointer_cast<LLM::TextModel>(blocks["language_model"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<TimestepEmbedder> timestep_embedder() {
|
|
||||||
return std::dynamic_pointer_cast<TimestepEmbedder>(blocks["t_embedder1"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<BottleneckPatchEmbed> patch_embedder() {
|
|
||||||
return std::dynamic_pointer_cast<BottleneckPatchEmbed>(blocks["x_embedder"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<FinalLayer> final_layer() {
|
|
||||||
return std::dynamic_pointer_cast<FinalLayer>(blocks["final_layer2"]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HiDreamO1VisionRunner : public GGMLRunner {
|
|
||||||
HiDreamO1Params params;
|
|
||||||
std::shared_ptr<LLM::VisionModel> model;
|
|
||||||
|
|
||||||
std::vector<int> window_index_vec;
|
|
||||||
std::vector<int> window_inverse_index_vec;
|
|
||||||
std::vector<float> window_mask_vec;
|
|
||||||
std::vector<float> pe_vec;
|
|
||||||
std::array<std::vector<int32_t>, 4> pos_embed_idx_data_;
|
|
||||||
std::array<std::vector<float>, 4> pos_embed_weight_data_;
|
|
||||||
|
|
||||||
HiDreamO1VisionRunner(ggml_backend_t backend,
|
|
||||||
bool offload_params_to_cpu,
|
|
||||||
const String2TensorStorage& tensor_storage_map = {},
|
|
||||||
const std::string& prefix = "model.visual")
|
|
||||||
: GGMLRunner(backend, offload_params_to_cpu),
|
|
||||||
params(make_hidream_o1_params()),
|
|
||||||
model(std::make_shared<LLM::VisionModel>(false, params.llm.vision)) {
|
|
||||||
model->init(params_ctx, tensor_storage_map, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_desc() override {
|
|
||||||
return "hidream_o1_vision";
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, ggml_tensor*>& tensors, const std::string& prefix = "model.visual") {
|
|
||||||
model->get_param_tensors(tensors, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_tensor* encode_image(GGMLRunnerContext* runner_ctx, ggml_tensor* image) {
|
|
||||||
return LLM::LLMRunner::encode_image_common(this,
|
|
||||||
compute_ctx,
|
|
||||||
runner_ctx,
|
|
||||||
image,
|
|
||||||
params.llm.vision,
|
|
||||||
model,
|
|
||||||
window_index_vec,
|
|
||||||
window_inverse_index_vec,
|
|
||||||
window_mask_vec,
|
|
||||||
pe_vec,
|
|
||||||
pos_embed_idx_data_,
|
|
||||||
pos_embed_weight_data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_cgraph* build_graph(const sd::Tensor<float>& image_tensor) {
|
|
||||||
ggml_cgraph* gf = new_graph_custom(HIDREAM_O1_GRAPH_SIZE);
|
|
||||||
ggml_tensor* image = make_input(image_tensor);
|
|
||||||
auto runner_ctx = get_context();
|
|
||||||
auto image_embeds = encode_image(&runner_ctx, image);
|
|
||||||
ggml_build_forward_expand(gf, image_embeds);
|
|
||||||
return gf;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<float> compute(int n_threads, const sd::Tensor<float>& image) {
|
|
||||||
auto get_graph = [&]() {
|
|
||||||
return build_graph(image);
|
|
||||||
};
|
|
||||||
auto output = GGMLRunner::compute<float>(get_graph, n_threads, false);
|
|
||||||
return output.has_value() ? std::move(output.value()) : sd::Tensor<float>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HiDreamO1Runner : public GGMLRunner {
|
|
||||||
HiDreamO1Params params;
|
|
||||||
HiDreamO1Model model;
|
|
||||||
|
|
||||||
std::vector<float> attention_mask_vec;
|
|
||||||
|
|
||||||
HiDreamO1Runner(ggml_backend_t backend,
|
|
||||||
bool offload_params_to_cpu,
|
|
||||||
const String2TensorStorage& tensor_storage_map = {},
|
|
||||||
const std::string& prefix = "model")
|
|
||||||
: GGMLRunner(backend, offload_params_to_cpu),
|
|
||||||
params(make_hidream_o1_params()) {
|
|
||||||
model = HiDreamO1Model(params);
|
|
||||||
model.init(params_ctx, tensor_storage_map, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_desc() override {
|
|
||||||
return "hidream_o1";
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, ggml_tensor*>& tensors, const std::string& prefix) {
|
|
||||||
model.get_param_tensors(tensors, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_cgraph* build_graph(const sd::Tensor<float>& x_tensor,
|
|
||||||
const sd::Tensor<float>& timestep_tensor,
|
|
||||||
const sd::Tensor<int32_t>& input_ids_tensor,
|
|
||||||
const sd::Tensor<int32_t>& input_pos_tensor,
|
|
||||||
const sd::Tensor<int32_t>& token_types_tensor,
|
|
||||||
const sd::Tensor<int32_t>& vinput_mask_tensor,
|
|
||||||
const std::vector<std::pair<int, sd::Tensor<float>>>& image_embeds_tensor,
|
|
||||||
const std::vector<sd::Tensor<float>>& ref_images) {
|
|
||||||
ggml_cgraph* gf = new_graph_custom(HIDREAM_O1_GRAPH_SIZE);
|
|
||||||
ggml_tensor* x = make_input(x_tensor);
|
|
||||||
ggml_tensor* timestep = make_input(timestep_tensor);
|
|
||||||
ggml_tensor* input_ids = make_input(input_ids_tensor);
|
|
||||||
ggml_tensor* input_pos = make_input(input_pos_tensor);
|
|
||||||
|
|
||||||
auto text_model = model.text_model();
|
|
||||||
auto t_embedder1 = model.timestep_embedder();
|
|
||||||
auto x_embedder = model.patch_embedder();
|
|
||||||
auto final_layer2 = model.final_layer();
|
|
||||||
|
|
||||||
std::vector<ggml_tensor*> ref_image_tensors;
|
|
||||||
for (const auto& image : ref_images) {
|
|
||||||
ref_image_tensors.push_back(make_input(image));
|
|
||||||
}
|
|
||||||
|
|
||||||
attention_mask_vec = std::vector<float>(static_cast<size_t>(token_types_tensor.shape()[0] * token_types_tensor.shape()[0]), 0.0f);
|
|
||||||
int64_t total_seq_len = token_types_tensor.shape()[0];
|
|
||||||
for (int64_t query = 0; query < total_seq_len; ++query) {
|
|
||||||
bool is_gen = token_types_tensor.values()[static_cast<size_t>(query)] > 0;
|
|
||||||
for (int64_t key = 0; key < total_seq_len; ++key) {
|
|
||||||
if (!is_gen && key > query) {
|
|
||||||
attention_mask_vec[static_cast<size_t>(query * total_seq_len + key)] = -INFINITY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto attention_mask = ggml_new_tensor_2d(compute_ctx, GGML_TYPE_F32, total_seq_len, total_seq_len);
|
|
||||||
set_backend_tensor_data(attention_mask, attention_mask_vec.data());
|
|
||||||
|
|
||||||
auto runner_ctx = get_context();
|
|
||||||
auto txt = text_model->embed(&runner_ctx, input_ids);
|
|
||||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds;
|
|
||||||
image_embeds.reserve(image_embeds_tensor.size());
|
|
||||||
for (const auto& image_embed : image_embeds_tensor) {
|
|
||||||
image_embeds.emplace_back(image_embed.first, make_input(image_embed.second));
|
|
||||||
}
|
|
||||||
txt = LLM::splice_image_embeds(&runner_ctx, txt, image_embeds);
|
|
||||||
|
|
||||||
auto t_emb = t_embedder1->forward(&runner_ctx, timestep);
|
|
||||||
int64_t txt_seq_len = input_ids->ne[0];
|
|
||||||
if (txt_seq_len > 1) {
|
|
||||||
auto prefix = ggml_ext_slice(compute_ctx, txt, 1, 0, txt_seq_len - 1);
|
|
||||||
txt = ggml_concat(compute_ctx, prefix, ggml_reshape_3d(compute_ctx, t_emb, t_emb->ne[0], 1, 1), 1);
|
|
||||||
} else {
|
|
||||||
txt = ggml_reshape_3d(compute_ctx, t_emb, t_emb->ne[0], 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vinputs = DiT::pad_and_patchify(&runner_ctx, x, PATCH_SIZE, PATCH_SIZE);
|
|
||||||
int64_t target_tokens = vinputs->ne[1];
|
|
||||||
for (ggml_tensor* ref_image : ref_image_tensors) {
|
|
||||||
auto ref = DiT::pad_and_patchify(&runner_ctx, ref_image, PATCH_SIZE, PATCH_SIZE);
|
|
||||||
vinputs = ggml_concat(compute_ctx, vinputs, ref, 1);
|
|
||||||
}
|
|
||||||
auto vis = x_embedder->forward(&runner_ctx, vinputs);
|
|
||||||
|
|
||||||
auto inputs_embeds = ggml_concat(compute_ctx, txt, vis, 1);
|
|
||||||
auto hidden_states = text_model->forward_embeds(&runner_ctx, inputs_embeds, input_pos, attention_mask, {});
|
|
||||||
auto x_pred_all = final_layer2->forward(&runner_ctx, hidden_states);
|
|
||||||
|
|
||||||
int64_t x_pred_start = txt_seq_len;
|
|
||||||
if (!vinput_mask_tensor.empty()) {
|
|
||||||
int64_t seq_len = static_cast<int64_t>(vinput_mask_tensor.shape()[0]);
|
|
||||||
int64_t first_vinput = 0;
|
|
||||||
while (first_vinput < seq_len && vinput_mask_tensor.values()[static_cast<size_t>(first_vinput)] == 0) {
|
|
||||||
first_vinput++;
|
|
||||||
}
|
|
||||||
x_pred_start = first_vinput;
|
|
||||||
}
|
|
||||||
auto x_pred = ggml_ext_slice(compute_ctx, x_pred_all, 1, x_pred_start, x_pred_start + target_tokens);
|
|
||||||
x_pred = DiT::unpatchify_and_crop(compute_ctx, x_pred, x->ne[1], x->ne[0], PATCH_SIZE, PATCH_SIZE);
|
|
||||||
|
|
||||||
float sigma = 1.0f - timestep_tensor.values()[0];
|
|
||||||
sigma = std::max(1e-6f, sigma);
|
|
||||||
auto out = ggml_scale(compute_ctx, ggml_sub(compute_ctx, x, x_pred), 1.0f / sigma);
|
|
||||||
|
|
||||||
ggml_build_forward_expand(gf, out);
|
|
||||||
return gf;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd::Tensor<float> compute(int n_threads,
|
|
||||||
const sd::Tensor<float>& x,
|
|
||||||
const sd::Tensor<float>& timestep,
|
|
||||||
const sd::Tensor<int32_t>& input_ids,
|
|
||||||
const sd::Tensor<int32_t>& input_pos,
|
|
||||||
const sd::Tensor<int32_t>& token_types,
|
|
||||||
const sd::Tensor<int32_t>& vinput_mask,
|
|
||||||
const std::vector<std::pair<int, sd::Tensor<float>>>& image_embeds,
|
|
||||||
const std::vector<sd::Tensor<float>>& ref_images) {
|
|
||||||
auto get_graph = [&]() {
|
|
||||||
return build_graph(x, timestep, input_ids, input_pos, token_types, vinput_mask, image_embeds, ref_images);
|
|
||||||
};
|
|
||||||
return restore_trailing_singleton_dims(GGMLRunner::compute<float>(get_graph, n_threads, false), x.dim());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HiDreamO1Conditioner : public Conditioner {
|
|
||||||
Qwen2Tokenizer tokenizer;
|
|
||||||
std::shared_ptr<HiDreamO1VisionRunner> vision_runner;
|
|
||||||
|
|
||||||
HiDreamO1Conditioner(ggml_backend_t backend,
|
|
||||||
bool offload_params_to_cpu,
|
|
||||||
const String2TensorStorage& tensor_storage_map = {})
|
|
||||||
: vision_runner(std::make_shared<HiDreamO1VisionRunner>(backend, offload_params_to_cpu, tensor_storage_map)) {}
|
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, ggml_tensor*>& tensors) override {
|
|
||||||
vision_runner->get_param_tensors(tensors);
|
|
||||||
}
|
|
||||||
|
|
||||||
void alloc_params_buffer() override {
|
|
||||||
vision_runner->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_params_buffer() override {
|
|
||||||
vision_runner->free_params_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_params_buffer_size() override {
|
|
||||||
return vision_runner->get_params_buffer_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_max_graph_vram_bytes(size_t max_graph_vram_bytes) override {
|
|
||||||
vision_runner->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_flash_attention_enabled(bool enabled) override {
|
|
||||||
vision_runner->set_flash_attention_enabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
|
||||||
vision_runner->set_weight_adapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDCondition get_learned_condition(int n_threads,
|
|
||||||
const ConditionerParams& conditioner_params) override {
|
|
||||||
SDCondition result;
|
|
||||||
|
|
||||||
int width = conditioner_params.width;
|
|
||||||
int height = conditioner_params.height;
|
|
||||||
int64_t target_image_len = static_cast<int64_t>(width / PATCH_SIZE) * static_cast<int64_t>(height / PATCH_SIZE);
|
|
||||||
|
|
||||||
std::vector<sd::Tensor<float>> ref_images;
|
|
||||||
if (conditioner_params.ref_images != nullptr) {
|
|
||||||
ref_images = *conditioner_params.ref_images;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<int, sd::Tensor<float>>> vlm_images;
|
|
||||||
std::vector<std::array<int32_t, 3>> image_grids;
|
|
||||||
std::vector<int32_t> skip_vision_start;
|
|
||||||
|
|
||||||
std::string prompt = "<|im_start|>user\n";
|
|
||||||
|
|
||||||
if (ref_images.empty()) {
|
|
||||||
prompt += conditioner_params.text;
|
|
||||||
prompt += "<|im_end|>\n<|im_start|>assistant\n<|boi_token|><|tms_token|>";
|
|
||||||
auto input_ids = tokenizer.encode(prompt, nullptr);
|
|
||||||
|
|
||||||
std::vector<int32_t> input_ids_pad = input_ids;
|
|
||||||
input_ids_pad.push_back(VISION_START_TOKEN_ID);
|
|
||||||
input_ids_pad.insert(input_ids_pad.end(), target_image_len - 1, IMAGE_TOKEN_ID);
|
|
||||||
|
|
||||||
image_grids.push_back({1, static_cast<int32_t>(height / PATCH_SIZE), static_cast<int32_t>(width / PATCH_SIZE)});
|
|
||||||
skip_vision_start.push_back(1);
|
|
||||||
|
|
||||||
std::vector<int32_t> token_types(input_ids_pad.size(), 0);
|
|
||||||
int txt_seq_len = static_cast<int>(input_ids.size());
|
|
||||||
int bgn = txt_seq_len - TIMESTEP_TOKEN_NUM;
|
|
||||||
for (int i = bgn; i < static_cast<int>(token_types.size()); ++i) {
|
|
||||||
token_types[i] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto position_ids = build_position_ids(input_ids_pad, image_grids, skip_vision_start);
|
|
||||||
|
|
||||||
std::vector<int64_t> input_shape{static_cast<int64_t>(input_ids.size())};
|
|
||||||
std::vector<int64_t> position_shape{static_cast<int64_t>(input_ids_pad.size() * 4)};
|
|
||||||
std::vector<int64_t> token_type_shape{static_cast<int64_t>(token_types.size())};
|
|
||||||
std::vector<int32_t> vinput_mask(token_types.size(), 0);
|
|
||||||
for (int64_t i = txt_seq_len; i < static_cast<int64_t>(vinput_mask.size()); ++i) {
|
|
||||||
vinput_mask[static_cast<size_t>(i)] = 1;
|
|
||||||
}
|
|
||||||
std::vector<int64_t> vinput_mask_shape{static_cast<int64_t>(vinput_mask.size())};
|
|
||||||
|
|
||||||
result.c_input_ids = sd::Tensor<int32_t>(input_shape, std::move(input_ids));
|
|
||||||
result.c_position_ids = sd::Tensor<int32_t>(position_shape, position_ids);
|
|
||||||
result.c_token_types = sd::Tensor<int32_t>(token_type_shape, std::move(token_types));
|
|
||||||
result.c_vinput_mask = sd::Tensor<int32_t>(vinput_mask_shape, std::move(vinput_mask));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int K = static_cast<int>(ref_images.size());
|
|
||||||
int max_size;
|
|
||||||
if (K == 1) {
|
|
||||||
max_size = std::max(height, width);
|
|
||||||
} else if (K == 2) {
|
|
||||||
max_size = std::max(height, width) * 48 / 64;
|
|
||||||
} else if (K <= 4) {
|
|
||||||
max_size = std::max(height, width) / 2;
|
|
||||||
} else if (K <= 8) {
|
|
||||||
max_size = std::max(height, width) * 24 / 64;
|
|
||||||
} else {
|
|
||||||
max_size = std::max(height, width) / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cond_img_size;
|
|
||||||
if (K <= 4) {
|
|
||||||
cond_img_size = 384;
|
|
||||||
} else if (K <= 8) {
|
|
||||||
cond_img_size = 384 * 48 / 64;
|
|
||||||
} else {
|
|
||||||
cond_img_size = 384 / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& ref_image : ref_images) {
|
|
||||||
auto resized_ref = resize_to_area(ref_image, max_size);
|
|
||||||
resized_ref = sd::ops::clamp(resized_ref, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
// VLM image: Qwen3-VL expects mean=[0.5]/std=[0.5] (i.e. range [-1,1]),
|
|
||||||
// not CLIP normalization. Resize the already-resized ref directly to
|
|
||||||
// (cond_w, cond_h) to match the Python pipeline's pil_r.resize().
|
|
||||||
auto dims = calculate_dimensions(cond_img_size,
|
|
||||||
static_cast<double>(resized_ref.shape()[0]) / static_cast<double>(resized_ref.shape()[1]));
|
|
||||||
sd::Tensor<float> vlm_image = sd::ops::interpolate(
|
|
||||||
resized_ref,
|
|
||||||
{dims.first, dims.second, resized_ref.shape()[2], resized_ref.shape()[3]});
|
|
||||||
vlm_image = vlm_image * 2.0f - 1.0f;
|
|
||||||
int64_t image_tokens = static_cast<int64_t>(dims.first / PATCH_SIZE) * static_cast<int64_t>(dims.second / PATCH_SIZE);
|
|
||||||
|
|
||||||
auto patch_img = resized_ref * 2.0f - 1.0f;
|
|
||||||
result.c_ref_images.push_back(std::move(patch_img));
|
|
||||||
int64_t prompt_start = static_cast<int64_t>(tokenizer.encode(prompt + "<|vision_start|>", nullptr).size());
|
|
||||||
prompt += "<|vision_start|>";
|
|
||||||
prompt += repeat_special_token("<|image_pad|>", image_tokens);
|
|
||||||
prompt += "<|vision_end|>";
|
|
||||||
vlm_images.emplace_back(static_cast<int>(prompt_start), std::move(vlm_image));
|
|
||||||
image_grids.push_back({1, dims.second / PATCH_SIZE, dims.first / PATCH_SIZE});
|
|
||||||
skip_vision_start.push_back(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
prompt += conditioner_params.text;
|
|
||||||
prompt += "<|im_end|>\n<|im_start|>assistant\n<|boi_token|><|tms_token|>";
|
|
||||||
auto input_ids = tokenizer.encode(prompt, nullptr);
|
|
||||||
|
|
||||||
std::vector<int32_t> input_ids_pad = input_ids;
|
|
||||||
input_ids_pad.push_back(VISION_START_TOKEN_ID);
|
|
||||||
input_ids_pad.insert(input_ids_pad.end(), target_image_len - 1, IMAGE_TOKEN_ID);
|
|
||||||
image_grids.push_back({1, static_cast<int32_t>(height / PATCH_SIZE), static_cast<int32_t>(width / PATCH_SIZE)});
|
|
||||||
skip_vision_start.push_back(1);
|
|
||||||
|
|
||||||
for (const auto& ref_image : result.c_ref_images) {
|
|
||||||
int64_t ref_len = static_cast<int64_t>(ref_image.shape()[0] / PATCH_SIZE) * static_cast<int64_t>(ref_image.shape()[1] / PATCH_SIZE);
|
|
||||||
input_ids_pad.push_back(VISION_START_TOKEN_ID);
|
|
||||||
input_ids_pad.insert(input_ids_pad.end(), ref_len - 1, IMAGE_TOKEN_ID);
|
|
||||||
image_grids.push_back({1, static_cast<int32_t>(ref_image.shape()[1] / PATCH_SIZE), static_cast<int32_t>(ref_image.shape()[0] / PATCH_SIZE)});
|
|
||||||
skip_vision_start.push_back(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int32_t> token_types(input_ids_pad.size(), 0);
|
|
||||||
int txt_seq_len = static_cast<int>(input_ids.size());
|
|
||||||
int bgn = txt_seq_len - TIMESTEP_TOKEN_NUM;
|
|
||||||
for (int i = bgn; i < static_cast<int>(token_types.size()); ++i) {
|
|
||||||
token_types[i] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int64_t> input_shape{static_cast<int64_t>(input_ids.size())};
|
|
||||||
std::vector<int64_t> position_shape{static_cast<int64_t>(input_ids_pad.size() * 4)};
|
|
||||||
std::vector<int64_t> token_type_shape{static_cast<int64_t>(token_types.size())};
|
|
||||||
std::vector<int32_t> vinput_mask(token_types.size(), 0);
|
|
||||||
for (int i = txt_seq_len; i < static_cast<int>(vinput_mask.size()); ++i) {
|
|
||||||
vinput_mask[static_cast<size_t>(i)] = 1;
|
|
||||||
}
|
|
||||||
std::vector<int64_t> vinput_mask_shape{static_cast<int64_t>(vinput_mask.size())};
|
|
||||||
|
|
||||||
result.c_input_ids = sd::Tensor<int32_t>(input_shape, std::move(input_ids));
|
|
||||||
result.c_position_ids = sd::Tensor<int32_t>(position_shape, build_position_ids(input_ids_pad, image_grids, skip_vision_start));
|
|
||||||
result.c_token_types = sd::Tensor<int32_t>(token_type_shape, std::move(token_types));
|
|
||||||
result.c_vinput_mask = sd::Tensor<int32_t>(vinput_mask_shape, std::move(vinput_mask));
|
|
||||||
result.c_image_embeds.reserve(vlm_images.size());
|
|
||||||
for (const auto& vlm_image : vlm_images) {
|
|
||||||
auto image_embed = vision_runner->compute(n_threads, vlm_image.second);
|
|
||||||
if (image_embed.empty()) {
|
|
||||||
LOG_ERROR("hidream_o1 conditioner: encode VLM image failed");
|
|
||||||
return SDCondition();
|
|
||||||
}
|
|
||||||
result.c_image_embeds.emplace_back(vlm_image.first, std::move(image_embed));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace HiDreamO1
|
|
||||||
|
|
||||||
#endif // __SD_HIDREAM_O1_H__
|
|
||||||
760
src/llm.hpp
760
src/llm.hpp
File diff suppressed because it is too large
Load Diff
221
src/model.cpp
221
src/model.cpp
@ -437,10 +437,6 @@ SDVersion ModelLoader::get_sd_version() {
|
|||||||
if (tensor_storage.name.find("model.diffusion_model.joint_blocks.") != std::string::npos) {
|
if (tensor_storage.name.find("model.diffusion_model.joint_blocks.") != std::string::npos) {
|
||||||
return VERSION_SD3;
|
return VERSION_SD3;
|
||||||
}
|
}
|
||||||
if (tensor_storage.name.find("model.x_embedder.proj1.weight") != std::string::npos &&
|
|
||||||
tensor_storage_map.find("model.language_model.layers.0.self_attn.q_proj.weight") != tensor_storage_map.end()) {
|
|
||||||
return VERSION_HIDREAM_O1;
|
|
||||||
}
|
|
||||||
if (tensor_storage.name.find("model.diffusion_model.transformer_blocks.0.img_mod.1.weight") != std::string::npos) {
|
if (tensor_storage.name.find("model.diffusion_model.transformer_blocks.0.img_mod.1.weight") != std::string::npos) {
|
||||||
return VERSION_QWEN_IMAGE;
|
return VERSION_QWEN_IMAGE;
|
||||||
}
|
}
|
||||||
@ -737,168 +733,8 @@ void ModelLoader::set_wtype_override(ggml_type wtype, std::string tensor_type_ru
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelLoader::process_model_files(bool enable_mmap, bool writable_mmap) {
|
|
||||||
if (model_files_processed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t start_time = ggml_time_ms();
|
|
||||||
|
|
||||||
std::vector<TensorStorage> processed_tensor_storages;
|
|
||||||
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
|
||||||
if (is_unused_tensor(tensor_storage.name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
processed_tensor_storages.push_back(tensor_storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t file_index = 0; file_index < file_paths_.size(); file_index++) {
|
|
||||||
std::string file_path = file_paths_[file_index];
|
|
||||||
|
|
||||||
std::vector<TensorStorage> file_tensors;
|
|
||||||
for (const auto& ts : processed_tensor_storages) {
|
|
||||||
if (ts.file_index == file_index) {
|
|
||||||
file_tensors.push_back(ts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (file_tensors.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_zip = false;
|
|
||||||
for (auto const& ts : file_tensors) {
|
|
||||||
if (ts.index_in_zip >= 0) {
|
|
||||||
is_zip = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelFileData fdata = {};
|
|
||||||
fdata.path = file_path;
|
|
||||||
fdata.is_zip = is_zip;
|
|
||||||
fdata.tensors = std::move(file_tensors);
|
|
||||||
|
|
||||||
if (enable_mmap && !is_zip) {
|
|
||||||
LOG_DEBUG("using mmap for I/O");
|
|
||||||
std::unique_ptr<MmapWrapper> mmapped = MmapWrapper::create(file_path, writable_mmap);
|
|
||||||
if (mmapped) {
|
|
||||||
uint8_t* mmap_data = static_cast<uint8_t*>(mmapped->writable_data());
|
|
||||||
ggml_backend_buffer_t buf_mmap = ggml_backend_cpu_buffer_from_ptr(mmap_data, mmapped->size());
|
|
||||||
if (buf_mmap) {
|
|
||||||
LOG_INFO("using mmap for '%s'", file_path.c_str());
|
|
||||||
fdata.mmbuffer = std::shared_ptr<struct ggml_backend_buffer>(buf_mmap, ggml_backend_buffer_free);
|
|
||||||
} else {
|
|
||||||
LOG_WARN("mmap: failed to create backend buffer for file %s", fdata.path.c_str());
|
|
||||||
}
|
|
||||||
fdata.mmapped = std::shared_ptr<MmapWrapper>(std::move(mmapped));
|
|
||||||
} else {
|
|
||||||
LOG_WARN("failed to memory-map '%s' (falling back to read())", file_path.c_str());
|
|
||||||
}
|
|
||||||
} else if (!is_zip) {
|
|
||||||
LOG_INFO("NOT using mmap for '%s' (mmap disabled by caller)",
|
|
||||||
file_path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
file_data.push_back(std::move(fdata));
|
|
||||||
}
|
|
||||||
|
|
||||||
model_files_processed = true;
|
|
||||||
|
|
||||||
int64_t end_time = ggml_time_ms();
|
|
||||||
int64_t process_time_ms = end_time - start_time;
|
|
||||||
|
|
||||||
LOG_INFO("model files processing completed in %.2fs", process_time_ms / 1000.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<MmapTensorStore> ModelLoader::mmap_tensors(std::map<std::string, ggml_tensor*>& tensors,
|
|
||||||
std::set<std::string> ignore_tensors,
|
|
||||||
bool writable_mmap) {
|
|
||||||
process_model_files(true, writable_mmap);
|
|
||||||
|
|
||||||
std::vector<MmapTensorStore> result;
|
|
||||||
uint64_t mapped_bytes = 0;
|
|
||||||
size_t mapped_tensors = 0;
|
|
||||||
|
|
||||||
LOG_DEBUG("memory-mapping tensors...");
|
|
||||||
|
|
||||||
int64_t t_start = ggml_time_ms();
|
|
||||||
|
|
||||||
for (auto& fdata : file_data) {
|
|
||||||
if (!fdata.mmbuffer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const std::vector<TensorStorage>& file_tensors = fdata.tensors;
|
|
||||||
|
|
||||||
size_t file_mapped_bytes = 0;
|
|
||||||
size_t file_mapped_tensors = 0;
|
|
||||||
|
|
||||||
for (const auto& tensor_storage : file_tensors) {
|
|
||||||
const std::string& name = tensor_storage.name;
|
|
||||||
|
|
||||||
bool is_ignored = false;
|
|
||||||
for (const auto& ignore_prefix : ignore_tensors) {
|
|
||||||
if (starts_with(name, ignore_prefix)) {
|
|
||||||
is_ignored = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_ignored)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto it = tensors.find(name);
|
|
||||||
if (it == tensors.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ggml_tensor* dst_tensor = it->second;
|
|
||||||
if (dst_tensor == nullptr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tensor_storage.type != dst_tensor->type)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t tensor_size = tensor_storage.nbytes();
|
|
||||||
size_t tensor_offset = tensor_storage.offset;
|
|
||||||
|
|
||||||
if (tensor_storage.ne[0] != dst_tensor->ne[0] ||
|
|
||||||
tensor_storage.ne[1] != dst_tensor->ne[1] ||
|
|
||||||
tensor_storage.ne[2] != dst_tensor->ne[2] ||
|
|
||||||
tensor_storage.ne[3] != dst_tensor->ne[3] ||
|
|
||||||
tensor_size != ggml_nbytes(dst_tensor)) {
|
|
||||||
// let load_tensors worry about this
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ggml_backend_buffer_t buf_mmap = fdata.mmbuffer.get();
|
|
||||||
uint8_t* mmap_data = static_cast<uint8_t*>(ggml_backend_buffer_get_base(buf_mmap));
|
|
||||||
dst_tensor->buffer = buf_mmap;
|
|
||||||
dst_tensor->data = mmap_data + tensor_offset;
|
|
||||||
|
|
||||||
file_mapped_bytes += tensor_size;
|
|
||||||
file_mapped_tensors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_mapped_bytes > 0) {
|
|
||||||
mapped_tensors += file_mapped_tensors;
|
|
||||||
mapped_bytes += file_mapped_bytes;
|
|
||||||
result.push_back({fdata.mmapped, fdata.mmbuffer});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t t_end = ggml_time_ms();
|
|
||||||
int64_t duration_ms = t_end - t_start;
|
|
||||||
|
|
||||||
LOG_INFO("memory-mapped %zu tensors in %zu files (%.2f MB), taking %.2fs",
|
|
||||||
mapped_tensors,
|
|
||||||
result.size(),
|
|
||||||
mapped_bytes / (1024.0 * 1024.0),
|
|
||||||
duration_ms / 1000.0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads_p, bool enable_mmap) {
|
bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads_p, bool enable_mmap) {
|
||||||
process_model_files(enable_mmap, false);
|
int64_t process_time_ms = 0;
|
||||||
|
|
||||||
std::atomic<int64_t> read_time_ms(0);
|
std::atomic<int64_t> read_time_ms(0);
|
||||||
std::atomic<int64_t> memcpy_time_ms(0);
|
std::atomic<int64_t> memcpy_time_ms(0);
|
||||||
std::atomic<int64_t> copy_to_backend_time_ms(0);
|
std::atomic<int64_t> copy_to_backend_time_ms(0);
|
||||||
@ -910,25 +746,52 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
|
|
||||||
int64_t start_time = ggml_time_ms();
|
int64_t start_time = ggml_time_ms();
|
||||||
|
|
||||||
size_t total_tensors_to_process = 0;
|
std::vector<TensorStorage> processed_tensor_storages;
|
||||||
for (const auto& fdata : file_data) {
|
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
||||||
total_tensors_to_process += fdata.tensors.size();
|
if (is_unused_tensor(tensor_storage.name)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
processed_tensor_storages.push_back(tensor_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_time_ms = ggml_time_ms() - start_time;
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
size_t total_tensors_processed = 0;
|
size_t total_tensors_processed = 0;
|
||||||
const int64_t t_start = start_time;
|
const size_t total_tensors_to_process = processed_tensor_storages.size();
|
||||||
|
const int64_t t_start = ggml_time_ms();
|
||||||
int last_n_threads = 1;
|
int last_n_threads = 1;
|
||||||
|
|
||||||
for (auto& fdata : file_data) {
|
for (size_t file_index = 0; file_index < file_paths_.size(); file_index++) {
|
||||||
const std::string& file_path = fdata.path;
|
std::string file_path = file_paths_[file_index];
|
||||||
LOG_DEBUG("loading tensors from %s", file_path.c_str());
|
LOG_DEBUG("loading tensors from %s", file_path.c_str());
|
||||||
|
|
||||||
const std::vector<TensorStorage>& file_tensors = fdata.tensors;
|
std::vector<const TensorStorage*> file_tensors;
|
||||||
|
for (const auto& ts : processed_tensor_storages) {
|
||||||
|
if (ts.file_index == file_index) {
|
||||||
|
file_tensors.push_back(&ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file_tensors.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_zip = fdata.is_zip;
|
bool is_zip = false;
|
||||||
|
for (auto const& ts : file_tensors) {
|
||||||
|
if (ts->index_in_zip >= 0) {
|
||||||
|
is_zip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<MmapWrapper> mmapped = fdata.mmapped;
|
std::unique_ptr<MmapWrapper> mmapped;
|
||||||
|
if (enable_mmap && !is_zip) {
|
||||||
|
LOG_DEBUG("using mmap for I/O");
|
||||||
|
mmapped = MmapWrapper::create(file_path);
|
||||||
|
if (!mmapped) {
|
||||||
|
LOG_WARN("failed to memory-map '%s'", file_path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int n_threads = is_zip ? 1 : std::min(num_threads_to_use, (int)file_tensors.size());
|
int n_threads = is_zip ? 1 : std::min(num_threads_to_use, (int)file_tensors.size());
|
||||||
if (n_threads < 1) {
|
if (n_threads < 1) {
|
||||||
@ -970,7 +833,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TensorStorage& tensor_storage = file_tensors[idx];
|
const TensorStorage& tensor_storage = *file_tensors[idx];
|
||||||
ggml_tensor* dst_tensor = nullptr;
|
ggml_tensor* dst_tensor = nullptr;
|
||||||
|
|
||||||
t0 = ggml_time_ms();
|
t0 = ggml_time_ms();
|
||||||
@ -987,11 +850,6 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip mmapped tensors
|
|
||||||
if (dst_tensor->buffer != nullptr && dst_tensor->buffer == fdata.mmbuffer.get()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t nbytes_to_read = tensor_storage.nbytes_to_read();
|
size_t nbytes_to_read = tensor_storage.nbytes_to_read();
|
||||||
|
|
||||||
auto read_data = [&](char* buf, size_t n) {
|
auto read_data = [&](char* buf, size_t n) {
|
||||||
@ -1135,8 +993,9 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t end_time = ggml_time_ms();
|
int64_t end_time = ggml_time_ms();
|
||||||
LOG_INFO("loading tensors completed, taking %.2fs (read: %.2fs, memcpy: %.2fs, convert: %.2fs, copy_to_backend: %.2fs)",
|
LOG_INFO("loading tensors completed, taking %.2fs (process: %.2fs, read: %.2fs, memcpy: %.2fs, convert: %.2fs, copy_to_backend: %.2fs)",
|
||||||
(end_time - start_time) / 1000.f,
|
(end_time - start_time) / 1000.f,
|
||||||
|
process_time_ms / 1000.f,
|
||||||
(read_time_ms.load() / (float)last_n_threads) / 1000.f,
|
(read_time_ms.load() / (float)last_n_threads) / 1000.f,
|
||||||
(memcpy_time_ms.load() / (float)last_n_threads) / 1000.f,
|
(memcpy_time_ms.load() / (float)last_n_threads) / 1000.f,
|
||||||
(convert_time_ms.load() / (float)last_n_threads) / 1000.f,
|
(convert_time_ms.load() / (float)last_n_threads) / 1000.f,
|
||||||
|
|||||||
23
src/model.h
23
src/model.h
@ -43,7 +43,6 @@ enum SDVersion {
|
|||||||
VERSION_FLUX2,
|
VERSION_FLUX2,
|
||||||
VERSION_FLUX2_KLEIN,
|
VERSION_FLUX2_KLEIN,
|
||||||
VERSION_LTXAV,
|
VERSION_LTXAV,
|
||||||
VERSION_HIDREAM_O1,
|
|
||||||
VERSION_Z_IMAGE,
|
VERSION_Z_IMAGE,
|
||||||
VERSION_OVIS_IMAGE,
|
VERSION_OVIS_IMAGE,
|
||||||
VERSION_ERNIE_IMAGE,
|
VERSION_ERNIE_IMAGE,
|
||||||
@ -173,7 +172,6 @@ static inline bool sd_version_is_dit(SDVersion version) {
|
|||||||
sd_version_is_sd3(version) ||
|
sd_version_is_sd3(version) ||
|
||||||
sd_version_is_wan(version) ||
|
sd_version_is_wan(version) ||
|
||||||
sd_version_is_qwen_image(version) ||
|
sd_version_is_qwen_image(version) ||
|
||||||
version == VERSION_HIDREAM_O1 ||
|
|
||||||
sd_version_is_anima(version) ||
|
sd_version_is_anima(version) ||
|
||||||
sd_version_is_z_image(version) ||
|
sd_version_is_z_image(version) ||
|
||||||
sd_version_is_ernie_image(version)) {
|
sd_version_is_ernie_image(version)) {
|
||||||
@ -204,27 +202,10 @@ using TensorTypeRules = std::vector<std::pair<std::string, ggml_type>>;
|
|||||||
|
|
||||||
TensorTypeRules parse_tensor_type_rules(const std::string& tensor_type_rules);
|
TensorTypeRules parse_tensor_type_rules(const std::string& tensor_type_rules);
|
||||||
|
|
||||||
class MmapWrapper;
|
|
||||||
|
|
||||||
struct ModelFileData {
|
|
||||||
std::string path;
|
|
||||||
std::vector<TensorStorage> tensors;
|
|
||||||
std::shared_ptr<MmapWrapper> mmapped;
|
|
||||||
std::shared_ptr<struct ggml_backend_buffer> mmbuffer;
|
|
||||||
bool is_zip;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MmapTensorStore {
|
|
||||||
std::shared_ptr<MmapWrapper> mmapped;
|
|
||||||
std::shared_ptr<struct ggml_backend_buffer> mmbuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModelLoader {
|
class ModelLoader {
|
||||||
protected:
|
protected:
|
||||||
SDVersion version_ = VERSION_COUNT;
|
SDVersion version_ = VERSION_COUNT;
|
||||||
std::vector<std::string> file_paths_;
|
std::vector<std::string> file_paths_;
|
||||||
std::vector<ModelFileData> file_data;
|
|
||||||
bool model_files_processed = false;
|
|
||||||
String2TensorStorage tensor_storage_map;
|
String2TensorStorage tensor_storage_map;
|
||||||
|
|
||||||
void add_tensor_storage(const TensorStorage& tensor_storage);
|
void add_tensor_storage(const TensorStorage& tensor_storage);
|
||||||
@ -248,10 +229,6 @@ public:
|
|||||||
std::map<ggml_type, uint32_t> get_vae_wtype_stat();
|
std::map<ggml_type, uint32_t> get_vae_wtype_stat();
|
||||||
String2TensorStorage& get_tensor_storage_map() { return tensor_storage_map; }
|
String2TensorStorage& get_tensor_storage_map() { return tensor_storage_map; }
|
||||||
void set_wtype_override(ggml_type wtype, std::string tensor_type_rules = "");
|
void set_wtype_override(ggml_type wtype, std::string tensor_type_rules = "");
|
||||||
void process_model_files(bool enable_mmap = false, bool writable_mmap = true);
|
|
||||||
std::vector<MmapTensorStore> mmap_tensors(std::map<std::string, ggml_tensor*>& tensors,
|
|
||||||
std::set<std::string> ignore_tensors = {},
|
|
||||||
bool writable = true);
|
|
||||||
bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads = 0, bool use_mmap = false);
|
bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads = 0, bool use_mmap = false);
|
||||||
bool load_tensors(std::map<std::string, ggml_tensor*>& tensors,
|
bool load_tensors(std::map<std::string, ggml_tensor*>& tensors,
|
||||||
std::set<std::string> ignore_tensors = {},
|
std::set<std::string> ignore_tensors = {},
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "ggml_extend.hpp"
|
#include "ggml_extend.hpp"
|
||||||
#include "ggml_graph_cut.h"
|
|
||||||
|
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "rng.hpp"
|
#include "rng.hpp"
|
||||||
@ -56,7 +55,6 @@ const char* model_version_to_str[] = {
|
|||||||
"Flux.2",
|
"Flux.2",
|
||||||
"Flux.2 klein",
|
"Flux.2 klein",
|
||||||
"LTXAV",
|
"LTXAV",
|
||||||
"HiDream O1",
|
|
||||||
"Z-Image",
|
"Z-Image",
|
||||||
"Ovis Image",
|
"Ovis Image",
|
||||||
"Ernie Image",
|
"Ernie Image",
|
||||||
@ -78,8 +76,6 @@ const char* sampling_methods_str[] = {
|
|||||||
"Res Multistep",
|
"Res Multistep",
|
||||||
"Res 2s",
|
"Res 2s",
|
||||||
"ER-SDE",
|
"ER-SDE",
|
||||||
"Euler CFG++",
|
|
||||||
"Euler A CFG++",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*================================================== Helper Functions ================================================*/
|
/*================================================== Helper Functions ================================================*/
|
||||||
@ -115,7 +111,6 @@ static float get_cache_reuse_threshold(const sd_cache_params_t& params) {
|
|||||||
|
|
||||||
class StableDiffusionGGML {
|
class StableDiffusionGGML {
|
||||||
public:
|
public:
|
||||||
std::vector<MmapTensorStore> mmap_tensor_store;
|
|
||||||
ggml_backend_t backend = nullptr; // general backend
|
ggml_backend_t backend = nullptr; // general backend
|
||||||
ggml_backend_t clip_backend = nullptr;
|
ggml_backend_t clip_backend = nullptr;
|
||||||
ggml_backend_t control_net_backend = nullptr;
|
ggml_backend_t control_net_backend = nullptr;
|
||||||
@ -219,7 +214,6 @@ public:
|
|||||||
ggml_log_set(ggml_log_callback_default, nullptr);
|
ggml_log_set(ggml_log_callback_default, nullptr);
|
||||||
|
|
||||||
init_backend();
|
init_backend();
|
||||||
max_vram = sd::ggml_graph_cut::resolve_max_vram_gib(max_vram, backend);
|
|
||||||
|
|
||||||
ModelLoader model_loader;
|
ModelLoader model_loader;
|
||||||
|
|
||||||
@ -391,51 +385,6 @@ public:
|
|||||||
apply_lora_immediately = false;
|
apply_lora_immediately = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, ggml_tensor*> mmap_able_tensors;
|
|
||||||
bool enable_mmap_tensors = false;
|
|
||||||
bool main_backend_mmap = false;
|
|
||||||
bool needs_writable_mmap = false;
|
|
||||||
if (sd_ctx_params->enable_mmap) {
|
|
||||||
if (apply_lora_immediately) {
|
|
||||||
needs_writable_mmap = true;
|
|
||||||
LOG_WARN("in mode 'immediately', LoRAs will cause extra memory usage with mmap");
|
|
||||||
}
|
|
||||||
enable_mmap_tensors = true;
|
|
||||||
if (offload_params_to_cpu) {
|
|
||||||
main_backend_mmap = true;
|
|
||||||
} else {
|
|
||||||
ggml_backend_dev_t dev = ggml_backend_get_device(backend);
|
|
||||||
struct ggml_backend_dev_props props;
|
|
||||||
ggml_backend_dev_get_props(dev, &props);
|
|
||||||
main_backend_mmap = props.caps.buffer_from_host_ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// split definition to avoid msvc choking on the extra parameter handling
|
|
||||||
auto get_param_tensors_p = [&](auto&& model, bool force_cpu, const char* prefix) {
|
|
||||||
std::map<std::string, ggml_tensor*> temp;
|
|
||||||
model->get_param_tensors(temp, prefix);
|
|
||||||
bool do_mmap = enable_mmap_tensors && (main_backend_mmap || force_cpu);
|
|
||||||
for (const auto& [key, tensor] : temp) {
|
|
||||||
tensors[key] = tensor;
|
|
||||||
if (do_mmap) {
|
|
||||||
mmap_able_tensors[key] = tensor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto get_param_tensors = [&](auto&& model, bool force_cpu = false) {
|
|
||||||
std::map<std::string, ggml_tensor*> temp;
|
|
||||||
model->get_param_tensors(temp);
|
|
||||||
bool do_mmap = enable_mmap_tensors && (main_backend_mmap || force_cpu);
|
|
||||||
for (const auto& [key, tensor] : temp) {
|
|
||||||
tensors[key] = tensor;
|
|
||||||
if (do_mmap) {
|
|
||||||
mmap_able_tensors[key] = tensor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sd_version_is_control(version)) {
|
if (sd_version_is_control(version)) {
|
||||||
// Might need vae encode for control cond
|
// Might need vae encode for control cond
|
||||||
vae_decode_only = false;
|
vae_decode_only = false;
|
||||||
@ -456,7 +405,9 @@ public:
|
|||||||
|
|
||||||
bool clip_on_cpu = sd_ctx_params->keep_clip_on_cpu;
|
bool clip_on_cpu = sd_ctx_params->keep_clip_on_cpu;
|
||||||
|
|
||||||
const size_t max_graph_vram_bytes = sd::ggml_graph_cut::max_vram_gib_to_bytes(max_vram);
|
const size_t max_graph_vram_bytes = max_vram <= 0.f
|
||||||
|
? 0
|
||||||
|
: static_cast<size_t>(static_cast<double>(max_vram) * 1024.0 * 1024.0 * 1024.0);
|
||||||
|
|
||||||
{
|
{
|
||||||
clip_backend = backend;
|
clip_backend = backend;
|
||||||
@ -556,7 +507,8 @@ public:
|
|||||||
offload_params_to_cpu,
|
offload_params_to_cpu,
|
||||||
tensor_storage_map);
|
tensor_storage_map);
|
||||||
clip_vision->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
clip_vision->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors(clip_vision);
|
clip_vision->alloc_params_buffer();
|
||||||
|
clip_vision->get_param_tensors(tensors);
|
||||||
}
|
}
|
||||||
} else if (sd_version_is_qwen_image(version)) {
|
} else if (sd_version_is_qwen_image(version)) {
|
||||||
bool enable_vision = false;
|
bool enable_vision = false;
|
||||||
@ -575,14 +527,6 @@ public:
|
|||||||
"model.diffusion_model",
|
"model.diffusion_model",
|
||||||
version,
|
version,
|
||||||
sd_ctx_params->qwen_image_zero_cond_t);
|
sd_ctx_params->qwen_image_zero_cond_t);
|
||||||
} else if (version == VERSION_HIDREAM_O1) {
|
|
||||||
cond_stage_model = std::make_shared<HiDreamO1::HiDreamO1Conditioner>(clip_backend,
|
|
||||||
offload_params_to_cpu,
|
|
||||||
tensor_storage_map);
|
|
||||||
diffusion_model = std::make_shared<HiDreamO1Model>(backend,
|
|
||||||
offload_params_to_cpu,
|
|
||||||
tensor_storage_map,
|
|
||||||
"model");
|
|
||||||
} else if (sd_version_is_anima(version)) {
|
} else if (sd_version_is_anima(version)) {
|
||||||
cond_stage_model = std::make_shared<AnimaConditioner>(clip_backend,
|
cond_stage_model = std::make_shared<AnimaConditioner>(clip_backend,
|
||||||
offload_params_to_cpu,
|
offload_params_to_cpu,
|
||||||
@ -640,10 +584,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
cond_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
cond_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors(cond_stage_model, clip_on_cpu);
|
cond_stage_model->alloc_params_buffer();
|
||||||
|
cond_stage_model->get_param_tensors(tensors);
|
||||||
|
|
||||||
diffusion_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
diffusion_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors(diffusion_model);
|
diffusion_model->alloc_params_buffer();
|
||||||
|
diffusion_model->get_param_tensors(tensors);
|
||||||
|
|
||||||
if (sd_version_is_unet_edit(version)) {
|
if (sd_version_is_unet_edit(version)) {
|
||||||
vae_decode_only = false;
|
vae_decode_only = false;
|
||||||
@ -651,7 +597,8 @@ public:
|
|||||||
|
|
||||||
if (high_noise_diffusion_model) {
|
if (high_noise_diffusion_model) {
|
||||||
high_noise_diffusion_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
high_noise_diffusion_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors(high_noise_diffusion_model);
|
high_noise_diffusion_model->alloc_params_buffer();
|
||||||
|
high_noise_diffusion_model->get_param_tensors(tensors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sd_ctx_params->keep_vae_on_cpu && !ggml_backend_is_cpu(backend)) {
|
if (sd_ctx_params->keep_vae_on_cpu && !ggml_backend_is_cpu(backend)) {
|
||||||
@ -721,9 +668,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool force_vae_cpu = sd_ctx_params->keep_vae_on_cpu;
|
if (version == VERSION_CHROMA_RADIANCE) {
|
||||||
|
|
||||||
if (version == VERSION_CHROMA_RADIANCE || version == VERSION_HIDREAM_O1) {
|
|
||||||
LOG_INFO("using FakeVAE");
|
LOG_INFO("using FakeVAE");
|
||||||
first_stage_model = std::make_shared<FakeVAE>(version,
|
first_stage_model = std::make_shared<FakeVAE>(version,
|
||||||
vae_backend,
|
vae_backend,
|
||||||
@ -732,17 +677,20 @@ public:
|
|||||||
LOG_INFO("using TAE for encoding / decoding");
|
LOG_INFO("using TAE for encoding / decoding");
|
||||||
first_stage_model = create_tae();
|
first_stage_model = create_tae();
|
||||||
first_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
first_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors_p(first_stage_model, force_vae_cpu, "tae");
|
first_stage_model->alloc_params_buffer();
|
||||||
|
first_stage_model->get_param_tensors(tensors, "tae");
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("using VAE for encoding / decoding");
|
LOG_INFO("using VAE for encoding / decoding");
|
||||||
first_stage_model = create_vae();
|
first_stage_model = create_vae();
|
||||||
first_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
first_stage_model->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors_p(first_stage_model, force_vae_cpu, "first_stage_model");
|
first_stage_model->alloc_params_buffer();
|
||||||
|
first_stage_model->get_param_tensors(tensors, "first_stage_model");
|
||||||
if (use_tae && tae_preview_only) {
|
if (use_tae && tae_preview_only) {
|
||||||
LOG_INFO("using TAE for preview");
|
LOG_INFO("using TAE for preview");
|
||||||
preview_vae = create_tae();
|
preview_vae = create_tae();
|
||||||
preview_vae->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
preview_vae->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
get_param_tensors_p(first_stage_model, force_vae_cpu, "vae");
|
preview_vae->alloc_params_buffer();
|
||||||
|
preview_vae->get_param_tensors(tensors, "tae");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,7 +769,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (use_pmid) {
|
if (use_pmid) {
|
||||||
get_param_tensors_p(pmid_model, false, "pmid");
|
if (!pmid_model->alloc_params_buffer()) {
|
||||||
|
LOG_ERROR(" pmid model params buffer allocation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pmid_model->get_param_tensors(tensors, "pmid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sd_ctx_params->flash_attn) {
|
if (sd_ctx_params->flash_attn) {
|
||||||
@ -904,45 +856,6 @@ public:
|
|||||||
ignore_tensors.insert("text_encoders.llm.vision_tower.");
|
ignore_tensors.insert("text_encoders.llm.vision_tower.");
|
||||||
ignore_tensors.insert("text_encoders.llm.multi_modal_projector.");
|
ignore_tensors.insert("text_encoders.llm.multi_modal_projector.");
|
||||||
}
|
}
|
||||||
if (version == VERSION_HIDREAM_O1) {
|
|
||||||
ignore_tensors.insert("lm_head.");
|
|
||||||
ignore_tensors.insert("model.visual.deepstack_merger_list.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable_mmap_tensors) {
|
|
||||||
if (mmap_able_tensors.empty()) {
|
|
||||||
LOG_DEBUG("no tensors could be memory-mapped");
|
|
||||||
} else {
|
|
||||||
mmap_tensor_store = model_loader.mmap_tensors(mmap_able_tensors, ignore_tensors, needs_writable_mmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clip_vision) {
|
|
||||||
clip_vision->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (cond_stage_model) {
|
|
||||||
cond_stage_model->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (diffusion_model) {
|
|
||||||
diffusion_model->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (high_noise_diffusion_model) {
|
|
||||||
high_noise_diffusion_model->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (first_stage_model) {
|
|
||||||
first_stage_model->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (preview_vae) {
|
|
||||||
preview_vae->alloc_params_buffer();
|
|
||||||
}
|
|
||||||
if (use_pmid && pmid_model) {
|
|
||||||
if (!pmid_model->alloc_params_buffer()) {
|
|
||||||
LOG_ERROR(" pmid model params buffer allocation failed");
|
|
||||||
ggml_free(ctx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = model_loader.load_tensors(tensors, ignore_tensors, n_threads, sd_ctx_params->enable_mmap);
|
bool success = model_loader.load_tensors(tensors, ignore_tensors, n_threads, sd_ctx_params->enable_mmap);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
LOG_ERROR("load tensors from model loader failed");
|
LOG_ERROR("load tensors from model loader failed");
|
||||||
@ -1049,7 +962,6 @@ public:
|
|||||||
sd_version_is_ltxav(version) ||
|
sd_version_is_ltxav(version) ||
|
||||||
sd_version_is_wan(version) ||
|
sd_version_is_wan(version) ||
|
||||||
sd_version_is_qwen_image(version) ||
|
sd_version_is_qwen_image(version) ||
|
||||||
version == VERSION_HIDREAM_O1 ||
|
|
||||||
sd_version_is_anima(version) ||
|
sd_version_is_anima(version) ||
|
||||||
sd_version_is_ernie_image(version) ||
|
sd_version_is_ernie_image(version) ||
|
||||||
sd_version_is_z_image(version)) {
|
sd_version_is_z_image(version)) {
|
||||||
@ -1656,9 +1568,6 @@ public:
|
|||||||
if (sd_version_is_anima(version)) {
|
if (sd_version_is_anima(version)) {
|
||||||
return std::vector<float>{t / static_cast<float>(TIMESTEPS)};
|
return std::vector<float>{t / static_cast<float>(TIMESTEPS)};
|
||||||
}
|
}
|
||||||
if (version == VERSION_HIDREAM_O1) {
|
|
||||||
return std::vector<float>{1.0f - (t / static_cast<float>(TIMESTEPS))};
|
|
||||||
}
|
|
||||||
if (sd_version_is_z_image(version)) {
|
if (sd_version_is_z_image(version)) {
|
||||||
return std::vector<float>{1000.f - t};
|
return std::vector<float>{1000.f - t};
|
||||||
}
|
}
|
||||||
@ -1747,7 +1656,6 @@ public:
|
|||||||
int shifted_timestep,
|
int shifted_timestep,
|
||||||
sample_method_t method,
|
sample_method_t method,
|
||||||
bool is_flow_denoiser,
|
bool is_flow_denoiser,
|
||||||
const char* extra_sample_args,
|
|
||||||
const std::vector<float>& sigmas,
|
const std::vector<float>& sigmas,
|
||||||
int start_merge_step,
|
int start_merge_step,
|
||||||
const std::vector<sd::Tensor<float>>& ref_latents,
|
const std::vector<sd::Tensor<float>>& ref_latents,
|
||||||
@ -1766,15 +1674,6 @@ public:
|
|||||||
cache_params,
|
cache_params,
|
||||||
denoiser.get(),
|
denoiser.get(),
|
||||||
sigmas);
|
sigmas);
|
||||||
|
|
||||||
// Spectrum cache is not supported for CFG++ samplers
|
|
||||||
if (method == EULER_CFG_PP_SAMPLE_METHOD || method == EULER_A_CFG_PP_SAMPLE_METHOD) {
|
|
||||||
if (cache_runtime.spectrum_enabled) {
|
|
||||||
LOG_WARN("Spectrum cache requested but not supported for CFG++ samplers");
|
|
||||||
cache_runtime.spectrum_enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t steps = sigmas.size() - 1;
|
size_t steps = sigmas.size() - 1;
|
||||||
bool has_skiplayer = slg_scale != 0.0f && !skip_layers.empty();
|
bool has_skiplayer = slg_scale != 0.0f && !skip_layers.empty();
|
||||||
if (has_skiplayer && !sd_version_is_dit(version)) {
|
if (has_skiplayer && !sd_version_is_dit(version)) {
|
||||||
@ -1782,10 +1681,6 @@ public:
|
|||||||
LOG_WARN("SLG is incompatible with this model type");
|
LOG_WARN("SLG is incompatible with this model type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version == VERSION_HIDREAM_O1 && !noise.empty()) {
|
|
||||||
noise *= eta;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t t0 = ggml_time_us();
|
int64_t t0 = ggml_time_us();
|
||||||
sd::Tensor<float> x_t = !noise.empty()
|
sd::Tensor<float> x_t = !noise.empty()
|
||||||
? denoiser->noise_scaling(sigmas[0], noise, init_latent)
|
? denoiser->noise_scaling(sigmas[0], noise, init_latent)
|
||||||
@ -1793,7 +1688,7 @@ public:
|
|||||||
sd::Tensor<float> denoised = x_t;
|
sd::Tensor<float> denoised = x_t;
|
||||||
SamplePreviewContext preview = prepare_sample_preview_context();
|
SamplePreviewContext preview = prepare_sample_preview_context();
|
||||||
|
|
||||||
auto denoise = [&](const sd::Tensor<float>& x, float sigma, int step, sd::Tensor<float>* out_uncond_denoised = nullptr) -> sd::Tensor<float> {
|
auto denoise = [&](const sd::Tensor<float>& x, float sigma, int step) -> sd::Tensor<float> {
|
||||||
if (step == 1 || step == -1) {
|
if (step == 1 || step == -1) {
|
||||||
pretty_progress(0, (int)steps, 0);
|
pretty_progress(0, (int)steps, 0);
|
||||||
}
|
}
|
||||||
@ -1816,7 +1711,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cache_runtime.spectrum_enabled && cache_runtime.spectrum.should_predict()) {
|
if (cache_runtime.spectrum_enabled && cache_runtime.spectrum.should_predict()) {
|
||||||
if (out_uncond_denoised == nullptr) {
|
|
||||||
cache_runtime.spectrum.predict(&denoised);
|
cache_runtime.spectrum.predict(&denoised);
|
||||||
if (!denoise_mask.empty()) {
|
if (!denoise_mask.empty()) {
|
||||||
denoised = denoised * denoise_mask + init_latent * (1.0f - denoise_mask);
|
denoised = denoised * denoise_mask + init_latent * (1.0f - denoise_mask);
|
||||||
@ -1827,7 +1721,6 @@ public:
|
|||||||
report_sample_progress(step, steps, t0);
|
report_sample_progress(step, steps, t0);
|
||||||
return denoised;
|
return denoised;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sd_should_preview_noisy() && preview.callback != nullptr) {
|
if (sd_should_preview_noisy() && preview.callback != nullptr) {
|
||||||
preview_image(step, noised_input, version, preview.mode, preview.callback, preview.data, true);
|
preview_image(step, noised_input, version, preview.mode, preview.callback, preview.data, true);
|
||||||
@ -1866,12 +1759,6 @@ public:
|
|||||||
diffusion_params.y = condition.c_vector.empty() ? nullptr : &condition.c_vector;
|
diffusion_params.y = condition.c_vector.empty() ? nullptr : &condition.c_vector;
|
||||||
diffusion_params.t5_ids = condition.c_t5_ids.empty() ? nullptr : &condition.c_t5_ids;
|
diffusion_params.t5_ids = condition.c_t5_ids.empty() ? nullptr : &condition.c_t5_ids;
|
||||||
diffusion_params.t5_weights = condition.c_t5_weights.empty() ? nullptr : &condition.c_t5_weights;
|
diffusion_params.t5_weights = condition.c_t5_weights.empty() ? nullptr : &condition.c_t5_weights;
|
||||||
diffusion_params.input_ids = condition.c_input_ids.empty() ? nullptr : &condition.c_input_ids;
|
|
||||||
diffusion_params.input_pos = condition.c_position_ids.empty() ? nullptr : &condition.c_position_ids;
|
|
||||||
diffusion_params.token_types = condition.c_token_types.empty() ? nullptr : &condition.c_token_types;
|
|
||||||
diffusion_params.vinput_mask = condition.c_vinput_mask.empty() ? nullptr : &condition.c_vinput_mask;
|
|
||||||
diffusion_params.image_embeds = condition.c_image_embeds.empty() ? nullptr : &condition.c_image_embeds;
|
|
||||||
diffusion_params.ref_latents = condition.c_ref_images.empty() ? &ref_latents : &condition.c_ref_images;
|
|
||||||
diffusion_params.skip_layers = local_skip_layers;
|
diffusion_params.skip_layers = local_skip_layers;
|
||||||
|
|
||||||
sd::Tensor<float> cached_output;
|
sd::Tensor<float> cached_output;
|
||||||
@ -1956,10 +1843,6 @@ public:
|
|||||||
latent_result += (cond_out - skip_cond_out) * slg_scale;
|
latent_result += (cond_out - skip_cond_out) * slg_scale;
|
||||||
}
|
}
|
||||||
denoised = latent_result * c_out + x * c_skip;
|
denoised = latent_result * c_out + x * c_skip;
|
||||||
if (out_uncond_denoised != nullptr) {
|
|
||||||
sd::Tensor<float> base_uncond = !uncond_out.empty() ? uncond_out : cond_out;
|
|
||||||
*out_uncond_denoised = base_uncond * c_out + x * c_skip;
|
|
||||||
}
|
|
||||||
if (cache_runtime.spectrum_enabled) {
|
if (cache_runtime.spectrum_enabled) {
|
||||||
cache_runtime.spectrum.update(denoised);
|
cache_runtime.spectrum.update(denoised);
|
||||||
}
|
}
|
||||||
@ -1973,7 +1856,7 @@ public:
|
|||||||
return denoised;
|
return denoised;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto x0_opt = sample_k_diffusion(method, denoise, x_t, sigmas, sampler_rng, eta, is_flow_denoiser, extra_sample_args);
|
auto x0_opt = sample_k_diffusion(method, denoise, x_t, sigmas, sampler_rng, eta, is_flow_denoiser);
|
||||||
if (x0_opt.empty()) {
|
if (x0_opt.empty()) {
|
||||||
LOG_ERROR("Diffusion model sampling failed");
|
LOG_ERROR("Diffusion model sampling failed");
|
||||||
if (control_net) {
|
if (control_net) {
|
||||||
@ -2025,8 +1908,6 @@ public:
|
|||||||
latent_channel = 128;
|
latent_channel = 128;
|
||||||
} else if (version == VERSION_WAN2_2_TI2V) {
|
} else if (version == VERSION_WAN2_2_TI2V) {
|
||||||
latent_channel = 48;
|
latent_channel = 48;
|
||||||
} else if (version == VERSION_HIDREAM_O1) {
|
|
||||||
latent_channel = 3;
|
|
||||||
} else if (version == VERSION_CHROMA_RADIANCE) {
|
} else if (version == VERSION_CHROMA_RADIANCE) {
|
||||||
latent_channel = 3;
|
latent_channel = 3;
|
||||||
} else if (sd_version_uses_flux2_vae(version)) {
|
} else if (sd_version_uses_flux2_vae(version)) {
|
||||||
@ -2175,8 +2056,6 @@ const char* sample_method_to_str[] = {
|
|||||||
"res_multistep",
|
"res_multistep",
|
||||||
"res_2s",
|
"res_2s",
|
||||||
"er_sde",
|
"er_sde",
|
||||||
"euler_cfg_pp",
|
|
||||||
"euler_a_cfg_pp",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* sd_sample_method_name(enum sample_method_t sample_method) {
|
const char* sd_sample_method_name(enum sample_method_t sample_method) {
|
||||||
@ -2486,7 +2365,6 @@ void sd_sample_params_init(sd_sample_params_t* sample_params) {
|
|||||||
sample_params->custom_sigmas = nullptr;
|
sample_params->custom_sigmas = nullptr;
|
||||||
sample_params->custom_sigmas_count = 0;
|
sample_params->custom_sigmas_count = 0;
|
||||||
sample_params->flow_shift = INFINITY;
|
sample_params->flow_shift = INFINITY;
|
||||||
sample_params->extra_sample_args = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sd_sample_params_to_str(const sd_sample_params_t* sample_params) {
|
char* sd_sample_params_to_str(const sd_sample_params_t* sample_params) {
|
||||||
@ -2508,8 +2386,7 @@ char* sd_sample_params_to_str(const sd_sample_params_t* sample_params) {
|
|||||||
"sample_steps: %d, "
|
"sample_steps: %d, "
|
||||||
"eta: %.2f, "
|
"eta: %.2f, "
|
||||||
"shifted_timestep: %d, "
|
"shifted_timestep: %d, "
|
||||||
"flow_shift: %.2f, "
|
"flow_shift: %.2f)",
|
||||||
"extra_sample_args: %s)",
|
|
||||||
sample_params->guidance.txt_cfg,
|
sample_params->guidance.txt_cfg,
|
||||||
std::isfinite(sample_params->guidance.img_cfg)
|
std::isfinite(sample_params->guidance.img_cfg)
|
||||||
? sample_params->guidance.img_cfg
|
? sample_params->guidance.img_cfg
|
||||||
@ -2524,8 +2401,7 @@ char* sd_sample_params_to_str(const sd_sample_params_t* sample_params) {
|
|||||||
sample_params->sample_steps,
|
sample_params->sample_steps,
|
||||||
sample_params->eta,
|
sample_params->eta,
|
||||||
sample_params->shifted_timestep,
|
sample_params->shifted_timestep,
|
||||||
sample_params->flow_shift,
|
sample_params->flow_shift);
|
||||||
SAFE_STR(sample_params->extra_sample_args));
|
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -2778,9 +2654,6 @@ static float resolve_eta(sd_ctx_t* sd_ctx,
|
|||||||
float eta,
|
float eta,
|
||||||
enum sample_method_t sample_method) {
|
enum sample_method_t sample_method) {
|
||||||
if (eta == INFINITY) {
|
if (eta == INFINITY) {
|
||||||
if (sd_ctx->sd->version == VERSION_HIDREAM_O1) {
|
|
||||||
return 8.f;
|
|
||||||
}
|
|
||||||
switch (sample_method) {
|
switch (sample_method) {
|
||||||
case DDIM_TRAILING_SAMPLE_METHOD:
|
case DDIM_TRAILING_SAMPLE_METHOD:
|
||||||
case TCD_SAMPLE_METHOD:
|
case TCD_SAMPLE_METHOD:
|
||||||
@ -2790,7 +2663,6 @@ static float resolve_eta(sd_ctx_t* sd_ctx,
|
|||||||
case EULER_A_SAMPLE_METHOD:
|
case EULER_A_SAMPLE_METHOD:
|
||||||
case DPMPP2S_A_SAMPLE_METHOD:
|
case DPMPP2S_A_SAMPLE_METHOD:
|
||||||
case ER_SDE_SAMPLE_METHOD:
|
case ER_SDE_SAMPLE_METHOD:
|
||||||
case EULER_A_CFG_PP_SAMPLE_METHOD:
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
@ -3014,8 +2886,6 @@ struct GenerationRequest {
|
|||||||
struct SamplePlan {
|
struct SamplePlan {
|
||||||
enum sample_method_t sample_method = SAMPLE_METHOD_COUNT;
|
enum sample_method_t sample_method = SAMPLE_METHOD_COUNT;
|
||||||
enum sample_method_t high_noise_sample_method = SAMPLE_METHOD_COUNT;
|
enum sample_method_t high_noise_sample_method = SAMPLE_METHOD_COUNT;
|
||||||
const char* extra_sample_args = nullptr;
|
|
||||||
const char* high_noise_extra_sample_args = nullptr;
|
|
||||||
float eta = 0.f;
|
float eta = 0.f;
|
||||||
float high_noise_eta = 0.f;
|
float high_noise_eta = 0.f;
|
||||||
int sample_steps = 0;
|
int sample_steps = 0;
|
||||||
@ -3029,7 +2899,6 @@ struct SamplePlan {
|
|||||||
const sd_img_gen_params_t* sd_img_gen_params,
|
const sd_img_gen_params_t* sd_img_gen_params,
|
||||||
const GenerationRequest& request) {
|
const GenerationRequest& request) {
|
||||||
sample_method = sd_img_gen_params->sample_params.sample_method;
|
sample_method = sd_img_gen_params->sample_params.sample_method;
|
||||||
extra_sample_args = sd_img_gen_params->sample_params.extra_sample_args;
|
|
||||||
eta = sd_img_gen_params->sample_params.eta;
|
eta = sd_img_gen_params->sample_params.eta;
|
||||||
sample_steps = sd_img_gen_params->sample_params.sample_steps;
|
sample_steps = sd_img_gen_params->sample_params.sample_steps;
|
||||||
resolve(sd_ctx, &request, &sd_img_gen_params->sample_params);
|
resolve(sd_ctx, &request, &sd_img_gen_params->sample_params);
|
||||||
@ -3039,13 +2908,11 @@ struct SamplePlan {
|
|||||||
const sd_vid_gen_params_t* sd_vid_gen_params,
|
const sd_vid_gen_params_t* sd_vid_gen_params,
|
||||||
const GenerationRequest& request) {
|
const GenerationRequest& request) {
|
||||||
sample_method = sd_vid_gen_params->sample_params.sample_method;
|
sample_method = sd_vid_gen_params->sample_params.sample_method;
|
||||||
extra_sample_args = sd_vid_gen_params->sample_params.extra_sample_args;
|
|
||||||
eta = sd_vid_gen_params->sample_params.eta;
|
eta = sd_vid_gen_params->sample_params.eta;
|
||||||
sample_steps = sd_vid_gen_params->sample_params.sample_steps;
|
sample_steps = sd_vid_gen_params->sample_params.sample_steps;
|
||||||
if (sd_ctx->sd->high_noise_diffusion_model) {
|
if (sd_ctx->sd->high_noise_diffusion_model) {
|
||||||
high_noise_sample_steps = sd_vid_gen_params->high_noise_sample_params.sample_steps;
|
high_noise_sample_steps = sd_vid_gen_params->high_noise_sample_params.sample_steps;
|
||||||
high_noise_sample_method = sd_vid_gen_params->high_noise_sample_params.sample_method;
|
high_noise_sample_method = sd_vid_gen_params->high_noise_sample_params.sample_method;
|
||||||
high_noise_extra_sample_args = sd_vid_gen_params->high_noise_sample_params.extra_sample_args;
|
|
||||||
high_noise_eta = sd_vid_gen_params->high_noise_sample_params.eta;
|
high_noise_eta = sd_vid_gen_params->high_noise_sample_params.eta;
|
||||||
}
|
}
|
||||||
moe_boundary = sd_vid_gen_params->moe_boundary;
|
moe_boundary = sd_vid_gen_params->moe_boundary;
|
||||||
@ -3367,9 +3234,6 @@ static std::optional<ImageGenerationLatents> prepare_image_generation_latents(sd
|
|||||||
|
|
||||||
std::vector<sd::Tensor<float>> ref_latents;
|
std::vector<sd::Tensor<float>> ref_latents;
|
||||||
for (size_t i = 0; i < ref_images.size(); i++) {
|
for (size_t i = 0; i < ref_images.size(); i++) {
|
||||||
if (sd_ctx->sd->version == VERSION_HIDREAM_O1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sd::Tensor<float> ref_latent;
|
sd::Tensor<float> ref_latent;
|
||||||
if (request->auto_resize_ref_image) {
|
if (request->auto_resize_ref_image) {
|
||||||
LOG_DEBUG("auto resize ref images");
|
LOG_DEBUG("auto resize ref images");
|
||||||
@ -3780,7 +3644,6 @@ SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* s
|
|||||||
request.shifted_timestep,
|
request.shifted_timestep,
|
||||||
plan.sample_method,
|
plan.sample_method,
|
||||||
sd_ctx->sd->is_flow_denoiser(),
|
sd_ctx->sd->is_flow_denoiser(),
|
||||||
plan.extra_sample_args,
|
|
||||||
plan.sigmas,
|
plan.sigmas,
|
||||||
plan.start_merge_step,
|
plan.start_merge_step,
|
||||||
latents.ref_latents,
|
latents.ref_latents,
|
||||||
@ -3823,7 +3686,9 @@ SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* s
|
|||||||
hires_upscaler = std::make_unique<UpscalerGGML>(sd_ctx->sd->n_threads,
|
hires_upscaler = std::make_unique<UpscalerGGML>(sd_ctx->sd->n_threads,
|
||||||
false,
|
false,
|
||||||
request.hires.upscale_tile_size);
|
request.hires.upscale_tile_size);
|
||||||
const size_t max_graph_vram_bytes = sd::ggml_graph_cut::max_vram_gib_to_bytes(sd_ctx->sd->max_vram);
|
const size_t max_graph_vram_bytes = sd_ctx->sd->max_vram <= 0.f
|
||||||
|
? 0
|
||||||
|
: static_cast<size_t>(static_cast<double>(sd_ctx->sd->max_vram) * 1024.0 * 1024.0 * 1024.0);
|
||||||
hires_upscaler->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
hires_upscaler->set_max_graph_vram_bytes(max_graph_vram_bytes);
|
||||||
if (!hires_upscaler->load_from_file(request.hires.model_path,
|
if (!hires_upscaler->load_from_file(request.hires.model_path,
|
||||||
sd_ctx->sd->offload_params_to_cpu,
|
sd_ctx->sd->offload_params_to_cpu,
|
||||||
@ -3905,7 +3770,6 @@ SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* s
|
|||||||
request.shifted_timestep,
|
request.shifted_timestep,
|
||||||
plan.sample_method,
|
plan.sample_method,
|
||||||
sd_ctx->sd->is_flow_denoiser(),
|
sd_ctx->sd->is_flow_denoiser(),
|
||||||
plan.extra_sample_args,
|
|
||||||
hires_sigma_sched,
|
hires_sigma_sched,
|
||||||
plan.start_merge_step,
|
plan.start_merge_step,
|
||||||
latents.ref_latents,
|
latents.ref_latents,
|
||||||
@ -4320,7 +4184,6 @@ SD_API bool generate_video(sd_ctx_t* sd_ctx,
|
|||||||
request.shifted_timestep,
|
request.shifted_timestep,
|
||||||
plan.high_noise_sample_method,
|
plan.high_noise_sample_method,
|
||||||
sd_ctx->sd->is_flow_denoiser(),
|
sd_ctx->sd->is_flow_denoiser(),
|
||||||
plan.high_noise_extra_sample_args,
|
|
||||||
high_noise_sigmas,
|
high_noise_sigmas,
|
||||||
-1,
|
-1,
|
||||||
std::vector<sd::Tensor<float>>{},
|
std::vector<sd::Tensor<float>>{},
|
||||||
@ -4364,7 +4227,6 @@ SD_API bool generate_video(sd_ctx_t* sd_ctx,
|
|||||||
sd_vid_gen_params->sample_params.shifted_timestep,
|
sd_vid_gen_params->sample_params.shifted_timestep,
|
||||||
plan.sample_method,
|
plan.sample_method,
|
||||||
sd_ctx->sd->is_flow_denoiser(),
|
sd_ctx->sd->is_flow_denoiser(),
|
||||||
plan.extra_sample_args,
|
|
||||||
plan.sigmas,
|
plan.sigmas,
|
||||||
-1,
|
-1,
|
||||||
std::vector<sd::Tensor<float>>{},
|
std::vector<sd::Tensor<float>>{},
|
||||||
|
|||||||
@ -81,11 +81,6 @@ Qwen2Tokenizer::Qwen2Tokenizer(const std::string& merges_utf8_str) {
|
|||||||
"</tool_response>",
|
"</tool_response>",
|
||||||
"<think>",
|
"<think>",
|
||||||
"</think>",
|
"</think>",
|
||||||
"<|boi_token|>",
|
|
||||||
"<|bor_token|>",
|
|
||||||
"<|eor_token|>",
|
|
||||||
"<|bot_token|>",
|
|
||||||
"<|tms_token|>",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (merges_utf8_str.size() > 0) {
|
if (merges_utf8_str.size() > 0) {
|
||||||
|
|||||||
96
src/util.cpp
96
src/util.cpp
@ -112,7 +112,7 @@ private:
|
|||||||
HANDLE hmapping_;
|
HANDLE hmapping_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename, bool writable) {
|
std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename) {
|
||||||
void* mapped_data = nullptr;
|
void* mapped_data = nullptr;
|
||||||
size_t file_size = 0;
|
size_t file_size = 0;
|
||||||
|
|
||||||
@ -137,18 +137,14 @@ std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename, bo
|
|||||||
|
|
||||||
file_size = static_cast<size_t>(size.QuadPart);
|
file_size = static_cast<size_t>(size.QuadPart);
|
||||||
|
|
||||||
DWORD page_prot = writable ? PAGE_WRITECOPY : PAGE_READONLY;
|
HANDLE mapping_handle = CreateFileMapping(file_handle, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||||
|
|
||||||
HANDLE mapping_handle = CreateFileMapping(file_handle, nullptr, page_prot, 0, 0, nullptr);
|
|
||||||
|
|
||||||
if (mapping_handle == nullptr) {
|
if (mapping_handle == nullptr) {
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD view_access = writable ? FILE_MAP_COPY : FILE_MAP_READ;
|
mapped_data = MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, file_size);
|
||||||
|
|
||||||
mapped_data = MapViewOfFile(mapping_handle, view_access, 0, 0, file_size);
|
|
||||||
|
|
||||||
if (mapped_data == nullptr) {
|
if (mapped_data == nullptr) {
|
||||||
CloseHandle(mapping_handle);
|
CloseHandle(mapping_handle);
|
||||||
@ -176,85 +172,28 @@ bool is_directory(const std::string& path) {
|
|||||||
return (stat(path.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode));
|
return (stat(path.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MmapFlags {
|
|
||||||
bool sequential;
|
|
||||||
bool populate;
|
|
||||||
bool willneed;
|
|
||||||
bool dontneed;
|
|
||||||
};
|
|
||||||
|
|
||||||
static MmapFlags get_mmap_flags() {
|
|
||||||
MmapFlags result = {};
|
|
||||||
const char* SD_MMAP_FLAGS = std::getenv("SD_MMAP_FLAGS");
|
|
||||||
if (SD_MMAP_FLAGS && *SD_MMAP_FLAGS) {
|
|
||||||
std::stringstream ss(SD_MMAP_FLAGS);
|
|
||||||
std::string token;
|
|
||||||
while (std::getline(ss, token, ',')) {
|
|
||||||
std::string ntoken = trim(token);
|
|
||||||
std::transform(ntoken.begin(), ntoken.end(), ntoken.begin(), ::tolower);
|
|
||||||
if (ntoken == "sequential") {
|
|
||||||
result.sequential = true;
|
|
||||||
} else if (ntoken == "populate") {
|
|
||||||
result.populate = true;
|
|
||||||
} else if (ntoken == "willneed") {
|
|
||||||
result.willneed = true;
|
|
||||||
} else if (ntoken == "dontneed") {
|
|
||||||
result.dontneed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MmapWrapperImpl : public MmapWrapper {
|
class MmapWrapperImpl : public MmapWrapper {
|
||||||
public:
|
public:
|
||||||
MmapWrapperImpl(void* data, size_t size, int fd)
|
MmapWrapperImpl(void* data, size_t size)
|
||||||
: MmapWrapper(data, size), fd_(fd) {}
|
: MmapWrapper(data, size) {}
|
||||||
|
|
||||||
~MmapWrapperImpl() override {
|
~MmapWrapperImpl() override {
|
||||||
#ifdef __linux__
|
|
||||||
auto cfg_flags = get_mmap_flags();
|
|
||||||
|
|
||||||
// Drop the kernel pagecache pages for this file. madvise(DONTNEED)
|
|
||||||
// alone only unmaps from the process address space; pagecache
|
|
||||||
// entries persist (`free` reports them as buff/cache and the OOM
|
|
||||||
// killer doesn't touch them, but they ARE counted against
|
|
||||||
// overcommit and can starve other allocations on tight-RAM
|
|
||||||
// systems). posix_fadvise(POSIX_FADV_DONTNEED) is the documented
|
|
||||||
// way to evict pagecache for a specific fd's pages.
|
|
||||||
if (cfg_flags.dontneed) {
|
|
||||||
madvise(data_, size_, MADV_DONTNEED);
|
|
||||||
posix_fadvise(fd_, 0, 0, POSIX_FADV_DONTNEED);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
munmap(data_, size_);
|
munmap(data_, size_);
|
||||||
close(fd_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
int fd_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename, bool writable) {
|
std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename) {
|
||||||
int file_descriptor = open(filename.c_str(), O_RDONLY);
|
int file_descriptor = open(filename.c_str(), O_RDONLY);
|
||||||
if (file_descriptor == -1) {
|
if (file_descriptor == -1) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cfg_flags = get_mmap_flags();
|
|
||||||
|
|
||||||
int mmap_flags = MAP_PRIVATE;
|
int mmap_flags = MAP_PRIVATE;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// Sequential access hint helps the kernel read-ahead efficiently and
|
// performance flags used by llama.cpp
|
||||||
// also encourages eviction of already-read pages (the kernel keeps
|
// posix_fadvise(file_descriptor, 0, 0, POSIX_FADV_SEQUENTIAL);
|
||||||
// a smaller working set when this is set).
|
// mmap_flags |= MAP_POPULATE;
|
||||||
if (cfg_flags.sequential) {
|
|
||||||
posix_fadvise(file_descriptor, 0, 0, POSIX_FADV_SEQUENTIAL);
|
|
||||||
}
|
|
||||||
if (cfg_flags.populate) {
|
|
||||||
mmap_flags |= MAP_POPULATE;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@ -265,27 +204,20 @@ std::unique_ptr<MmapWrapper> MmapWrapper::create(const std::string& filename, bo
|
|||||||
|
|
||||||
size_t file_size = sb.st_size;
|
size_t file_size = sb.st_size;
|
||||||
|
|
||||||
if (file_size == 0) {
|
void* mapped_data = mmap(nullptr, file_size, PROT_READ, mmap_flags, file_descriptor, 0);
|
||||||
|
|
||||||
close(file_descriptor);
|
close(file_descriptor);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mmap_prot = PROT_READ | (writable ? PROT_WRITE : 0);
|
|
||||||
|
|
||||||
void* mapped_data = mmap(nullptr, file_size, mmap_prot, mmap_flags, file_descriptor, 0);
|
|
||||||
|
|
||||||
if (mapped_data == MAP_FAILED) {
|
if (mapped_data == MAP_FAILED) {
|
||||||
close(file_descriptor);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (cfg_flags.willneed) {
|
// performance flags used by llama.cpp
|
||||||
posix_madvise(mapped_data, file_size, POSIX_MADV_WILLNEED);
|
// posix_madvise(mapped_data, file_size, POSIX_MADV_WILLNEED);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return std::make_unique<MmapWrapperImpl>(mapped_data, file_size, file_descriptor);
|
return std::make_unique<MmapWrapperImpl>(mapped_data, file_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -42,7 +42,7 @@ sd::Tensor<float> clip_preprocess(const sd::Tensor<float>& image, int target_wid
|
|||||||
|
|
||||||
class MmapWrapper {
|
class MmapWrapper {
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<MmapWrapper> create(const std::string& filename, bool writable = false);
|
static std::unique_ptr<MmapWrapper> create(const std::string& filename);
|
||||||
|
|
||||||
virtual ~MmapWrapper() = default;
|
virtual ~MmapWrapper() = default;
|
||||||
|
|
||||||
@ -52,7 +52,6 @@ public:
|
|||||||
MmapWrapper& operator=(MmapWrapper&&) = delete;
|
MmapWrapper& operator=(MmapWrapper&&) = delete;
|
||||||
|
|
||||||
const uint8_t* data() const { return static_cast<uint8_t*>(data_); }
|
const uint8_t* data() const { return static_cast<uint8_t*>(data_); }
|
||||||
uint8_t* writable_data() { return static_cast<uint8_t*>(data_); }
|
|
||||||
size_t size() const { return size_; }
|
size_t size() const { return size_; }
|
||||||
bool copy_data(void* buf, size_t n, size_t offset) const;
|
bool copy_data(void* buf, size_t n, size_t offset) const;
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@ public:
|
|||||||
scale_factor = 16;
|
scale_factor = 16;
|
||||||
} else if (sd_version_uses_flux2_vae(version)) {
|
} else if (sd_version_uses_flux2_vae(version)) {
|
||||||
scale_factor = 16;
|
scale_factor = 16;
|
||||||
} else if (version == VERSION_CHROMA_RADIANCE || version == VERSION_HIDREAM_O1) {
|
} else if (version == VERSION_CHROMA_RADIANCE) {
|
||||||
scale_factor = 1;
|
scale_factor = 1;
|
||||||
}
|
}
|
||||||
return scale_factor;
|
return scale_factor;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user