Compare commits
41 Commits
master-369
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11ab095230 | ||
|
|
a3a88fc9b2 | ||
|
|
8823dc48bc | ||
|
|
1ac5a616de | ||
|
|
d939f6e86a | ||
|
|
e72aea796e | ||
|
|
a908436729 | ||
|
|
583a02e29e | ||
|
|
96c3e64057 | ||
|
|
0392273e10 | ||
|
|
bf1a388b44 | ||
|
|
c9005337a8 | ||
|
|
2f0bd31a84 | ||
|
|
bfbb929790 | ||
|
|
689e44c9a8 | ||
|
|
985aedda32 | ||
|
|
3f3610b5cd | ||
|
|
118683de8a | ||
|
|
bcc9c0d0b3 | ||
|
|
5865b5e703 | ||
|
|
edf2cb3846 | ||
|
|
99e17232a4 | ||
|
|
710169df5c | ||
|
|
e4c50f1de5 | ||
|
|
0743a1b3b5 | ||
|
|
34a6fd4e60 | ||
|
|
3c1187ce83 | ||
|
|
20eb674100 | ||
|
|
bc80225336 | ||
|
|
ab7e8d285e | ||
|
|
673dbdda17 | ||
|
|
0249509a30 | ||
|
|
52b67c538b | ||
|
|
20345888a3 | ||
|
|
490c51d963 | ||
|
|
45c46779af | ||
|
|
869d023416 | ||
|
|
e9bc3b6c06 | ||
|
|
b542894fb9 | ||
|
|
5498cc0d67 | ||
|
|
aa2b8e0ca5 |
6
.github/workflows/build.yml
vendored
@ -163,7 +163,7 @@ jobs:
|
|||||||
- build: "avx512"
|
- build: "avx512"
|
||||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX512=ON -DGGML_AVX=ON -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON"
|
defines: "-DGGML_NATIVE=OFF -DGGML_AVX512=ON -DGGML_AVX=ON -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||||
- build: "cuda12"
|
- build: "cuda12"
|
||||||
defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES=90;89;86;80;75"
|
defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES='61;70;75;80;86;89;90;100;120'"
|
||||||
- build: 'vulkan'
|
- build: 'vulkan'
|
||||||
defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON"
|
defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||||
steps:
|
steps:
|
||||||
@ -176,9 +176,9 @@ jobs:
|
|||||||
- name: Install cuda-toolkit
|
- name: Install cuda-toolkit
|
||||||
id: cuda-toolkit
|
id: cuda-toolkit
|
||||||
if: ${{ matrix.build == 'cuda12' }}
|
if: ${{ matrix.build == 'cuda12' }}
|
||||||
uses: Jimver/cuda-toolkit@v0.2.19
|
uses: Jimver/cuda-toolkit@v0.2.22
|
||||||
with:
|
with:
|
||||||
cuda: "12.6.2"
|
cuda: "12.8.1"
|
||||||
method: "network"
|
method: "network"
|
||||||
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]'
|
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]'
|
||||||
|
|
||||||
|
|||||||
@ -87,6 +87,38 @@ file(GLOB SD_LIB_SOURCES
|
|||||||
"*.hpp"
|
"*.hpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
find_program(GIT_EXE NAMES git git.exe NO_CMAKE_FIND_ROOT_PATH)
|
||||||
|
if(GIT_EXE)
|
||||||
|
execute_process(COMMAND ${GIT_EXE} describe --tags --abbrev=7 --dirty=+
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE SDCPP_BUILD_VERSION
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
execute_process(COMMAND ${GIT_EXE} rev-parse --short HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE SDCPP_BUILD_COMMIT
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT SDCPP_BUILD_VERSION)
|
||||||
|
set(SDCPP_BUILD_VERSION unknown)
|
||||||
|
endif()
|
||||||
|
message(STATUS "stable-diffusion.cpp version ${SDCPP_BUILD_VERSION}")
|
||||||
|
|
||||||
|
if(NOT SDCPP_BUILD_COMMIT)
|
||||||
|
set(SDCPP_BUILD_COMMIT unknown)
|
||||||
|
endif()
|
||||||
|
message(STATUS "stable-diffusion.cpp commit ${SDCPP_BUILD_COMMIT}")
|
||||||
|
|
||||||
|
set_property(
|
||||||
|
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp
|
||||||
|
APPEND PROPERTY COMPILE_DEFINITIONS
|
||||||
|
SDCPP_BUILD_COMMIT=${SDCPP_BUILD_COMMIT} SDCPP_BUILD_VERSION=${SDCPP_BUILD_VERSION}
|
||||||
|
)
|
||||||
|
|
||||||
if(SD_BUILD_SHARED_LIBS)
|
if(SD_BUILD_SHARED_LIBS)
|
||||||
message("-- Build shared library")
|
message("-- Build shared library")
|
||||||
message(${SD_LIB_SOURCES})
|
message(${SD_LIB_SOURCES})
|
||||||
|
|||||||
20
README.md
@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./assets/cat_with_sd_cpp_42.png" width="360x">
|
<img src="./assets/logo.png" width="360x">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# stable-diffusion.cpp
|
# stable-diffusion.cpp
|
||||||
@ -15,6 +15,12 @@ API and command-line option may change frequently.***
|
|||||||
|
|
||||||
## 🔥Important News
|
## 🔥Important News
|
||||||
|
|
||||||
|
* **2025/12/01** 🚀 stable-diffusion.cpp now supports **Z-Image**
|
||||||
|
👉 Details: [PR #1020](https://github.com/leejet/stable-diffusion.cpp/pull/1020)
|
||||||
|
|
||||||
|
* **2025/11/30** 🚀 stable-diffusion.cpp now supports **FLUX.2-dev**
|
||||||
|
👉 Details: [PR #1016](https://github.com/leejet/stable-diffusion.cpp/pull/1016)
|
||||||
|
|
||||||
* **2025/10/13** 🚀 stable-diffusion.cpp now supports **Qwen-Image-Edit / Qwen-Image-Edit 2509**
|
* **2025/10/13** 🚀 stable-diffusion.cpp now supports **Qwen-Image-Edit / Qwen-Image-Edit 2509**
|
||||||
👉 Details: [PR #877](https://github.com/leejet/stable-diffusion.cpp/pull/877)
|
👉 Details: [PR #877](https://github.com/leejet/stable-diffusion.cpp/pull/877)
|
||||||
|
|
||||||
@ -37,10 +43,13 @@ API and command-line option may change frequently.***
|
|||||||
- SDXL, [SDXL-Turbo](https://huggingface.co/stabilityai/sdxl-turbo)
|
- SDXL, [SDXL-Turbo](https://huggingface.co/stabilityai/sdxl-turbo)
|
||||||
- [Some SD1.x and SDXL distilled models](./docs/distilled_sd.md)
|
- [Some SD1.x and SDXL distilled models](./docs/distilled_sd.md)
|
||||||
- [SD3/SD3.5](./docs/sd3.md)
|
- [SD3/SD3.5](./docs/sd3.md)
|
||||||
- [Flux-dev/Flux-schnell](./docs/flux.md)
|
- [FlUX.1-dev/FlUX.1-schnell](./docs/flux.md)
|
||||||
|
- [FLUX.2-dev](./docs/flux2.md)
|
||||||
- [Chroma](./docs/chroma.md)
|
- [Chroma](./docs/chroma.md)
|
||||||
- [Chroma1-Radiance](./docs/chroma_radiance.md)
|
- [Chroma1-Radiance](./docs/chroma_radiance.md)
|
||||||
- [Qwen Image](./docs/qwen_image.md)
|
- [Qwen Image](./docs/qwen_image.md)
|
||||||
|
- [Z-Image](./docs/z_image.md)
|
||||||
|
- [Ovis-Image](./docs/ovis_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/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
- [Qwen Image Edit/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
||||||
@ -96,7 +105,7 @@ API and command-line option may change frequently.***
|
|||||||
### Download model weights
|
### Download model weights
|
||||||
|
|
||||||
- download weights(.ckpt or .safetensors or .gguf). For example
|
- download weights(.ckpt or .safetensors or .gguf). For example
|
||||||
- Stable Diffusion v1.5 from https://huggingface.co/runwayml/stable-diffusion-v1-5
|
- Stable Diffusion v1.5 from https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -L -O https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
curl -L -O https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
||||||
@ -118,12 +127,15 @@ If you want to improve performance or reduce VRAM/RAM usage, please refer to [pe
|
|||||||
|
|
||||||
- [SD1.x/SD2.x/SDXL](./docs/sd.md)
|
- [SD1.x/SD2.x/SDXL](./docs/sd.md)
|
||||||
- [SD3/SD3.5](./docs/sd3.md)
|
- [SD3/SD3.5](./docs/sd3.md)
|
||||||
- [Flux-dev/Flux-schnell](./docs/flux.md)
|
- [FlUX.1-dev/FlUX.1-schnell](./docs/flux.md)
|
||||||
|
- [FLUX.2-dev](./docs/flux2.md)
|
||||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||||
- [Chroma](./docs/chroma.md)
|
- [Chroma](./docs/chroma.md)
|
||||||
- [🔥Qwen Image](./docs/qwen_image.md)
|
- [🔥Qwen Image](./docs/qwen_image.md)
|
||||||
- [🔥Qwen Image Edit/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
- [🔥Qwen Image Edit/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
||||||
- [🔥Wan2.1/Wan2.2](./docs/wan.md)
|
- [🔥Wan2.1/Wan2.2](./docs/wan.md)
|
||||||
|
- [🔥Z-Image](./docs/z_image.md)
|
||||||
|
- [Ovis-Image](./docs/ovis_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)
|
||||||
|
|||||||
BIN
assets/flux2/example.png
Normal file
|
After Width: | Height: | Size: 556 KiB |
BIN
assets/logo.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/ovis_image/example.png
Normal file
|
After Width: | Height: | Size: 401 KiB |
BIN
assets/z_image/bf16.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/z_image/q2_K.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/z_image/q3_K.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/z_image/q4_0.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/z_image/q4_K.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/z_image/q5_0.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/z_image/q6_K.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/z_image/q8_0.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
107
clip.hpp
@ -3,34 +3,10 @@
|
|||||||
|
|
||||||
#include "ggml_extend.hpp"
|
#include "ggml_extend.hpp"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
#include "tokenize_util.h"
|
||||||
|
|
||||||
/*================================================== CLIPTokenizer ===================================================*/
|
/*================================================== CLIPTokenizer ===================================================*/
|
||||||
|
|
||||||
__STATIC_INLINE__ std::pair<std::unordered_map<std::string, float>, std::string> extract_and_remove_lora(std::string text) {
|
|
||||||
std::regex re("<lora:([^:]+):([^>]+)>");
|
|
||||||
std::smatch matches;
|
|
||||||
std::unordered_map<std::string, float> filename2multiplier;
|
|
||||||
|
|
||||||
while (std::regex_search(text, matches, re)) {
|
|
||||||
std::string filename = matches[1].str();
|
|
||||||
float multiplier = std::stof(matches[2].str());
|
|
||||||
|
|
||||||
text = std::regex_replace(text, re, "", std::regex_constants::format_first_only);
|
|
||||||
|
|
||||||
if (multiplier == 0.f) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filename2multiplier.find(filename) == filename2multiplier.end()) {
|
|
||||||
filename2multiplier[filename] = multiplier;
|
|
||||||
} else {
|
|
||||||
filename2multiplier[filename] += multiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(filename2multiplier, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
__STATIC_INLINE__ std::vector<std::pair<int, std::u32string>> bytes_to_unicode() {
|
__STATIC_INLINE__ std::vector<std::pair<int, std::u32string>> bytes_to_unicode() {
|
||||||
std::vector<std::pair<int, std::u32string>> byte_unicode_pairs;
|
std::vector<std::pair<int, std::u32string>> byte_unicode_pairs;
|
||||||
std::set<int> byte_set;
|
std::set<int> byte_set;
|
||||||
@ -72,6 +48,8 @@ private:
|
|||||||
int encoder_len;
|
int encoder_len;
|
||||||
int bpe_len;
|
int bpe_len;
|
||||||
|
|
||||||
|
std::vector<std::string> special_tokens;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::string UNK_TOKEN = "<|endoftext|>";
|
const std::string UNK_TOKEN = "<|endoftext|>";
|
||||||
const std::string BOS_TOKEN = "<|startoftext|>";
|
const std::string BOS_TOKEN = "<|startoftext|>";
|
||||||
@ -117,6 +95,15 @@ private:
|
|||||||
return pairs;
|
return pairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_special_token(const std::string& token) {
|
||||||
|
for (auto& special_token : special_tokens) {
|
||||||
|
if (special_token == token) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CLIPTokenizer(int pad_token_id = 49407, const std::string& merges_utf8_str = "")
|
CLIPTokenizer(int pad_token_id = 49407, const std::string& merges_utf8_str = "")
|
||||||
: PAD_TOKEN_ID(pad_token_id) {
|
: PAD_TOKEN_ID(pad_token_id) {
|
||||||
@ -125,6 +112,8 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
load_from_merges(ModelLoader::load_merges());
|
load_from_merges(ModelLoader::load_merges());
|
||||||
}
|
}
|
||||||
|
add_special_token("<|startoftext|>");
|
||||||
|
add_special_token("<|endoftext|>");
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_from_merges(const std::string& merges_utf8_str) {
|
void load_from_merges(const std::string& merges_utf8_str) {
|
||||||
@ -201,6 +190,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_special_token(const std::string& token) {
|
||||||
|
special_tokens.push_back(token);
|
||||||
|
}
|
||||||
|
|
||||||
std::u32string bpe(const std::u32string& token) {
|
std::u32string bpe(const std::u32string& token) {
|
||||||
std::vector<std::u32string> word;
|
std::vector<std::u32string> word;
|
||||||
|
|
||||||
@ -379,25 +372,54 @@ public:
|
|||||||
return trim(text);
|
return trim(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> token_split(const std::string& text) {
|
||||||
|
std::regex pat(R"('s|'t|'re|'ve|'m|'ll|'d|[[:alpha:]]+|[[:digit:]]|[^[:space:][:alpha:][:digit:]]+)",
|
||||||
|
std::regex::icase);
|
||||||
|
std::sregex_iterator iter(text.begin(), text.end(), pat);
|
||||||
|
std::sregex_iterator end;
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
for (; iter != end; ++iter) {
|
||||||
|
result.emplace_back(iter->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> encode(std::string text, on_new_token_cb_t on_new_token_cb) {
|
std::vector<int> encode(std::string text, on_new_token_cb_t on_new_token_cb) {
|
||||||
std::string original_text = text;
|
std::string original_text = text;
|
||||||
std::vector<int32_t> bpe_tokens;
|
std::vector<int32_t> bpe_tokens;
|
||||||
text = whitespace_clean(text);
|
text = whitespace_clean(text);
|
||||||
std::transform(text.begin(), text.end(), text.begin(), [](unsigned char c) { return std::tolower(c); });
|
std::transform(text.begin(), text.end(), text.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
std::regex pat(R"(<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[[:alpha:]]+|[[:digit:]]|[^[:space:][:alpha:][:digit:]]+)",
|
|
||||||
std::regex::icase);
|
|
||||||
|
|
||||||
std::smatch matches;
|
|
||||||
std::string str = text;
|
std::string str = text;
|
||||||
std::vector<std::string> token_strs;
|
std::vector<std::string> token_strs;
|
||||||
while (std::regex_search(str, matches, pat)) {
|
|
||||||
bool skip = on_new_token_cb(str, bpe_tokens);
|
auto splited_texts = split_with_special_tokens(text, special_tokens);
|
||||||
if (skip) {
|
|
||||||
|
for (auto& splited_text : splited_texts) {
|
||||||
|
LOG_DEBUG("token %s", splited_text.c_str());
|
||||||
|
if (is_special_token(splited_text)) {
|
||||||
|
LOG_DEBUG("special %s", splited_text.c_str());
|
||||||
|
bool skip = on_new_token_cb(splited_text, bpe_tokens);
|
||||||
|
if (skip) {
|
||||||
|
token_strs.push_back(splited_text);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (auto& token : matches) {
|
|
||||||
std::string token_str = token.str();
|
auto tokens = token_split(splited_text);
|
||||||
|
for (auto& token : tokens) {
|
||||||
|
if (on_new_token_cb != nullptr) {
|
||||||
|
bool skip = on_new_token_cb(token, bpe_tokens);
|
||||||
|
if (skip) {
|
||||||
|
token_strs.push_back(token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string token_str = token;
|
||||||
std::u32string utf32_token;
|
std::u32string utf32_token;
|
||||||
for (int i = 0; i < token_str.length(); i++) {
|
for (int i = 0; i < token_str.length(); i++) {
|
||||||
unsigned char b = token_str[i];
|
unsigned char b = token_str[i];
|
||||||
@ -417,14 +439,13 @@ public:
|
|||||||
bpe_tokens.push_back(encoder[bpe_str]);
|
bpe_tokens.push_back(encoder[bpe_str]);
|
||||||
token_strs.push_back(utf32_to_utf8(bpe_str));
|
token_strs.push_back(utf32_to_utf8(bpe_str));
|
||||||
}
|
}
|
||||||
str = matches.suffix();
|
|
||||||
}
|
}
|
||||||
std::stringstream ss;
|
// std::stringstream ss;
|
||||||
ss << "[";
|
// ss << "[";
|
||||||
for (auto token : token_strs) {
|
// for (auto token : token_strs) {
|
||||||
ss << "\"" << token << "\", ";
|
// ss << "\"" << token << "\", ";
|
||||||
}
|
// }
|
||||||
ss << "]";
|
// ss << "]";
|
||||||
// LOG_DEBUG("split prompt \"%s\" to tokens %s", original_text.c_str(), ss.str().c_str());
|
// LOG_DEBUG("split prompt \"%s\" to tokens %s", original_text.c_str(), ss.str().c_str());
|
||||||
// printf("split prompt \"%s\" to tokens %s \n", original_text.c_str(), ss.str().c_str());
|
// printf("split prompt \"%s\" to tokens %s \n", original_text.c_str(), ss.str().c_str());
|
||||||
return bpe_tokens;
|
return bpe_tokens;
|
||||||
@ -963,7 +984,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* input_ids,
|
struct ggml_tensor* input_ids,
|
||||||
int num_custom_embeddings,
|
int num_custom_embeddings,
|
||||||
void* custom_embeddings_data,
|
void* custom_embeddings_data,
|
||||||
@ -975,7 +996,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
|||||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
return build_graph(input_ids, num_custom_embeddings, custom_embeddings_data, max_token_idx, return_pooled, clip_skip);
|
return build_graph(input_ids, num_custom_embeddings, custom_embeddings_data, max_token_idx, return_pooled, clip_skip);
|
||||||
};
|
};
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
286
conditioner.hpp
@ -2,7 +2,7 @@
|
|||||||
#define __CONDITIONER_HPP__
|
#define __CONDITIONER_HPP__
|
||||||
|
|
||||||
#include "clip.hpp"
|
#include "clip.hpp"
|
||||||
#include "qwenvl.hpp"
|
#include "llm.hpp"
|
||||||
#include "t5.hpp"
|
#include "t5.hpp"
|
||||||
|
|
||||||
struct SDCondition {
|
struct SDCondition {
|
||||||
@ -56,20 +56,26 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
std::shared_ptr<CLIPTextModelRunner> text_model2;
|
std::shared_ptr<CLIPTextModelRunner> text_model2;
|
||||||
|
|
||||||
std::string trigger_word = "img"; // should be user settable
|
std::string trigger_word = "img"; // should be user settable
|
||||||
std::string embd_dir;
|
std::map<std::string, std::string> embedding_map;
|
||||||
int32_t num_custom_embeddings = 0;
|
int32_t num_custom_embeddings = 0;
|
||||||
int32_t num_custom_embeddings_2 = 0;
|
int32_t num_custom_embeddings_2 = 0;
|
||||||
std::vector<uint8_t> token_embed_custom;
|
std::vector<uint8_t> token_embed_custom;
|
||||||
std::vector<std::string> readed_embeddings;
|
std::map<std::string, std::pair<int, int>> embedding_pos_map;
|
||||||
|
|
||||||
FrozenCLIPEmbedderWithCustomWords(ggml_backend_t backend,
|
FrozenCLIPEmbedderWithCustomWords(ggml_backend_t backend,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
const String2TensorStorage& tensor_storage_map,
|
const String2TensorStorage& tensor_storage_map,
|
||||||
const std::string& embd_dir,
|
const std::map<std::string, std::string>& orig_embedding_map,
|
||||||
SDVersion version = VERSION_SD1,
|
SDVersion version = VERSION_SD1,
|
||||||
PMVersion pv = PM_VERSION_1)
|
PMVersion pv = PM_VERSION_1)
|
||||||
: version(version), pm_version(pv), tokenizer(sd_version_is_sd2(version) ? 0 : 49407), embd_dir(embd_dir) {
|
: version(version), pm_version(pv), tokenizer(sd_version_is_sd2(version) ? 0 : 49407) {
|
||||||
bool force_clip_f32 = embd_dir.size() > 0;
|
for (const auto& kv : orig_embedding_map) {
|
||||||
|
std::string name = kv.first;
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
embedding_map[name] = kv.second;
|
||||||
|
tokenizer.add_special_token(name);
|
||||||
|
}
|
||||||
|
bool force_clip_f32 = !embedding_map.empty();
|
||||||
if (sd_version_is_sd1(version)) {
|
if (sd_version_is_sd1(version)) {
|
||||||
text_model = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "cond_stage_model.transformer.text_model", OPENAI_CLIP_VIT_L_14, true, force_clip_f32);
|
text_model = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "cond_stage_model.transformer.text_model", OPENAI_CLIP_VIT_L_14, true, force_clip_f32);
|
||||||
} else if (sd_version_is_sd2(version)) {
|
} else if (sd_version_is_sd2(version)) {
|
||||||
@ -117,14 +123,17 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool load_embedding(std::string embd_name, std::string embd_path, std::vector<int32_t>& bpe_tokens) {
|
bool load_embedding(std::string embd_name, std::string embd_path, std::vector<int32_t>& bpe_tokens) {
|
||||||
// the order matters
|
|
||||||
ModelLoader model_loader;
|
ModelLoader model_loader;
|
||||||
if (!model_loader.init_from_file_and_convert_name(embd_path)) {
|
if (!model_loader.init_from_file_and_convert_name(embd_path)) {
|
||||||
LOG_ERROR("embedding '%s' failed", embd_name.c_str());
|
LOG_ERROR("embedding '%s' failed", embd_name.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (std::find(readed_embeddings.begin(), readed_embeddings.end(), embd_name) != readed_embeddings.end()) {
|
auto iter = embedding_pos_map.find(embd_name);
|
||||||
|
if (iter != embedding_pos_map.end()) {
|
||||||
LOG_DEBUG("embedding already read in: %s", embd_name.c_str());
|
LOG_DEBUG("embedding already read in: %s", embd_name.c_str());
|
||||||
|
for (int i = iter->second.first; i < iter->second.second; i++) {
|
||||||
|
bpe_tokens.push_back(text_model->model.vocab_size + i);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
struct ggml_init_params params;
|
struct ggml_init_params params;
|
||||||
@ -155,7 +164,7 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
model_loader.load_tensors(on_load, 1);
|
model_loader.load_tensors(on_load, 1);
|
||||||
readed_embeddings.push_back(embd_name);
|
int pos_start = num_custom_embeddings;
|
||||||
if (embd) {
|
if (embd) {
|
||||||
int64_t hidden_size = text_model->model.hidden_size;
|
int64_t hidden_size = text_model->model.hidden_size;
|
||||||
token_embed_custom.resize(token_embed_custom.size() + ggml_nbytes(embd));
|
token_embed_custom.resize(token_embed_custom.size() + ggml_nbytes(embd));
|
||||||
@ -182,6 +191,11 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
}
|
}
|
||||||
LOG_DEBUG("embedding '%s' applied, custom embeddings: %i (text model 2)", embd_name.c_str(), num_custom_embeddings_2);
|
LOG_DEBUG("embedding '%s' applied, custom embeddings: %i (text model 2)", embd_name.c_str(), num_custom_embeddings_2);
|
||||||
}
|
}
|
||||||
|
int pos_end = num_custom_embeddings;
|
||||||
|
if (pos_end == pos_start) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
embedding_pos_map[embd_name] = std::pair{pos_start, pos_end};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,25 +210,13 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
|
|
||||||
std::vector<int> convert_token_to_id(std::string text) {
|
std::vector<int> convert_token_to_id(std::string text) {
|
||||||
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
||||||
size_t word_end = str.find(",");
|
auto iter = embedding_map.find(str);
|
||||||
std::string embd_name = word_end == std::string::npos ? str : str.substr(0, word_end);
|
if (iter == embedding_map.end()) {
|
||||||
embd_name = trim(embd_name);
|
return false;
|
||||||
std::string embd_path = get_full_path(embd_dir, embd_name + ".pt");
|
|
||||||
if (embd_path.size() == 0) {
|
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".ckpt");
|
|
||||||
}
|
}
|
||||||
if (embd_path.size() == 0) {
|
std::string embedding_path = iter->second;
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".safetensors");
|
if (load_embedding(str, embedding_path, bpe_tokens)) {
|
||||||
}
|
return true;
|
||||||
if (embd_path.size() > 0) {
|
|
||||||
if (load_embedding(embd_name, embd_path, bpe_tokens)) {
|
|
||||||
if (word_end != std::string::npos) {
|
|
||||||
str = str.substr(word_end);
|
|
||||||
} else {
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -245,25 +247,13 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
||||||
size_t word_end = str.find(",");
|
auto iter = embedding_map.find(str);
|
||||||
std::string embd_name = word_end == std::string::npos ? str : str.substr(0, word_end);
|
if (iter == embedding_map.end()) {
|
||||||
embd_name = trim(embd_name);
|
return false;
|
||||||
std::string embd_path = get_full_path(embd_dir, embd_name + ".pt");
|
|
||||||
if (embd_path.size() == 0) {
|
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".ckpt");
|
|
||||||
}
|
}
|
||||||
if (embd_path.size() == 0) {
|
std::string embedding_path = iter->second;
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".safetensors");
|
if (load_embedding(str, embedding_path, bpe_tokens)) {
|
||||||
}
|
return true;
|
||||||
if (embd_path.size() > 0) {
|
|
||||||
if (load_embedding(embd_name, embd_path, bpe_tokens)) {
|
|
||||||
if (word_end != std::string::npos) {
|
|
||||||
str = str.substr(word_end);
|
|
||||||
} else {
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -376,25 +366,13 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
auto on_new_token_cb = [&](std::string& str, std::vector<int32_t>& bpe_tokens) -> bool {
|
||||||
size_t word_end = str.find(",");
|
auto iter = embedding_map.find(str);
|
||||||
std::string embd_name = word_end == std::string::npos ? str : str.substr(0, word_end);
|
if (iter == embedding_map.end()) {
|
||||||
embd_name = trim(embd_name);
|
return false;
|
||||||
std::string embd_path = get_full_path(embd_dir, embd_name + ".pt");
|
|
||||||
if (embd_path.size() == 0) {
|
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".ckpt");
|
|
||||||
}
|
}
|
||||||
if (embd_path.size() == 0) {
|
std::string embedding_path = iter->second;
|
||||||
embd_path = get_full_path(embd_dir, embd_name + ".safetensors");
|
if (load_embedding(str, embedding_path, bpe_tokens)) {
|
||||||
}
|
return true;
|
||||||
if (embd_path.size() > 0) {
|
|
||||||
if (load_embedding(embd_name, embd_path, bpe_tokens)) {
|
|
||||||
if (word_end != std::string::npos) {
|
|
||||||
str = str.substr(word_end);
|
|
||||||
} else {
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -703,7 +681,7 @@ struct FrozenCLIPVisionEmbedder : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
ggml_tensor* pixel_values,
|
ggml_tensor* pixel_values,
|
||||||
bool return_pooled,
|
bool return_pooled,
|
||||||
int clip_skip,
|
int clip_skip,
|
||||||
@ -712,7 +690,7 @@ struct FrozenCLIPVisionEmbedder : public GGMLRunner {
|
|||||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
return build_graph(pixel_values, return_pooled, clip_skip);
|
return build_graph(pixel_values, return_pooled, clip_skip);
|
||||||
};
|
};
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1623,61 +1601,74 @@ struct T5CLIPEmbedder : public Conditioner {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
struct LLMEmbedder : public Conditioner {
|
||||||
Qwen::Qwen2Tokenizer tokenizer;
|
SDVersion version;
|
||||||
std::shared_ptr<Qwen::Qwen2_5_VLRunner> qwenvl;
|
std::shared_ptr<LLM::BPETokenizer> tokenizer;
|
||||||
|
std::shared_ptr<LLM::LLMRunner> llm;
|
||||||
|
|
||||||
Qwen2_5_VLCLIPEmbedder(ggml_backend_t backend,
|
LLMEmbedder(ggml_backend_t backend,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
const String2TensorStorage& tensor_storage_map = {},
|
const String2TensorStorage& tensor_storage_map = {},
|
||||||
const std::string prefix = "",
|
SDVersion version = VERSION_QWEN_IMAGE,
|
||||||
bool enable_vision = false) {
|
const std::string prefix = "",
|
||||||
qwenvl = std::make_shared<Qwen::Qwen2_5_VLRunner>(backend,
|
bool enable_vision = false)
|
||||||
offload_params_to_cpu,
|
: version(version) {
|
||||||
tensor_storage_map,
|
LLM::LLMArch arch = LLM::LLMArch::QWEN2_5_VL;
|
||||||
"text_encoders.qwen2vl",
|
if (sd_version_is_flux2(version)) {
|
||||||
enable_vision);
|
arch = LLM::LLMArch::MISTRAL_SMALL_3_2;
|
||||||
|
} else if (sd_version_is_z_image(version) || version == VERSION_OVIS_IMAGE) {
|
||||||
|
arch = LLM::LLMArch::QWEN3;
|
||||||
|
}
|
||||||
|
if (arch == LLM::LLMArch::MISTRAL_SMALL_3_2) {
|
||||||
|
tokenizer = std::make_shared<LLM::MistralTokenizer>();
|
||||||
|
} else {
|
||||||
|
tokenizer = std::make_shared<LLM::Qwen2Tokenizer>();
|
||||||
|
}
|
||||||
|
llm = std::make_shared<LLM::LLMRunner>(arch,
|
||||||
|
backend,
|
||||||
|
offload_params_to_cpu,
|
||||||
|
tensor_storage_map,
|
||||||
|
"text_encoders.llm",
|
||||||
|
enable_vision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||||
qwenvl->get_param_tensors(tensors, "text_encoders.qwen2vl");
|
llm->get_param_tensors(tensors, "text_encoders.llm");
|
||||||
}
|
}
|
||||||
|
|
||||||
void alloc_params_buffer() override {
|
void alloc_params_buffer() override {
|
||||||
qwenvl->alloc_params_buffer();
|
llm->alloc_params_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_params_buffer() override {
|
void free_params_buffer() override {
|
||||||
qwenvl->free_params_buffer();
|
llm->free_params_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_params_buffer_size() override {
|
size_t get_params_buffer_size() override {
|
||||||
size_t buffer_size = 0;
|
size_t buffer_size = 0;
|
||||||
buffer_size += qwenvl->get_params_buffer_size();
|
buffer_size += llm->get_params_buffer_size();
|
||||||
return buffer_size;
|
return buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||||
if (qwenvl) {
|
if (llm) {
|
||||||
qwenvl->set_weight_adapter(adapter);
|
llm->set_weight_adapter(adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::vector<int>, std::vector<float>> tokenize(std::string text,
|
std::tuple<std::vector<int>, std::vector<float>> tokenize(std::string text,
|
||||||
size_t max_length = 0,
|
std::pair<int, int> attn_range,
|
||||||
size_t system_prompt_length = 0,
|
size_t max_length = 0,
|
||||||
bool padding = false) {
|
bool padding = false) {
|
||||||
std::vector<std::pair<std::string, float>> parsed_attention;
|
std::vector<std::pair<std::string, float>> parsed_attention;
|
||||||
if (system_prompt_length > 0) {
|
parsed_attention.emplace_back(text.substr(0, attn_range.first), 1.f);
|
||||||
parsed_attention.emplace_back(text.substr(0, system_prompt_length), 1.f);
|
if (attn_range.second - attn_range.first > 0) {
|
||||||
auto new_parsed_attention = parse_prompt_attention(text.substr(system_prompt_length, text.size() - system_prompt_length));
|
auto new_parsed_attention = parse_prompt_attention(text.substr(attn_range.first, attn_range.second - attn_range.first));
|
||||||
parsed_attention.insert(parsed_attention.end(),
|
parsed_attention.insert(parsed_attention.end(),
|
||||||
new_parsed_attention.begin(),
|
new_parsed_attention.begin(),
|
||||||
new_parsed_attention.end());
|
new_parsed_attention.end());
|
||||||
} else {
|
|
||||||
parsed_attention = parse_prompt_attention(text);
|
|
||||||
}
|
}
|
||||||
|
parsed_attention.emplace_back(text.substr(attn_range.second), 1.f);
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "[";
|
ss << "[";
|
||||||
@ -1693,12 +1684,12 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
for (const auto& item : parsed_attention) {
|
for (const auto& item : parsed_attention) {
|
||||||
const std::string& curr_text = item.first;
|
const std::string& curr_text = item.first;
|
||||||
float curr_weight = item.second;
|
float curr_weight = item.second;
|
||||||
std::vector<int> curr_tokens = tokenizer.tokenize(curr_text, nullptr);
|
std::vector<int> curr_tokens = tokenizer->tokenize(curr_text, nullptr);
|
||||||
tokens.insert(tokens.end(), curr_tokens.begin(), curr_tokens.end());
|
tokens.insert(tokens.end(), curr_tokens.begin(), curr_tokens.end());
|
||||||
weights.insert(weights.end(), curr_tokens.size(), curr_weight);
|
weights.insert(weights.end(), curr_tokens.size(), curr_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenizer.pad_tokens(tokens, weights, max_length, padding);
|
tokenizer->pad_tokens(tokens, weights, max_length, padding);
|
||||||
|
|
||||||
// for (int i = 0; i < tokens.size(); i++) {
|
// for (int i = 0; i < tokens.size(); i++) {
|
||||||
// std::cout << tokens[i] << ":" << weights[i] << ", " << i << std::endl;
|
// std::cout << tokens[i] << ":" << weights[i] << ", " << i << std::endl;
|
||||||
@ -1713,9 +1704,11 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
const ConditionerParams& conditioner_params) override {
|
const ConditionerParams& conditioner_params) override {
|
||||||
std::string prompt;
|
std::string prompt;
|
||||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds;
|
std::vector<std::pair<int, ggml_tensor*>> image_embeds;
|
||||||
size_t system_prompt_length = 0;
|
std::pair<int, int> prompt_attn_range;
|
||||||
int prompt_template_encode_start_idx = 34;
|
int prompt_template_encode_start_idx = 34;
|
||||||
if (qwenvl->enable_vision && conditioner_params.ref_images.size() > 0) {
|
int max_length = 0;
|
||||||
|
std::set<int> out_layers;
|
||||||
|
if (llm->enable_vision && conditioner_params.ref_images.size() > 0) {
|
||||||
LOG_INFO("QwenImageEditPlusPipeline");
|
LOG_INFO("QwenImageEditPlusPipeline");
|
||||||
prompt_template_encode_start_idx = 64;
|
prompt_template_encode_start_idx = 64;
|
||||||
int image_embed_idx = 64 + 6;
|
int image_embed_idx = 64 + 6;
|
||||||
@ -1727,7 +1720,7 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
|
|
||||||
for (int i = 0; i < conditioner_params.ref_images.size(); i++) {
|
for (int i = 0; i < conditioner_params.ref_images.size(); i++) {
|
||||||
sd_image_f32_t image = sd_image_t_to_sd_image_f32_t(*conditioner_params.ref_images[i]);
|
sd_image_f32_t image = sd_image_t_to_sd_image_f32_t(*conditioner_params.ref_images[i]);
|
||||||
double factor = qwenvl->params.vision.patch_size * qwenvl->params.vision.spatial_merge_size;
|
double factor = llm->params.vision.patch_size * llm->params.vision.spatial_merge_size;
|
||||||
int height = image.height;
|
int height = image.height;
|
||||||
int width = image.width;
|
int width = image.width;
|
||||||
int h_bar = static_cast<int>(std::round(height / factor)) * factor;
|
int h_bar = static_cast<int>(std::round(height / factor)) * factor;
|
||||||
@ -1757,7 +1750,7 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
resized_image.data = nullptr;
|
resized_image.data = nullptr;
|
||||||
|
|
||||||
ggml_tensor* image_embed = nullptr;
|
ggml_tensor* image_embed = nullptr;
|
||||||
qwenvl->encode_image(n_threads, image_tensor, &image_embed, work_ctx);
|
llm->encode_image(n_threads, image_tensor, &image_embed, work_ctx);
|
||||||
image_embeds.emplace_back(image_embed_idx, image_embed);
|
image_embeds.emplace_back(image_embed_idx, image_embed);
|
||||||
image_embed_idx += 1 + image_embed->ne[1] + 6;
|
image_embed_idx += 1 + image_embed->ne[1] + 6;
|
||||||
|
|
||||||
@ -1771,17 +1764,70 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prompt = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n";
|
prompt = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n";
|
||||||
|
|
||||||
system_prompt_length = prompt.size();
|
|
||||||
|
|
||||||
prompt += img_prompt;
|
prompt += img_prompt;
|
||||||
|
|
||||||
|
prompt_attn_range.first = static_cast<int>(prompt.size());
|
||||||
prompt += conditioner_params.text;
|
prompt += conditioner_params.text;
|
||||||
|
prompt_attn_range.second = static_cast<int>(prompt.size());
|
||||||
|
|
||||||
prompt += "<|im_end|>\n<|im_start|>assistant\n";
|
prompt += "<|im_end|>\n<|im_start|>assistant\n";
|
||||||
|
} else if (sd_version_is_flux2(version)) {
|
||||||
|
prompt_template_encode_start_idx = 0;
|
||||||
|
out_layers = {10, 20, 30};
|
||||||
|
|
||||||
|
prompt = "[SYSTEM_PROMPT]You are an AI that reasons about image descriptions. You give structured responses focusing on object relationships, object\nattribution and actions without speculation.[/SYSTEM_PROMPT][INST]";
|
||||||
|
|
||||||
|
prompt_attn_range.first = static_cast<int>(prompt.size());
|
||||||
|
prompt += conditioner_params.text;
|
||||||
|
prompt_attn_range.second = static_cast<int>(prompt.size());
|
||||||
|
|
||||||
|
prompt += "[/INST]";
|
||||||
|
} else if (sd_version_is_z_image(version)) {
|
||||||
|
prompt_template_encode_start_idx = 0;
|
||||||
|
out_layers = {35}; // -2
|
||||||
|
|
||||||
|
prompt = "<|im_start|>user\n";
|
||||||
|
|
||||||
|
prompt_attn_range.first = static_cast<int>(prompt.size());
|
||||||
|
prompt += conditioner_params.text;
|
||||||
|
prompt_attn_range.second = static_cast<int>(prompt.size());
|
||||||
|
|
||||||
|
prompt += "<|im_end|>\n<|im_start|>assistant\n";
|
||||||
|
} else if (sd_version_is_flux2(version)) {
|
||||||
|
prompt_template_encode_start_idx = 0;
|
||||||
|
out_layers = {10, 20, 30};
|
||||||
|
|
||||||
|
prompt = "[SYSTEM_PROMPT]You are an AI that reasons about image descriptions. You give structured responses focusing on object relationships, object\nattribution and actions without speculation.[/SYSTEM_PROMPT][INST]";
|
||||||
|
|
||||||
|
prompt_attn_range.first = prompt.size();
|
||||||
|
prompt += conditioner_params.text;
|
||||||
|
prompt_attn_range.second = prompt.size();
|
||||||
|
|
||||||
|
prompt += "[/INST]";
|
||||||
|
} else if (version == VERSION_OVIS_IMAGE) {
|
||||||
|
prompt_template_encode_start_idx = 28;
|
||||||
|
max_length = prompt_template_encode_start_idx + 256;
|
||||||
|
|
||||||
|
prompt = "<|im_start|>user\nDescribe the image by detailing the color, quantity, text, shape, size, texture, spatial relationships of the objects and background:";
|
||||||
|
|
||||||
|
prompt_attn_range.first = static_cast<int>(prompt.size());
|
||||||
|
prompt += " " + conditioner_params.text;
|
||||||
|
prompt_attn_range.second = static_cast<int>(prompt.size());
|
||||||
|
|
||||||
|
prompt += "<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\n";
|
||||||
} else {
|
} else {
|
||||||
prompt = "<|im_start|>system\nDescribe the image by detailing the color, shape, size, texture, quantity, text, spatial relationships of the objects and background:<|im_end|>\n<|im_start|>user\n" + conditioner_params.text + "<|im_end|>\n<|im_start|>assistant\n";
|
prompt_template_encode_start_idx = 34;
|
||||||
|
|
||||||
|
prompt = "<|im_start|>system\nDescribe the image by detailing the color, shape, size, texture, quantity, text, spatial relationships of the objects and background:<|im_end|>\n<|im_start|>user\n";
|
||||||
|
|
||||||
|
prompt_attn_range.first = static_cast<int>(prompt.size());
|
||||||
|
prompt += conditioner_params.text;
|
||||||
|
prompt_attn_range.second = static_cast<int>(prompt.size());
|
||||||
|
|
||||||
|
prompt += "<|im_end|>\n<|im_start|>assistant\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tokens_and_weights = tokenize(prompt, 0, system_prompt_length, false);
|
auto tokens_and_weights = tokenize(prompt, prompt_attn_range, max_length, max_length > 0);
|
||||||
auto& tokens = std::get<0>(tokens_and_weights);
|
auto& tokens = std::get<0>(tokens_and_weights);
|
||||||
auto& weights = std::get<1>(tokens_and_weights);
|
auto& weights = std::get<1>(tokens_and_weights);
|
||||||
|
|
||||||
@ -1790,11 +1836,12 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
|
|
||||||
auto input_ids = vector_to_ggml_tensor_i32(work_ctx, tokens);
|
auto input_ids = vector_to_ggml_tensor_i32(work_ctx, tokens);
|
||||||
|
|
||||||
qwenvl->compute(n_threads,
|
llm->compute(n_threads,
|
||||||
input_ids,
|
input_ids,
|
||||||
image_embeds,
|
image_embeds,
|
||||||
&hidden_states,
|
out_layers,
|
||||||
work_ctx);
|
&hidden_states,
|
||||||
|
work_ctx);
|
||||||
{
|
{
|
||||||
auto tensor = hidden_states;
|
auto tensor = hidden_states;
|
||||||
float original_mean = ggml_ext_tensor_mean(tensor);
|
float original_mean = ggml_ext_tensor_mean(tensor);
|
||||||
@ -1813,17 +1860,34 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
|||||||
|
|
||||||
GGML_ASSERT(hidden_states->ne[1] > prompt_template_encode_start_idx);
|
GGML_ASSERT(hidden_states->ne[1] > prompt_template_encode_start_idx);
|
||||||
|
|
||||||
|
int64_t min_length = 0;
|
||||||
|
if (sd_version_is_flux2(version)) {
|
||||||
|
min_length = 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t zero_pad_len = 0;
|
||||||
|
if (min_length > 0) {
|
||||||
|
if (hidden_states->ne[1] - prompt_template_encode_start_idx < min_length) {
|
||||||
|
zero_pad_len = min_length - hidden_states->ne[1] + prompt_template_encode_start_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ggml_tensor* new_hidden_states = ggml_new_tensor_3d(work_ctx,
|
ggml_tensor* new_hidden_states = ggml_new_tensor_3d(work_ctx,
|
||||||
GGML_TYPE_F32,
|
GGML_TYPE_F32,
|
||||||
hidden_states->ne[0],
|
hidden_states->ne[0],
|
||||||
hidden_states->ne[1] - prompt_template_encode_start_idx,
|
hidden_states->ne[1] - prompt_template_encode_start_idx + zero_pad_len,
|
||||||
hidden_states->ne[2]);
|
hidden_states->ne[2]);
|
||||||
|
|
||||||
ggml_ext_tensor_iter(new_hidden_states, [&](ggml_tensor* new_hidden_states, int64_t i0, int64_t i1, int64_t i2, int64_t i3) {
|
ggml_ext_tensor_iter(new_hidden_states, [&](ggml_tensor* new_hidden_states, int64_t i0, int64_t i1, int64_t i2, int64_t i3) {
|
||||||
float value = ggml_ext_tensor_get_f32(hidden_states, i0, i1 + prompt_template_encode_start_idx, i2, i3);
|
float value = 0.f;
|
||||||
|
if (i1 + prompt_template_encode_start_idx < hidden_states->ne[1]) {
|
||||||
|
value = ggml_ext_tensor_get_f32(hidden_states, i0, i1 + prompt_template_encode_start_idx, i2, i3);
|
||||||
|
}
|
||||||
ggml_ext_tensor_set_f32(new_hidden_states, value, i0, i1, i2, i3);
|
ggml_ext_tensor_set_f32(new_hidden_states, value, i0, i1, i2, i3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// print_ggml_tensor(new_hidden_states);
|
||||||
|
|
||||||
int64_t t1 = ggml_time_ms();
|
int64_t t1 = ggml_time_ms();
|
||||||
LOG_DEBUG("computing condition graph completed, taking %" PRId64 " ms", t1 - t0);
|
LOG_DEBUG("computing condition graph completed, taking %" PRId64 " ms", t1 - t0);
|
||||||
return {new_hidden_states, nullptr, nullptr};
|
return {new_hidden_states, nullptr, nullptr};
|
||||||
|
|||||||
10
control.hpp
@ -414,7 +414,7 @@ struct ControlNet : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* hint,
|
struct ggml_tensor* hint,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
@ -430,8 +430,12 @@ struct ControlNet : public GGMLRunner {
|
|||||||
return build_graph(x, hint, timesteps, context, y);
|
return build_graph(x, hint, timesteps, context, y);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
bool res = GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
guided_hint_cached = true;
|
if (res) {
|
||||||
|
// cache guided_hint
|
||||||
|
guided_hint_cached = true;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_from_file(const std::string& file_path, int n_threads) {
|
bool load_from_file(const std::string& file_path, int n_threads) {
|
||||||
|
|||||||
219
denoiser.hpp
@ -11,14 +11,13 @@
|
|||||||
#define TIMESTEPS 1000
|
#define TIMESTEPS 1000
|
||||||
#define FLUX_TIMESTEPS 1000
|
#define FLUX_TIMESTEPS 1000
|
||||||
|
|
||||||
struct SigmaSchedule {
|
struct SigmaScheduler {
|
||||||
int version = 0;
|
|
||||||
typedef std::function<float(float)> t_to_sigma_t;
|
typedef std::function<float(float)> t_to_sigma_t;
|
||||||
|
|
||||||
virtual std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) = 0;
|
virtual std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DiscreteSchedule : SigmaSchedule {
|
struct DiscreteScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
std::vector<float> result;
|
std::vector<float> result;
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ struct DiscreteSchedule : SigmaSchedule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExponentialSchedule : SigmaSchedule {
|
struct ExponentialScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
std::vector<float> sigmas;
|
std::vector<float> sigmas;
|
||||||
|
|
||||||
@ -149,7 +148,10 @@ std::vector<float> log_linear_interpolation(std::vector<float> sigma_in,
|
|||||||
/*
|
/*
|
||||||
https://research.nvidia.com/labs/toronto-ai/AlignYourSteps/howto.html
|
https://research.nvidia.com/labs/toronto-ai/AlignYourSteps/howto.html
|
||||||
*/
|
*/
|
||||||
struct AYSSchedule : SigmaSchedule {
|
struct AYSScheduler : SigmaScheduler {
|
||||||
|
SDVersion version;
|
||||||
|
explicit AYSScheduler(SDVersion version)
|
||||||
|
: version(version) {}
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
const std::vector<float> noise_levels[] = {
|
const std::vector<float> noise_levels[] = {
|
||||||
/* SD1.5 */
|
/* SD1.5 */
|
||||||
@ -169,19 +171,19 @@ struct AYSSchedule : SigmaSchedule {
|
|||||||
std::vector<float> results(n + 1);
|
std::vector<float> results(n + 1);
|
||||||
|
|
||||||
if (sd_version_is_sd2((SDVersion)version)) {
|
if (sd_version_is_sd2((SDVersion)version)) {
|
||||||
LOG_WARN("AYS not designed for SD2.X models");
|
LOG_WARN("AYS_SCHEDULER not designed for SD2.X models");
|
||||||
} /* fallthrough */
|
} /* fallthrough */
|
||||||
else if (sd_version_is_sd1((SDVersion)version)) {
|
else if (sd_version_is_sd1((SDVersion)version)) {
|
||||||
LOG_INFO("AYS using SD1.5 noise levels");
|
LOG_INFO("AYS_SCHEDULER using SD1.5 noise levels");
|
||||||
inputs = noise_levels[0];
|
inputs = noise_levels[0];
|
||||||
} else if (sd_version_is_sdxl((SDVersion)version)) {
|
} else if (sd_version_is_sdxl((SDVersion)version)) {
|
||||||
LOG_INFO("AYS using SDXL noise levels");
|
LOG_INFO("AYS_SCHEDULER using SDXL noise levels");
|
||||||
inputs = noise_levels[1];
|
inputs = noise_levels[1];
|
||||||
} else if (version == VERSION_SVD) {
|
} else if (version == VERSION_SVD) {
|
||||||
LOG_INFO("AYS using SVD noise levels");
|
LOG_INFO("AYS_SCHEDULER using SVD noise levels");
|
||||||
inputs = noise_levels[2];
|
inputs = noise_levels[2];
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Version not compatible with AYS scheduler");
|
LOG_ERROR("Version not compatible with AYS_SCHEDULER scheduler");
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +205,7 @@ struct AYSSchedule : SigmaSchedule {
|
|||||||
/*
|
/*
|
||||||
* GITS Scheduler: https://github.com/zju-pi/diff-sampler/tree/main/gits-main
|
* GITS Scheduler: https://github.com/zju-pi/diff-sampler/tree/main/gits-main
|
||||||
*/
|
*/
|
||||||
struct GITSSchedule : SigmaSchedule {
|
struct GITSScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
if (sigma_max <= 0.0f) {
|
if (sigma_max <= 0.0f) {
|
||||||
return std::vector<float>{};
|
return std::vector<float>{};
|
||||||
@ -232,7 +234,7 @@ struct GITSSchedule : SigmaSchedule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SGMUniformSchedule : SigmaSchedule {
|
struct SGMUniformScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min_in, float sigma_max_in, t_to_sigma_t t_to_sigma_func) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min_in, float sigma_max_in, t_to_sigma_t t_to_sigma_func) override {
|
||||||
std::vector<float> result;
|
std::vector<float> result;
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
@ -251,7 +253,24 @@ struct SGMUniformSchedule : SigmaSchedule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KarrasSchedule : SigmaSchedule {
|
struct LCMScheduler : SigmaScheduler {
|
||||||
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
|
std::vector<float> result;
|
||||||
|
result.reserve(n + 1);
|
||||||
|
const int original_steps = 50;
|
||||||
|
const int k = TIMESTEPS / original_steps;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
// the rounding ensures we match the training schedule of the LCM model
|
||||||
|
int index = (i * original_steps) / n;
|
||||||
|
int timestep = (original_steps - index) * k - 1;
|
||||||
|
result.push_back(t_to_sigma(timestep));
|
||||||
|
}
|
||||||
|
result.push_back(0.0f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KarrasScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
// These *COULD* be function arguments here,
|
// These *COULD* be function arguments here,
|
||||||
// but does anybody ever bother to touch them?
|
// but does anybody ever bother to touch them?
|
||||||
@ -270,7 +289,7 @@ struct KarrasSchedule : SigmaSchedule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SimpleSchedule : SigmaSchedule {
|
struct SimpleScheduler : SigmaScheduler {
|
||||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||||
std::vector<float> result_sigmas;
|
std::vector<float> result_sigmas;
|
||||||
|
|
||||||
@ -299,8 +318,8 @@ struct SimpleSchedule : SigmaSchedule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Close to Beta Schedule, but increadably simple in code.
|
// Close to Beta Scheduler, but increadably simple in code.
|
||||||
struct SmoothStepSchedule : SigmaSchedule {
|
struct SmoothStepScheduler : SigmaScheduler {
|
||||||
static constexpr float smoothstep(float x) {
|
static constexpr float smoothstep(float x) {
|
||||||
return x * x * (3.0f - 2.0f * x);
|
return x * x * (3.0f - 2.0f * x);
|
||||||
}
|
}
|
||||||
@ -329,7 +348,6 @@ struct SmoothStepSchedule : SigmaSchedule {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Denoiser {
|
struct Denoiser {
|
||||||
std::shared_ptr<SigmaSchedule> scheduler = std::make_shared<DiscreteSchedule>();
|
|
||||||
virtual float sigma_min() = 0;
|
virtual float sigma_min() = 0;
|
||||||
virtual float sigma_max() = 0;
|
virtual float sigma_max() = 0;
|
||||||
virtual float sigma_to_t(float sigma) = 0;
|
virtual float sigma_to_t(float sigma) = 0;
|
||||||
@ -338,8 +356,51 @@ struct Denoiser {
|
|||||||
virtual ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) = 0;
|
virtual ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) = 0;
|
||||||
virtual ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) = 0;
|
virtual ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) = 0;
|
||||||
|
|
||||||
virtual std::vector<float> get_sigmas(uint32_t n) {
|
virtual std::vector<float> get_sigmas(uint32_t n, int /*image_seq_len*/, scheduler_t scheduler_type, SDVersion version) {
|
||||||
auto bound_t_to_sigma = std::bind(&Denoiser::t_to_sigma, this, std::placeholders::_1);
|
auto bound_t_to_sigma = std::bind(&Denoiser::t_to_sigma, this, std::placeholders::_1);
|
||||||
|
std::shared_ptr<SigmaScheduler> scheduler;
|
||||||
|
switch (scheduler_type) {
|
||||||
|
case DISCRETE_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with discrete scheduler");
|
||||||
|
scheduler = std::make_shared<DiscreteScheduler>();
|
||||||
|
break;
|
||||||
|
case KARRAS_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with Karras scheduler");
|
||||||
|
scheduler = std::make_shared<KarrasScheduler>();
|
||||||
|
break;
|
||||||
|
case EXPONENTIAL_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas exponential scheduler");
|
||||||
|
scheduler = std::make_shared<ExponentialScheduler>();
|
||||||
|
break;
|
||||||
|
case AYS_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with Align-Your-Steps scheduler");
|
||||||
|
scheduler = std::make_shared<AYSScheduler>(version);
|
||||||
|
break;
|
||||||
|
case GITS_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with GITS scheduler");
|
||||||
|
scheduler = std::make_shared<GITSScheduler>();
|
||||||
|
break;
|
||||||
|
case SGM_UNIFORM_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with SGM Uniform scheduler");
|
||||||
|
scheduler = std::make_shared<SGMUniformScheduler>();
|
||||||
|
break;
|
||||||
|
case SIMPLE_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with Simple scheduler");
|
||||||
|
scheduler = std::make_shared<SimpleScheduler>();
|
||||||
|
break;
|
||||||
|
case SMOOTHSTEP_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with SmoothStep scheduler");
|
||||||
|
scheduler = std::make_shared<SmoothStepScheduler>();
|
||||||
|
break;
|
||||||
|
case LCM_SCHEDULER:
|
||||||
|
LOG_INFO("get_sigmas with LCM scheduler");
|
||||||
|
scheduler = std::make_shared<LCMScheduler>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_INFO("get_sigmas with discrete scheduler (default)");
|
||||||
|
scheduler = std::make_shared<DiscreteScheduler>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
return scheduler->get_sigmas(n, sigma_min(), sigma_max(), bound_t_to_sigma);
|
return scheduler->get_sigmas(n, sigma_min(), sigma_max(), bound_t_to_sigma);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -426,7 +487,6 @@ struct EDMVDenoiser : public CompVisVDenoiser {
|
|||||||
|
|
||||||
EDMVDenoiser(float min_sigma = 0.002, float max_sigma = 120.0)
|
EDMVDenoiser(float min_sigma = 0.002, float max_sigma = 120.0)
|
||||||
: min_sigma(min_sigma), max_sigma(max_sigma) {
|
: min_sigma(min_sigma), max_sigma(max_sigma) {
|
||||||
scheduler = std::make_shared<ExponentialSchedule>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float t_to_sigma(float t) override {
|
float t_to_sigma(float t) override {
|
||||||
@ -522,10 +582,14 @@ struct FluxFlowDenoiser : public Denoiser {
|
|||||||
set_parameters(shift);
|
set_parameters(shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_parameters(float shift = 1.15f) {
|
void set_shift(float shift) {
|
||||||
this->shift = shift;
|
this->shift = shift;
|
||||||
for (int i = 1; i < TIMESTEPS + 1; i++) {
|
}
|
||||||
sigmas[i - 1] = t_to_sigma(i / TIMESTEPS * TIMESTEPS);
|
|
||||||
|
void set_parameters(float shift) {
|
||||||
|
set_shift(shift);
|
||||||
|
for (int i = 0; i < TIMESTEPS; i++) {
|
||||||
|
sigmas[i] = t_to_sigma(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,10 +631,42 @@ struct FluxFlowDenoiser : public Denoiser {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Flux2FlowDenoiser : public FluxFlowDenoiser {
|
||||||
|
Flux2FlowDenoiser() = default;
|
||||||
|
|
||||||
|
float compute_empirical_mu(uint32_t n, int image_seq_len) {
|
||||||
|
const float a1 = 8.73809524e-05f;
|
||||||
|
const float b1 = 1.89833333f;
|
||||||
|
const float a2 = 0.00016927f;
|
||||||
|
const float b2 = 0.45666666f;
|
||||||
|
|
||||||
|
if (image_seq_len > 4300) {
|
||||||
|
float mu = a2 * image_seq_len + b2;
|
||||||
|
return mu;
|
||||||
|
}
|
||||||
|
|
||||||
|
float m_200 = a2 * image_seq_len + b2;
|
||||||
|
float m_10 = a1 * image_seq_len + b1;
|
||||||
|
|
||||||
|
float a = (m_200 - m_10) / 190.0f;
|
||||||
|
float b = m_200 - 200.0f * a;
|
||||||
|
float mu = a * n + b;
|
||||||
|
|
||||||
|
return mu;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<float> get_sigmas(uint32_t n, int image_seq_len, scheduler_t scheduler_type, SDVersion version) override {
|
||||||
|
float mu = compute_empirical_mu(n, image_seq_len);
|
||||||
|
LOG_DEBUG("Flux2FlowDenoiser: set shift to %.3f", mu);
|
||||||
|
set_shift(mu);
|
||||||
|
return Denoiser::get_sigmas(n, image_seq_len, scheduler_type, version);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::function<ggml_tensor*(ggml_tensor*, float, int)> denoise_cb_t;
|
typedef std::function<ggml_tensor*(ggml_tensor*, float, int)> denoise_cb_t;
|
||||||
|
|
||||||
// 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 void sample_k_diffusion(sample_method_t method,
|
static bool sample_k_diffusion(sample_method_t method,
|
||||||
denoise_cb_t model,
|
denoise_cb_t model,
|
||||||
ggml_context* work_ctx,
|
ggml_context* work_ctx,
|
||||||
ggml_tensor* x,
|
ggml_tensor* x,
|
||||||
@ -580,7 +676,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
size_t steps = sigmas.size() - 1;
|
size_t steps = sigmas.size() - 1;
|
||||||
// sample_euler_ancestral
|
// sample_euler_ancestral
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case EULER_A: {
|
case EULER_A_SAMPLE_METHOD: {
|
||||||
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
||||||
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
@ -589,6 +685,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigma, i + 1);
|
ggml_tensor* denoised = model(x, sigma, i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// d = (x - denoised) / sigma
|
// d = (x - denoised) / sigma
|
||||||
{
|
{
|
||||||
@ -633,7 +732,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case EULER: // Implemented without any sigma churn
|
case EULER_SAMPLE_METHOD: // Implemented without any sigma churn
|
||||||
{
|
{
|
||||||
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
@ -642,6 +741,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigma, i + 1);
|
ggml_tensor* denoised = model(x, sigma, i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// d = (x - denoised) / sigma
|
// d = (x - denoised) / sigma
|
||||||
{
|
{
|
||||||
@ -666,13 +768,16 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case HEUN: {
|
case HEUN_SAMPLE_METHOD: {
|
||||||
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
||||||
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigmas[i], -(i + 1));
|
ggml_tensor* denoised = model(x, sigmas[i], -(i + 1));
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// d = (x - denoised) / sigma
|
// d = (x - denoised) / sigma
|
||||||
{
|
{
|
||||||
@ -707,7 +812,10 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ggml_tensor* denoised = model(x2, sigmas[i + 1], i + 1);
|
ggml_tensor* denoised = model(x2, sigmas[i + 1], i + 1);
|
||||||
float* vec_denoised = (float*)denoised->data;
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float* vec_denoised = (float*)denoised->data;
|
||||||
for (int j = 0; j < ggml_nelements(x); j++) {
|
for (int j = 0; j < ggml_nelements(x); j++) {
|
||||||
float d2 = (vec_x2[j] - vec_denoised[j]) / sigmas[i + 1];
|
float d2 = (vec_x2[j] - vec_denoised[j]) / sigmas[i + 1];
|
||||||
vec_d[j] = (vec_d[j] + d2) / 2;
|
vec_d[j] = (vec_d[j] + d2) / 2;
|
||||||
@ -716,13 +824,16 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case DPM2: {
|
case DPM2_SAMPLE_METHOD: {
|
||||||
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
||||||
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// d = (x - denoised) / sigma
|
// d = (x - denoised) / sigma
|
||||||
{
|
{
|
||||||
@ -759,7 +870,10 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ggml_tensor* denoised = model(x2, sigma_mid, i + 1);
|
ggml_tensor* denoised = model(x2, sigma_mid, i + 1);
|
||||||
float* vec_denoised = (float*)denoised->data;
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float* vec_denoised = (float*)denoised->data;
|
||||||
for (int j = 0; j < ggml_nelements(x); j++) {
|
for (int j = 0; j < ggml_nelements(x); j++) {
|
||||||
float d2 = (vec_x2[j] - vec_denoised[j]) / sigma_mid;
|
float d2 = (vec_x2[j] - vec_denoised[j]) / sigma_mid;
|
||||||
vec_x[j] = vec_x[j] + d2 * dt_2;
|
vec_x[j] = vec_x[j] + d2 * dt_2;
|
||||||
@ -768,13 +882,16 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case DPMPP2S_A: {
|
case DPMPP2S_A_SAMPLE_METHOD: {
|
||||||
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
||||||
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* x2 = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// get_ancestral_step
|
// get_ancestral_step
|
||||||
float sigma_up = std::min(sigmas[i + 1],
|
float sigma_up = std::min(sigmas[i + 1],
|
||||||
@ -811,6 +928,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ggml_tensor* denoised = model(x2, sigmas[i + 1], i + 1);
|
ggml_tensor* denoised = model(x2, sigmas[i + 1], i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Second half-step
|
// Second half-step
|
||||||
for (int j = 0; j < ggml_nelements(x); j++) {
|
for (int j = 0; j < ggml_nelements(x); j++) {
|
||||||
@ -832,7 +952,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case DPMPP2M: // DPM++ (2M) from Karras et al (2022)
|
case DPMPP2M_SAMPLE_METHOD: // DPM++ (2M) from Karras et al (2022)
|
||||||
{
|
{
|
||||||
struct ggml_tensor* old_denoised = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* old_denoised = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
@ -841,6 +961,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
float t = t_fn(sigmas[i]);
|
float t = t_fn(sigmas[i]);
|
||||||
float t_next = t_fn(sigmas[i + 1]);
|
float t_next = t_fn(sigmas[i + 1]);
|
||||||
@ -871,7 +994,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case DPMPP2Mv2: // Modified DPM++ (2M) from https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/8457
|
case DPMPP2Mv2_SAMPLE_METHOD: // Modified DPM++ (2M) from https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/8457
|
||||||
{
|
{
|
||||||
struct ggml_tensor* old_denoised = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* old_denoised = ggml_dup_tensor(work_ctx, x);
|
||||||
|
|
||||||
@ -880,6 +1003,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
ggml_tensor* denoised = model(x, sigmas[i], i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
float t = t_fn(sigmas[i]);
|
float t = t_fn(sigmas[i]);
|
||||||
float t_next = t_fn(sigmas[i + 1]);
|
float t_next = t_fn(sigmas[i + 1]);
|
||||||
@ -914,7 +1040,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case IPNDM: // iPNDM sampler from https://github.com/zju-pi/diff-sampler/tree/main/diff-solvers-main
|
case IPNDM_SAMPLE_METHOD: // iPNDM sampler from https://github.com/zju-pi/diff-sampler/tree/main/diff-solvers-main
|
||||||
{
|
{
|
||||||
int max_order = 4;
|
int max_order = 4;
|
||||||
ggml_tensor* x_next = x;
|
ggml_tensor* x_next = x;
|
||||||
@ -930,7 +1056,10 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
// Denoising step
|
// Denoising step
|
||||||
ggml_tensor* denoised = model(x_cur, sigma, i + 1);
|
ggml_tensor* denoised = model(x_cur, sigma, i + 1);
|
||||||
float* vec_denoised = (float*)denoised->data;
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float* vec_denoised = (float*)denoised->data;
|
||||||
// d_cur = (x_cur - denoised) / sigma
|
// d_cur = (x_cur - denoised) / sigma
|
||||||
struct ggml_tensor* d_cur = ggml_dup_tensor(work_ctx, x_cur);
|
struct ggml_tensor* d_cur = ggml_dup_tensor(work_ctx, x_cur);
|
||||||
float* vec_d_cur = (float*)d_cur->data;
|
float* vec_d_cur = (float*)d_cur->data;
|
||||||
@ -989,7 +1118,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case IPNDM_V: // iPNDM_v sampler from https://github.com/zju-pi/diff-sampler/tree/main/diff-solvers-main
|
case IPNDM_V_SAMPLE_METHOD: // iPNDM_v sampler from https://github.com/zju-pi/diff-sampler/tree/main/diff-solvers-main
|
||||||
{
|
{
|
||||||
int max_order = 4;
|
int max_order = 4;
|
||||||
std::vector<ggml_tensor*> buffer_model;
|
std::vector<ggml_tensor*> buffer_model;
|
||||||
@ -1063,7 +1192,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
d_cur = ggml_dup_tensor(work_ctx, x_next);
|
d_cur = ggml_dup_tensor(work_ctx, x_next);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case LCM: // Latent Consistency Models
|
case LCM_SAMPLE_METHOD: // Latent Consistency Models
|
||||||
{
|
{
|
||||||
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* noise = ggml_dup_tensor(work_ctx, x);
|
||||||
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
struct ggml_tensor* d = ggml_dup_tensor(work_ctx, x);
|
||||||
@ -1073,6 +1202,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
// denoise
|
// denoise
|
||||||
ggml_tensor* denoised = model(x, sigma, i + 1);
|
ggml_tensor* denoised = model(x, sigma, i + 1);
|
||||||
|
if (denoised == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// x = denoised
|
// x = denoised
|
||||||
{
|
{
|
||||||
@ -1098,8 +1230,8 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case DDIM_TRAILING: // Denoising Diffusion Implicit Models
|
case DDIM_TRAILING_SAMPLE_METHOD: // Denoising Diffusion Implicit Models
|
||||||
// with the "trailing" timestep spacing
|
// with the "trailing" timestep spacing
|
||||||
{
|
{
|
||||||
// See J. Song et al., "Denoising Diffusion Implicit
|
// See J. Song et al., "Denoising Diffusion Implicit
|
||||||
// Models", arXiv:2010.02502 [cs.LG]
|
// Models", arXiv:2010.02502 [cs.LG]
|
||||||
@ -1109,7 +1241,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
// end beta) (which unfortunately k-diffusion's data
|
// end beta) (which unfortunately k-diffusion's data
|
||||||
// structure hides from the denoiser), and the sigmas are
|
// structure hides from the denoiser), and the sigmas are
|
||||||
// also needed to invert the behavior of CompVisDenoiser
|
// also needed to invert the behavior of CompVisDenoiser
|
||||||
// (k-diffusion's LMSDiscreteScheduler)
|
// (k-diffusion's LMSDiscreteSchedulerr)
|
||||||
float beta_start = 0.00085f;
|
float beta_start = 0.00085f;
|
||||||
float beta_end = 0.0120f;
|
float beta_end = 0.0120f;
|
||||||
std::vector<double> alphas_cumprod;
|
std::vector<double> alphas_cumprod;
|
||||||
@ -1137,7 +1269,7 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
// The "trailing" DDIM timestep, see S. Lin et al.,
|
// The "trailing" DDIM timestep, see S. Lin et al.,
|
||||||
// "Common Diffusion Noise Schedules and Sample Steps
|
// "Common Diffusion Noise Schedulers and Sample Steps
|
||||||
// are Flawed", arXiv:2305.08891 [cs], p. 4, Table
|
// are Flawed", arXiv:2305.08891 [cs], p. 4, Table
|
||||||
// 2. Most variables below follow Diffusers naming
|
// 2. Most variables below follow Diffusers naming
|
||||||
//
|
//
|
||||||
@ -1292,8 +1424,8 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
// factor c_in.
|
// factor c_in.
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case TCD: // Strategic Stochastic Sampling (Algorithm 4) in
|
case TCD_SAMPLE_METHOD: // Strategic Stochastic Sampling (Algorithm 4) in
|
||||||
// Trajectory Consistency Distillation
|
// Trajectory Consistency Distillation
|
||||||
{
|
{
|
||||||
// See J. Zheng et al., "Trajectory Consistency
|
// See J. Zheng et al., "Trajectory Consistency
|
||||||
// Distillation: Improved Latent Consistency Distillation
|
// Distillation: Improved Latent Consistency Distillation
|
||||||
@ -1465,8 +1597,9 @@ static void sample_k_diffusion(sample_method_t method,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Attempting to sample with nonexisting sample method %i", method);
|
LOG_ERROR("Attempting to sample with nonexisting sample method %i", method);
|
||||||
abort();
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __DENOISER_HPP__
|
#endif // __DENOISER_HPP__
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "qwen_image.hpp"
|
#include "qwen_image.hpp"
|
||||||
#include "unet.hpp"
|
#include "unet.hpp"
|
||||||
#include "wan.hpp"
|
#include "wan.hpp"
|
||||||
|
#include "z_image.hpp"
|
||||||
|
|
||||||
struct DiffusionParams {
|
struct DiffusionParams {
|
||||||
struct ggml_tensor* x = nullptr;
|
struct ggml_tensor* x = nullptr;
|
||||||
@ -26,7 +27,7 @@ struct DiffusionParams {
|
|||||||
|
|
||||||
struct DiffusionModel {
|
struct DiffusionModel {
|
||||||
virtual std::string get_desc() = 0;
|
virtual std::string get_desc() = 0;
|
||||||
virtual void compute(int n_threads,
|
virtual bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) = 0;
|
struct ggml_context* output_ctx = nullptr) = 0;
|
||||||
@ -86,7 +87,7 @@ struct UNetModel : public DiffusionModel {
|
|||||||
unet.set_flash_attention_enabled(enabled);
|
unet.set_flash_attention_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) override {
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
@ -147,7 +148,7 @@ struct MMDiTModel : public DiffusionModel {
|
|||||||
mmdit.set_flash_attention_enabled(enabled);
|
mmdit.set_flash_attention_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) override {
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
@ -209,7 +210,7 @@ struct FluxModel : public DiffusionModel {
|
|||||||
flux.set_flash_attention_enabled(enabled);
|
flux.set_flash_attention_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) override {
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
@ -276,7 +277,7 @@ struct WanModel : public DiffusionModel {
|
|||||||
wan.set_flash_attention_enabled(enabled);
|
wan.set_flash_attention_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) override {
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
@ -342,7 +343,7 @@ struct QwenImageModel : public DiffusionModel {
|
|||||||
qwen_image.set_flash_attention_enabled(enabled);
|
qwen_image.set_flash_attention_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
DiffusionParams diffusion_params,
|
DiffusionParams diffusion_params,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) override {
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
@ -357,4 +358,67 @@ struct QwenImageModel : public DiffusionModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZImageModel : public DiffusionModel {
|
||||||
|
std::string prefix;
|
||||||
|
ZImage::ZImageRunner z_image;
|
||||||
|
|
||||||
|
ZImageModel(ggml_backend_t backend,
|
||||||
|
bool offload_params_to_cpu,
|
||||||
|
const String2TensorStorage& tensor_storage_map = {},
|
||||||
|
const std::string prefix = "model.diffusion_model",
|
||||||
|
SDVersion version = VERSION_Z_IMAGE)
|
||||||
|
: prefix(prefix), z_image(backend, offload_params_to_cpu, tensor_storage_map, prefix, version) {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_desc() override {
|
||||||
|
return z_image.get_desc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void alloc_params_buffer() override {
|
||||||
|
z_image.alloc_params_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_params_buffer() override {
|
||||||
|
z_image.free_params_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_compute_buffer() override {
|
||||||
|
z_image.free_compute_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||||
|
z_image.get_param_tensors(tensors, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_params_buffer_size() override {
|
||||||
|
return z_image.get_params_buffer_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||||
|
z_image.set_weight_adapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t get_adm_in_channels() override {
|
||||||
|
return 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_flash_attn_enabled(bool enabled) {
|
||||||
|
z_image.set_flash_attention_enabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compute(int n_threads,
|
||||||
|
DiffusionParams diffusion_params,
|
||||||
|
struct ggml_tensor** output = nullptr,
|
||||||
|
struct ggml_context* output_ctx = nullptr) override {
|
||||||
|
return z_image.compute(n_threads,
|
||||||
|
diffusion_params.x,
|
||||||
|
diffusion_params.timesteps,
|
||||||
|
diffusion_params.context,
|
||||||
|
diffusion_params.ref_latents,
|
||||||
|
true, // increase_ref_index
|
||||||
|
output,
|
||||||
|
output_ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,7 +15,7 @@ You can run Flux using stable-diffusion.cpp with a GPU that has 6GB or even 4GB
|
|||||||
|
|
||||||
You can download the preconverted gguf weights from [FLUX.1-dev-gguf](https://huggingface.co/leejet/FLUX.1-dev-gguf) or [FLUX.1-schnell](https://huggingface.co/leejet/FLUX.1-schnell-gguf), this way you don't have to do the conversion yourself.
|
You can download the preconverted gguf weights from [FLUX.1-dev-gguf](https://huggingface.co/leejet/FLUX.1-dev-gguf) or [FLUX.1-schnell](https://huggingface.co/leejet/FLUX.1-schnell-gguf), this way you don't have to do the conversion yourself.
|
||||||
|
|
||||||
Using fp16 will lead to overflow, but ggml's support for bf16 is not yet fully developed. Therefore, we need to convert flux to gguf format here, which also saves VRAM. For example:
|
For example:
|
||||||
```
|
```
|
||||||
.\bin\Release\sd.exe -M convert -m ..\..\ComfyUI\models\unet\flux1-dev.sft -o ..\models\flux1-dev-q8_0.gguf -v --type q8_0
|
.\bin\Release\sd.exe -M convert -m ..\..\ComfyUI\models\unet\flux1-dev.sft -o ..\models\flux1-dev-q8_0.gguf -v --type q8_0
|
||||||
```
|
```
|
||||||
|
|||||||
21
docs/flux2.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# How to Use
|
||||||
|
|
||||||
|
## Download weights
|
||||||
|
|
||||||
|
- Download FLUX.2-dev
|
||||||
|
- gguf: https://huggingface.co/city96/FLUX.2-dev-gguf/tree/main
|
||||||
|
- Download vae
|
||||||
|
- safetensors: https://huggingface.co/black-forest-labs/FLUX.2-dev/tree/main
|
||||||
|
- Download Mistral-Small-3.2-24B-Instruct-2506-GGUF
|
||||||
|
- gguf: https://huggingface.co/unsloth/Mistral-Small-3.2-24B-Instruct-2506-GGUF/tree/main
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\flux2-dev-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\flux2_ae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Mistral-Small-3.2-24B-Instruct-2506-Q4_K_M.gguf -r .\kontext_input.png -p "change 'flux.cpp' to 'flux2-dev.cpp'" --cfg-scale 1.0 --sampling-method euler -v --diffusion-fa --offload-to-cpu
|
||||||
|
```
|
||||||
|
|
||||||
|
<img alt="flux2 example" src="../assets/flux2/example.png" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
19
docs/ovis_image.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# How to Use
|
||||||
|
|
||||||
|
## Download weights
|
||||||
|
|
||||||
|
- Download Ovis-Image-7B
|
||||||
|
- safetensors: https://huggingface.co/Comfy-Org/Ovis-Image/tree/main/split_files/diffusion_models
|
||||||
|
- gguf: https://huggingface.co/leejet/Ovis-Image-7B-GGUF
|
||||||
|
- Download vae
|
||||||
|
- safetensors: https://huggingface.co/black-forest-labs/FLUX.1-schnell/tree/main
|
||||||
|
- Download Ovis 2.5
|
||||||
|
- safetensors: https://huggingface.co/Comfy-Org/Ovis-Image/tree/main/split_files/text_encoders
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
.\bin\Release\sd.exe --diffusion-model ovis_image-Q4_0.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\ovis_2.5.safetensors -p "a lovely cat" --cfg-scale 5.0 -v --offload-to-cpu --diffusion-fa
|
||||||
|
```
|
||||||
|
|
||||||
|
<img alt="ovis image example" src="../assets/ovis_image/example.png" />
|
||||||
@ -14,7 +14,7 @@
|
|||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
```
|
```
|
||||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\qwen-image-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --qwen2vl ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p '一个穿着"QWEN"标志的T恤的中国美女正拿着黑色的马克笔面相镜头微笑。她身后的玻璃板上手写体写着 “一、Qwen-Image的技术路线: 探索视觉生成基础模型的极限,开创理解与生成一体化的未来。二、Qwen-Image的模型特色:1、复杂文字渲染。支持中英渲染、自动布局; 2、精准图像编辑。支持文字编辑、物体增减、风格变换。三、Qwen-Image的未来愿景:赋能专业内容创作、助力生成式AI发展。”' --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu -H 1024 -W 1024 --diffusion-fa --flow-shift 3
|
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\qwen-image-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf -p '一个穿着"QWEN"标志的T恤的中国美女正拿着黑色的马克笔面相镜头微笑。她身后的玻璃板上手写体写着 “一、Qwen-Image的技术路线: 探索视觉生成基础模型的极限,开创理解与生成一体化的未来。二、Qwen-Image的模型特色:1、复杂文字渲染。支持中英渲染、自动布局; 2、精准图像编辑。支持文字编辑、物体增减、风格变换。三、Qwen-Image的未来愿景:赋能专业内容创作、助力生成式AI发展。”' --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu -H 1024 -W 1024 --diffusion-fa --flow-shift 3
|
||||||
```
|
```
|
||||||
|
|
||||||
<img alt="qwen example" src="../assets/qwen/example.png" />
|
<img alt="qwen example" src="../assets/qwen/example.png" />
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
### Qwen Image Edit
|
### Qwen Image Edit
|
||||||
|
|
||||||
```
|
```
|
||||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen_Image_Edit-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --qwen2vl ..\..\ComfyUI\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --seed 1118877715456453
|
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen_Image_Edit-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --seed 1118877715456453
|
||||||
```
|
```
|
||||||
|
|
||||||
<img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" />
|
<img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" />
|
||||||
@ -29,7 +29,7 @@
|
|||||||
### Qwen Image Edit 2509
|
### Qwen Image Edit 2509
|
||||||
|
|
||||||
```
|
```
|
||||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen-Image-Edit-2509-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --qwen2vl ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf --qwen2vl_vision ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'Qwen Image Edit 2509'"
|
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen-Image-Edit-2509-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --llm ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf --llm_vision ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'Qwen Image Edit 2509'"
|
||||||
```
|
```
|
||||||
|
|
||||||
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" />
|
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" />
|
||||||
28
docs/z_image.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# How to Use
|
||||||
|
|
||||||
|
You can run Z-Image with stable-diffusion.cpp on GPUs with 4GB of VRAM — or even less.
|
||||||
|
|
||||||
|
## Download weights
|
||||||
|
|
||||||
|
- Download Z-Image-Turbo
|
||||||
|
- safetensors: https://huggingface.co/Comfy-Org/z_image_turbo/tree/main/split_files/diffusion_models
|
||||||
|
- gguf: https://huggingface.co/leejet/Z-Image-Turbo-GGUF/tree/main
|
||||||
|
- Download vae
|
||||||
|
- safetensors: https://huggingface.co/black-forest-labs/FLUX.1-schnell/tree/main
|
||||||
|
- Download Qwen3 4b
|
||||||
|
- safetensors: https://huggingface.co/Comfy-Org/z_image_turbo/tree/main/split_files/text_encoders
|
||||||
|
- gguf: https://huggingface.co/unsloth/Qwen3-4B-Instruct-2507-GGUF/tree/main
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
.\bin\Release\sd.exe --diffusion-model z_image_turbo-Q3_K.gguf --vae ..\..\ComfyUI\models\vae\ae.sft --llm ..\..\ComfyUI\models\text_encoders\Qwen3-4B-Instruct-2507-Q4_K_M.gguf -p "A cinematic, melancholic photograph of a solitary hooded figure walking through a sprawling, rain-slicked metropolis at night. The city lights are a chaotic blur of neon orange and cool blue, reflecting on the wet asphalt. The scene evokes a sense of being a single component in a vast machine. Superimposed over the image in a sleek, modern, slightly glitched font is the philosophical quote: 'THE CITY IS A CIRCUIT BOARD, AND I AM A BROKEN TRANSISTOR.' -- moody, atmospheric, profound, dark academic" --cfg-scale 1.0 -v --offload-to-cpu --diffusion-fa -H 1024 -W 512
|
||||||
|
```
|
||||||
|
|
||||||
|
<img width="256" alt="z-image example" src="../assets/z_image/q3_K.png" />
|
||||||
|
|
||||||
|
## Comparison of Different Quantization Types
|
||||||
|
|
||||||
|
| bf16 | q8_0 | q6_K | q5_0 | q4_K | q4_0 | q3_K | q2_K|
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| <img width="256" alt="bf16" src="../assets/z_image/bf16.png" /> | <img width="256" alt="q8_0" src="../assets/z_image/q8_0.png" /> | <img width="256" alt="q6_K" src="../assets/z_image/q6_K.png" /> | <img width="256" alt="q5_0" src="../assets/z_image/q5_0.png" /> | <img width="256" alt="q4_K" src="../assets/z_image/q4_K.png" /> | <img width="256" alt="q4_0" src="../assets/z_image/q4_0.png" /> | <img width="256" alt="q3_K" src="../assets/z_image/q3_K.png" /> | <img width="256" alt="q2_K" src="../assets/z_image/q2_K.png" /> |
|
||||||
@ -156,9 +156,10 @@ struct ESRGAN : public GGMLRunner {
|
|||||||
|
|
||||||
ESRGAN(ggml_backend_t backend,
|
ESRGAN(ggml_backend_t backend,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
|
int tile_size = 128,
|
||||||
const String2TensorStorage& tensor_storage_map = {})
|
const String2TensorStorage& tensor_storage_map = {})
|
||||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||||
// rrdb_net will be created in load_from_file
|
this->tile_size = tile_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_desc() override {
|
std::string get_desc() override {
|
||||||
@ -353,14 +354,14 @@ struct ESRGAN : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
ggml_tensor** output,
|
ggml_tensor** output,
|
||||||
ggml_context* output_ctx = nullptr) {
|
ggml_context* output_ctx = nullptr) {
|
||||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
return build_graph(x);
|
return build_graph(x);
|
||||||
};
|
};
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,14 +3,30 @@
|
|||||||
```
|
```
|
||||||
usage: ./bin/sd [options]
|
usage: ./bin/sd [options]
|
||||||
|
|
||||||
Options:
|
CLI Options:
|
||||||
|
-o, --output <string> path to write result image to (default: ./output.png)
|
||||||
|
--preview-path <string> path to write preview image to (default: ./preview.png)
|
||||||
|
--preview-interval <int> interval in denoising steps between consecutive updates of the image preview file (default is 1, meaning updating at
|
||||||
|
every step)
|
||||||
|
--canny apply canny preprocessor (edge detection)
|
||||||
|
-v, --verbose print extra info
|
||||||
|
--color colors the logging tags according to level
|
||||||
|
--taesd-preview-only prevents usage of taesd for decoding the final image. (for use with --preview tae)
|
||||||
|
--preview-noisy enables previewing noisy inputs of the models rather than the denoised outputs
|
||||||
|
-M, --mode run mode, one of [img_gen, vid_gen, upscale, convert], default: img_gen
|
||||||
|
--preview preview method. must be one of the following [none, proj, tae, vae] (default is none)
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
|
||||||
|
Context Options:
|
||||||
-m, --model <string> path to full model
|
-m, --model <string> path to full model
|
||||||
--clip_l <string> path to the clip-l text encoder
|
--clip_l <string> path to the clip-l text encoder
|
||||||
--clip_g <string> path to the clip-g text encoder
|
--clip_g <string> path to the clip-g text encoder
|
||||||
--clip_vision <string> path to the clip-vision encoder
|
--clip_vision <string> path to the clip-vision encoder
|
||||||
--t5xxl <string> path to the t5xxl text encoder
|
--t5xxl <string> path to the t5xxl text encoder
|
||||||
--qwen2vl <string> path to the qwen2vl text encoder
|
--llm <string> path to the llm text encoder. For example: (qwenvl2.5 for qwen-image, mistral-small3.2 for flux2, ...)
|
||||||
--qwen2vl_vision <string> path to the qwen2vl vit
|
--llm_vision <string> path to the llm vit
|
||||||
|
--qwen2vl <string> alias of --llm. Deprecated.
|
||||||
|
--qwen2vl_vision <string> alias of --llm_vision. Deprecated.
|
||||||
--diffusion-model <string> path to the standalone diffusion model
|
--diffusion-model <string> path to the standalone diffusion model
|
||||||
--high-noise-diffusion-model <string> path to the standalone high noise diffusion model
|
--high-noise-diffusion-model <string> path to the standalone high noise diffusion model
|
||||||
--vae <string> path to standalone vae model
|
--vae <string> path to standalone vae model
|
||||||
@ -18,26 +34,52 @@ Options:
|
|||||||
--control-net <string> path to control net model
|
--control-net <string> path to control net model
|
||||||
--embd-dir <string> embeddings directory
|
--embd-dir <string> embeddings directory
|
||||||
--lora-model-dir <string> lora model directory
|
--lora-model-dir <string> lora model directory
|
||||||
-i, --init-img <string> path to the init image
|
|
||||||
--end-img <string> path to the end image, required by flf2v
|
|
||||||
--tensor-type-rules <string> weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
--tensor-type-rules <string> weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
||||||
--photo-maker <string> path to PHOTOMAKER model
|
--photo-maker <string> path to PHOTOMAKER model
|
||||||
--pm-id-images-dir <string> path to PHOTOMAKER input id images dir
|
--upscale-model <string> path to esrgan model.
|
||||||
--pm-id-embed-path <string> path to PHOTOMAKER v2 id embed
|
-t, --threads <int> number of threads to use during computation (default: -1). If threads <= 0, then threads will be set to the number of
|
||||||
|
CPU physical cores
|
||||||
|
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
||||||
|
--vae-tile-overlap <float> tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
||||||
|
--flow-shift <float> shift value for Flow models like SD3.x or WAN (default: auto)
|
||||||
|
--vae-tiling process vae in tiles to reduce memory usage
|
||||||
|
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
||||||
|
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM when needed
|
||||||
|
--control-net-cpu keep controlnet in cpu (for low vram)
|
||||||
|
--clip-on-cpu keep clip in cpu (for low vram)
|
||||||
|
--vae-on-cpu keep vae in cpu (for low vram)
|
||||||
|
--diffusion-fa use flash attention in the diffusion model
|
||||||
|
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||||
|
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||||
|
--chroma-disable-dit-mask disable dit mask for chroma
|
||||||
|
--chroma-enable-t5-mask enable t5 mask for chroma
|
||||||
|
--type weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K, q4_K). If not specified, the default is the
|
||||||
|
type of the weight file
|
||||||
|
--rng RNG, one of [std_default, cuda, cpu], default: cuda(sd-webui), cpu(comfyui)
|
||||||
|
--sampler-rng sampler RNG, one of [std_default, cuda, cpu]. If not specified, use --rng
|
||||||
|
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow, flux2_flow]
|
||||||
|
--lora-apply-mode the way to apply LoRA, one of [auto, immediately, at_runtime], default is auto. In auto mode, if the model weights
|
||||||
|
contain any quantized parameters, the at_runtime mode will be used; otherwise,
|
||||||
|
immediately will be used.The immediately mode may have precision and
|
||||||
|
compatibility issues with quantized parameters, but it usually offers faster inference
|
||||||
|
speed and, in some cases, lower memory usage. The at_runtime mode, on the
|
||||||
|
other hand, is exactly the opposite.
|
||||||
|
--vae-tile-size tile size for vae tiling, format [X]x[Y] (default: 32x32)
|
||||||
|
--vae-relative-tile-size relative tile size for vae tiling, format [X]x[Y], in fraction of image size if < 1, in number of tiles per dim if >=1
|
||||||
|
(overrides --vae-tile-size)
|
||||||
|
|
||||||
|
Generation Options:
|
||||||
|
-p, --prompt <string> the prompt to render
|
||||||
|
-n, --negative-prompt <string> the negative prompt (default: "")
|
||||||
|
-i, --init-img <string> path to the init image
|
||||||
|
--end-img <string> path to the end image, required by flf2v
|
||||||
--mask <string> path to the mask image
|
--mask <string> path to the mask image
|
||||||
--control-image <string> path to control image, control net
|
--control-image <string> path to control image, control net
|
||||||
--control-video <string> path to control video frames, It must be a directory path. The video frames inside should be stored as images in
|
--control-video <string> path to control video frames, It must be a directory path. The video frames inside should be stored as images in
|
||||||
lexicographical (character) order. For example, if the control video path is
|
lexicographical (character) order. For example, if the control video path is
|
||||||
`frames`, the directory contain images such as 00.png, 01.png, ... etc.
|
`frames`, the directory contain images such as 00.png, 01.png, ... etc.
|
||||||
-o, --output <string> path to write result image to (default: ./output.png)
|
--pm-id-images-dir <string> path to PHOTOMAKER input id images dir
|
||||||
-p, --prompt <string> the prompt to render
|
--pm-id-embed-path <string> path to PHOTOMAKER v2 id embed
|
||||||
-n, --negative-prompt <string> the negative prompt (default: "")
|
|
||||||
--preview-path <string> path to write preview image to (default: ./preview.png)
|
|
||||||
--easycache <string> enable EasyCache for DiT models, accepts optional "threshold,start_percent,end_percent" values (defaults to 0.2,0.15,0.95)
|
|
||||||
--upscale-model <string> path to esrgan model.
|
|
||||||
-t, --threads <int> number of threads to use during computation (default: -1). If threads <= 0, then threads will be set to the number of
|
|
||||||
CPU physical cores
|
|
||||||
--upscale-repeats <int> Run the ESRGAN upscaler this many times (default: 1)
|
|
||||||
-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)
|
||||||
@ -45,13 +87,11 @@ Options:
|
|||||||
--clip-skip <int> ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer (default: -1). <= 0 represents unspecified,
|
--clip-skip <int> ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer (default: -1). <= 0 represents unspecified,
|
||||||
will be 1 for SD1.x, 2 for SD2.x
|
will be 1 for SD1.x, 2 for SD2.x
|
||||||
-b, --batch-count <int> batch count
|
-b, --batch-count <int> batch count
|
||||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
|
||||||
--video-frames <int> video frames (default: 1)
|
--video-frames <int> video frames (default: 1)
|
||||||
--fps <int> fps (default: 24)
|
--fps <int> fps (default: 24)
|
||||||
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for NitroSD-Realism around 250 and 500 for
|
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for NitroSD-Realism around 250 and 500 for
|
||||||
NitroSD-Vibrant
|
NitroSD-Vibrant
|
||||||
--preview-interval <int> interval in denoising steps between consecutive updates of the image preview file (default is 1, meaning updating at
|
--upscale-repeats <int> Run the ESRGAN upscaler this many times (default: 1)
|
||||||
every step)
|
|
||||||
--cfg-scale <float> unconditional guidance scale: (default: 7.0)
|
--cfg-scale <float> unconditional guidance scale: (default: 7.0)
|
||||||
--img-cfg-scale <float> image guidance scale for inpaint or instruct-pix2pix models: (default: same as --cfg-scale)
|
--img-cfg-scale <float> image guidance scale for inpaint or instruct-pix2pix models: (default: same as --cfg-scale)
|
||||||
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
||||||
@ -71,54 +111,18 @@ Options:
|
|||||||
--pm-style-strength <float>
|
--pm-style-strength <float>
|
||||||
--control-strength <float> strength to apply Control Net (default: 0.9). 1.0 corresponds to full destruction of information in init image
|
--control-strength <float> strength to apply Control Net (default: 0.9). 1.0 corresponds to full destruction of information in init image
|
||||||
--moe-boundary <float> timestep boundary for Wan2.2 MoE model. (default: 0.875). Only enabled if `--high-noise-steps` is set to -1
|
--moe-boundary <float> timestep boundary for Wan2.2 MoE model. (default: 0.875). Only enabled if `--high-noise-steps` is set to -1
|
||||||
--flow-shift <float> shift value for Flow models like SD3.x or WAN (default: auto)
|
|
||||||
--vace-strength <float> wan vace strength
|
--vace-strength <float> wan vace strength
|
||||||
--vae-tile-overlap <float> tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
|
||||||
--vae-tiling process vae in tiles to reduce memory usage
|
|
||||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
|
||||||
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM when needed
|
|
||||||
--control-net-cpu keep controlnet in cpu (for low vram)
|
|
||||||
--clip-on-cpu keep clip in cpu (for low vram)
|
|
||||||
--vae-on-cpu keep vae in cpu (for low vram)
|
|
||||||
--diffusion-fa use flash attention in the diffusion model
|
|
||||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
|
||||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
|
||||||
--canny apply canny preprocessor (edge detection)
|
|
||||||
-v, --verbose print extra info
|
|
||||||
--color colors the logging tags according to level
|
|
||||||
--chroma-disable-dit-mask disable dit mask for chroma
|
|
||||||
--chroma-enable-t5-mask enable t5 mask for chroma
|
|
||||||
--increase-ref-index automatically increase the indices of references images based on the order they are listed (starting with 1).
|
--increase-ref-index automatically increase the indices of references images based on the order they are listed (starting with 1).
|
||||||
--disable-auto-resize-ref-image disable auto resize of ref images
|
--disable-auto-resize-ref-image disable auto resize of ref images
|
||||||
--taesd-preview-only prevents usage of taesd for decoding the final image. (for use with --preview tae)
|
|
||||||
--preview-noisy enables previewing noisy inputs of the models rather than the denoised outputs
|
|
||||||
-M, --mode run mode, one of [img_gen, vid_gen, upscale, convert], default: img_gen
|
|
||||||
--type weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K, q4_K). If not specified, the default is the
|
|
||||||
type of the weight file
|
|
||||||
--rng RNG, one of [std_default, cuda, cpu], default: cuda(sd-webui), cpu(comfyui)
|
|
||||||
--sampler-rng sampler RNG, one of [std_default, cuda, cpu]. If not specified, use --rng
|
|
||||||
-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, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing,
|
--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] (default: euler for Flux/SD3/Wan, euler_a otherwise)
|
tcd] (default: euler for Flux/SD3/Wan, euler_a otherwise)
|
||||||
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow]
|
|
||||||
--lora-apply-mode the way to apply LoRA, one of [auto, immediately, at_runtime], default is auto. In auto mode, if the model weights
|
|
||||||
contain any quantized parameters, the at_runtime mode will be used; otherwise,
|
|
||||||
immediately will be used.The immediately mode may have precision and
|
|
||||||
compatibility issues with quantized parameters, but it usually offers faster inference
|
|
||||||
speed and, in some cases, lower memory usage. The at_runtime mode, on the other
|
|
||||||
hand, is exactly the opposite.
|
|
||||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple], default:
|
|
||||||
discrete
|
|
||||||
--skip-layers layers to skip for SLG steps (default: [7,8,9])
|
|
||||||
--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,
|
--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] default: euler for Flux/SD3/Wan, euler_a otherwise
|
ddim_trailing, tcd] default: euler for Flux/SD3/Wan, euler_a otherwise
|
||||||
--high-noise-scheduler (high noise) denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform,
|
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple, lcm],
|
||||||
simple], default: discrete
|
default: discrete
|
||||||
|
--skip-layers layers to skip for SLG steps (default: [7,8,9])
|
||||||
--high-noise-skip-layers (high noise) layers to skip for SLG steps (default: [7,8,9])
|
--high-noise-skip-layers (high noise) layers to skip for SLG steps (default: [7,8,9])
|
||||||
-r, --ref-image reference image for Flux Kontext models (can be used multiple times)
|
-r, --ref-image reference image for Flux Kontext models (can be used multiple times)
|
||||||
-h, --help show this help message and exit
|
--easycache enable EasyCache for DiT models with optional "threshold,start_percent,end_percent" (default: 0.2,0.15,0.95)
|
||||||
--vae-tile-size tile size for vae tiling, format [X]x[Y] (default: 32x32)
|
|
||||||
--vae-relative-tile-size relative tile size for vae tiling, format [X]x[Y], in fraction of image size if < 1, in number of tiles per dim if >=1
|
|
||||||
(overrides --vae-tile-size)
|
|
||||||
--preview preview method. must be one of the following [none, proj, tae, vae] (default is none)
|
|
||||||
```
|
```
|
||||||
|
|||||||
348
flux.hpp
@ -14,9 +14,9 @@ namespace Flux {
|
|||||||
|
|
||||||
struct MLPEmbedder : public UnaryBlock {
|
struct MLPEmbedder : public UnaryBlock {
|
||||||
public:
|
public:
|
||||||
MLPEmbedder(int64_t in_dim, int64_t hidden_dim) {
|
MLPEmbedder(int64_t in_dim, int64_t hidden_dim, bool bias = true) {
|
||||||
blocks["in_layer"] = std::shared_ptr<GGMLBlock>(new Linear(in_dim, hidden_dim, true));
|
blocks["in_layer"] = std::shared_ptr<GGMLBlock>(new Linear(in_dim, hidden_dim, bias));
|
||||||
blocks["out_layer"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_dim, hidden_dim, true));
|
blocks["out_layer"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_dim, hidden_dim, bias));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) override {
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) override {
|
||||||
@ -89,12 +89,13 @@ namespace Flux {
|
|||||||
public:
|
public:
|
||||||
SelfAttention(int64_t dim,
|
SelfAttention(int64_t dim,
|
||||||
int64_t num_heads = 8,
|
int64_t num_heads = 8,
|
||||||
bool qkv_bias = false)
|
bool qkv_bias = false,
|
||||||
|
bool proj_bias = true)
|
||||||
: num_heads(num_heads) {
|
: num_heads(num_heads) {
|
||||||
int64_t head_dim = dim / num_heads;
|
int64_t head_dim = dim / num_heads;
|
||||||
blocks["qkv"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim * 3, qkv_bias));
|
blocks["qkv"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim * 3, qkv_bias));
|
||||||
blocks["norm"] = std::shared_ptr<GGMLBlock>(new QKNorm(head_dim));
|
blocks["norm"] = std::shared_ptr<GGMLBlock>(new QKNorm(head_dim));
|
||||||
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim));
|
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim, proj_bias));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<struct ggml_tensor*> pre_attention(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
std::vector<struct ggml_tensor*> pre_attention(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||||
@ -133,6 +134,54 @@ namespace Flux {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MLP : public UnaryBlock {
|
||||||
|
bool use_mlp_silu_act;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MLP(int64_t hidden_size, int64_t intermediate_size, bool use_mlp_silu_act = false, bool bias = false)
|
||||||
|
: use_mlp_silu_act(use_mlp_silu_act) {
|
||||||
|
int64_t mlp_mult_factor = use_mlp_silu_act ? 2 : 1;
|
||||||
|
blocks["0"] = std::make_shared<Linear>(hidden_size, intermediate_size * mlp_mult_factor, bias);
|
||||||
|
blocks["2"] = std::make_shared<Linear>(intermediate_size, hidden_size, bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||||
|
auto mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["0"]);
|
||||||
|
auto mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["2"]);
|
||||||
|
|
||||||
|
x = mlp_0->forward(ctx, x);
|
||||||
|
if (use_mlp_silu_act) {
|
||||||
|
x = ggml_ext_silu_act(ctx->ggml_ctx, x);
|
||||||
|
} else {
|
||||||
|
x = ggml_gelu_inplace(ctx->ggml_ctx, x);
|
||||||
|
}
|
||||||
|
x = mlp_2->forward(ctx, x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct YakMLP : public UnaryBlock {
|
||||||
|
public:
|
||||||
|
YakMLP(int64_t hidden_size, int64_t intermediate_size, bool bias = true) {
|
||||||
|
blocks["gate_proj"] = std::make_shared<Linear>(hidden_size, intermediate_size, bias);
|
||||||
|
blocks["up_proj"] = std::make_shared<Linear>(hidden_size, intermediate_size, bias);
|
||||||
|
blocks["down_proj"] = std::make_shared<Linear>(intermediate_size, hidden_size, bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||||
|
auto gate_proj = std::dynamic_pointer_cast<Linear>(blocks["gate_proj"]);
|
||||||
|
auto up_proj = std::dynamic_pointer_cast<Linear>(blocks["up_proj"]);
|
||||||
|
auto down_proj = std::dynamic_pointer_cast<Linear>(blocks["down_proj"]);
|
||||||
|
|
||||||
|
auto gate = gate_proj->forward(ctx, x);
|
||||||
|
gate = ggml_silu_inplace(ctx->ggml_ctx, gate);
|
||||||
|
x = up_proj->forward(ctx, x);
|
||||||
|
x = ggml_mul(ctx->ggml_ctx, x, gate);
|
||||||
|
x = down_proj->forward(ctx, x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ModulationOut {
|
struct ModulationOut {
|
||||||
ggml_tensor* shift = nullptr;
|
ggml_tensor* shift = nullptr;
|
||||||
ggml_tensor* scale = nullptr;
|
ggml_tensor* scale = nullptr;
|
||||||
@ -155,10 +204,10 @@ namespace Flux {
|
|||||||
int multiplier;
|
int multiplier;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Modulation(int64_t dim, bool is_double)
|
Modulation(int64_t dim, bool is_double, bool bias = true)
|
||||||
: is_double(is_double) {
|
: is_double(is_double) {
|
||||||
multiplier = is_double ? 6 : 3;
|
multiplier = is_double ? 6 : 3;
|
||||||
blocks["lin"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim * multiplier));
|
blocks["lin"] = std::shared_ptr<GGMLBlock>(new Linear(dim, dim * multiplier, bias));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModulationOut> forward(GGMLRunnerContext* ctx, struct ggml_tensor* vec) {
|
std::vector<ModulationOut> forward(GGMLRunnerContext* ctx, struct ggml_tensor* vec) {
|
||||||
@ -203,32 +252,41 @@ namespace Flux {
|
|||||||
DoubleStreamBlock(int64_t hidden_size,
|
DoubleStreamBlock(int64_t hidden_size,
|
||||||
int64_t num_heads,
|
int64_t num_heads,
|
||||||
float mlp_ratio,
|
float mlp_ratio,
|
||||||
int idx = 0,
|
int idx = 0,
|
||||||
bool qkv_bias = false,
|
bool qkv_bias = false,
|
||||||
bool prune_mod = false)
|
bool prune_mod = false,
|
||||||
|
bool share_modulation = false,
|
||||||
|
bool mlp_proj_bias = true,
|
||||||
|
bool use_yak_mlp = false,
|
||||||
|
bool use_mlp_silu_act = false)
|
||||||
: idx(idx), prune_mod(prune_mod) {
|
: idx(idx), prune_mod(prune_mod) {
|
||||||
int64_t mlp_hidden_dim = hidden_size * mlp_ratio;
|
int64_t mlp_hidden_dim = hidden_size * mlp_ratio;
|
||||||
if (!prune_mod) {
|
|
||||||
|
if (!prune_mod && !share_modulation) {
|
||||||
blocks["img_mod"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, true));
|
blocks["img_mod"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, true));
|
||||||
}
|
}
|
||||||
blocks["img_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
blocks["img_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
||||||
blocks["img_attn"] = std::shared_ptr<GGMLBlock>(new SelfAttention(hidden_size, num_heads, qkv_bias));
|
blocks["img_attn"] = std::shared_ptr<GGMLBlock>(new SelfAttention(hidden_size, num_heads, qkv_bias, mlp_proj_bias));
|
||||||
|
|
||||||
blocks["img_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
blocks["img_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
||||||
blocks["img_mlp.0"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, mlp_hidden_dim));
|
if (use_yak_mlp) {
|
||||||
// img_mlp.1 is nn.GELU(approximate="tanh")
|
blocks["img_mlp"] = std::shared_ptr<GGMLBlock>(new YakMLP(hidden_size, mlp_hidden_dim, mlp_proj_bias));
|
||||||
blocks["img_mlp.2"] = std::shared_ptr<GGMLBlock>(new Linear(mlp_hidden_dim, hidden_size));
|
} else {
|
||||||
|
blocks["img_mlp"] = std::shared_ptr<GGMLBlock>(new MLP(hidden_size, mlp_hidden_dim, use_mlp_silu_act, mlp_proj_bias));
|
||||||
|
}
|
||||||
|
|
||||||
if (!prune_mod) {
|
if (!prune_mod && !share_modulation) {
|
||||||
blocks["txt_mod"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, true));
|
blocks["txt_mod"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, true));
|
||||||
}
|
}
|
||||||
blocks["txt_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
blocks["txt_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
||||||
blocks["txt_attn"] = std::shared_ptr<GGMLBlock>(new SelfAttention(hidden_size, num_heads, qkv_bias));
|
blocks["txt_attn"] = std::shared_ptr<GGMLBlock>(new SelfAttention(hidden_size, num_heads, qkv_bias, mlp_proj_bias));
|
||||||
|
|
||||||
blocks["txt_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
blocks["txt_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
||||||
blocks["txt_mlp.0"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, mlp_hidden_dim));
|
if (use_yak_mlp) {
|
||||||
// img_mlp.1 is nn.GELU(approximate="tanh")
|
blocks["txt_mlp"] = std::shared_ptr<GGMLBlock>(new YakMLP(hidden_size, mlp_hidden_dim, mlp_proj_bias));
|
||||||
blocks["txt_mlp.2"] = std::shared_ptr<GGMLBlock>(new Linear(mlp_hidden_dim, hidden_size));
|
} else {
|
||||||
|
blocks["txt_mlp"] = std::shared_ptr<GGMLBlock>(new MLP(hidden_size, mlp_hidden_dim, use_mlp_silu_act, mlp_proj_bias));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModulationOut> get_distil_img_mod(GGMLRunnerContext* ctx, struct ggml_tensor* vec) {
|
std::vector<ModulationOut> get_distil_img_mod(GGMLRunnerContext* ctx, struct ggml_tensor* vec) {
|
||||||
@ -254,7 +312,9 @@ namespace Flux {
|
|||||||
struct ggml_tensor* txt,
|
struct ggml_tensor* txt,
|
||||||
struct ggml_tensor* vec,
|
struct ggml_tensor* vec,
|
||||||
struct ggml_tensor* pe,
|
struct ggml_tensor* pe,
|
||||||
struct ggml_tensor* mask = nullptr) {
|
struct ggml_tensor* mask = nullptr,
|
||||||
|
std::vector<ModulationOut> img_mods = {},
|
||||||
|
std::vector<ModulationOut> txt_mods = {}) {
|
||||||
// img: [N, n_img_token, hidden_size]
|
// img: [N, n_img_token, hidden_size]
|
||||||
// txt: [N, n_txt_token, hidden_size]
|
// txt: [N, n_txt_token, hidden_size]
|
||||||
// pe: [n_img_token + n_txt_token, d_head/2, 2, 2]
|
// pe: [n_img_token + n_txt_token, d_head/2, 2, 2]
|
||||||
@ -263,31 +323,31 @@ namespace Flux {
|
|||||||
auto img_attn = std::dynamic_pointer_cast<SelfAttention>(blocks["img_attn"]);
|
auto img_attn = std::dynamic_pointer_cast<SelfAttention>(blocks["img_attn"]);
|
||||||
|
|
||||||
auto img_norm2 = std::dynamic_pointer_cast<LayerNorm>(blocks["img_norm2"]);
|
auto img_norm2 = std::dynamic_pointer_cast<LayerNorm>(blocks["img_norm2"]);
|
||||||
auto img_mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["img_mlp.0"]);
|
auto img_mlp = std::dynamic_pointer_cast<UnaryBlock>(blocks["img_mlp"]);
|
||||||
auto img_mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["img_mlp.2"]);
|
|
||||||
|
|
||||||
auto txt_norm1 = std::dynamic_pointer_cast<LayerNorm>(blocks["txt_norm1"]);
|
auto txt_norm1 = std::dynamic_pointer_cast<LayerNorm>(blocks["txt_norm1"]);
|
||||||
auto txt_attn = std::dynamic_pointer_cast<SelfAttention>(blocks["txt_attn"]);
|
auto txt_attn = std::dynamic_pointer_cast<SelfAttention>(blocks["txt_attn"]);
|
||||||
|
|
||||||
auto txt_norm2 = std::dynamic_pointer_cast<LayerNorm>(blocks["txt_norm2"]);
|
auto txt_norm2 = std::dynamic_pointer_cast<LayerNorm>(blocks["txt_norm2"]);
|
||||||
auto txt_mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["txt_mlp.0"]);
|
auto txt_mlp = std::dynamic_pointer_cast<UnaryBlock>(blocks["txt_mlp"]);
|
||||||
auto txt_mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["txt_mlp.2"]);
|
|
||||||
|
|
||||||
std::vector<ModulationOut> img_mods;
|
if (img_mods.empty()) {
|
||||||
if (prune_mod) {
|
if (prune_mod) {
|
||||||
img_mods = get_distil_img_mod(ctx, vec);
|
img_mods = get_distil_img_mod(ctx, vec);
|
||||||
} else {
|
} else {
|
||||||
auto img_mod = std::dynamic_pointer_cast<Modulation>(blocks["img_mod"]);
|
auto img_mod = std::dynamic_pointer_cast<Modulation>(blocks["img_mod"]);
|
||||||
img_mods = img_mod->forward(ctx, vec);
|
img_mods = img_mod->forward(ctx, vec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ModulationOut img_mod1 = img_mods[0];
|
ModulationOut img_mod1 = img_mods[0];
|
||||||
ModulationOut img_mod2 = img_mods[1];
|
ModulationOut img_mod2 = img_mods[1];
|
||||||
std::vector<ModulationOut> txt_mods;
|
if (txt_mods.empty()) {
|
||||||
if (prune_mod) {
|
if (prune_mod) {
|
||||||
txt_mods = get_distil_txt_mod(ctx, vec);
|
txt_mods = get_distil_txt_mod(ctx, vec);
|
||||||
} else {
|
} else {
|
||||||
auto txt_mod = std::dynamic_pointer_cast<Modulation>(blocks["txt_mod"]);
|
auto txt_mod = std::dynamic_pointer_cast<Modulation>(blocks["txt_mod"]);
|
||||||
txt_mods = txt_mod->forward(ctx, vec);
|
txt_mods = txt_mod->forward(ctx, vec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ModulationOut txt_mod1 = txt_mods[0];
|
ModulationOut txt_mod1 = txt_mods[0];
|
||||||
ModulationOut txt_mod2 = txt_mods[1];
|
ModulationOut txt_mod2 = txt_mods[1];
|
||||||
@ -337,20 +397,15 @@ namespace Flux {
|
|||||||
// calculate the img bloks
|
// calculate the img bloks
|
||||||
img = ggml_add(ctx->ggml_ctx, img, ggml_mul(ctx->ggml_ctx, img_attn->post_attention(ctx, img_attn_out), img_mod1.gate));
|
img = ggml_add(ctx->ggml_ctx, img, ggml_mul(ctx->ggml_ctx, img_attn->post_attention(ctx, img_attn_out), img_mod1.gate));
|
||||||
|
|
||||||
auto img_mlp_out = img_mlp_0->forward(ctx, Flux::modulate(ctx->ggml_ctx, img_norm2->forward(ctx, img), img_mod2.shift, img_mod2.scale));
|
auto img_mlp_out = img_mlp->forward(ctx, Flux::modulate(ctx->ggml_ctx, img_norm2->forward(ctx, img), img_mod2.shift, img_mod2.scale));
|
||||||
img_mlp_out = ggml_gelu_inplace(ctx->ggml_ctx, img_mlp_out);
|
|
||||||
img_mlp_out = img_mlp_2->forward(ctx, img_mlp_out);
|
|
||||||
|
|
||||||
img = ggml_add(ctx->ggml_ctx, img, ggml_mul(ctx->ggml_ctx, img_mlp_out, img_mod2.gate));
|
img = ggml_add(ctx->ggml_ctx, img, ggml_mul(ctx->ggml_ctx, img_mlp_out, img_mod2.gate));
|
||||||
|
|
||||||
// calculate the txt bloks
|
// calculate the txt bloks
|
||||||
txt = ggml_add(ctx->ggml_ctx, txt, ggml_mul(ctx->ggml_ctx, txt_attn->post_attention(ctx, txt_attn_out), txt_mod1.gate));
|
txt = ggml_add(ctx->ggml_ctx, txt, ggml_mul(ctx->ggml_ctx, txt_attn->post_attention(ctx, txt_attn_out), txt_mod1.gate));
|
||||||
|
|
||||||
auto txt_mlp_out = txt_mlp_0->forward(ctx, Flux::modulate(ctx->ggml_ctx, txt_norm2->forward(ctx, txt), txt_mod2.shift, txt_mod2.scale));
|
auto txt_mlp_out = txt_mlp->forward(ctx, Flux::modulate(ctx->ggml_ctx, txt_norm2->forward(ctx, txt), txt_mod2.shift, txt_mod2.scale));
|
||||||
txt_mlp_out = ggml_gelu_inplace(ctx->ggml_ctx, txt_mlp_out);
|
txt = ggml_add(ctx->ggml_ctx, txt, ggml_mul(ctx->ggml_ctx, txt_mlp_out, txt_mod2.gate));
|
||||||
txt_mlp_out = txt_mlp_2->forward(ctx, txt_mlp_out);
|
|
||||||
|
|
||||||
txt = ggml_add(ctx->ggml_ctx, txt, ggml_mul(ctx->ggml_ctx, txt_mlp_out, txt_mod2.gate));
|
|
||||||
|
|
||||||
return {img, txt};
|
return {img, txt};
|
||||||
}
|
}
|
||||||
@ -363,28 +418,39 @@ namespace Flux {
|
|||||||
int64_t mlp_hidden_dim;
|
int64_t mlp_hidden_dim;
|
||||||
bool prune_mod;
|
bool prune_mod;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
bool use_yak_mlp;
|
||||||
|
bool use_mlp_silu_act;
|
||||||
|
int64_t mlp_mult_factor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SingleStreamBlock(int64_t hidden_size,
|
SingleStreamBlock(int64_t hidden_size,
|
||||||
int64_t num_heads,
|
int64_t num_heads,
|
||||||
float mlp_ratio = 4.0f,
|
float mlp_ratio = 4.0f,
|
||||||
int idx = 0,
|
int idx = 0,
|
||||||
float qk_scale = 0.f,
|
float qk_scale = 0.f,
|
||||||
bool prune_mod = false)
|
bool prune_mod = false,
|
||||||
: hidden_size(hidden_size), num_heads(num_heads), idx(idx), prune_mod(prune_mod) {
|
bool share_modulation = false,
|
||||||
|
bool mlp_proj_bias = true,
|
||||||
|
bool use_yak_mlp = false,
|
||||||
|
bool use_mlp_silu_act = false)
|
||||||
|
: hidden_size(hidden_size), num_heads(num_heads), idx(idx), prune_mod(prune_mod), use_yak_mlp(use_yak_mlp), use_mlp_silu_act(use_mlp_silu_act) {
|
||||||
int64_t head_dim = hidden_size / num_heads;
|
int64_t head_dim = hidden_size / num_heads;
|
||||||
float scale = qk_scale;
|
float scale = qk_scale;
|
||||||
if (scale <= 0.f) {
|
if (scale <= 0.f) {
|
||||||
scale = 1 / sqrt((float)head_dim);
|
scale = 1 / sqrt((float)head_dim);
|
||||||
}
|
}
|
||||||
mlp_hidden_dim = hidden_size * mlp_ratio;
|
mlp_hidden_dim = hidden_size * mlp_ratio;
|
||||||
|
mlp_mult_factor = 1;
|
||||||
|
if (use_yak_mlp || use_mlp_silu_act) {
|
||||||
|
mlp_mult_factor = 2;
|
||||||
|
}
|
||||||
|
|
||||||
blocks["linear1"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size * 3 + mlp_hidden_dim));
|
blocks["linear1"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size * 3 + mlp_hidden_dim * mlp_mult_factor, mlp_proj_bias));
|
||||||
blocks["linear2"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size + mlp_hidden_dim, hidden_size));
|
blocks["linear2"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size + mlp_hidden_dim, hidden_size, mlp_proj_bias));
|
||||||
blocks["norm"] = std::shared_ptr<GGMLBlock>(new QKNorm(head_dim));
|
blocks["norm"] = std::shared_ptr<GGMLBlock>(new QKNorm(head_dim));
|
||||||
blocks["pre_norm"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
blocks["pre_norm"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-6f, false));
|
||||||
// mlp_act is nn.GELU(approximate="tanh")
|
// mlp_act is nn.GELU(approximate="tanh")
|
||||||
if (!prune_mod) {
|
if (!prune_mod && !share_modulation) {
|
||||||
blocks["modulation"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, false));
|
blocks["modulation"] = std::shared_ptr<GGMLBlock>(new Modulation(hidden_size, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,7 +464,8 @@ namespace Flux {
|
|||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* vec,
|
struct ggml_tensor* vec,
|
||||||
struct ggml_tensor* pe,
|
struct ggml_tensor* pe,
|
||||||
struct ggml_tensor* mask = nullptr) {
|
struct ggml_tensor* mask = nullptr,
|
||||||
|
std::vector<ModulationOut> mods = {}) {
|
||||||
// x: [N, n_token, hidden_size]
|
// x: [N, n_token, hidden_size]
|
||||||
// pe: [n_token, d_head/2, 2, 2]
|
// pe: [n_token, d_head/2, 2, 2]
|
||||||
// return: [N, n_token, hidden_size]
|
// return: [N, n_token, hidden_size]
|
||||||
@ -407,14 +474,20 @@ namespace Flux {
|
|||||||
auto linear2 = std::dynamic_pointer_cast<Linear>(blocks["linear2"]);
|
auto linear2 = std::dynamic_pointer_cast<Linear>(blocks["linear2"]);
|
||||||
auto norm = std::dynamic_pointer_cast<QKNorm>(blocks["norm"]);
|
auto norm = std::dynamic_pointer_cast<QKNorm>(blocks["norm"]);
|
||||||
auto pre_norm = std::dynamic_pointer_cast<LayerNorm>(blocks["pre_norm"]);
|
auto pre_norm = std::dynamic_pointer_cast<LayerNorm>(blocks["pre_norm"]);
|
||||||
ModulationOut mod;
|
|
||||||
if (prune_mod) {
|
|
||||||
mod = get_distil_mod(ctx, vec);
|
|
||||||
} else {
|
|
||||||
auto modulation = std::dynamic_pointer_cast<Modulation>(blocks["modulation"]);
|
|
||||||
|
|
||||||
mod = modulation->forward(ctx, vec)[0];
|
ModulationOut mod;
|
||||||
|
if (!mods.empty()) {
|
||||||
|
mod = mods[0];
|
||||||
|
} else {
|
||||||
|
if (prune_mod) {
|
||||||
|
mod = get_distil_mod(ctx, vec);
|
||||||
|
} else {
|
||||||
|
auto modulation = std::dynamic_pointer_cast<Modulation>(blocks["modulation"]);
|
||||||
|
|
||||||
|
mod = modulation->forward(ctx, vec)[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto x_mod = Flux::modulate(ctx->ggml_ctx, pre_norm->forward(ctx, x), mod.shift, mod.scale);
|
auto x_mod = Flux::modulate(ctx->ggml_ctx, pre_norm->forward(ctx, x), mod.shift, mod.scale);
|
||||||
auto qkv_mlp = linear1->forward(ctx, x_mod); // [N, n_token, hidden_size * 3 + mlp_hidden_dim]
|
auto qkv_mlp = linear1->forward(ctx, x_mod); // [N, n_token, hidden_size * 3 + mlp_hidden_dim]
|
||||||
qkv_mlp = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, qkv_mlp, 2, 0, 1, 3)); // [hidden_size * 3 + mlp_hidden_dim, N, n_token]
|
qkv_mlp = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, qkv_mlp, 2, 0, 1, 3)); // [hidden_size * 3 + mlp_hidden_dim, N, n_token]
|
||||||
@ -432,11 +505,11 @@ namespace Flux {
|
|||||||
qkv_mlp,
|
qkv_mlp,
|
||||||
qkv_mlp->ne[0],
|
qkv_mlp->ne[0],
|
||||||
qkv_mlp->ne[1],
|
qkv_mlp->ne[1],
|
||||||
mlp_hidden_dim,
|
mlp_hidden_dim * mlp_mult_factor,
|
||||||
qkv_mlp->nb[1],
|
qkv_mlp->nb[1],
|
||||||
qkv_mlp->nb[2],
|
qkv_mlp->nb[2],
|
||||||
qkv_mlp->nb[2] * hidden_size * 3); // [mlp_hidden_dim , N, n_token]
|
qkv_mlp->nb[2] * hidden_size * 3); // [mlp_hidden_dim*mlp_mult_factor , N, n_token]
|
||||||
mlp = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, mlp, 1, 2, 0, 3)); // [N, n_token, mlp_hidden_dim]
|
mlp = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, mlp, 1, 2, 0, 3)); // [N, n_token, mlp_hidden_dim*mlp_mult_factor]
|
||||||
|
|
||||||
auto qkv_vec = split_qkv(ctx->ggml_ctx, qkv); // q,k,v: [N, n_token, hidden_size]
|
auto qkv_vec = split_qkv(ctx->ggml_ctx, qkv); // q,k,v: [N, n_token, hidden_size]
|
||||||
int64_t head_dim = hidden_size / num_heads;
|
int64_t head_dim = hidden_size / num_heads;
|
||||||
@ -447,8 +520,15 @@ namespace Flux {
|
|||||||
k = norm->key_norm(ctx, k);
|
k = norm->key_norm(ctx, k);
|
||||||
auto attn = Rope::attention(ctx, q, k, v, pe, mask); // [N, n_token, hidden_size]
|
auto attn = Rope::attention(ctx, q, k, v, pe, mask); // [N, n_token, hidden_size]
|
||||||
|
|
||||||
auto attn_mlp = ggml_concat(ctx->ggml_ctx, attn, ggml_gelu_inplace(ctx->ggml_ctx, mlp), 0); // [N, n_token, hidden_size + mlp_hidden_dim]
|
if (use_yak_mlp) {
|
||||||
auto output = linear2->forward(ctx, attn_mlp); // [N, n_token, hidden_size]
|
mlp = ggml_ext_silu_act(ctx->ggml_ctx, mlp, false);
|
||||||
|
} else if (use_mlp_silu_act) {
|
||||||
|
mlp = ggml_ext_silu_act(ctx->ggml_ctx, mlp);
|
||||||
|
} else {
|
||||||
|
mlp = ggml_gelu_inplace(ctx->ggml_ctx, mlp);
|
||||||
|
}
|
||||||
|
auto attn_mlp = ggml_concat(ctx->ggml_ctx, attn, mlp, 0); // [N, n_token, hidden_size + mlp_hidden_dim]
|
||||||
|
auto output = linear2->forward(ctx, attn_mlp); // [N, n_token, hidden_size]
|
||||||
|
|
||||||
output = ggml_add(ctx->ggml_ctx, x, ggml_mul(ctx->ggml_ctx, output, mod.gate));
|
output = ggml_add(ctx->ggml_ctx, x, ggml_mul(ctx->ggml_ctx, output, mod.gate));
|
||||||
return output;
|
return output;
|
||||||
@ -462,12 +542,13 @@ namespace Flux {
|
|||||||
LastLayer(int64_t hidden_size,
|
LastLayer(int64_t hidden_size,
|
||||||
int64_t patch_size,
|
int64_t patch_size,
|
||||||
int64_t out_channels,
|
int64_t out_channels,
|
||||||
bool prune_mod = false)
|
bool prune_mod = false,
|
||||||
|
bool bias = true)
|
||||||
: prune_mod(prune_mod) {
|
: prune_mod(prune_mod) {
|
||||||
blocks["norm_final"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-06f, false));
|
blocks["norm_final"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size, 1e-06f, false));
|
||||||
blocks["linear"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, patch_size * patch_size * out_channels));
|
blocks["linear"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, patch_size * patch_size * out_channels, bias));
|
||||||
if (!prune_mod) {
|
if (!prune_mod) {
|
||||||
blocks["adaLN_modulation.1"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, 2 * hidden_size));
|
blocks["adaLN_modulation.1"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, 2 * hidden_size, bias));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,6 +765,12 @@ namespace Flux {
|
|||||||
bool qkv_bias = true;
|
bool qkv_bias = true;
|
||||||
bool guidance_embed = true;
|
bool guidance_embed = true;
|
||||||
int64_t in_dim = 64;
|
int64_t in_dim = 64;
|
||||||
|
bool disable_bias = false;
|
||||||
|
bool share_modulation = false;
|
||||||
|
bool semantic_txt_norm = false;
|
||||||
|
bool use_yak_mlp = false;
|
||||||
|
bool use_mlp_silu_act = false;
|
||||||
|
float ref_index_scale = 1.f;
|
||||||
ChromaRadianceParams chroma_radiance_params;
|
ChromaRadianceParams chroma_radiance_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -702,18 +789,23 @@ namespace Flux {
|
|||||||
kernel_size,
|
kernel_size,
|
||||||
stride);
|
stride);
|
||||||
} else {
|
} else {
|
||||||
blocks["img_in"] = std::make_shared<Linear>(params.in_channels, params.hidden_size, true);
|
blocks["img_in"] = std::make_shared<Linear>(params.in_channels, params.hidden_size, !params.disable_bias);
|
||||||
}
|
}
|
||||||
if (params.is_chroma) {
|
if (params.is_chroma) {
|
||||||
blocks["distilled_guidance_layer"] = std::make_shared<ChromaApproximator>(params.in_dim, params.hidden_size);
|
blocks["distilled_guidance_layer"] = std::make_shared<ChromaApproximator>(params.in_dim, params.hidden_size);
|
||||||
} else {
|
} else {
|
||||||
blocks["time_in"] = std::make_shared<MLPEmbedder>(256, params.hidden_size);
|
blocks["time_in"] = std::make_shared<MLPEmbedder>(256, params.hidden_size, !params.disable_bias);
|
||||||
blocks["vector_in"] = std::make_shared<MLPEmbedder>(params.vec_in_dim, params.hidden_size);
|
if (params.vec_in_dim > 0) {
|
||||||
|
blocks["vector_in"] = std::make_shared<MLPEmbedder>(params.vec_in_dim, params.hidden_size, !params.disable_bias);
|
||||||
|
}
|
||||||
if (params.guidance_embed) {
|
if (params.guidance_embed) {
|
||||||
blocks["guidance_in"] = std::make_shared<MLPEmbedder>(256, params.hidden_size);
|
blocks["guidance_in"] = std::make_shared<MLPEmbedder>(256, params.hidden_size, !params.disable_bias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocks["txt_in"] = std::make_shared<Linear>(params.context_in_dim, params.hidden_size, true);
|
if (params.semantic_txt_norm) {
|
||||||
|
blocks["txt_norm"] = std::make_shared<RMSNorm>(params.context_in_dim);
|
||||||
|
}
|
||||||
|
blocks["txt_in"] = std::make_shared<Linear>(params.context_in_dim, params.hidden_size, !params.disable_bias);
|
||||||
|
|
||||||
for (int i = 0; i < params.depth; i++) {
|
for (int i = 0; i < params.depth; i++) {
|
||||||
blocks["double_blocks." + std::to_string(i)] = std::make_shared<DoubleStreamBlock>(params.hidden_size,
|
blocks["double_blocks." + std::to_string(i)] = std::make_shared<DoubleStreamBlock>(params.hidden_size,
|
||||||
@ -721,7 +813,11 @@ namespace Flux {
|
|||||||
params.mlp_ratio,
|
params.mlp_ratio,
|
||||||
i,
|
i,
|
||||||
params.qkv_bias,
|
params.qkv_bias,
|
||||||
params.is_chroma);
|
params.is_chroma,
|
||||||
|
params.share_modulation,
|
||||||
|
!params.disable_bias,
|
||||||
|
params.use_yak_mlp,
|
||||||
|
params.use_mlp_silu_act);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < params.depth_single_blocks; i++) {
|
for (int i = 0; i < params.depth_single_blocks; i++) {
|
||||||
@ -730,7 +826,11 @@ namespace Flux {
|
|||||||
params.mlp_ratio,
|
params.mlp_ratio,
|
||||||
i,
|
i,
|
||||||
0.f,
|
0.f,
|
||||||
params.is_chroma);
|
params.is_chroma,
|
||||||
|
params.share_modulation,
|
||||||
|
!params.disable_bias,
|
||||||
|
params.use_yak_mlp,
|
||||||
|
params.use_mlp_silu_act);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.version == VERSION_CHROMA_RADIANCE) {
|
if (params.version == VERSION_CHROMA_RADIANCE) {
|
||||||
@ -748,7 +848,13 @@ namespace Flux {
|
|||||||
params.in_channels);
|
params.in_channels);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
blocks["final_layer"] = std::make_shared<LastLayer>(params.hidden_size, 1, params.out_channels, params.is_chroma);
|
blocks["final_layer"] = std::make_shared<LastLayer>(params.hidden_size, 1, params.out_channels, params.is_chroma, !params.disable_bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.share_modulation) {
|
||||||
|
blocks["double_stream_modulation_img"] = std::make_shared<Modulation>(params.hidden_size, true, !params.disable_bias);
|
||||||
|
blocks["double_stream_modulation_txt"] = std::make_shared<Modulation>(params.hidden_size, true, !params.disable_bias);
|
||||||
|
blocks["single_stream_modulation"] = std::make_shared<Modulation>(params.hidden_size, false, !params.disable_bias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -861,9 +967,8 @@ namespace Flux {
|
|||||||
txt_img_mask = ggml_pad(ctx->ggml_ctx, y, img->ne[1], 0, 0, 0);
|
txt_img_mask = ggml_pad(ctx->ggml_ctx, y, img->ne[1], 0, 0, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto time_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["time_in"]);
|
auto time_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["time_in"]);
|
||||||
auto vector_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["vector_in"]);
|
vec = time_in->forward(ctx, ggml_ext_timestep_embedding(ctx->ggml_ctx, timesteps, 256, 10000, 1000.f));
|
||||||
vec = time_in->forward(ctx, ggml_ext_timestep_embedding(ctx->ggml_ctx, timesteps, 256, 10000, 1000.f));
|
|
||||||
if (params.guidance_embed) {
|
if (params.guidance_embed) {
|
||||||
GGML_ASSERT(guidance != nullptr);
|
GGML_ASSERT(guidance != nullptr);
|
||||||
auto guidance_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["guidance_in"]);
|
auto guidance_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["guidance_in"]);
|
||||||
@ -872,7 +977,29 @@ namespace Flux {
|
|||||||
vec = ggml_add(ctx->ggml_ctx, vec, guidance_in->forward(ctx, g_in));
|
vec = ggml_add(ctx->ggml_ctx, vec, guidance_in->forward(ctx, g_in));
|
||||||
}
|
}
|
||||||
|
|
||||||
vec = ggml_add(ctx->ggml_ctx, vec, vector_in->forward(ctx, y));
|
if (params.vec_in_dim > 0) {
|
||||||
|
auto vector_in = std::dynamic_pointer_cast<MLPEmbedder>(blocks["vector_in"]);
|
||||||
|
vec = ggml_add(ctx->ggml_ctx, vec, vector_in->forward(ctx, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModulationOut> ds_img_mods;
|
||||||
|
std::vector<ModulationOut> ds_txt_mods;
|
||||||
|
std::vector<ModulationOut> ss_mods;
|
||||||
|
if (params.share_modulation) {
|
||||||
|
auto double_stream_modulation_img = std::dynamic_pointer_cast<Modulation>(blocks["double_stream_modulation_img"]);
|
||||||
|
auto double_stream_modulation_txt = std::dynamic_pointer_cast<Modulation>(blocks["double_stream_modulation_txt"]);
|
||||||
|
auto single_stream_modulation = std::dynamic_pointer_cast<Modulation>(blocks["single_stream_modulation"]);
|
||||||
|
|
||||||
|
ds_img_mods = double_stream_modulation_img->forward(ctx, vec);
|
||||||
|
ds_txt_mods = double_stream_modulation_txt->forward(ctx, vec);
|
||||||
|
ss_mods = single_stream_modulation->forward(ctx, vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.semantic_txt_norm) {
|
||||||
|
auto semantic_txt_norm = std::dynamic_pointer_cast<RMSNorm>(blocks["txt_norm"]);
|
||||||
|
|
||||||
|
txt = semantic_txt_norm->forward(ctx, txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
txt = txt_in->forward(ctx, txt);
|
txt = txt_in->forward(ctx, txt);
|
||||||
@ -884,7 +1011,7 @@ namespace Flux {
|
|||||||
|
|
||||||
auto block = std::dynamic_pointer_cast<DoubleStreamBlock>(blocks["double_blocks." + std::to_string(i)]);
|
auto block = std::dynamic_pointer_cast<DoubleStreamBlock>(blocks["double_blocks." + std::to_string(i)]);
|
||||||
|
|
||||||
auto img_txt = block->forward(ctx, img, txt, vec, pe, txt_img_mask);
|
auto img_txt = block->forward(ctx, img, txt, vec, pe, txt_img_mask, ds_img_mods, ds_txt_mods);
|
||||||
img = img_txt.first; // [N, n_img_token, hidden_size]
|
img = img_txt.first; // [N, n_img_token, hidden_size]
|
||||||
txt = img_txt.second; // [N, n_txt_token, hidden_size]
|
txt = img_txt.second; // [N, n_txt_token, hidden_size]
|
||||||
}
|
}
|
||||||
@ -896,7 +1023,7 @@ namespace Flux {
|
|||||||
}
|
}
|
||||||
auto block = std::dynamic_pointer_cast<SingleStreamBlock>(blocks["single_blocks." + std::to_string(i)]);
|
auto block = std::dynamic_pointer_cast<SingleStreamBlock>(blocks["single_blocks." + std::to_string(i)]);
|
||||||
|
|
||||||
txt_img = block->forward(ctx, txt_img, vec, pe, txt_img_mask);
|
txt_img = block->forward(ctx, txt_img, vec, pe, txt_img_mask, ss_mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
txt_img = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, txt_img, 0, 2, 1, 3)); // [n_txt_token + n_img_token, N, hidden_size]
|
txt_img = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, txt_img, 0, 2, 1, 3)); // [n_txt_token + n_img_token, N, hidden_size]
|
||||||
@ -1133,6 +1260,27 @@ namespace Flux {
|
|||||||
} else if (version == VERSION_CHROMA_RADIANCE) {
|
} else if (version == VERSION_CHROMA_RADIANCE) {
|
||||||
flux_params.in_channels = 3;
|
flux_params.in_channels = 3;
|
||||||
flux_params.patch_size = 16;
|
flux_params.patch_size = 16;
|
||||||
|
} else if (version == VERSION_OVIS_IMAGE) {
|
||||||
|
flux_params.semantic_txt_norm = true;
|
||||||
|
flux_params.use_yak_mlp = true;
|
||||||
|
flux_params.context_in_dim = 2048;
|
||||||
|
flux_params.vec_in_dim = 0;
|
||||||
|
} else if (sd_version_is_flux2(version)) {
|
||||||
|
flux_params.context_in_dim = 15360;
|
||||||
|
flux_params.in_channels = 128;
|
||||||
|
flux_params.hidden_size = 6144;
|
||||||
|
flux_params.num_heads = 48;
|
||||||
|
flux_params.patch_size = 1;
|
||||||
|
flux_params.out_channels = 128;
|
||||||
|
flux_params.mlp_ratio = 3.f;
|
||||||
|
flux_params.theta = 2000;
|
||||||
|
flux_params.axes_dim = {32, 32, 32, 32};
|
||||||
|
flux_params.vec_in_dim = 0;
|
||||||
|
flux_params.qkv_bias = false;
|
||||||
|
flux_params.disable_bias = true;
|
||||||
|
flux_params.share_modulation = true;
|
||||||
|
flux_params.ref_index_scale = 10.f;
|
||||||
|
flux_params.use_mlp_silu_act = true;
|
||||||
}
|
}
|
||||||
for (auto pair : tensor_storage_map) {
|
for (auto pair : tensor_storage_map) {
|
||||||
std::string tensor_name = pair.first;
|
std::string tensor_name = pair.first;
|
||||||
@ -1275,13 +1423,23 @@ namespace Flux {
|
|||||||
ref_latents[i] = to_backend(ref_latents[i]);
|
ref_latents[i] = to_backend(ref_latents[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<int> txt_arange_dims;
|
||||||
|
if (sd_version_is_flux2(version)) {
|
||||||
|
txt_arange_dims = {3};
|
||||||
|
increase_ref_index = true;
|
||||||
|
} else if (version == VERSION_OVIS_IMAGE) {
|
||||||
|
txt_arange_dims = {1, 2};
|
||||||
|
}
|
||||||
|
|
||||||
pe_vec = Rope::gen_flux_pe(x->ne[1],
|
pe_vec = Rope::gen_flux_pe(x->ne[1],
|
||||||
x->ne[0],
|
x->ne[0],
|
||||||
flux_params.patch_size,
|
flux_params.patch_size,
|
||||||
x->ne[3],
|
x->ne[3],
|
||||||
context->ne[1],
|
context->ne[1],
|
||||||
|
txt_arange_dims,
|
||||||
ref_latents,
|
ref_latents,
|
||||||
increase_ref_index,
|
increase_ref_index,
|
||||||
|
flux_params.ref_index_scale,
|
||||||
flux_params.theta,
|
flux_params.theta,
|
||||||
flux_params.axes_dim);
|
flux_params.axes_dim);
|
||||||
int pos_len = pe_vec.size() / flux_params.axes_dim_sum / 2;
|
int pos_len = pe_vec.size() / flux_params.axes_dim_sum / 2;
|
||||||
@ -1323,7 +1481,7 @@ namespace Flux {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
struct ggml_tensor* context,
|
struct ggml_tensor* context,
|
||||||
@ -1344,7 +1502,7 @@ namespace Flux {
|
|||||||
return build_graph(x, timesteps, context, c_concat, y, guidance, ref_latents, increase_ref_index, skip_layers);
|
return build_graph(x, timesteps, context, c_concat, y, guidance, ref_latents, increase_ref_index, skip_layers);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
@ -1360,9 +1518,9 @@ namespace Flux {
|
|||||||
// cpu f16:
|
// cpu f16:
|
||||||
// cuda f16: nan
|
// cuda f16: nan
|
||||||
// cuda q8_0: pass
|
// cuda q8_0: pass
|
||||||
// auto x = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 16, 16, 16, 1);
|
auto x = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 16, 16, 128, 1);
|
||||||
// ggml_set_f32(x, 0.01f);
|
// ggml_set_f32(x, 0.01f);
|
||||||
auto x = load_tensor_from_file(work_ctx, "chroma_x.bin");
|
// auto x = load_tensor_from_file(work_ctx, "chroma_x.bin");
|
||||||
// print_ggml_tensor(x);
|
// print_ggml_tensor(x);
|
||||||
|
|
||||||
std::vector<float> timesteps_vec(1, 1.f);
|
std::vector<float> timesteps_vec(1, 1.f);
|
||||||
@ -1371,9 +1529,9 @@ namespace Flux {
|
|||||||
std::vector<float> guidance_vec(1, 0.f);
|
std::vector<float> guidance_vec(1, 0.f);
|
||||||
auto guidance = vector_to_ggml_tensor(work_ctx, guidance_vec);
|
auto guidance = vector_to_ggml_tensor(work_ctx, guidance_vec);
|
||||||
|
|
||||||
// auto context = ggml_new_tensor_3d(work_ctx, GGML_TYPE_F32, 4096, 256, 1);
|
auto context = ggml_new_tensor_3d(work_ctx, GGML_TYPE_F32, 15360, 256, 1);
|
||||||
// ggml_set_f32(context, 0.01f);
|
// ggml_set_f32(context, 0.01f);
|
||||||
auto context = load_tensor_from_file(work_ctx, "chroma_context.bin");
|
// auto context = load_tensor_from_file(work_ctx, "chroma_context.bin");
|
||||||
// print_ggml_tensor(context);
|
// print_ggml_tensor(context);
|
||||||
|
|
||||||
// auto y = ggml_new_tensor_2d(work_ctx, GGML_TYPE_F32, 768, 1);
|
// auto y = ggml_new_tensor_2d(work_ctx, GGML_TYPE_F32, 768, 1);
|
||||||
@ -1395,7 +1553,7 @@ namespace Flux {
|
|||||||
static void load_from_file_and_test(const std::string& file_path) {
|
static void load_from_file_and_test(const std::string& file_path) {
|
||||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||||
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
ggml_type model_data_type = GGML_TYPE_COUNT;
|
||||||
|
|
||||||
ModelLoader model_loader;
|
ModelLoader model_loader;
|
||||||
if (!model_loader.init_from_file_and_convert_name(file_path, "model.diffusion_model.")) {
|
if (!model_loader.init_from_file_and_convert_name(file_path, "model.diffusion_model.")) {
|
||||||
@ -1404,9 +1562,11 @@ namespace Flux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
if (model_data_type != GGML_TYPE_COUNT) {
|
||||||
if (ends_with(name, "weight")) {
|
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||||
tensor_storage.expected_type = model_data_type;
|
if (ends_with(name, "weight")) {
|
||||||
|
tensor_storage.expected_type = model_data_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1414,7 +1574,7 @@ namespace Flux {
|
|||||||
false,
|
false,
|
||||||
tensor_storage_map,
|
tensor_storage_map,
|
||||||
"model.diffusion_model",
|
"model.diffusion_model",
|
||||||
VERSION_CHROMA_RADIANCE,
|
VERSION_FLUX2,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
flux->alloc_params_buffer();
|
flux->alloc_params_buffer();
|
||||||
|
|||||||
@ -60,6 +60,14 @@
|
|||||||
#define SD_UNUSED(x) (void)(x)
|
#define SD_UNUSED(x) (void)(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
__STATIC_INLINE__ int align_up_offset(int n, int multiple) {
|
||||||
|
return (multiple - n % multiple) % multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
__STATIC_INLINE__ int align_up(int n, int multiple) {
|
||||||
|
return n + align_up_offset(n, multiple);
|
||||||
|
}
|
||||||
|
|
||||||
__STATIC_INLINE__ void ggml_log_callback_default(ggml_log_level level, const char* text, void*) {
|
__STATIC_INLINE__ void ggml_log_callback_default(ggml_log_level level, const char* text, void*) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case GGML_LOG_LEVEL_DEBUG:
|
case GGML_LOG_LEVEL_DEBUG:
|
||||||
@ -760,6 +768,27 @@ __STATIC_INLINE__ std::vector<struct ggml_tensor*> ggml_ext_chunk(struct ggml_co
|
|||||||
return chunks;
|
return chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__STATIC_INLINE__ ggml_tensor* ggml_ext_silu_act(ggml_context* ctx, ggml_tensor* x, bool gate_first = true) {
|
||||||
|
// x: [ne3, ne2, ne1, ne0]
|
||||||
|
// return: [ne3, ne2, ne1, ne0/2]
|
||||||
|
|
||||||
|
auto x_vec = ggml_ext_chunk(ctx, x, 2, 0);
|
||||||
|
ggml_tensor* gate;
|
||||||
|
if (gate_first) {
|
||||||
|
gate = x_vec[0];
|
||||||
|
x = x_vec[1];
|
||||||
|
} else {
|
||||||
|
x = x_vec[0];
|
||||||
|
gate = x_vec[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
gate = ggml_silu_inplace(ctx, gate);
|
||||||
|
|
||||||
|
x = ggml_mul(ctx, x, gate); // [ne3, ne2, ne1, ne0/2]
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::function<void(ggml_tensor*, ggml_tensor*, bool)> on_tile_process;
|
typedef std::function<void(ggml_tensor*, ggml_tensor*, bool)> on_tile_process;
|
||||||
|
|
||||||
__STATIC_INLINE__ void sd_tiling_calc_tiles(int& num_tiles_dim,
|
__STATIC_INLINE__ void sd_tiling_calc_tiles(int& num_tiles_dim,
|
||||||
@ -997,6 +1026,9 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_ext_conv_2d(struct ggml_context* ctx,
|
|||||||
if (scale != 1.f) {
|
if (scale != 1.f) {
|
||||||
x = ggml_scale(ctx, x, scale);
|
x = ggml_scale(ctx, x, scale);
|
||||||
}
|
}
|
||||||
|
if (w->ne[2] != x->ne[2] && ggml_n_dims(w) == 2) {
|
||||||
|
w = ggml_reshape_4d(ctx, w, 1, 1, w->ne[0], w->ne[1]);
|
||||||
|
}
|
||||||
if (direct) {
|
if (direct) {
|
||||||
x = ggml_conv_2d_direct(ctx, w, x, s0, s1, p0, p1, d0, d1);
|
x = ggml_conv_2d_direct(ctx, w, x, s0, s1, p0, p1, d0, d1);
|
||||||
} else {
|
} else {
|
||||||
@ -1123,6 +1155,14 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_ext_ones(struct ggml_context* ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE__ ggml_tensor* ggml_ext_cast_f32(ggml_context* ctx, ggml_tensor* a) {
|
__STATIC_INLINE__ ggml_tensor* ggml_ext_cast_f32(ggml_context* ctx, ggml_tensor* a) {
|
||||||
|
#ifdef SD_USE_VULKAN
|
||||||
|
auto zero_index = ggml_get_tensor(ctx, "ggml_runner_build_in_tensor:zero_int");
|
||||||
|
auto out = ggml_reshape_1d(ctx, a, ggml_nelements(a));
|
||||||
|
out = ggml_get_rows(ctx, out, zero_index);
|
||||||
|
out = ggml_reshape(ctx, out, a);
|
||||||
|
// auto out = ggml_cast(ctx, a, GGML_TYPE_F32);
|
||||||
|
return out;
|
||||||
|
#else
|
||||||
auto out = ggml_reshape_2d(ctx, a, 1, ggml_nelements(a));
|
auto out = ggml_reshape_2d(ctx, a, 1, ggml_nelements(a));
|
||||||
ggml_tensor* one = ggml_ext_ones(ctx, 1, 1, 1, 1); // [1,]
|
ggml_tensor* one = ggml_ext_ones(ctx, 1, 1, 1, 1); // [1,]
|
||||||
if (ggml_is_transposed(out)) {
|
if (ggml_is_transposed(out)) {
|
||||||
@ -1130,7 +1170,8 @@ __STATIC_INLINE__ ggml_tensor* ggml_ext_cast_f32(ggml_context* ctx, ggml_tensor*
|
|||||||
} else {
|
} else {
|
||||||
out = ggml_mul_mat(ctx, out, one);
|
out = ggml_mul_mat(ctx, out, one);
|
||||||
}
|
}
|
||||||
out = ggml_reshape(ctx, out, a);
|
out = ggml_reshape(ctx, out, a);
|
||||||
|
#endif
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,10 +1400,14 @@ __STATIC_INLINE__ void ggml_ext_backend_tensor_get_and_sync(ggml_backend_t backe
|
|||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE__ float ggml_ext_backend_tensor_get_f32(ggml_tensor* tensor) {
|
__STATIC_INLINE__ float ggml_ext_backend_tensor_get_f32(ggml_tensor* tensor) {
|
||||||
GGML_ASSERT(tensor->type == GGML_TYPE_F32 || tensor->type == GGML_TYPE_F16 || tensor->type == GGML_TYPE_I32);
|
GGML_ASSERT(tensor->type == GGML_TYPE_F32 || tensor->type == GGML_TYPE_F16 || tensor->type == GGML_TYPE_I32 || tensor->type == GGML_TYPE_BF16);
|
||||||
float value;
|
float value;
|
||||||
if (tensor->type == GGML_TYPE_F32) {
|
if (tensor->type == GGML_TYPE_F32) {
|
||||||
ggml_backend_tensor_get(tensor, &value, 0, sizeof(value));
|
ggml_backend_tensor_get(tensor, &value, 0, sizeof(value));
|
||||||
|
} else if (tensor->type == GGML_TYPE_BF16) {
|
||||||
|
ggml_bf16_t bf16_value;
|
||||||
|
ggml_backend_tensor_get(tensor, &bf16_value, 0, sizeof(bf16_value));
|
||||||
|
value = ggml_bf16_to_fp32(bf16_value);
|
||||||
} else if (tensor->type == GGML_TYPE_F16) {
|
} else if (tensor->type == GGML_TYPE_F16) {
|
||||||
ggml_fp16_t f16_value;
|
ggml_fp16_t f16_value;
|
||||||
ggml_backend_tensor_get(tensor, &f16_value, 0, sizeof(f16_value));
|
ggml_backend_tensor_get(tensor, &f16_value, 0, sizeof(f16_value));
|
||||||
@ -1538,6 +1583,9 @@ protected:
|
|||||||
std::vector<float> one_vec = {1.f};
|
std::vector<float> one_vec = {1.f};
|
||||||
ggml_tensor* one_tensor = nullptr;
|
ggml_tensor* one_tensor = nullptr;
|
||||||
|
|
||||||
|
std::vector<int> zero_int_vec = {0};
|
||||||
|
ggml_tensor* zero_int_tensor = nullptr;
|
||||||
|
|
||||||
std::map<struct ggml_tensor*, const void*> backend_tensor_data_map;
|
std::map<struct ggml_tensor*, const void*> backend_tensor_data_map;
|
||||||
std::map<std::string, struct ggml_tensor*> cache_tensor_map; // name -> tensor
|
std::map<std::string, struct ggml_tensor*> cache_tensor_map; // name -> tensor
|
||||||
const std::string final_result_name = "ggml_runner_final_result_tensor";
|
const std::string final_result_name = "ggml_runner_final_result_tensor";
|
||||||
@ -1608,10 +1656,15 @@ protected:
|
|||||||
one_tensor = ggml_new_tensor_1d(compute_ctx, GGML_TYPE_F32, 1);
|
one_tensor = ggml_new_tensor_1d(compute_ctx, GGML_TYPE_F32, 1);
|
||||||
ggml_set_name(one_tensor, "ggml_runner_build_in_tensor:one");
|
ggml_set_name(one_tensor, "ggml_runner_build_in_tensor:one");
|
||||||
set_backend_tensor_data(one_tensor, one_vec.data());
|
set_backend_tensor_data(one_tensor, one_vec.data());
|
||||||
|
|
||||||
|
zero_int_tensor = ggml_new_tensor_1d(compute_ctx, GGML_TYPE_I32, 1);
|
||||||
|
ggml_set_name(zero_int_tensor, "ggml_runner_build_in_tensor:zero_int");
|
||||||
|
set_backend_tensor_data(zero_int_tensor, zero_int_vec.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare_build_in_tensor_after(struct ggml_cgraph* gf) {
|
void prepare_build_in_tensor_after(struct ggml_cgraph* gf) {
|
||||||
ggml_build_forward_expand(gf, one_tensor);
|
ggml_build_forward_expand(gf, one_tensor);
|
||||||
|
ggml_build_forward_expand(gf, zero_int_tensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ggml_cgraph* new_graph_custom(size_t graph_size) {
|
struct ggml_cgraph* new_graph_custom(size_t graph_size) {
|
||||||
@ -1903,25 +1956,35 @@ public:
|
|||||||
return ggml_get_tensor(cache_ctx, name.c_str());
|
return ggml_get_tensor(cache_ctx, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(get_graph_cb_t get_graph,
|
bool compute(get_graph_cb_t get_graph,
|
||||||
int n_threads,
|
int n_threads,
|
||||||
bool free_compute_buffer_immediately = true,
|
bool free_compute_buffer_immediately = true,
|
||||||
struct ggml_tensor** output = nullptr,
|
struct ggml_tensor** output = nullptr,
|
||||||
struct ggml_context* output_ctx = nullptr) {
|
struct ggml_context* output_ctx = nullptr) {
|
||||||
if (!offload_params_to_runtime_backend()) {
|
if (!offload_params_to_runtime_backend()) {
|
||||||
LOG_ERROR("%s offload params to runtime backend failed", get_desc().c_str());
|
LOG_ERROR("%s offload params to runtime backend failed", get_desc().c_str());
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
if (!alloc_compute_buffer(get_graph)) {
|
||||||
|
LOG_ERROR("%s alloc compute buffer failed", get_desc().c_str());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
alloc_compute_buffer(get_graph);
|
|
||||||
reset_compute_ctx();
|
reset_compute_ctx();
|
||||||
struct ggml_cgraph* gf = get_compute_graph(get_graph);
|
struct ggml_cgraph* gf = get_compute_graph(get_graph);
|
||||||
GGML_ASSERT(ggml_gallocr_alloc_graph(compute_allocr, gf));
|
if (!ggml_gallocr_alloc_graph(compute_allocr, gf)) {
|
||||||
|
LOG_ERROR("%s alloc compute graph failed", get_desc().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
copy_data_to_backend_tensor();
|
copy_data_to_backend_tensor();
|
||||||
if (ggml_backend_is_cpu(runtime_backend)) {
|
if (ggml_backend_is_cpu(runtime_backend)) {
|
||||||
ggml_backend_cpu_set_n_threads(runtime_backend, n_threads);
|
ggml_backend_cpu_set_n_threads(runtime_backend, n_threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
ggml_backend_graph_compute(runtime_backend, gf);
|
ggml_status status = ggml_backend_graph_compute(runtime_backend, gf);
|
||||||
|
if (status != GGML_STATUS_SUCCESS) {
|
||||||
|
LOG_ERROR("%s compute failed: %s", get_desc().c_str(), ggml_status_to_string(status));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#ifdef GGML_PERF
|
#ifdef GGML_PERF
|
||||||
ggml_graph_print(gf);
|
ggml_graph_print(gf);
|
||||||
#endif
|
#endif
|
||||||
@ -1939,6 +2002,7 @@ public:
|
|||||||
if (free_compute_buffer_immediately) {
|
if (free_compute_buffer_immediately) {
|
||||||
free_compute_buffer();
|
free_compute_buffer();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_flash_attention_enabled(bool enabled) {
|
void set_flash_attention_enabled(bool enabled) {
|
||||||
|
|||||||
@ -91,6 +91,41 @@ const float flux_latent_rgb_proj[16][3] = {
|
|||||||
{-0.111849f, -0.055589f, -0.032361f}};
|
{-0.111849f, -0.055589f, -0.032361f}};
|
||||||
float flux_latent_rgb_bias[3] = {0.024600f, -0.006937f, -0.008089f};
|
float flux_latent_rgb_bias[3] = {0.024600f, -0.006937f, -0.008089f};
|
||||||
|
|
||||||
|
const float flux2_latent_rgb_proj[32][3] = {
|
||||||
|
{0.000736f, -0.008385f, -0.019710f},
|
||||||
|
{-0.001352f, -0.016392f, 0.020693f},
|
||||||
|
{-0.006376f, 0.002428f, 0.036736f},
|
||||||
|
{0.039384f, 0.074167f, 0.119789f},
|
||||||
|
{0.007464f, -0.005705f, -0.004734f},
|
||||||
|
{-0.004086f, 0.005287f, -0.000409f},
|
||||||
|
{-0.032835f, 0.050802f, -0.028120f},
|
||||||
|
{-0.003158f, -0.000835f, 0.000406f},
|
||||||
|
{-0.112840f, -0.084337f, -0.023083f},
|
||||||
|
{0.001462f, -0.006656f, 0.000549f},
|
||||||
|
{-0.009980f, -0.007480f, 0.009702f},
|
||||||
|
{0.032540f, 0.000214f, -0.061388f},
|
||||||
|
{0.011023f, 0.000694f, 0.007143f},
|
||||||
|
{-0.001468f, -0.006723f, -0.001678f},
|
||||||
|
{-0.005921f, -0.010320f, -0.003907f},
|
||||||
|
{-0.028434f, 0.027584f, 0.018457f},
|
||||||
|
{0.014349f, 0.011523f, 0.000441f},
|
||||||
|
{0.009874f, 0.003081f, 0.001507f},
|
||||||
|
{0.002218f, 0.005712f, 0.001563f},
|
||||||
|
{0.053010f, -0.019844f, 0.008683f},
|
||||||
|
{-0.002507f, 0.005384f, 0.000938f},
|
||||||
|
{-0.002177f, -0.011366f, 0.003559f},
|
||||||
|
{-0.000261f, 0.015121f, -0.003240f},
|
||||||
|
{-0.003944f, -0.002083f, 0.005043f},
|
||||||
|
{-0.009138f, 0.011336f, 0.003781f},
|
||||||
|
{0.011429f, 0.003985f, -0.003855f},
|
||||||
|
{0.010518f, -0.005586f, 0.010131f},
|
||||||
|
{0.007883f, 0.002912f, -0.001473f},
|
||||||
|
{-0.003318f, -0.003160f, 0.003684f},
|
||||||
|
{-0.034560f, -0.008740f, 0.012996f},
|
||||||
|
{0.000166f, 0.001079f, -0.012153f},
|
||||||
|
{0.017772f, 0.000937f, -0.011953f}};
|
||||||
|
float flux2_latent_rgb_bias[3] = {-0.028738f, -0.098463f, -0.107619f};
|
||||||
|
|
||||||
// This one was taken straight from
|
// This one was taken straight from
|
||||||
// https://github.com/Stability-AI/sd3.5/blob/8565799a3b41eb0c7ba976d18375f0f753f56402/sd3_impls.py#L288-L303
|
// https://github.com/Stability-AI/sd3.5/blob/8565799a3b41eb0c7ba976d18375f0f753f56402/sd3_impls.py#L288-L303
|
||||||
// (MiT Licence)
|
// (MiT Licence)
|
||||||
@ -128,16 +163,42 @@ const float sd_latent_rgb_proj[4][3] = {
|
|||||||
{-0.178022f, -0.200862f, -0.678514f}};
|
{-0.178022f, -0.200862f, -0.678514f}};
|
||||||
float sd_latent_rgb_bias[3] = {-0.017478f, -0.055834f, -0.105825f};
|
float sd_latent_rgb_bias[3] = {-0.017478f, -0.055834f, -0.105825f};
|
||||||
|
|
||||||
void preview_latent_video(uint8_t* buffer, struct ggml_tensor* latents, const float (*latent_rgb_proj)[3], const float latent_rgb_bias[3], int width, int height, int frames, int dim) {
|
void preview_latent_video(uint8_t* buffer, struct ggml_tensor* latents, const float (*latent_rgb_proj)[3], const float latent_rgb_bias[3], int patch_size) {
|
||||||
size_t buffer_head = 0;
|
size_t buffer_head = 0;
|
||||||
|
|
||||||
|
uint32_t latent_width = latents->ne[0];
|
||||||
|
uint32_t latent_height = latents->ne[1];
|
||||||
|
uint32_t dim = latents->ne[ggml_n_dims(latents) - 1];
|
||||||
|
uint32_t frames = 1;
|
||||||
|
if (ggml_n_dims(latents) == 4) {
|
||||||
|
frames = latents->ne[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rgb_width = latent_width * patch_size;
|
||||||
|
uint32_t rgb_height = latent_height * patch_size;
|
||||||
|
|
||||||
|
uint32_t unpatched_dim = dim / (patch_size * patch_size);
|
||||||
|
|
||||||
for (int k = 0; k < frames; k++) {
|
for (int k = 0; k < frames; k++) {
|
||||||
for (int j = 0; j < height; j++) {
|
for (int rgb_x = 0; rgb_x < rgb_width; rgb_x++) {
|
||||||
for (int i = 0; i < width; i++) {
|
for (int rgb_y = 0; rgb_y < rgb_height; rgb_y++) {
|
||||||
size_t latent_id = (i * latents->nb[0] + j * latents->nb[1] + k * latents->nb[2]);
|
int latent_x = rgb_x / patch_size;
|
||||||
|
int latent_y = rgb_y / patch_size;
|
||||||
|
|
||||||
|
int channel_offset = 0;
|
||||||
|
if (patch_size > 1) {
|
||||||
|
channel_offset = ((rgb_y % patch_size) * patch_size + (rgb_x % patch_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t latent_id = (latent_x * latents->nb[0] + latent_y * latents->nb[1] + k * latents->nb[2]);
|
||||||
|
|
||||||
|
// should be incremented by 1 for each pixel
|
||||||
|
size_t pixel_id = k * rgb_width * rgb_height + rgb_y * rgb_width + rgb_x;
|
||||||
|
|
||||||
float r = 0, g = 0, b = 0;
|
float r = 0, g = 0, b = 0;
|
||||||
if (latent_rgb_proj != nullptr) {
|
if (latent_rgb_proj != nullptr) {
|
||||||
for (int d = 0; d < dim; d++) {
|
for (int d = 0; d < unpatched_dim; d++) {
|
||||||
float value = *(float*)((char*)latents->data + latent_id + d * latents->nb[ggml_n_dims(latents) - 1]);
|
float value = *(float*)((char*)latents->data + latent_id + (d * patch_size * patch_size + channel_offset) * latents->nb[ggml_n_dims(latents) - 1]);
|
||||||
r += value * latent_rgb_proj[d][0];
|
r += value * latent_rgb_proj[d][0];
|
||||||
g += value * latent_rgb_proj[d][1];
|
g += value * latent_rgb_proj[d][1];
|
||||||
b += value * latent_rgb_proj[d][2];
|
b += value * latent_rgb_proj[d][2];
|
||||||
@ -164,9 +225,9 @@ void preview_latent_video(uint8_t* buffer, struct ggml_tensor* latents, const fl
|
|||||||
g = g >= 0 ? g <= 1 ? g : 1 : 0;
|
g = g >= 0 ? g <= 1 ? g : 1 : 0;
|
||||||
b = b >= 0 ? b <= 1 ? b : 1 : 0;
|
b = b >= 0 ? b <= 1 ? b : 1 : 0;
|
||||||
|
|
||||||
buffer[buffer_head++] = (uint8_t)(r * 255);
|
buffer[pixel_id * 3 + 0] = (uint8_t)(r * 255);
|
||||||
buffer[buffer_head++] = (uint8_t)(g * 255);
|
buffer[pixel_id * 3 + 1] = (uint8_t)(g * 255);
|
||||||
buffer[buffer_head++] = (uint8_t)(b * 255);
|
buffer[pixel_id * 3 + 2] = (uint8_t)(b * 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
mmdit.hpp
@ -101,10 +101,14 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
TimestepEmbedder(int64_t hidden_size,
|
TimestepEmbedder(int64_t hidden_size,
|
||||||
int64_t frequency_embedding_size = 256)
|
int64_t frequency_embedding_size = 256,
|
||||||
|
int64_t out_channels = 0)
|
||||||
: frequency_embedding_size(frequency_embedding_size) {
|
: frequency_embedding_size(frequency_embedding_size) {
|
||||||
|
if (out_channels <= 0) {
|
||||||
|
out_channels = hidden_size;
|
||||||
|
}
|
||||||
blocks["mlp.0"] = std::shared_ptr<GGMLBlock>(new Linear(frequency_embedding_size, hidden_size, true, true));
|
blocks["mlp.0"] = std::shared_ptr<GGMLBlock>(new Linear(frequency_embedding_size, hidden_size, true, true));
|
||||||
blocks["mlp.2"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size, true, true));
|
blocks["mlp.2"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, out_channels, true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* t) {
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* t) {
|
||||||
@ -890,7 +894,7 @@ struct MMDiTRunner : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
struct ggml_tensor* context,
|
struct ggml_tensor* context,
|
||||||
@ -906,7 +910,7 @@ struct MMDiTRunner : public GGMLRunner {
|
|||||||
return build_graph(x, timesteps, context, y, skip_layers);
|
return build_graph(x, timesteps, context, y, skip_layers);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
|
|||||||
64
model.cpp
@ -17,6 +17,7 @@
|
|||||||
#include "stable-diffusion.h"
|
#include "stable-diffusion.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vocab.hpp"
|
#include "vocab.hpp"
|
||||||
|
#include "vocab_mistral.hpp"
|
||||||
#include "vocab_qwen.hpp"
|
#include "vocab_qwen.hpp"
|
||||||
#include "vocab_umt5.hpp"
|
#include "vocab_umt5.hpp"
|
||||||
|
|
||||||
@ -102,10 +103,15 @@ const char* unused_tensors[] = {
|
|||||||
"model_ema.diffusion_model",
|
"model_ema.diffusion_model",
|
||||||
"embedding_manager",
|
"embedding_manager",
|
||||||
"denoiser.sigmas",
|
"denoiser.sigmas",
|
||||||
"edm_vpred.sigma_max",
|
|
||||||
"text_encoders.t5xxl.transformer.encoder.embed_tokens.weight", // only used during training
|
"text_encoders.t5xxl.transformer.encoder.embed_tokens.weight", // only used during training
|
||||||
"text_encoders.qwen2vl.output.weight",
|
"ztsnr", // Found in some SDXL vpred models
|
||||||
"text_encoders.qwen2vl.lm_head.",
|
"edm_vpred.sigma_min", // Found in CosXL
|
||||||
|
// TODO: find another way to avoid the "unknown tensor" for these two
|
||||||
|
// "edm_vpred.sigma_max", // Used to detect CosXL
|
||||||
|
// "v_pred", // Used to detect SDXL vpred models
|
||||||
|
"text_encoders.llm.output.weight",
|
||||||
|
"text_encoders.llm.lm_head.",
|
||||||
|
"first_stage_model.bn.",
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_unused_tensor(std::string name) {
|
bool is_unused_tensor(std::string name) {
|
||||||
@ -117,11 +123,6 @@ bool is_unused_tensor(std::string name) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float bf16_to_f32(uint16_t bfloat16) {
|
|
||||||
uint32_t val_bits = (static_cast<uint32_t>(bfloat16) << 16);
|
|
||||||
return *reinterpret_cast<float*>(&val_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t f8_e4m3_to_f16(uint8_t f8) {
|
uint16_t f8_e4m3_to_f16(uint8_t f8) {
|
||||||
// do we need to support uz?
|
// do we need to support uz?
|
||||||
|
|
||||||
@ -204,13 +205,6 @@ uint16_t f8_e5m2_to_f16(uint8_t fp8) {
|
|||||||
return fp16_sign | (fp16_exponent << 10) | fp16_mantissa;
|
return fp16_sign | (fp16_exponent << 10) | fp16_mantissa;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bf16_to_f32_vec(uint16_t* src, float* dst, int64_t n) {
|
|
||||||
// support inplace op
|
|
||||||
for (int64_t i = n - 1; i >= 0; i--) {
|
|
||||||
dst[i] = bf16_to_f32(src[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void f8_e4m3_to_f16_vec(uint8_t* src, uint16_t* dst, int64_t n) {
|
void f8_e4m3_to_f16_vec(uint8_t* src, uint16_t* dst, int64_t n) {
|
||||||
// support inplace op
|
// support inplace op
|
||||||
for (int64_t i = n - 1; i >= 0; i--) {
|
for (int64_t i = n - 1; i >= 0; i--) {
|
||||||
@ -263,8 +257,8 @@ void convert_tensor(void* src,
|
|||||||
} else {
|
} else {
|
||||||
auto qtype = ggml_get_type_traits(src_type);
|
auto qtype = ggml_get_type_traits(src_type);
|
||||||
if (qtype->to_float == nullptr) {
|
if (qtype->to_float == nullptr) {
|
||||||
throw std::runtime_error(format("type %s unsupported for integer quantization: no dequantization available",
|
throw std::runtime_error(sd_format("type %s unsupported for integer quantization: no dequantization available",
|
||||||
ggml_type_name(src_type)));
|
ggml_type_name(src_type)));
|
||||||
}
|
}
|
||||||
qtype->to_float(src, (float*)dst, n);
|
qtype->to_float(src, (float*)dst, n);
|
||||||
}
|
}
|
||||||
@ -273,8 +267,8 @@ void convert_tensor(void* src,
|
|||||||
// src_type is quantized => dst_type == GGML_TYPE_F16 or dst_type is quantized
|
// src_type is quantized => dst_type == GGML_TYPE_F16 or dst_type is quantized
|
||||||
auto qtype = ggml_get_type_traits(src_type);
|
auto qtype = ggml_get_type_traits(src_type);
|
||||||
if (qtype->to_float == nullptr) {
|
if (qtype->to_float == nullptr) {
|
||||||
throw std::runtime_error(format("type %s unsupported for integer quantization: no dequantization available",
|
throw std::runtime_error(sd_format("type %s unsupported for integer quantization: no dequantization available",
|
||||||
ggml_type_name(src_type)));
|
ggml_type_name(src_type)));
|
||||||
}
|
}
|
||||||
std::vector<char> buf;
|
std::vector<char> buf;
|
||||||
buf.resize(sizeof(float) * n);
|
buf.resize(sizeof(float) * n);
|
||||||
@ -489,7 +483,7 @@ ggml_type str_to_ggml_type(const std::string& dtype) {
|
|||||||
if (dtype == "F16") {
|
if (dtype == "F16") {
|
||||||
ttype = GGML_TYPE_F16;
|
ttype = GGML_TYPE_F16;
|
||||||
} else if (dtype == "BF16") {
|
} else if (dtype == "BF16") {
|
||||||
ttype = GGML_TYPE_F32;
|
ttype = GGML_TYPE_BF16;
|
||||||
} else if (dtype == "F32") {
|
} else if (dtype == "F32") {
|
||||||
ttype = GGML_TYPE_F32;
|
ttype = GGML_TYPE_F32;
|
||||||
} else if (dtype == "F64") {
|
} else if (dtype == "F64") {
|
||||||
@ -617,10 +611,7 @@ bool ModelLoader::init_from_safetensors_file(const std::string& file_path, const
|
|||||||
|
|
||||||
size_t tensor_data_size = end - begin;
|
size_t tensor_data_size = end - begin;
|
||||||
|
|
||||||
if (dtype == "BF16") {
|
if (dtype == "F8_E4M3") {
|
||||||
tensor_storage.is_bf16 = true;
|
|
||||||
GGML_ASSERT(tensor_storage.nbytes() == tensor_data_size * 2);
|
|
||||||
} else if (dtype == "F8_E4M3") {
|
|
||||||
tensor_storage.is_f8_e4m3 = true;
|
tensor_storage.is_f8_e4m3 = true;
|
||||||
// f8 -> f16
|
// f8 -> f16
|
||||||
GGML_ASSERT(tensor_storage.nbytes() == tensor_data_size * 2);
|
GGML_ASSERT(tensor_storage.nbytes() == tensor_data_size * 2);
|
||||||
@ -1062,6 +1053,15 @@ SDVersion ModelLoader::get_sd_version() {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
if (tensor_storage.name.find("model.diffusion_model.double_stream_modulation_img.lin.weight") != std::string::npos) {
|
||||||
|
return VERSION_FLUX2;
|
||||||
|
}
|
||||||
|
if (tensor_storage.name.find("model.diffusion_model.double_blocks.0.img_mlp.gate_proj.weight") != std::string::npos) {
|
||||||
|
return VERSION_OVIS_IMAGE;
|
||||||
|
}
|
||||||
|
if (tensor_storage.name.find("model.diffusion_model.cap_embedder.0.weight") != std::string::npos) {
|
||||||
|
return VERSION_Z_IMAGE;
|
||||||
|
}
|
||||||
if (tensor_storage.name.find("model.diffusion_model.blocks.0.cross_attn.norm_k.weight") != std::string::npos) {
|
if (tensor_storage.name.find("model.diffusion_model.blocks.0.cross_attn.norm_k.weight") != std::string::npos) {
|
||||||
is_wan = true;
|
is_wan = true;
|
||||||
}
|
}
|
||||||
@ -1320,6 +1320,16 @@ std::string ModelLoader::load_qwen2_merges() {
|
|||||||
return merges_utf8_str;
|
return merges_utf8_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ModelLoader::load_mistral_merges() {
|
||||||
|
std::string merges_utf8_str(reinterpret_cast<const char*>(mistral_merges_utf8_c_str), sizeof(mistral_merges_utf8_c_str));
|
||||||
|
return merges_utf8_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ModelLoader::load_mistral_vocab_json() {
|
||||||
|
std::string json_str(reinterpret_cast<const char*>(mistral_vocab_json_utf8_c_str), sizeof(mistral_vocab_json_utf8_c_str));
|
||||||
|
return json_str;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ModelLoader::load_t5_tokenizer_json() {
|
std::string ModelLoader::load_t5_tokenizer_json() {
|
||||||
std::string json_str(reinterpret_cast<const char*>(t5_tokenizer_json_str), sizeof(t5_tokenizer_json_str));
|
std::string json_str(reinterpret_cast<const char*>(t5_tokenizer_json_str), sizeof(t5_tokenizer_json_str));
|
||||||
return json_str;
|
return json_str;
|
||||||
@ -1337,7 +1347,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
std::atomic<int64_t> copy_to_backend_time_ms(0);
|
std::atomic<int64_t> copy_to_backend_time_ms(0);
|
||||||
std::atomic<int64_t> convert_time_ms(0);
|
std::atomic<int64_t> convert_time_ms(0);
|
||||||
|
|
||||||
int num_threads_to_use = n_threads_p > 0 ? n_threads_p : get_num_physical_cores();
|
int num_threads_to_use = n_threads_p > 0 ? n_threads_p : sd_get_num_physical_cores();
|
||||||
LOG_DEBUG("using %d threads for model loading", num_threads_to_use);
|
LOG_DEBUG("using %d threads for model loading", num_threads_to_use);
|
||||||
|
|
||||||
int64_t start_time = ggml_time_ms();
|
int64_t start_time = ggml_time_ms();
|
||||||
@ -1500,9 +1510,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
|||||||
read_time_ms.fetch_add(t1 - t0);
|
read_time_ms.fetch_add(t1 - t0);
|
||||||
|
|
||||||
t0 = ggml_time_ms();
|
t0 = ggml_time_ms();
|
||||||
if (tensor_storage.is_bf16) {
|
if (tensor_storage.is_f8_e4m3) {
|
||||||
bf16_to_f32_vec((uint16_t*)read_buf, (float*)target_buf, tensor_storage.nelements());
|
|
||||||
} else if (tensor_storage.is_f8_e4m3) {
|
|
||||||
f8_e4m3_to_f16_vec((uint8_t*)read_buf, (uint16_t*)target_buf, tensor_storage.nelements());
|
f8_e4m3_to_f16_vec((uint8_t*)read_buf, (uint16_t*)target_buf, tensor_storage.nelements());
|
||||||
} else if (tensor_storage.is_f8_e5m2) {
|
} else if (tensor_storage.is_f8_e5m2) {
|
||||||
f8_e5m2_to_f16_vec((uint8_t*)read_buf, (uint16_t*)target_buf, tensor_storage.nelements());
|
f8_e5m2_to_f16_vec((uint8_t*)read_buf, (uint16_t*)target_buf, tensor_storage.nelements());
|
||||||
|
|||||||
31
model.h
@ -43,6 +43,9 @@ enum SDVersion {
|
|||||||
VERSION_WAN2_2_I2V,
|
VERSION_WAN2_2_I2V,
|
||||||
VERSION_WAN2_2_TI2V,
|
VERSION_WAN2_2_TI2V,
|
||||||
VERSION_QWEN_IMAGE,
|
VERSION_QWEN_IMAGE,
|
||||||
|
VERSION_FLUX2,
|
||||||
|
VERSION_Z_IMAGE,
|
||||||
|
VERSION_OVIS_IMAGE,
|
||||||
VERSION_COUNT,
|
VERSION_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,12 +91,20 @@ static inline bool sd_version_is_flux(SDVersion version) {
|
|||||||
version == VERSION_FLUX_FILL ||
|
version == VERSION_FLUX_FILL ||
|
||||||
version == VERSION_FLUX_CONTROLS ||
|
version == VERSION_FLUX_CONTROLS ||
|
||||||
version == VERSION_FLEX_2 ||
|
version == VERSION_FLEX_2 ||
|
||||||
|
version == VERSION_OVIS_IMAGE ||
|
||||||
version == VERSION_CHROMA_RADIANCE) {
|
version == VERSION_CHROMA_RADIANCE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool sd_version_is_flux2(SDVersion version) {
|
||||||
|
if (version == VERSION_FLUX2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool sd_version_is_wan(SDVersion version) {
|
static inline bool sd_version_is_wan(SDVersion version) {
|
||||||
if (version == VERSION_WAN2 || version == VERSION_WAN2_2_I2V || version == VERSION_WAN2_2_TI2V) {
|
if (version == VERSION_WAN2 || version == VERSION_WAN2_2_I2V || version == VERSION_WAN2_2_TI2V) {
|
||||||
return true;
|
return true;
|
||||||
@ -108,6 +119,13 @@ static inline bool sd_version_is_qwen_image(SDVersion version) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool sd_version_is_z_image(SDVersion version) {
|
||||||
|
if (version == VERSION_Z_IMAGE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool sd_version_is_inpaint(SDVersion version) {
|
static inline bool sd_version_is_inpaint(SDVersion version) {
|
||||||
if (version == VERSION_SD1_INPAINT ||
|
if (version == VERSION_SD1_INPAINT ||
|
||||||
version == VERSION_SD2_INPAINT ||
|
version == VERSION_SD2_INPAINT ||
|
||||||
@ -121,9 +139,11 @@ static inline bool sd_version_is_inpaint(SDVersion version) {
|
|||||||
|
|
||||||
static inline bool sd_version_is_dit(SDVersion version) {
|
static inline bool sd_version_is_dit(SDVersion version) {
|
||||||
if (sd_version_is_flux(version) ||
|
if (sd_version_is_flux(version) ||
|
||||||
|
sd_version_is_flux2(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) ||
|
||||||
|
sd_version_is_z_image(version)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -150,7 +170,6 @@ struct TensorStorage {
|
|||||||
std::string name;
|
std::string name;
|
||||||
ggml_type type = GGML_TYPE_F32;
|
ggml_type type = GGML_TYPE_F32;
|
||||||
ggml_type expected_type = GGML_TYPE_COUNT;
|
ggml_type expected_type = GGML_TYPE_COUNT;
|
||||||
bool is_bf16 = false;
|
|
||||||
bool is_f8_e4m3 = false;
|
bool is_f8_e4m3 = false;
|
||||||
bool is_f8_e5m2 = false;
|
bool is_f8_e5m2 = false;
|
||||||
bool is_f64 = false;
|
bool is_f64 = false;
|
||||||
@ -184,7 +203,7 @@ struct TensorStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t nbytes_to_read() const {
|
int64_t nbytes_to_read() const {
|
||||||
if (is_bf16 || is_f8_e4m3 || is_f8_e5m2) {
|
if (is_f8_e4m3 || is_f8_e5m2) {
|
||||||
return nbytes() / 2;
|
return nbytes() / 2;
|
||||||
} else if (is_f64 || is_i64) {
|
} else if (is_f64 || is_i64) {
|
||||||
return nbytes() * 2;
|
return nbytes() * 2;
|
||||||
@ -232,9 +251,7 @@ struct TensorStorage {
|
|||||||
std::string to_string() const {
|
std::string to_string() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
const char* type_name = ggml_type_name(type);
|
const char* type_name = ggml_type_name(type);
|
||||||
if (is_bf16) {
|
if (is_f8_e4m3) {
|
||||||
type_name = "bf16";
|
|
||||||
} else if (is_f8_e4m3) {
|
|
||||||
type_name = "f8_e4m3";
|
type_name = "f8_e4m3";
|
||||||
} else if (is_f8_e5m2) {
|
} else if (is_f8_e5m2) {
|
||||||
type_name = "f8_e5m2";
|
type_name = "f8_e5m2";
|
||||||
@ -313,6 +330,8 @@ public:
|
|||||||
|
|
||||||
static std::string load_merges();
|
static std::string load_merges();
|
||||||
static std::string load_qwen2_merges();
|
static std::string load_qwen2_merges();
|
||||||
|
static std::string load_mistral_merges();
|
||||||
|
static std::string load_mistral_vocab_json();
|
||||||
static std::string load_t5_tokenizer_json();
|
static std::string load_t5_tokenizer_json();
|
||||||
static std::string load_umt5_tokenizer_json();
|
static std::string load_umt5_tokenizer_json();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -127,12 +127,14 @@ std::string convert_cond_stage_model_name(std::string name, std::string prefix)
|
|||||||
{"token_embd.", "shared."},
|
{"token_embd.", "shared."},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::vector<std::pair<std::string, std::string>> qwenvl_name_map{
|
static const std::vector<std::pair<std::string, std::string>> llm_name_map{
|
||||||
{"token_embd.", "model.embed_tokens."},
|
{"token_embd.", "model.embed_tokens."},
|
||||||
{"blk.", "model.layers."},
|
{"blk.", "model.layers."},
|
||||||
{"attn_q.", "self_attn.q_proj."},
|
{"attn_q.", "self_attn.q_proj."},
|
||||||
{"attn_k.", "self_attn.k_proj."},
|
{"attn_k.", "self_attn.k_proj."},
|
||||||
{"attn_v.", "self_attn.v_proj."},
|
{"attn_v.", "self_attn.v_proj."},
|
||||||
|
{"attn_q_norm.", "self_attn.q_norm."},
|
||||||
|
{"attn_k_norm.", "self_attn.k_norm."},
|
||||||
{"attn_output.", "self_attn.o_proj."},
|
{"attn_output.", "self_attn.o_proj."},
|
||||||
{"attn_norm.", "input_layernorm."},
|
{"attn_norm.", "input_layernorm."},
|
||||||
{"ffn_down.", "mlp.down_proj."},
|
{"ffn_down.", "mlp.down_proj."},
|
||||||
@ -142,7 +144,7 @@ std::string convert_cond_stage_model_name(std::string name, std::string prefix)
|
|||||||
{"output_norm.", "model.norm."},
|
{"output_norm.", "model.norm."},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::vector<std::pair<std::string, std::string>> qwenvl_vision_name_map{
|
static const std::vector<std::pair<std::string, std::string>> llm_vision_name_map{
|
||||||
{"mm.", "merger.mlp."},
|
{"mm.", "merger.mlp."},
|
||||||
{"v.post_ln.", "merger.ln_q."},
|
{"v.post_ln.", "merger.ln_q."},
|
||||||
{"v.patch_embd.weight", "patch_embed.proj.0.weight"},
|
{"v.patch_embd.weight", "patch_embed.proj.0.weight"},
|
||||||
@ -161,11 +163,11 @@ std::string convert_cond_stage_model_name(std::string name, std::string prefix)
|
|||||||
};
|
};
|
||||||
if (contains(name, "t5xxl")) {
|
if (contains(name, "t5xxl")) {
|
||||||
replace_with_name_map(name, t5_name_map);
|
replace_with_name_map(name, t5_name_map);
|
||||||
} else if (contains(name, "qwen2vl")) {
|
} else if (contains(name, "llm")) {
|
||||||
if (contains(name, "qwen2vl.visual")) {
|
if (contains(name, "llm.visual")) {
|
||||||
replace_with_name_map(name, qwenvl_vision_name_map);
|
replace_with_name_map(name, llm_vision_name_map);
|
||||||
} else {
|
} else {
|
||||||
replace_with_name_map(name, qwenvl_name_map);
|
replace_with_name_map(name, llm_name_map);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
name = convert_open_clip_to_hf_clip_name(name);
|
name = convert_open_clip_to_hf_clip_name(name);
|
||||||
@ -613,6 +615,44 @@ std::string convert_diffusers_dit_to_original_flux(std::string name) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string convert_diffusers_dit_to_original_lumina2(std::string name) {
|
||||||
|
int num_layers = 30;
|
||||||
|
int num_refiner_layers = 2;
|
||||||
|
static std::unordered_map<std::string, std::string> z_image_name_map;
|
||||||
|
|
||||||
|
if (z_image_name_map.empty()) {
|
||||||
|
z_image_name_map["all_x_embedder.2-1."] = "x_embedder.";
|
||||||
|
z_image_name_map["all_final_layer.2-1."] = "final_layer.";
|
||||||
|
|
||||||
|
// --- transformer blocks ---
|
||||||
|
auto add_attention_map = [&](const std::string& prefix, int num) {
|
||||||
|
for (int i = 0; i < num; ++i) {
|
||||||
|
std::string block_prefix = prefix + std::to_string(i) + ".";
|
||||||
|
std::string dst_prefix = prefix + std::to_string(i) + ".";
|
||||||
|
|
||||||
|
z_image_name_map[block_prefix + "attention.norm_q."] = dst_prefix + "attention.q_norm.";
|
||||||
|
z_image_name_map[block_prefix + "attention.norm_k."] = dst_prefix + "attention.k_norm.";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_out.0."] = dst_prefix + "attention.out.";
|
||||||
|
|
||||||
|
z_image_name_map[block_prefix + "attention.to_q.weight"] = dst_prefix + "attention.qkv.weight";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_q.bias"] = dst_prefix + "attention.qkv.bias";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_k.weight"] = dst_prefix + "attention.qkv.weight.1";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_k.bias"] = dst_prefix + "attention.qkv.bias.1";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_v.weight"] = dst_prefix + "attention.qkv.weight.2";
|
||||||
|
z_image_name_map[block_prefix + "attention.to_v.bias"] = dst_prefix + "attention.qkv.bias.2";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
add_attention_map("noise_refiner.", num_refiner_layers);
|
||||||
|
add_attention_map("context_refiner.", num_refiner_layers);
|
||||||
|
add_attention_map("layers.", num_layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_with_prefix_map(name, z_image_name_map);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string convert_diffusion_model_name(std::string name, std::string prefix, SDVersion version) {
|
std::string convert_diffusion_model_name(std::string name, std::string prefix, SDVersion version) {
|
||||||
if (sd_version_is_sd1(version) || sd_version_is_sd2(version)) {
|
if (sd_version_is_sd1(version) || sd_version_is_sd2(version)) {
|
||||||
name = convert_diffusers_unet_to_original_sd1(name);
|
name = convert_diffusers_unet_to_original_sd1(name);
|
||||||
@ -620,8 +660,10 @@ std::string convert_diffusion_model_name(std::string name, std::string prefix, S
|
|||||||
name = convert_diffusers_unet_to_original_sdxl(name);
|
name = convert_diffusers_unet_to_original_sdxl(name);
|
||||||
} else if (sd_version_is_sd3(version)) {
|
} else if (sd_version_is_sd3(version)) {
|
||||||
name = convert_diffusers_dit_to_original_sd3(name);
|
name = convert_diffusers_dit_to_original_sd3(name);
|
||||||
} else if (sd_version_is_flux(version)) {
|
} else if (sd_version_is_flux(version) || sd_version_is_flux2(version)) {
|
||||||
name = convert_diffusers_dit_to_original_flux(name);
|
name = convert_diffusers_dit_to_original_flux(name);
|
||||||
|
} else if (sd_version_is_z_image(version)) {
|
||||||
|
name = convert_diffusers_dit_to_original_lumina2(name);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -722,6 +764,11 @@ std::string convert_diffusers_vae_to_original_sd1(std::string name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string convert_first_stage_model_name(std::string name, std::string prefix) {
|
std::string convert_first_stage_model_name(std::string name, std::string prefix) {
|
||||||
|
static std::unordered_map<std::string, std::string> vae_name_map = {
|
||||||
|
{"decoder.post_quant_conv.", "post_quant_conv."},
|
||||||
|
{"encoder.quant_conv.", "quant_conv."},
|
||||||
|
};
|
||||||
|
replace_with_prefix_map(name, vae_name_map);
|
||||||
name = convert_diffusers_vae_to_original_sd1(name);
|
name = convert_diffusers_vae_to_original_sd1(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|||||||
4
pmid.hpp
@ -548,7 +548,7 @@ public:
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* id_pixel_values,
|
struct ggml_tensor* id_pixel_values,
|
||||||
struct ggml_tensor* prompt_embeds,
|
struct ggml_tensor* prompt_embeds,
|
||||||
struct ggml_tensor* id_embeds,
|
struct ggml_tensor* id_embeds,
|
||||||
@ -561,7 +561,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// GGMLRunner::compute(get_graph, n_threads, updated_prompt_embeds);
|
// GGMLRunner::compute(get_graph, n_threads, updated_prompt_embeds);
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, updated_prompt_embeds, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, true, updated_prompt_embeds, output_ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -588,7 +588,7 @@ namespace Qwen {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
struct ggml_tensor* context,
|
struct ggml_tensor* context,
|
||||||
@ -603,7 +603,7 @@ namespace Qwen {
|
|||||||
return build_graph(x, timesteps, context, ref_latents, increase_ref_index);
|
return build_graph(x, timesteps, context, ref_latents, increase_ref_index);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
|
|||||||
116
rope.hpp
@ -72,15 +72,30 @@ namespace Rope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate IDs for image patches and text
|
// Generate IDs for image patches and text
|
||||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_txt_ids(int bs, int context_len) {
|
__STATIC_INLINE__ std::vector<std::vector<float>> gen_flux_txt_ids(int bs, int context_len, int axes_dim_num, std::set<int> arange_dims) {
|
||||||
return std::vector<std::vector<float>>(bs * context_len, std::vector<float>(3, 0.0));
|
auto txt_ids = std::vector<std::vector<float>>(bs * context_len, std::vector<float>(axes_dim_num, 0.0f));
|
||||||
|
for (int dim = 0; dim < axes_dim_num; dim++) {
|
||||||
|
if (arange_dims.find(dim) != arange_dims.end()) {
|
||||||
|
for (int i = 0; i < bs * context_len; i++) {
|
||||||
|
txt_ids[i][dim] = (i % context_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return txt_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_img_ids(int h, int w, int patch_size, int bs, int index = 0, int h_offset = 0, int w_offset = 0) {
|
__STATIC_INLINE__ std::vector<std::vector<float>> gen_flux_img_ids(int h,
|
||||||
|
int w,
|
||||||
|
int patch_size,
|
||||||
|
int bs,
|
||||||
|
int axes_dim_num,
|
||||||
|
int index = 0,
|
||||||
|
int h_offset = 0,
|
||||||
|
int w_offset = 0) {
|
||||||
int h_len = (h + (patch_size / 2)) / patch_size;
|
int h_len = (h + (patch_size / 2)) / patch_size;
|
||||||
int w_len = (w + (patch_size / 2)) / patch_size;
|
int w_len = (w + (patch_size / 2)) / patch_size;
|
||||||
|
|
||||||
std::vector<std::vector<float>> img_ids(h_len * w_len, std::vector<float>(3, 0.0));
|
std::vector<std::vector<float>> img_ids(h_len * w_len, std::vector<float>(axes_dim_num, 0.0));
|
||||||
|
|
||||||
std::vector<float> row_ids = linspace<float>(h_offset, h_len - 1 + h_offset, h_len);
|
std::vector<float> row_ids = linspace<float>(h_offset, h_len - 1 + h_offset, h_len);
|
||||||
std::vector<float> col_ids = linspace<float>(w_offset, w_len - 1 + w_offset, w_len);
|
std::vector<float> col_ids = linspace<float>(w_offset, w_len - 1 + w_offset, w_len);
|
||||||
@ -153,8 +168,10 @@ namespace Rope {
|
|||||||
|
|
||||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_refs_ids(int patch_size,
|
__STATIC_INLINE__ std::vector<std::vector<float>> gen_refs_ids(int patch_size,
|
||||||
int bs,
|
int bs,
|
||||||
|
int axes_dim_num,
|
||||||
const std::vector<ggml_tensor*>& ref_latents,
|
const std::vector<ggml_tensor*>& ref_latents,
|
||||||
bool increase_ref_index) {
|
bool increase_ref_index,
|
||||||
|
float ref_index_scale) {
|
||||||
std::vector<std::vector<float>> ids;
|
std::vector<std::vector<float>> ids;
|
||||||
uint64_t curr_h_offset = 0;
|
uint64_t curr_h_offset = 0;
|
||||||
uint64_t curr_w_offset = 0;
|
uint64_t curr_w_offset = 0;
|
||||||
@ -170,7 +187,14 @@ namespace Rope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref_ids = gen_img_ids(ref->ne[1], ref->ne[0], patch_size, bs, index, h_offset, w_offset);
|
auto ref_ids = gen_flux_img_ids(ref->ne[1],
|
||||||
|
ref->ne[0],
|
||||||
|
patch_size,
|
||||||
|
bs,
|
||||||
|
axes_dim_num,
|
||||||
|
static_cast<int>(index * ref_index_scale),
|
||||||
|
h_offset,
|
||||||
|
w_offset);
|
||||||
ids = concat_ids(ids, ref_ids, bs);
|
ids = concat_ids(ids, ref_ids, bs);
|
||||||
|
|
||||||
if (increase_ref_index) {
|
if (increase_ref_index) {
|
||||||
@ -187,15 +211,18 @@ namespace Rope {
|
|||||||
int w,
|
int w,
|
||||||
int patch_size,
|
int patch_size,
|
||||||
int bs,
|
int bs,
|
||||||
|
int axes_dim_num,
|
||||||
int context_len,
|
int context_len,
|
||||||
|
std::set<int> txt_arange_dims,
|
||||||
const std::vector<ggml_tensor*>& ref_latents,
|
const std::vector<ggml_tensor*>& ref_latents,
|
||||||
bool increase_ref_index) {
|
bool increase_ref_index,
|
||||||
auto txt_ids = gen_txt_ids(bs, context_len);
|
float ref_index_scale) {
|
||||||
auto img_ids = gen_img_ids(h, w, patch_size, bs);
|
auto txt_ids = gen_flux_txt_ids(bs, context_len, axes_dim_num, txt_arange_dims);
|
||||||
|
auto img_ids = gen_flux_img_ids(h, w, patch_size, bs, axes_dim_num);
|
||||||
|
|
||||||
auto ids = concat_ids(txt_ids, img_ids, bs);
|
auto ids = concat_ids(txt_ids, img_ids, bs);
|
||||||
if (ref_latents.size() > 0) {
|
if (ref_latents.size() > 0) {
|
||||||
auto refs_ids = gen_refs_ids(patch_size, bs, ref_latents, increase_ref_index);
|
auto refs_ids = gen_refs_ids(patch_size, bs, axes_dim_num, ref_latents, increase_ref_index, ref_index_scale);
|
||||||
ids = concat_ids(ids, refs_ids, bs);
|
ids = concat_ids(ids, refs_ids, bs);
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
@ -207,11 +234,22 @@ namespace Rope {
|
|||||||
int patch_size,
|
int patch_size,
|
||||||
int bs,
|
int bs,
|
||||||
int context_len,
|
int context_len,
|
||||||
|
std::set<int> txt_arange_dims,
|
||||||
const std::vector<ggml_tensor*>& ref_latents,
|
const std::vector<ggml_tensor*>& ref_latents,
|
||||||
bool increase_ref_index,
|
bool increase_ref_index,
|
||||||
|
float ref_index_scale,
|
||||||
int theta,
|
int theta,
|
||||||
const std::vector<int>& axes_dim) {
|
const std::vector<int>& axes_dim) {
|
||||||
std::vector<std::vector<float>> ids = gen_flux_ids(h, w, patch_size, bs, context_len, ref_latents, increase_ref_index);
|
std::vector<std::vector<float>> ids = gen_flux_ids(h,
|
||||||
|
w,
|
||||||
|
patch_size,
|
||||||
|
bs,
|
||||||
|
static_cast<int>(axes_dim.size()),
|
||||||
|
context_len,
|
||||||
|
txt_arange_dims,
|
||||||
|
ref_latents,
|
||||||
|
increase_ref_index,
|
||||||
|
ref_index_scale);
|
||||||
return embed_nd(ids, bs, theta, axes_dim);
|
return embed_nd(ids, bs, theta, axes_dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,10 +270,11 @@ namespace Rope {
|
|||||||
txt_ids_repeated[i * txt_ids.size() + j] = {txt_ids[j], txt_ids[j], txt_ids[j]};
|
txt_ids_repeated[i * txt_ids.size() + j] = {txt_ids[j], txt_ids[j], txt_ids[j]};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto img_ids = gen_img_ids(h, w, patch_size, bs);
|
int axes_dim_num = 3;
|
||||||
auto ids = concat_ids(txt_ids_repeated, img_ids, bs);
|
auto img_ids = gen_flux_img_ids(h, w, patch_size, bs, axes_dim_num);
|
||||||
|
auto ids = concat_ids(txt_ids_repeated, img_ids, bs);
|
||||||
if (ref_latents.size() > 0) {
|
if (ref_latents.size() > 0) {
|
||||||
auto refs_ids = gen_refs_ids(patch_size, bs, ref_latents, increase_ref_index);
|
auto refs_ids = gen_refs_ids(patch_size, bs, axes_dim_num, ref_latents, increase_ref_index, 1.f);
|
||||||
ids = concat_ids(ids, refs_ids, bs);
|
ids = concat_ids(ids, refs_ids, bs);
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
@ -345,6 +384,55 @@ namespace Rope {
|
|||||||
return embed_nd(ids, 1, theta, axes_dim);
|
return embed_nd(ids, 1, theta, axes_dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__STATIC_INLINE__ int bound_mod(int a, int m) {
|
||||||
|
return (m - (a % m)) % m;
|
||||||
|
}
|
||||||
|
|
||||||
|
__STATIC_INLINE__ std::vector<std::vector<float>> gen_z_image_ids(int h,
|
||||||
|
int w,
|
||||||
|
int patch_size,
|
||||||
|
int bs,
|
||||||
|
int context_len,
|
||||||
|
int seq_multi_of,
|
||||||
|
const std::vector<ggml_tensor*>& ref_latents,
|
||||||
|
bool increase_ref_index) {
|
||||||
|
int padded_context_len = context_len + bound_mod(context_len, seq_multi_of);
|
||||||
|
auto txt_ids = std::vector<std::vector<float>>(bs * padded_context_len, std::vector<float>(3, 0.0f));
|
||||||
|
for (int i = 0; i < bs * padded_context_len; i++) {
|
||||||
|
txt_ids[i][0] = (i % padded_context_len) + 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int axes_dim_num = 3;
|
||||||
|
int index = padded_context_len + 1;
|
||||||
|
auto img_ids = gen_flux_img_ids(h, w, patch_size, bs, axes_dim_num, index);
|
||||||
|
|
||||||
|
int img_pad_len = bound_mod(static_cast<int>(img_ids.size() / bs), seq_multi_of);
|
||||||
|
if (img_pad_len > 0) {
|
||||||
|
std::vector<std::vector<float>> img_pad_ids(bs * img_pad_len, std::vector<float>(3, 0.f));
|
||||||
|
img_ids = concat_ids(img_ids, img_pad_ids, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ids = concat_ids(txt_ids, img_ids, bs);
|
||||||
|
|
||||||
|
// ignore ref_latents for now
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate z_image positional embeddings
|
||||||
|
__STATIC_INLINE__ std::vector<float> gen_z_image_pe(int h,
|
||||||
|
int w,
|
||||||
|
int patch_size,
|
||||||
|
int bs,
|
||||||
|
int context_len,
|
||||||
|
int seq_multi_of,
|
||||||
|
const std::vector<ggml_tensor*>& ref_latents,
|
||||||
|
bool increase_ref_index,
|
||||||
|
int theta,
|
||||||
|
const std::vector<int>& axes_dim) {
|
||||||
|
std::vector<std::vector<float>> ids = gen_z_image_ids(h, w, patch_size, bs, context_len, seq_multi_of, ref_latents, increase_ref_index);
|
||||||
|
return embed_nd(ids, bs, theta, axes_dim);
|
||||||
|
}
|
||||||
|
|
||||||
__STATIC_INLINE__ struct ggml_tensor* apply_rope(struct ggml_context* ctx,
|
__STATIC_INLINE__ struct ggml_tensor* apply_rope(struct ggml_context* ctx,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* pe,
|
struct ggml_tensor* pe,
|
||||||
|
|||||||
@ -36,42 +36,41 @@ enum rng_type_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum sample_method_t {
|
enum sample_method_t {
|
||||||
SAMPLE_METHOD_DEFAULT,
|
EULER_SAMPLE_METHOD,
|
||||||
EULER,
|
EULER_A_SAMPLE_METHOD,
|
||||||
HEUN,
|
HEUN_SAMPLE_METHOD,
|
||||||
DPM2,
|
DPM2_SAMPLE_METHOD,
|
||||||
DPMPP2S_A,
|
DPMPP2S_A_SAMPLE_METHOD,
|
||||||
DPMPP2M,
|
DPMPP2M_SAMPLE_METHOD,
|
||||||
DPMPP2Mv2,
|
DPMPP2Mv2_SAMPLE_METHOD,
|
||||||
IPNDM,
|
IPNDM_SAMPLE_METHOD,
|
||||||
IPNDM_V,
|
IPNDM_V_SAMPLE_METHOD,
|
||||||
LCM,
|
LCM_SAMPLE_METHOD,
|
||||||
DDIM_TRAILING,
|
DDIM_TRAILING_SAMPLE_METHOD,
|
||||||
TCD,
|
TCD_SAMPLE_METHOD,
|
||||||
EULER_A,
|
|
||||||
SAMPLE_METHOD_COUNT
|
SAMPLE_METHOD_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scheduler_t {
|
enum scheduler_t {
|
||||||
DEFAULT,
|
DISCRETE_SCHEDULER,
|
||||||
DISCRETE,
|
KARRAS_SCHEDULER,
|
||||||
KARRAS,
|
EXPONENTIAL_SCHEDULER,
|
||||||
EXPONENTIAL,
|
AYS_SCHEDULER,
|
||||||
AYS,
|
GITS_SCHEDULER,
|
||||||
GITS,
|
SGM_UNIFORM_SCHEDULER,
|
||||||
SGM_UNIFORM,
|
SIMPLE_SCHEDULER,
|
||||||
SIMPLE,
|
SMOOTHSTEP_SCHEDULER,
|
||||||
SMOOTHSTEP,
|
LCM_SCHEDULER,
|
||||||
SCHEDULE_COUNT
|
SCHEDULER_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum prediction_t {
|
enum prediction_t {
|
||||||
DEFAULT_PRED,
|
|
||||||
EPS_PRED,
|
EPS_PRED,
|
||||||
V_PRED,
|
V_PRED,
|
||||||
EDM_V_PRED,
|
EDM_V_PRED,
|
||||||
SD3_FLOW_PRED,
|
FLOW_PRED,
|
||||||
FLUX_FLOW_PRED,
|
FLUX_FLOW_PRED,
|
||||||
|
FLUX2_FLOW_PRED,
|
||||||
PREDICTION_COUNT
|
PREDICTION_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -151,21 +150,27 @@ typedef struct {
|
|||||||
float rel_size_y;
|
float rel_size_y;
|
||||||
} sd_tiling_params_t;
|
} sd_tiling_params_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
const char* path;
|
||||||
|
} sd_embedding_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* model_path;
|
const char* model_path;
|
||||||
const char* clip_l_path;
|
const char* clip_l_path;
|
||||||
const char* clip_g_path;
|
const char* clip_g_path;
|
||||||
const char* clip_vision_path;
|
const char* clip_vision_path;
|
||||||
const char* t5xxl_path;
|
const char* t5xxl_path;
|
||||||
const char* qwen2vl_path;
|
const char* llm_path;
|
||||||
const char* qwen2vl_vision_path;
|
const char* llm_vision_path;
|
||||||
const char* diffusion_model_path;
|
const char* diffusion_model_path;
|
||||||
const char* high_noise_diffusion_model_path;
|
const char* high_noise_diffusion_model_path;
|
||||||
const char* vae_path;
|
const char* vae_path;
|
||||||
const char* taesd_path;
|
const char* taesd_path;
|
||||||
const char* control_net_path;
|
const char* control_net_path;
|
||||||
const char* lora_model_dir;
|
const char* lora_model_dir;
|
||||||
const char* embedding_dir;
|
const sd_embedding_t* embeddings;
|
||||||
|
uint32_t embedding_count;
|
||||||
const char* photo_maker_path;
|
const char* photo_maker_path;
|
||||||
const char* tensor_type_rules;
|
const char* tensor_type_rules;
|
||||||
bool vae_decode_only;
|
bool vae_decode_only;
|
||||||
@ -237,6 +242,14 @@ typedef struct {
|
|||||||
} sd_easycache_params_t;
|
} sd_easycache_params_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool is_high_noise;
|
||||||
|
float multiplier;
|
||||||
|
const char* path;
|
||||||
|
} sd_lora_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const sd_lora_t* loras;
|
||||||
|
uint32_t lora_count;
|
||||||
const char* prompt;
|
const char* prompt;
|
||||||
const char* negative_prompt;
|
const char* negative_prompt;
|
||||||
int clip_skip;
|
int clip_skip;
|
||||||
@ -260,6 +273,8 @@ typedef struct {
|
|||||||
} sd_img_gen_params_t;
|
} sd_img_gen_params_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
const sd_lora_t* loras;
|
||||||
|
uint32_t lora_count;
|
||||||
const char* prompt;
|
const char* prompt;
|
||||||
const char* negative_prompt;
|
const char* negative_prompt;
|
||||||
int clip_skip;
|
int clip_skip;
|
||||||
@ -283,12 +298,12 @@ typedef struct sd_ctx_t sd_ctx_t;
|
|||||||
|
|
||||||
typedef void (*sd_log_cb_t)(enum sd_log_level_t level, const char* text, void* data);
|
typedef void (*sd_log_cb_t)(enum sd_log_level_t level, const char* text, void* data);
|
||||||
typedef void (*sd_progress_cb_t)(int step, int steps, float time, void* data);
|
typedef void (*sd_progress_cb_t)(int step, int steps, float time, void* data);
|
||||||
typedef void (*sd_preview_cb_t)(int step, int frame_count, sd_image_t* frames, bool is_noisy);
|
typedef void (*sd_preview_cb_t)(int step, int frame_count, sd_image_t* frames, bool is_noisy, void* data);
|
||||||
|
|
||||||
SD_API void sd_set_log_callback(sd_log_cb_t sd_log_cb, void* data);
|
SD_API void sd_set_log_callback(sd_log_cb_t sd_log_cb, void* data);
|
||||||
SD_API void sd_set_progress_callback(sd_progress_cb_t cb, void* data);
|
SD_API void sd_set_progress_callback(sd_progress_cb_t cb, void* data);
|
||||||
SD_API void sd_set_preview_callback(sd_preview_cb_t cb, enum preview_t mode, int interval, bool denoised, bool noisy);
|
SD_API void sd_set_preview_callback(sd_preview_cb_t cb, enum preview_t mode, int interval, bool denoised, bool noisy, void* data);
|
||||||
SD_API int32_t get_num_physical_cores();
|
SD_API int32_t sd_get_num_physical_cores();
|
||||||
SD_API const char* sd_get_system_info();
|
SD_API const char* sd_get_system_info();
|
||||||
|
|
||||||
SD_API const char* sd_type_name(enum sd_type_t type);
|
SD_API const char* sd_type_name(enum sd_type_t type);
|
||||||
@ -297,8 +312,8 @@ SD_API const char* sd_rng_type_name(enum rng_type_t rng_type);
|
|||||||
SD_API enum rng_type_t str_to_rng_type(const char* str);
|
SD_API enum rng_type_t str_to_rng_type(const char* str);
|
||||||
SD_API const char* sd_sample_method_name(enum sample_method_t sample_method);
|
SD_API const char* sd_sample_method_name(enum sample_method_t sample_method);
|
||||||
SD_API enum sample_method_t str_to_sample_method(const char* str);
|
SD_API enum sample_method_t str_to_sample_method(const char* str);
|
||||||
SD_API const char* sd_schedule_name(enum scheduler_t scheduler);
|
SD_API const char* sd_scheduler_name(enum scheduler_t scheduler);
|
||||||
SD_API enum scheduler_t str_to_schedule(const char* str);
|
SD_API enum scheduler_t str_to_scheduler(const char* str);
|
||||||
SD_API const char* sd_prediction_name(enum prediction_t prediction);
|
SD_API const char* sd_prediction_name(enum prediction_t prediction);
|
||||||
SD_API enum prediction_t str_to_prediction(const char* str);
|
SD_API enum prediction_t str_to_prediction(const char* str);
|
||||||
SD_API const char* sd_preview_name(enum preview_t preview);
|
SD_API const char* sd_preview_name(enum preview_t preview);
|
||||||
@ -313,11 +328,13 @@ SD_API char* sd_ctx_params_to_str(const sd_ctx_params_t* sd_ctx_params);
|
|||||||
|
|
||||||
SD_API sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params);
|
SD_API sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params);
|
||||||
SD_API void free_sd_ctx(sd_ctx_t* sd_ctx);
|
SD_API void free_sd_ctx(sd_ctx_t* sd_ctx);
|
||||||
SD_API enum sample_method_t sd_get_default_sample_method(const sd_ctx_t* sd_ctx);
|
|
||||||
|
|
||||||
SD_API void sd_sample_params_init(sd_sample_params_t* sample_params);
|
SD_API void sd_sample_params_init(sd_sample_params_t* sample_params);
|
||||||
SD_API char* sd_sample_params_to_str(const sd_sample_params_t* sample_params);
|
SD_API char* sd_sample_params_to_str(const sd_sample_params_t* sample_params);
|
||||||
|
|
||||||
|
SD_API enum sample_method_t sd_get_default_sample_method(const sd_ctx_t* sd_ctx);
|
||||||
|
SD_API enum scheduler_t sd_get_default_scheduler(const sd_ctx_t* sd_ctx);
|
||||||
|
|
||||||
SD_API void sd_img_gen_params_init(sd_img_gen_params_t* sd_img_gen_params);
|
SD_API void sd_img_gen_params_init(sd_img_gen_params_t* sd_img_gen_params);
|
||||||
SD_API char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params);
|
SD_API char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params);
|
||||||
SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* sd_img_gen_params);
|
SD_API sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* sd_img_gen_params);
|
||||||
@ -330,7 +347,8 @@ typedef struct upscaler_ctx_t upscaler_ctx_t;
|
|||||||
SD_API upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path,
|
SD_API upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
bool direct,
|
bool direct,
|
||||||
int n_threads);
|
int n_threads,
|
||||||
|
int tile_size);
|
||||||
SD_API void free_upscaler_ctx(upscaler_ctx_t* upscaler_ctx);
|
SD_API void free_upscaler_ctx(upscaler_ctx_t* upscaler_ctx);
|
||||||
|
|
||||||
SD_API sd_image_t upscale(upscaler_ctx_t* upscaler_ctx,
|
SD_API sd_image_t upscale(upscaler_ctx_t* upscaler_ctx,
|
||||||
@ -352,6 +370,9 @@ SD_API bool preprocess_canny(sd_image_t image,
|
|||||||
float strong,
|
float strong,
|
||||||
bool inverse);
|
bool inverse);
|
||||||
|
|
||||||
|
SD_API const char* sd_commit(void);
|
||||||
|
SD_API const char* sd_version(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
4
t5.hpp
@ -820,7 +820,7 @@ struct T5Runner : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* input_ids,
|
struct ggml_tensor* input_ids,
|
||||||
struct ggml_tensor* attention_mask,
|
struct ggml_tensor* attention_mask,
|
||||||
ggml_tensor** output,
|
ggml_tensor** output,
|
||||||
@ -828,7 +828,7 @@ struct T5Runner : public GGMLRunner {
|
|||||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
return build_graph(input_ids, attention_mask);
|
return build_graph(input_ids, attention_mask);
|
||||||
};
|
};
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<int> _relative_position_bucket(const std::vector<int>& relative_position,
|
static std::vector<int> _relative_position_bucket(const std::vector<int>& relative_position,
|
||||||
|
|||||||
4
tae.hpp
@ -247,7 +247,7 @@ struct TinyAutoEncoder : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* z,
|
struct ggml_tensor* z,
|
||||||
bool decode_graph,
|
bool decode_graph,
|
||||||
struct ggml_tensor** output,
|
struct ggml_tensor** output,
|
||||||
@ -256,7 +256,7 @@ struct TinyAutoEncoder : public GGMLRunner {
|
|||||||
return build_graph(z, decode_graph);
|
return build_graph(z, decode_graph);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -811,6 +811,8 @@ bool starts_with(const std::vector<char32_t>& text,
|
|||||||
return std::equal(prefix.begin(), prefix.end(), text.begin() + index);
|
return std::equal(prefix.begin(), prefix.end(), text.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mistral: [^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]*[\p{Ll}\p{Lm}\p{Lo}\p{M}]+|[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]+[\p{Ll}\p{Lm}\p{Lo}\p{M}]*|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n/]*|\s*[\r\n]+|\s+(?!\S)|\s+
|
||||||
|
// qwen2: (?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+
|
||||||
std::vector<std::string> token_split(const std::string& text) {
|
std::vector<std::string> token_split(const std::string& text) {
|
||||||
std::vector<std::string> tokens;
|
std::vector<std::string> tokens;
|
||||||
auto cps = utf8_to_codepoints(text);
|
auto cps = utf8_to_codepoints(text);
|
||||||
|
|||||||
4
unet.hpp
@ -645,7 +645,7 @@ struct UNetModelRunner : public GGMLRunner {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
struct ggml_tensor* context,
|
struct ggml_tensor* context,
|
||||||
@ -665,7 +665,7 @@ struct UNetModelRunner : public GGMLRunner {
|
|||||||
return build_graph(x, timesteps, context, c_concat, y, num_video_frames, controls, control_strength);
|
return build_graph(x, timesteps, context, c_concat, y, num_video_frames, controls, control_strength);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
|
|||||||
16
upscaler.cpp
@ -9,12 +9,15 @@ struct UpscalerGGML {
|
|||||||
std::shared_ptr<ESRGAN> esrgan_upscaler;
|
std::shared_ptr<ESRGAN> esrgan_upscaler;
|
||||||
std::string esrgan_path;
|
std::string esrgan_path;
|
||||||
int n_threads;
|
int n_threads;
|
||||||
bool direct = false;
|
bool direct = false;
|
||||||
|
int tile_size = 128;
|
||||||
|
|
||||||
UpscalerGGML(int n_threads,
|
UpscalerGGML(int n_threads,
|
||||||
bool direct = false)
|
bool direct = false,
|
||||||
|
int tile_size = 128)
|
||||||
: n_threads(n_threads),
|
: n_threads(n_threads),
|
||||||
direct(direct) {
|
direct(direct),
|
||||||
|
tile_size(tile_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_from_file(const std::string& esrgan_path,
|
bool load_from_file(const std::string& esrgan_path,
|
||||||
@ -51,7 +54,7 @@ struct UpscalerGGML {
|
|||||||
backend = ggml_backend_cpu_init();
|
backend = ggml_backend_cpu_init();
|
||||||
}
|
}
|
||||||
LOG_INFO("Upscaler weight type: %s", ggml_type_name(model_data_type));
|
LOG_INFO("Upscaler weight type: %s", ggml_type_name(model_data_type));
|
||||||
esrgan_upscaler = std::make_shared<ESRGAN>(backend, offload_params_to_cpu, model_loader.get_tensor_storage_map());
|
esrgan_upscaler = std::make_shared<ESRGAN>(backend, offload_params_to_cpu, tile_size, model_loader.get_tensor_storage_map());
|
||||||
if (direct) {
|
if (direct) {
|
||||||
esrgan_upscaler->set_conv2d_direct_enabled(true);
|
esrgan_upscaler->set_conv2d_direct_enabled(true);
|
||||||
}
|
}
|
||||||
@ -113,14 +116,15 @@ struct upscaler_ctx_t {
|
|||||||
upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path_c_str,
|
upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path_c_str,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
bool direct,
|
bool direct,
|
||||||
int n_threads) {
|
int n_threads,
|
||||||
|
int tile_size) {
|
||||||
upscaler_ctx_t* upscaler_ctx = (upscaler_ctx_t*)malloc(sizeof(upscaler_ctx_t));
|
upscaler_ctx_t* upscaler_ctx = (upscaler_ctx_t*)malloc(sizeof(upscaler_ctx_t));
|
||||||
if (upscaler_ctx == nullptr) {
|
if (upscaler_ctx == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::string esrgan_path(esrgan_path_c_str);
|
std::string esrgan_path(esrgan_path_c_str);
|
||||||
|
|
||||||
upscaler_ctx->upscaler = new UpscalerGGML(n_threads, direct);
|
upscaler_ctx->upscaler = new UpscalerGGML(n_threads, direct, tile_size);
|
||||||
if (upscaler_ctx->upscaler == nullptr) {
|
if (upscaler_ctx->upscaler == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
86
util.cpp
@ -57,7 +57,7 @@ void replace_all_chars(std::string& str, char target, char replacement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string format(const char* fmt, ...) {
|
std::string sd_format(const char* fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_list ap2;
|
va_list ap2;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
@ -95,20 +95,6 @@ bool is_directory(const std::string& path) {
|
|||||||
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
|
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_full_path(const std::string& dir, const std::string& filename) {
|
|
||||||
std::string full_path = dir + "\\" + filename;
|
|
||||||
|
|
||||||
WIN32_FIND_DATA find_file_data;
|
|
||||||
HANDLE hFind = FindFirstFile(full_path.c_str(), &find_file_data);
|
|
||||||
|
|
||||||
if (hFind != INVALID_HANDLE_VALUE) {
|
|
||||||
FindClose(hFind);
|
|
||||||
return full_path;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // Unix
|
#else // Unix
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -123,32 +109,12 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add windows version
|
|
||||||
std::string get_full_path(const std::string& dir, const std::string& filename) {
|
|
||||||
DIR* dp = opendir(dir.c_str());
|
|
||||||
|
|
||||||
if (dp != nullptr) {
|
|
||||||
struct dirent* entry;
|
|
||||||
|
|
||||||
while ((entry = readdir(dp)) != nullptr) {
|
|
||||||
if (strcasecmp(entry->d_name, filename.c_str()) == 0) {
|
|
||||||
closedir(dp);
|
|
||||||
return dir + "/" + entry->d_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// get_num_physical_cores is copy from
|
// get_num_physical_cores is copy from
|
||||||
// https://github.com/ggerganov/llama.cpp/blob/master/examples/common.cpp
|
// https://github.com/ggerganov/llama.cpp/blob/master/examples/common.cpp
|
||||||
// LICENSE: https://github.com/ggerganov/llama.cpp/blob/master/LICENSE
|
// LICENSE: https://github.com/ggerganov/llama.cpp/blob/master/LICENSE
|
||||||
int32_t get_num_physical_cores() {
|
int32_t sd_get_num_physical_cores() {
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// enumerate the set of thread siblings, num entries is num cores
|
// enumerate the set of thread siblings, num entries is num cores
|
||||||
std::unordered_set<std::string> siblings;
|
std::unordered_set<std::string> siblings;
|
||||||
@ -187,6 +153,7 @@ static sd_progress_cb_t sd_progress_cb = nullptr;
|
|||||||
void* sd_progress_cb_data = nullptr;
|
void* sd_progress_cb_data = nullptr;
|
||||||
|
|
||||||
static sd_preview_cb_t sd_preview_cb = nullptr;
|
static sd_preview_cb_t sd_preview_cb = nullptr;
|
||||||
|
static void* sd_preview_cb_data = nullptr;
|
||||||
preview_t sd_preview_mode = PREVIEW_NONE;
|
preview_t sd_preview_mode = PREVIEW_NONE;
|
||||||
int sd_preview_interval = 1;
|
int sd_preview_interval = 1;
|
||||||
bool sd_preview_denoised = true;
|
bool sd_preview_denoised = true;
|
||||||
@ -273,13 +240,16 @@ void pretty_progress(int step, int steps, float time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
progress += "|";
|
progress += "|";
|
||||||
printf(time > 1.0f ? "\r%s %i/%i - %.2fs/it" : "\r%s %i/%i - %.2fit/s\033[K",
|
|
||||||
progress.c_str(), step, steps,
|
const char* lf = (step == steps ? "\n" : "");
|
||||||
time > 1.0f || time == 0 ? time : (1.0f / time));
|
const char* unit = "s/it";
|
||||||
fflush(stdout); // for linux
|
float speed = time;
|
||||||
if (step == steps) {
|
if (speed < 1.0f && speed > 0.f) {
|
||||||
printf("\n");
|
speed = 1.0f / speed;
|
||||||
|
unit = "it/s";
|
||||||
}
|
}
|
||||||
|
printf("\r%s %i/%i - %.2f%s\033[K%s", progress.c_str(), step, steps, speed, unit, lf);
|
||||||
|
fflush(stdout); // for linux
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ltrim(const std::string& s) {
|
std::string ltrim(const std::string& s) {
|
||||||
@ -335,8 +305,9 @@ void sd_set_progress_callback(sd_progress_cb_t cb, void* data) {
|
|||||||
sd_progress_cb = cb;
|
sd_progress_cb = cb;
|
||||||
sd_progress_cb_data = data;
|
sd_progress_cb_data = data;
|
||||||
}
|
}
|
||||||
void sd_set_preview_callback(sd_preview_cb_t cb, preview_t mode = PREVIEW_PROJ, int interval = 1, bool denoised = true, bool noisy = false) {
|
void sd_set_preview_callback(sd_preview_cb_t cb, preview_t mode, int interval, bool denoised, bool noisy, void* data) {
|
||||||
sd_preview_cb = cb;
|
sd_preview_cb = cb;
|
||||||
|
sd_preview_cb_data = data;
|
||||||
sd_preview_mode = mode;
|
sd_preview_mode = mode;
|
||||||
sd_preview_interval = interval;
|
sd_preview_interval = interval;
|
||||||
sd_preview_denoised = denoised;
|
sd_preview_denoised = denoised;
|
||||||
@ -346,6 +317,9 @@ void sd_set_preview_callback(sd_preview_cb_t cb, preview_t mode = PREVIEW_PROJ,
|
|||||||
sd_preview_cb_t sd_get_preview_callback() {
|
sd_preview_cb_t sd_get_preview_callback() {
|
||||||
return sd_preview_cb;
|
return sd_preview_cb;
|
||||||
}
|
}
|
||||||
|
void* sd_get_preview_callback_data() {
|
||||||
|
return sd_preview_cb_data;
|
||||||
|
}
|
||||||
|
|
||||||
preview_t sd_get_preview_mode() {
|
preview_t sd_get_preview_mode() {
|
||||||
return sd_preview_mode;
|
return sd_preview_mode;
|
||||||
@ -370,19 +344,19 @@ const char* sd_get_system_info() {
|
|||||||
static char buffer[1024];
|
static char buffer[1024];
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "System Info: \n";
|
ss << "System Info: \n";
|
||||||
ss << " SSE3 = " << ggml_cpu_has_sse3() << std::endl;
|
ss << " SSE3 = " << ggml_cpu_has_sse3() << " | ";
|
||||||
ss << " AVX = " << ggml_cpu_has_avx() << std::endl;
|
ss << " AVX = " << ggml_cpu_has_avx() << " | ";
|
||||||
ss << " AVX2 = " << ggml_cpu_has_avx2() << std::endl;
|
ss << " AVX2 = " << ggml_cpu_has_avx2() << " | ";
|
||||||
ss << " AVX512 = " << ggml_cpu_has_avx512() << std::endl;
|
ss << " AVX512 = " << ggml_cpu_has_avx512() << " | ";
|
||||||
ss << " AVX512_VBMI = " << ggml_cpu_has_avx512_vbmi() << std::endl;
|
ss << " AVX512_VBMI = " << ggml_cpu_has_avx512_vbmi() << " | ";
|
||||||
ss << " AVX512_VNNI = " << ggml_cpu_has_avx512_vnni() << std::endl;
|
ss << " AVX512_VNNI = " << ggml_cpu_has_avx512_vnni() << " | ";
|
||||||
ss << " FMA = " << ggml_cpu_has_fma() << std::endl;
|
ss << " FMA = " << ggml_cpu_has_fma() << " | ";
|
||||||
ss << " NEON = " << ggml_cpu_has_neon() << std::endl;
|
ss << " NEON = " << ggml_cpu_has_neon() << " | ";
|
||||||
ss << " ARM_FMA = " << ggml_cpu_has_arm_fma() << std::endl;
|
ss << " ARM_FMA = " << ggml_cpu_has_arm_fma() << " | ";
|
||||||
ss << " F16C = " << ggml_cpu_has_f16c() << std::endl;
|
ss << " F16C = " << ggml_cpu_has_f16c() << " | ";
|
||||||
ss << " FP16_VA = " << ggml_cpu_has_fp16_va() << std::endl;
|
ss << " FP16_VA = " << ggml_cpu_has_fp16_va() << " | ";
|
||||||
ss << " WASM_SIMD = " << ggml_cpu_has_wasm_simd() << std::endl;
|
ss << " WASM_SIMD = " << ggml_cpu_has_wasm_simd() << " | ";
|
||||||
ss << " VSX = " << ggml_cpu_has_vsx() << std::endl;
|
ss << " VSX = " << ggml_cpu_has_vsx() << " | ";
|
||||||
snprintf(buffer, sizeof(buffer), "%s", ss.str().c_str());
|
snprintf(buffer, sizeof(buffer), "%s", ss.str().c_str());
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
4
util.h
@ -14,7 +14,7 @@ bool ends_with(const std::string& str, const std::string& ending);
|
|||||||
bool starts_with(const std::string& str, const std::string& start);
|
bool starts_with(const std::string& str, const std::string& start);
|
||||||
bool contains(const std::string& str, const std::string& substr);
|
bool contains(const std::string& str, const std::string& substr);
|
||||||
|
|
||||||
std::string format(const char* fmt, ...);
|
std::string sd_format(const char* fmt, ...);
|
||||||
|
|
||||||
void replace_all_chars(std::string& str, char target, char replacement);
|
void replace_all_chars(std::string& str, char target, char replacement);
|
||||||
|
|
||||||
@ -22,7 +22,6 @@ int round_up_to(int value, int base);
|
|||||||
|
|
||||||
bool file_exists(const std::string& filename);
|
bool file_exists(const std::string& filename);
|
||||||
bool is_directory(const std::string& path);
|
bool is_directory(const std::string& path);
|
||||||
std::string get_full_path(const std::string& dir, const std::string& filename);
|
|
||||||
|
|
||||||
std::u32string utf8_to_utf32(const std::string& utf8_str);
|
std::u32string utf8_to_utf32(const std::string& utf8_str);
|
||||||
std::string utf32_to_utf8(const std::u32string& utf32_str);
|
std::string utf32_to_utf8(const std::u32string& utf32_str);
|
||||||
@ -58,6 +57,7 @@ sd_progress_cb_t sd_get_progress_callback();
|
|||||||
void* sd_get_progress_callback_data();
|
void* sd_get_progress_callback_data();
|
||||||
|
|
||||||
sd_preview_cb_t sd_get_preview_callback();
|
sd_preview_cb_t sd_get_preview_callback();
|
||||||
|
void* sd_get_preview_callback_data();
|
||||||
preview_t sd_get_preview_mode();
|
preview_t sd_get_preview_mode();
|
||||||
int sd_get_preview_interval();
|
int sd_get_preview_interval();
|
||||||
bool sd_should_preview_denoised();
|
bool sd_should_preview_denoised();
|
||||||
|
|||||||
63
vae.hpp
@ -487,6 +487,7 @@ public:
|
|||||||
// ldm.models.autoencoder.AutoencoderKL
|
// ldm.models.autoencoder.AutoencoderKL
|
||||||
class AutoencodingEngine : public GGMLBlock {
|
class AutoencodingEngine : public GGMLBlock {
|
||||||
protected:
|
protected:
|
||||||
|
SDVersion version;
|
||||||
bool decode_only = true;
|
bool decode_only = true;
|
||||||
bool use_video_decoder = false;
|
bool use_video_decoder = false;
|
||||||
bool use_quant = true;
|
bool use_quant = true;
|
||||||
@ -507,10 +508,15 @@ public:
|
|||||||
bool decode_only = true,
|
bool decode_only = true,
|
||||||
bool use_linear_projection = false,
|
bool use_linear_projection = false,
|
||||||
bool use_video_decoder = false)
|
bool use_video_decoder = false)
|
||||||
: decode_only(decode_only), use_video_decoder(use_video_decoder) {
|
: version(version), decode_only(decode_only), use_video_decoder(use_video_decoder) {
|
||||||
if (sd_version_is_dit(version)) {
|
if (sd_version_is_dit(version)) {
|
||||||
dd_config.z_channels = 16;
|
if (sd_version_is_flux2(version)) {
|
||||||
use_quant = false;
|
dd_config.z_channels = 32;
|
||||||
|
embed_dim = 32;
|
||||||
|
} else {
|
||||||
|
use_quant = false;
|
||||||
|
dd_config.z_channels = 16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (use_video_decoder) {
|
if (use_video_decoder) {
|
||||||
use_quant = false;
|
use_quant = false;
|
||||||
@ -547,6 +553,24 @@ public:
|
|||||||
|
|
||||||
struct ggml_tensor* decode(GGMLRunnerContext* ctx, struct ggml_tensor* z) {
|
struct ggml_tensor* decode(GGMLRunnerContext* ctx, struct ggml_tensor* z) {
|
||||||
// z: [N, z_channels, h, w]
|
// z: [N, z_channels, h, w]
|
||||||
|
if (sd_version_is_flux2(version)) {
|
||||||
|
// [N, C*p*p, h, w] -> [N, C, h*p, w*p]
|
||||||
|
int64_t p = 2;
|
||||||
|
|
||||||
|
int64_t N = z->ne[3];
|
||||||
|
int64_t C = z->ne[2] / p / p;
|
||||||
|
int64_t h = z->ne[1];
|
||||||
|
int64_t w = z->ne[0];
|
||||||
|
int64_t H = h * p;
|
||||||
|
int64_t W = w * p;
|
||||||
|
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, w * h, p * p, C, N); // [N, C, p*p, h*w]
|
||||||
|
z = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, z, 1, 0, 2, 3)); // [N, C, h*w, p*p]
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, p, p, w, h * C * N); // [N*C*h, w, p, p]
|
||||||
|
z = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, z, 0, 2, 1, 3)); // [N*C*h, p, w, p]
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, W, H, C, N); // [N, C, h*p, w*p]
|
||||||
|
}
|
||||||
|
|
||||||
if (use_quant) {
|
if (use_quant) {
|
||||||
auto post_quant_conv = std::dynamic_pointer_cast<Conv2d>(blocks["post_quant_conv"]);
|
auto post_quant_conv = std::dynamic_pointer_cast<Conv2d>(blocks["post_quant_conv"]);
|
||||||
z = post_quant_conv->forward(ctx, z); // [N, z_channels, h, w]
|
z = post_quant_conv->forward(ctx, z); // [N, z_channels, h, w]
|
||||||
@ -563,19 +587,37 @@ public:
|
|||||||
// x: [N, in_channels, h, w]
|
// x: [N, in_channels, h, w]
|
||||||
auto encoder = std::dynamic_pointer_cast<Encoder>(blocks["encoder"]);
|
auto encoder = std::dynamic_pointer_cast<Encoder>(blocks["encoder"]);
|
||||||
|
|
||||||
auto h = encoder->forward(ctx, x); // [N, 2*z_channels, h/8, w/8]
|
auto z = encoder->forward(ctx, x); // [N, 2*z_channels, h/8, w/8]
|
||||||
if (use_quant) {
|
if (use_quant) {
|
||||||
auto quant_conv = std::dynamic_pointer_cast<Conv2d>(blocks["quant_conv"]);
|
auto quant_conv = std::dynamic_pointer_cast<Conv2d>(blocks["quant_conv"]);
|
||||||
h = quant_conv->forward(ctx, h); // [N, 2*embed_dim, h/8, w/8]
|
z = quant_conv->forward(ctx, z); // [N, 2*embed_dim, h/8, w/8]
|
||||||
}
|
}
|
||||||
return h;
|
if (sd_version_is_flux2(version)) {
|
||||||
|
z = ggml_ext_chunk(ctx->ggml_ctx, z, 2, 2)[0];
|
||||||
|
|
||||||
|
// [N, C, H, W] -> [N, C*p*p, H/p, W/p]
|
||||||
|
int64_t p = 2;
|
||||||
|
int64_t N = z->ne[3];
|
||||||
|
int64_t C = z->ne[2];
|
||||||
|
int64_t H = z->ne[1];
|
||||||
|
int64_t W = z->ne[0];
|
||||||
|
int64_t h = H / p;
|
||||||
|
int64_t w = W / p;
|
||||||
|
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, p, w, p, h * C * N); // [N*C*h, p, w, p]
|
||||||
|
z = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, z, 0, 2, 1, 3)); // [N*C*h, w, p, p]
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, p * p, w * h, C, N); // [N, C, h*w, p*p]
|
||||||
|
z = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, z, 1, 0, 2, 3)); // [N, C, p*p, h*w]
|
||||||
|
z = ggml_reshape_4d(ctx->ggml_ctx, z, w, h, p * p * C, N); // [N, C*p*p, h*w]
|
||||||
|
}
|
||||||
|
return z;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VAE : public GGMLRunner {
|
struct VAE : public GGMLRunner {
|
||||||
VAE(ggml_backend_t backend, bool offload_params_to_cpu)
|
VAE(ggml_backend_t backend, bool offload_params_to_cpu)
|
||||||
: GGMLRunner(backend, offload_params_to_cpu) {}
|
: GGMLRunner(backend, offload_params_to_cpu) {}
|
||||||
virtual void compute(const int n_threads,
|
virtual bool compute(const int n_threads,
|
||||||
struct ggml_tensor* z,
|
struct ggml_tensor* z,
|
||||||
bool decode_graph,
|
bool decode_graph,
|
||||||
struct ggml_tensor** output,
|
struct ggml_tensor** output,
|
||||||
@ -587,7 +629,7 @@ struct VAE : public GGMLRunner {
|
|||||||
struct FakeVAE : public VAE {
|
struct FakeVAE : public VAE {
|
||||||
FakeVAE(ggml_backend_t backend, bool offload_params_to_cpu)
|
FakeVAE(ggml_backend_t backend, bool offload_params_to_cpu)
|
||||||
: VAE(backend, offload_params_to_cpu) {}
|
: VAE(backend, offload_params_to_cpu) {}
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* z,
|
struct ggml_tensor* z,
|
||||||
bool decode_graph,
|
bool decode_graph,
|
||||||
struct ggml_tensor** output,
|
struct ggml_tensor** output,
|
||||||
@ -599,6 +641,7 @@ struct FakeVAE : public VAE {
|
|||||||
float value = ggml_ext_tensor_get_f32(z, i0, i1, i2, i3);
|
float value = ggml_ext_tensor_get_f32(z, i0, i1, i2, i3);
|
||||||
ggml_ext_tensor_set_f32(*output, value, i0, i1, i2, i3);
|
ggml_ext_tensor_set_f32(*output, value, i0, i1, i2, i3);
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) override {}
|
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) override {}
|
||||||
@ -669,7 +712,7 @@ struct AutoEncoderKL : public VAE {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* z,
|
struct ggml_tensor* z,
|
||||||
bool decode_graph,
|
bool decode_graph,
|
||||||
struct ggml_tensor** output,
|
struct ggml_tensor** output,
|
||||||
@ -680,7 +723,7 @@ struct AutoEncoderKL : public VAE {
|
|||||||
};
|
};
|
||||||
// ggml_set_f32(z, 0.5f);
|
// ggml_set_f32(z, 0.5f);
|
||||||
// print_ggml_tensor(z);
|
// print_ggml_tensor(z);
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
|
|||||||
20
version.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "stable-diffusion.h"
|
||||||
|
|
||||||
|
#ifndef SDCPP_BUILD_COMMIT
|
||||||
|
#define SDCPP_BUILD_COMMIT unknown
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDCPP_BUILD_VERSION
|
||||||
|
#define SDCPP_BUILD_VERSION unknown
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIZE2(x) #x
|
||||||
|
#define STRINGIZE(x) STRINGIZE2(x)
|
||||||
|
|
||||||
|
const char* sd_commit(void) {
|
||||||
|
return STRINGIZE(SDCPP_BUILD_COMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sd_version(void) {
|
||||||
|
return STRINGIZE(SDCPP_BUILD_VERSION);
|
||||||
|
}
|
||||||
488508
vocab_mistral.hpp
Normal file
25
wan.hpp
@ -1175,7 +1175,7 @@ namespace WAN {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(const int n_threads,
|
bool compute(const int n_threads,
|
||||||
struct ggml_tensor* z,
|
struct ggml_tensor* z,
|
||||||
bool decode_graph,
|
bool decode_graph,
|
||||||
struct ggml_tensor** output,
|
struct ggml_tensor** output,
|
||||||
@ -1184,7 +1184,7 @@ namespace WAN {
|
|||||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
return build_graph(z, decode_graph);
|
return build_graph(z, decode_graph);
|
||||||
};
|
};
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
||||||
} else { // chunk 1 result is weird
|
} else { // chunk 1 result is weird
|
||||||
ae.clear_cache();
|
ae.clear_cache();
|
||||||
int64_t t = z->ne[2];
|
int64_t t = z->ne[2];
|
||||||
@ -1193,11 +1193,11 @@ namespace WAN {
|
|||||||
return build_graph_partial(z, decode_graph, i);
|
return build_graph_partial(z, decode_graph, i);
|
||||||
};
|
};
|
||||||
struct ggml_tensor* out = nullptr;
|
struct ggml_tensor* out = nullptr;
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, &out, output_ctx);
|
bool res = GGMLRunner::compute(get_graph, n_threads, true, &out, output_ctx);
|
||||||
ae.clear_cache();
|
ae.clear_cache();
|
||||||
if (t == 1) {
|
if (t == 1) {
|
||||||
*output = out;
|
*output = out;
|
||||||
return;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
*output = ggml_new_tensor_4d(output_ctx, GGML_TYPE_F32, out->ne[0], out->ne[1], (t - 1) * 4 + 1, out->ne[3]);
|
*output = ggml_new_tensor_4d(output_ctx, GGML_TYPE_F32, out->ne[0], out->ne[1], (t - 1) * 4 + 1, out->ne[3]);
|
||||||
@ -1221,11 +1221,12 @@ namespace WAN {
|
|||||||
out = ggml_new_tensor_4d(output_ctx, GGML_TYPE_F32, out->ne[0], out->ne[1], 4, out->ne[3]);
|
out = ggml_new_tensor_4d(output_ctx, GGML_TYPE_F32, out->ne[0], out->ne[1], 4, out->ne[3]);
|
||||||
|
|
||||||
for (i = 1; i < t; i++) {
|
for (i = 1; i < t; i++) {
|
||||||
GGMLRunner::compute(get_graph, n_threads, true, &out);
|
res = res || GGMLRunner::compute(get_graph, n_threads, true, &out);
|
||||||
ae.clear_cache();
|
ae.clear_cache();
|
||||||
copy_to_output();
|
copy_to_output();
|
||||||
}
|
}
|
||||||
free_cache_ctx_and_buffer();
|
free_cache_ctx_and_buffer();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2075,15 +2076,19 @@ namespace WAN {
|
|||||||
wan_params.text_len = 512;
|
wan_params.text_len = 512;
|
||||||
} else {
|
} else {
|
||||||
if (wan_params.vace_layers > 0) {
|
if (wan_params.vace_layers > 0) {
|
||||||
desc = "Wan2.1-VACE-1.3B";
|
desc = "Wan2.1-VACE-1.3B";
|
||||||
|
wan_params.in_dim = 16;
|
||||||
|
} else if (wan_params.model_type == "i2v") {
|
||||||
|
desc = "Wan2.1-I2V-1.3B";
|
||||||
|
wan_params.in_dim = 36;
|
||||||
} else {
|
} else {
|
||||||
desc = "Wan2.1-T2V-1.3B";
|
desc = "Wan2.1-T2V-1.3B";
|
||||||
|
wan_params.in_dim = 16;
|
||||||
}
|
}
|
||||||
wan_params.dim = 1536;
|
wan_params.dim = 1536;
|
||||||
wan_params.eps = 1e-06;
|
wan_params.eps = 1e-06;
|
||||||
wan_params.ffn_dim = 8960;
|
wan_params.ffn_dim = 8960;
|
||||||
wan_params.freq_dim = 256;
|
wan_params.freq_dim = 256;
|
||||||
wan_params.in_dim = 16;
|
|
||||||
wan_params.num_heads = 12;
|
wan_params.num_heads = 12;
|
||||||
wan_params.out_dim = 16;
|
wan_params.out_dim = 16;
|
||||||
wan_params.text_len = 512;
|
wan_params.text_len = 512;
|
||||||
@ -2190,7 +2195,7 @@ namespace WAN {
|
|||||||
return gf;
|
return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compute(int n_threads,
|
bool compute(int n_threads,
|
||||||
struct ggml_tensor* x,
|
struct ggml_tensor* x,
|
||||||
struct ggml_tensor* timesteps,
|
struct ggml_tensor* timesteps,
|
||||||
struct ggml_tensor* context,
|
struct ggml_tensor* context,
|
||||||
@ -2205,7 +2210,7 @@ namespace WAN {
|
|||||||
return build_graph(x, timesteps, context, clip_fea, c_concat, time_dim_concat, vace_context, vace_strength);
|
return build_graph(x, timesteps, context, clip_fea, c_concat, time_dim_concat, vace_context, vace_strength);
|
||||||
};
|
};
|
||||||
|
|
||||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
|
|||||||
675
z_image.hpp
Normal file
@ -0,0 +1,675 @@
|
|||||||
|
#ifndef __Z_IMAGE_HPP__
|
||||||
|
#define __Z_IMAGE_HPP__
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "flux.hpp"
|
||||||
|
#include "ggml_extend.hpp"
|
||||||
|
#include "mmdit.hpp"
|
||||||
|
|
||||||
|
// Ref: https://github.com/Alpha-VLLM/Lumina-Image-2.0/blob/main/models/model.py
|
||||||
|
// Ref: https://github.com/huggingface/diffusers/pull/12703
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ZImage {
|
||||||
|
constexpr int Z_IMAGE_GRAPH_SIZE = 20480;
|
||||||
|
constexpr int ADALN_EMBED_DIM = 256;
|
||||||
|
constexpr int SEQ_MULTI_OF = 32;
|
||||||
|
|
||||||
|
struct JointAttention : public GGMLBlock {
|
||||||
|
protected:
|
||||||
|
int64_t head_dim;
|
||||||
|
int64_t num_heads;
|
||||||
|
int64_t num_kv_heads;
|
||||||
|
bool qk_norm;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JointAttention(int64_t hidden_size, int64_t head_dim, int64_t num_heads, int64_t num_kv_heads, bool qk_norm)
|
||||||
|
: head_dim(head_dim), num_heads(num_heads), num_kv_heads(num_kv_heads), qk_norm(qk_norm) {
|
||||||
|
blocks["qkv"] = std::make_shared<Linear>(hidden_size, (num_heads + num_kv_heads * 2) * head_dim, false);
|
||||||
|
float scale = 1.f;
|
||||||
|
#if GGML_USE_HIP
|
||||||
|
// Prevent NaN issues with certain ROCm setups
|
||||||
|
scale = 1.f / 16.f;
|
||||||
|
#endif
|
||||||
|
blocks["out"] = std::make_shared<Linear>(num_heads * head_dim, hidden_size, false, false, false, scale);
|
||||||
|
if (qk_norm) {
|
||||||
|
blocks["q_norm"] = std::make_shared<RMSNorm>(head_dim);
|
||||||
|
blocks["k_norm"] = std::make_shared<RMSNorm>(head_dim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* pe,
|
||||||
|
struct ggml_tensor* mask = nullptr) {
|
||||||
|
// x: [N, n_token, hidden_size]
|
||||||
|
int64_t n_token = x->ne[1];
|
||||||
|
int64_t N = x->ne[2];
|
||||||
|
auto qkv_proj = std::dynamic_pointer_cast<Linear>(blocks["qkv"]);
|
||||||
|
auto out_proj = std::dynamic_pointer_cast<Linear>(blocks["out"]);
|
||||||
|
|
||||||
|
auto qkv = qkv_proj->forward(ctx, x); // [N, n_token, (num_heads + num_kv_heads*2)*head_dim]
|
||||||
|
qkv = ggml_reshape_4d(ctx->ggml_ctx, qkv, head_dim, num_heads + num_kv_heads * 2, qkv->ne[1], qkv->ne[2]); // [N, n_token, num_heads + num_kv_heads*2, head_dim]
|
||||||
|
qkv = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, qkv, 0, 2, 3, 1)); // [num_heads + num_kv_heads*2, N, n_token, head_dim]
|
||||||
|
|
||||||
|
auto q = ggml_view_4d(ctx->ggml_ctx, qkv, qkv->ne[0], qkv->ne[1], qkv->ne[2], num_heads, qkv->nb[1], qkv->nb[2], qkv->nb[3], 0); // [num_heads, N, n_token, head_dim]
|
||||||
|
auto k = ggml_view_4d(ctx->ggml_ctx, qkv, qkv->ne[0], qkv->ne[1], qkv->ne[2], num_kv_heads, qkv->nb[1], qkv->nb[2], qkv->nb[3], qkv->nb[3] * num_heads); // [num_kv_heads, N, n_token, head_dim]
|
||||||
|
auto v = ggml_view_4d(ctx->ggml_ctx, qkv, qkv->ne[0], qkv->ne[1], qkv->ne[2], num_kv_heads, qkv->nb[1], qkv->nb[2], qkv->nb[3], qkv->nb[3] * (num_heads + num_kv_heads)); // [num_kv_heads, N, n_token, head_dim]
|
||||||
|
|
||||||
|
q = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, q, 0, 3, 1, 2)); // [N, n_token, num_heads, head_dim]
|
||||||
|
k = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, k, 0, 3, 1, 2)); // [N, n_token, num_kv_heads, head_dim]
|
||||||
|
v = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, v, 0, 3, 1, 2)); // [N, n_token, num_kv_heads, head_dim]
|
||||||
|
|
||||||
|
if (qk_norm) {
|
||||||
|
auto q_norm = std::dynamic_pointer_cast<RMSNorm>(blocks["q_norm"]);
|
||||||
|
auto k_norm = std::dynamic_pointer_cast<RMSNorm>(blocks["k_norm"]);
|
||||||
|
|
||||||
|
q = q_norm->forward(ctx, q);
|
||||||
|
k = k_norm->forward(ctx, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = Rope::attention(ctx, q, k, v, pe, mask, 1.f / 128.f); // [N, n_token, num_heads * head_dim]
|
||||||
|
|
||||||
|
x = out_proj->forward(ctx, x); // [N, n_token, hidden_size]
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FeedForward : public GGMLBlock {
|
||||||
|
public:
|
||||||
|
FeedForward(int64_t dim,
|
||||||
|
int64_t hidden_dim,
|
||||||
|
int64_t multiple_of,
|
||||||
|
float ffn_dim_multiplier = 0.f) {
|
||||||
|
if (ffn_dim_multiplier > 0.f) {
|
||||||
|
hidden_dim = static_cast<int64_t>(ffn_dim_multiplier * hidden_dim);
|
||||||
|
}
|
||||||
|
hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) / multiple_of);
|
||||||
|
blocks["w1"] = std::make_shared<Linear>(dim, hidden_dim, false);
|
||||||
|
|
||||||
|
bool force_prec_f32 = false;
|
||||||
|
float scale = 1.f / 128.f;
|
||||||
|
#ifdef SD_USE_VULKAN
|
||||||
|
force_prec_f32 = true;
|
||||||
|
#endif
|
||||||
|
// The purpose of the scale here is to prevent NaN issues in certain situations.
|
||||||
|
// For example, when using CUDA but the weights are k-quants.
|
||||||
|
blocks["w2"] = std::make_shared<Linear>(hidden_dim, dim, false, false, force_prec_f32, scale);
|
||||||
|
blocks["w3"] = std::make_shared<Linear>(dim, hidden_dim, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||||
|
auto w1 = std::dynamic_pointer_cast<Linear>(blocks["w1"]);
|
||||||
|
auto w2 = std::dynamic_pointer_cast<Linear>(blocks["w2"]);
|
||||||
|
auto w3 = std::dynamic_pointer_cast<Linear>(blocks["w3"]);
|
||||||
|
|
||||||
|
auto x1 = w1->forward(ctx, x);
|
||||||
|
auto x3 = w3->forward(ctx, x);
|
||||||
|
x = ggml_mul(ctx->ggml_ctx, ggml_silu(ctx->ggml_ctx, x1), x3);
|
||||||
|
x = w2->forward(ctx, x);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__STATIC_INLINE__ struct ggml_tensor* modulate(struct ggml_context* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* scale) {
|
||||||
|
// x: [N, L, C]
|
||||||
|
// scale: [N, C]
|
||||||
|
scale = ggml_reshape_3d(ctx, scale, scale->ne[0], 1, scale->ne[1]); // [N, 1, C]
|
||||||
|
x = ggml_add(ctx, x, ggml_mul(ctx, x, scale));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JointTransformerBlock : public GGMLBlock {
|
||||||
|
protected:
|
||||||
|
bool modulation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JointTransformerBlock(int layer_id,
|
||||||
|
int64_t hidden_size,
|
||||||
|
int64_t head_dim,
|
||||||
|
int64_t num_heads,
|
||||||
|
int64_t num_kv_heads,
|
||||||
|
int64_t multiple_of,
|
||||||
|
float ffn_dim_multiplier,
|
||||||
|
float norm_eps,
|
||||||
|
bool qk_norm,
|
||||||
|
bool modulation = true)
|
||||||
|
: modulation(modulation) {
|
||||||
|
blocks["attention"] = std::make_shared<JointAttention>(hidden_size, head_dim, num_heads, num_kv_heads, qk_norm);
|
||||||
|
blocks["feed_forward"] = std::make_shared<FeedForward>(hidden_size, hidden_size, multiple_of, ffn_dim_multiplier);
|
||||||
|
blocks["attention_norm1"] = std::make_shared<RMSNorm>(hidden_size, norm_eps);
|
||||||
|
blocks["ffn_norm1"] = std::make_shared<RMSNorm>(hidden_size, norm_eps);
|
||||||
|
blocks["attention_norm2"] = std::make_shared<RMSNorm>(hidden_size, norm_eps);
|
||||||
|
blocks["ffn_norm2"] = std::make_shared<RMSNorm>(hidden_size, norm_eps);
|
||||||
|
if (modulation) {
|
||||||
|
blocks["adaLN_modulation.0"] = std::make_shared<Linear>(MIN(hidden_size, ADALN_EMBED_DIM), 4 * hidden_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* pe,
|
||||||
|
struct ggml_tensor* mask = nullptr,
|
||||||
|
struct ggml_tensor* adaln_input = nullptr) {
|
||||||
|
auto attention = std::dynamic_pointer_cast<JointAttention>(blocks["attention"]);
|
||||||
|
auto feed_forward = std::dynamic_pointer_cast<FeedForward>(blocks["feed_forward"]);
|
||||||
|
auto attention_norm1 = std::dynamic_pointer_cast<RMSNorm>(blocks["attention_norm1"]);
|
||||||
|
auto ffn_norm1 = std::dynamic_pointer_cast<RMSNorm>(blocks["ffn_norm1"]);
|
||||||
|
auto attention_norm2 = std::dynamic_pointer_cast<RMSNorm>(blocks["attention_norm2"]);
|
||||||
|
auto ffn_norm2 = std::dynamic_pointer_cast<RMSNorm>(blocks["ffn_norm2"]);
|
||||||
|
|
||||||
|
if (modulation) {
|
||||||
|
GGML_ASSERT(adaln_input != nullptr);
|
||||||
|
auto adaLN_modulation_0 = std::dynamic_pointer_cast<Linear>(blocks["adaLN_modulation.0"]);
|
||||||
|
|
||||||
|
auto m = adaLN_modulation_0->forward(ctx, adaln_input); // [N, 4 * hidden_size]
|
||||||
|
auto mods = ggml_ext_chunk(ctx->ggml_ctx, m, 4, 0);
|
||||||
|
auto scale_msa = mods[0];
|
||||||
|
auto gate_msa = mods[1];
|
||||||
|
auto scale_mlp = mods[2];
|
||||||
|
auto gate_mlp = mods[3];
|
||||||
|
|
||||||
|
auto residual = x;
|
||||||
|
x = modulate(ctx->ggml_ctx, attention_norm1->forward(ctx, x), scale_msa);
|
||||||
|
x = attention->forward(ctx, x, pe, mask);
|
||||||
|
x = attention_norm2->forward(ctx, x);
|
||||||
|
x = ggml_mul(ctx->ggml_ctx, x, ggml_tanh(ctx->ggml_ctx, gate_msa));
|
||||||
|
x = ggml_add(ctx->ggml_ctx, x, residual);
|
||||||
|
|
||||||
|
residual = x;
|
||||||
|
x = modulate(ctx->ggml_ctx, ffn_norm1->forward(ctx, x), scale_mlp);
|
||||||
|
x = feed_forward->forward(ctx, x);
|
||||||
|
x = ffn_norm2->forward(ctx, x);
|
||||||
|
x = ggml_mul(ctx->ggml_ctx, x, ggml_tanh(ctx->ggml_ctx, gate_mlp));
|
||||||
|
x = ggml_add(ctx->ggml_ctx, x, residual);
|
||||||
|
} else {
|
||||||
|
GGML_ASSERT(adaln_input == nullptr);
|
||||||
|
|
||||||
|
auto residual = x;
|
||||||
|
x = attention_norm1->forward(ctx, x);
|
||||||
|
x = attention->forward(ctx, x, pe, mask);
|
||||||
|
x = attention_norm2->forward(ctx, x);
|
||||||
|
x = ggml_add(ctx->ggml_ctx, x, residual);
|
||||||
|
|
||||||
|
residual = x;
|
||||||
|
x = ffn_norm1->forward(ctx, x);
|
||||||
|
x = feed_forward->forward(ctx, x);
|
||||||
|
x = ffn_norm2->forward(ctx, x);
|
||||||
|
x = ggml_add(ctx->ggml_ctx, x, residual);
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinalLayer : public GGMLBlock {
|
||||||
|
public:
|
||||||
|
FinalLayer(int64_t hidden_size,
|
||||||
|
int64_t patch_size,
|
||||||
|
int64_t out_channels) {
|
||||||
|
blocks["norm_final"] = std::make_shared<LayerNorm>(hidden_size, 1e-06f, false);
|
||||||
|
blocks["linear"] = std::make_shared<Linear>(hidden_size, patch_size * patch_size * out_channels, true, true);
|
||||||
|
blocks["adaLN_modulation.1"] = std::make_shared<Linear>(MIN(hidden_size, ADALN_EMBED_DIM), hidden_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* c) {
|
||||||
|
// x: [N, n_token, hidden_size]
|
||||||
|
// c: [N, hidden_size]
|
||||||
|
// return: [N, n_token, patch_size * patch_size * out_channels]
|
||||||
|
auto norm_final = std::dynamic_pointer_cast<LayerNorm>(blocks["norm_final"]);
|
||||||
|
auto linear = std::dynamic_pointer_cast<Linear>(blocks["linear"]);
|
||||||
|
auto adaLN_modulation_1 = std::dynamic_pointer_cast<Linear>(blocks["adaLN_modulation.1"]);
|
||||||
|
|
||||||
|
auto scale = adaLN_modulation_1->forward(ctx, ggml_silu(ctx->ggml_ctx, c)); // [N, hidden_size]
|
||||||
|
x = norm_final->forward(ctx, x);
|
||||||
|
x = modulate(ctx->ggml_ctx, x, scale);
|
||||||
|
x = linear->forward(ctx, x);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZImageParams {
|
||||||
|
int64_t patch_size = 2;
|
||||||
|
int64_t hidden_size = 3840;
|
||||||
|
int64_t in_channels = 16;
|
||||||
|
int64_t out_channels = 16;
|
||||||
|
int64_t num_layers = 30;
|
||||||
|
int64_t num_refiner_layers = 2;
|
||||||
|
int64_t head_dim = 128;
|
||||||
|
int64_t num_heads = 30;
|
||||||
|
int64_t num_kv_heads = 30;
|
||||||
|
int64_t multiple_of = 256;
|
||||||
|
float ffn_dim_multiplier = 8.0 / 3.0f;
|
||||||
|
float norm_eps = 1e-5f;
|
||||||
|
bool qk_norm = true;
|
||||||
|
int64_t cap_feat_dim = 2560;
|
||||||
|
float theta = 256.f;
|
||||||
|
std::vector<int> axes_dim = {32, 48, 48};
|
||||||
|
int64_t axes_dim_sum = 128;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZImageModel : public GGMLBlock {
|
||||||
|
protected:
|
||||||
|
ZImageParams z_image_params;
|
||||||
|
|
||||||
|
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||||
|
params["cap_pad_token"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, z_image_params.hidden_size);
|
||||||
|
params["x_pad_token"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, z_image_params.hidden_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ZImageModel() = default;
|
||||||
|
ZImageModel(ZImageParams z_image_params)
|
||||||
|
: z_image_params(z_image_params) {
|
||||||
|
blocks["x_embedder"] = std::make_shared<Linear>(z_image_params.patch_size * z_image_params.patch_size * z_image_params.in_channels, z_image_params.hidden_size);
|
||||||
|
blocks["t_embedder"] = std::make_shared<TimestepEmbedder>(MIN(z_image_params.hidden_size, 1024), 256, 256);
|
||||||
|
blocks["cap_embedder.0"] = std::make_shared<RMSNorm>(z_image_params.cap_feat_dim, z_image_params.norm_eps);
|
||||||
|
blocks["cap_embedder.1"] = std::make_shared<Linear>(z_image_params.cap_feat_dim, z_image_params.hidden_size);
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_refiner_layers; i++) {
|
||||||
|
auto block = std::make_shared<JointTransformerBlock>(i,
|
||||||
|
z_image_params.hidden_size,
|
||||||
|
z_image_params.head_dim,
|
||||||
|
z_image_params.num_heads,
|
||||||
|
z_image_params.num_kv_heads,
|
||||||
|
z_image_params.multiple_of,
|
||||||
|
z_image_params.ffn_dim_multiplier,
|
||||||
|
z_image_params.norm_eps,
|
||||||
|
z_image_params.qk_norm,
|
||||||
|
true);
|
||||||
|
|
||||||
|
blocks["noise_refiner." + std::to_string(i)] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_refiner_layers; i++) {
|
||||||
|
auto block = std::make_shared<JointTransformerBlock>(i,
|
||||||
|
z_image_params.hidden_size,
|
||||||
|
z_image_params.head_dim,
|
||||||
|
z_image_params.num_heads,
|
||||||
|
z_image_params.num_kv_heads,
|
||||||
|
z_image_params.multiple_of,
|
||||||
|
z_image_params.ffn_dim_multiplier,
|
||||||
|
z_image_params.norm_eps,
|
||||||
|
z_image_params.qk_norm,
|
||||||
|
false);
|
||||||
|
|
||||||
|
blocks["context_refiner." + std::to_string(i)] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_layers; i++) {
|
||||||
|
auto block = std::make_shared<JointTransformerBlock>(i,
|
||||||
|
z_image_params.hidden_size,
|
||||||
|
z_image_params.head_dim,
|
||||||
|
z_image_params.num_heads,
|
||||||
|
z_image_params.num_kv_heads,
|
||||||
|
z_image_params.multiple_of,
|
||||||
|
z_image_params.ffn_dim_multiplier,
|
||||||
|
z_image_params.norm_eps,
|
||||||
|
z_image_params.qk_norm,
|
||||||
|
true);
|
||||||
|
|
||||||
|
blocks["layers." + std::to_string(i)] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks["final_layer"] = std::make_shared<FinalLayer>(z_image_params.hidden_size, z_image_params.patch_size, z_image_params.out_channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* pad_to_patch_size(struct ggml_context* ctx,
|
||||||
|
struct ggml_tensor* x) {
|
||||||
|
int64_t W = x->ne[0];
|
||||||
|
int64_t H = x->ne[1];
|
||||||
|
|
||||||
|
int pad_h = (z_image_params.patch_size - H % z_image_params.patch_size) % z_image_params.patch_size;
|
||||||
|
int pad_w = (z_image_params.patch_size - W % z_image_params.patch_size) % z_image_params.patch_size;
|
||||||
|
x = ggml_pad(ctx, x, pad_w, pad_h, 0, 0); // [N, C, H + pad_h, W + pad_w]
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* patchify(struct ggml_context* ctx,
|
||||||
|
struct ggml_tensor* x) {
|
||||||
|
// x: [N, C, H, W]
|
||||||
|
// return: [N, h*w, patch_size*patch_size*C]
|
||||||
|
int64_t N = x->ne[3];
|
||||||
|
int64_t C = x->ne[2];
|
||||||
|
int64_t H = x->ne[1];
|
||||||
|
int64_t W = x->ne[0];
|
||||||
|
int64_t p = z_image_params.patch_size;
|
||||||
|
int64_t h = H / z_image_params.patch_size;
|
||||||
|
int64_t w = W / z_image_params.patch_size;
|
||||||
|
|
||||||
|
GGML_ASSERT(h * p == H && w * p == W);
|
||||||
|
|
||||||
|
x = ggml_reshape_4d(ctx, x, p, w, p, h * C * N); // [N*C*h, p, w, p]
|
||||||
|
x = ggml_cont(ctx, ggml_permute(ctx, x, 0, 2, 1, 3)); // [N*C*h, w, p, p]
|
||||||
|
x = ggml_reshape_4d(ctx, x, p * p, w * h, C, N); // [N, C, h*w, p*p]
|
||||||
|
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 2, 0, 1, 3)); // [N, h*w, C, p*p]
|
||||||
|
x = ggml_reshape_3d(ctx, x, C * p * p, w * h, N); // [N, h*w, p*p*C]
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* process_img(struct ggml_context* ctx,
|
||||||
|
struct ggml_tensor* x) {
|
||||||
|
x = pad_to_patch_size(ctx, x);
|
||||||
|
x = patchify(ctx, x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* unpatchify(struct ggml_context* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
int64_t h,
|
||||||
|
int64_t w) {
|
||||||
|
// x: [N, h*w, patch_size*patch_size*C]
|
||||||
|
// return: [N, C, H, W]
|
||||||
|
int64_t N = x->ne[2];
|
||||||
|
int64_t C = x->ne[0] / z_image_params.patch_size / z_image_params.patch_size;
|
||||||
|
int64_t H = h * z_image_params.patch_size;
|
||||||
|
int64_t W = w * z_image_params.patch_size;
|
||||||
|
int64_t p = z_image_params.patch_size;
|
||||||
|
|
||||||
|
GGML_ASSERT(C * p * p == x->ne[0]);
|
||||||
|
|
||||||
|
x = ggml_reshape_4d(ctx, x, C, p * p, w * h, N); // [N, h*w, p*p, C]
|
||||||
|
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 2, 0, 3)); // [N, C, h*w, p*p]
|
||||||
|
x = ggml_reshape_4d(ctx, x, p, p, w, h * C * N); // [N*C*h, w, p, p]
|
||||||
|
x = ggml_cont(ctx, ggml_permute(ctx, x, 0, 2, 1, 3)); // [N*C*h, p, w, p]
|
||||||
|
x = ggml_reshape_4d(ctx, x, W, H, C, N); // [N, C, h*p, w*p]
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward_core(GGMLRunnerContext* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* timestep,
|
||||||
|
struct ggml_tensor* context,
|
||||||
|
struct ggml_tensor* pe) {
|
||||||
|
auto x_embedder = std::dynamic_pointer_cast<Linear>(blocks["x_embedder"]);
|
||||||
|
auto t_embedder = std::dynamic_pointer_cast<TimestepEmbedder>(blocks["t_embedder"]);
|
||||||
|
auto cap_embedder_0 = std::dynamic_pointer_cast<RMSNorm>(blocks["cap_embedder.0"]);
|
||||||
|
auto cap_embedder_1 = std::dynamic_pointer_cast<Linear>(blocks["cap_embedder.1"]);
|
||||||
|
auto norm_final = std::dynamic_pointer_cast<RMSNorm>(blocks["norm_final"]);
|
||||||
|
auto final_layer = std::dynamic_pointer_cast<FinalLayer>(blocks["final_layer"]);
|
||||||
|
|
||||||
|
auto txt_pad_token = params["cap_pad_token"];
|
||||||
|
auto img_pad_token = params["x_pad_token"];
|
||||||
|
|
||||||
|
int64_t N = x->ne[2];
|
||||||
|
int64_t n_img_token = x->ne[1];
|
||||||
|
int64_t n_txt_token = context->ne[1];
|
||||||
|
|
||||||
|
auto t_emb = t_embedder->forward(ctx, timestep);
|
||||||
|
|
||||||
|
auto txt = cap_embedder_1->forward(ctx, cap_embedder_0->forward(ctx, context)); // [N, n_txt_token, hidden_size]
|
||||||
|
auto img = x_embedder->forward(ctx, x); // [N, n_img_token, hidden_size]
|
||||||
|
|
||||||
|
int64_t n_txt_pad_token = Rope::bound_mod(n_txt_token, SEQ_MULTI_OF);
|
||||||
|
if (n_txt_pad_token > 0) {
|
||||||
|
auto txt_pad_tokens = ggml_repeat_4d(ctx->ggml_ctx, txt_pad_token, txt_pad_token->ne[0], n_txt_pad_token, N, 1);
|
||||||
|
txt = ggml_concat(ctx->ggml_ctx, txt, txt_pad_tokens, 1); // [N, n_txt_token + n_txt_pad_token, hidden_size]
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t n_img_pad_token = Rope::bound_mod(n_img_token, SEQ_MULTI_OF);
|
||||||
|
if (n_img_pad_token > 0) {
|
||||||
|
auto img_pad_tokens = ggml_repeat_4d(ctx->ggml_ctx, img_pad_token, img_pad_token->ne[0], n_img_pad_token, N, 1);
|
||||||
|
img = ggml_concat(ctx->ggml_ctx, img, img_pad_tokens, 1); // [N, n_img_token + n_img_pad_token, hidden_size]
|
||||||
|
}
|
||||||
|
|
||||||
|
GGML_ASSERT(txt->ne[1] + img->ne[1] == pe->ne[3]);
|
||||||
|
|
||||||
|
auto txt_pe = ggml_ext_slice(ctx->ggml_ctx, pe, 3, 0, txt->ne[1]);
|
||||||
|
auto img_pe = ggml_ext_slice(ctx->ggml_ctx, pe, 3, txt->ne[1], pe->ne[3]);
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_refiner_layers; i++) {
|
||||||
|
auto block = std::dynamic_pointer_cast<JointTransformerBlock>(blocks["context_refiner." + std::to_string(i)]);
|
||||||
|
|
||||||
|
txt = block->forward(ctx, txt, txt_pe, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_refiner_layers; i++) {
|
||||||
|
auto block = std::dynamic_pointer_cast<JointTransformerBlock>(blocks["noise_refiner." + std::to_string(i)]);
|
||||||
|
|
||||||
|
img = block->forward(ctx, img, img_pe, nullptr, t_emb);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto txt_img = ggml_concat(ctx->ggml_ctx, txt, img, 1); // [N, n_txt_token + n_txt_pad_token + n_img_token + n_img_pad_token, hidden_size]
|
||||||
|
|
||||||
|
for (int i = 0; i < z_image_params.num_layers; i++) {
|
||||||
|
auto block = std::dynamic_pointer_cast<JointTransformerBlock>(blocks["layers." + std::to_string(i)]);
|
||||||
|
|
||||||
|
txt_img = block->forward(ctx, txt_img, pe, nullptr, t_emb);
|
||||||
|
}
|
||||||
|
|
||||||
|
txt_img = final_layer->forward(ctx, txt_img, t_emb); // [N, n_txt_token + n_txt_pad_token + n_img_token + n_img_pad_token, ph*pw*C]
|
||||||
|
|
||||||
|
img = ggml_ext_slice(ctx->ggml_ctx, txt_img, 1, n_txt_token + n_txt_pad_token, n_txt_token + n_txt_pad_token + n_img_token); // [N, n_img_token, ph*pw*C]
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* timestep,
|
||||||
|
struct ggml_tensor* context,
|
||||||
|
struct ggml_tensor* pe,
|
||||||
|
std::vector<ggml_tensor*> ref_latents = {}) {
|
||||||
|
// Forward pass of DiT.
|
||||||
|
// x: [N, C, H, W]
|
||||||
|
// timestep: [N,]
|
||||||
|
// context: [N, L, D]
|
||||||
|
// pe: [L, d_head/2, 2, 2]
|
||||||
|
// return: [N, C, H, W]
|
||||||
|
|
||||||
|
int64_t W = x->ne[0];
|
||||||
|
int64_t H = x->ne[1];
|
||||||
|
int64_t C = x->ne[2];
|
||||||
|
int64_t N = x->ne[3];
|
||||||
|
|
||||||
|
auto img = process_img(ctx->ggml_ctx, x);
|
||||||
|
uint64_t n_img_token = img->ne[1];
|
||||||
|
|
||||||
|
if (ref_latents.size() > 0) {
|
||||||
|
for (ggml_tensor* ref : ref_latents) {
|
||||||
|
ref = process_img(ctx->ggml_ctx, ref);
|
||||||
|
img = ggml_concat(ctx->ggml_ctx, img, ref, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t h_len = ((H + (z_image_params.patch_size / 2)) / z_image_params.patch_size);
|
||||||
|
int64_t w_len = ((W + (z_image_params.patch_size / 2)) / z_image_params.patch_size);
|
||||||
|
|
||||||
|
auto out = forward_core(ctx, img, timestep, context, pe);
|
||||||
|
|
||||||
|
out = ggml_ext_slice(ctx->ggml_ctx, out, 1, 0, n_img_token); // [N, n_img_token, ph*pw*C]
|
||||||
|
out = unpatchify(ctx->ggml_ctx, out, h_len, w_len); // [N, C, H + pad_h, W + pad_w]
|
||||||
|
|
||||||
|
// slice
|
||||||
|
out = ggml_ext_slice(ctx->ggml_ctx, out, 1, 0, H); // [N, C, H, W + pad_w]
|
||||||
|
out = ggml_ext_slice(ctx->ggml_ctx, out, 0, 0, W); // [N, C, H, W]
|
||||||
|
|
||||||
|
out = ggml_scale(ctx->ggml_ctx, out, -1.f);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZImageRunner : public GGMLRunner {
|
||||||
|
public:
|
||||||
|
ZImageParams z_image_params;
|
||||||
|
ZImageModel z_image;
|
||||||
|
std::vector<float> pe_vec;
|
||||||
|
std::vector<float> timestep_vec;
|
||||||
|
SDVersion version;
|
||||||
|
|
||||||
|
ZImageRunner(ggml_backend_t backend,
|
||||||
|
bool offload_params_to_cpu,
|
||||||
|
const String2TensorStorage& tensor_storage_map = {},
|
||||||
|
const std::string prefix = "",
|
||||||
|
SDVersion version = VERSION_Z_IMAGE)
|
||||||
|
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||||
|
z_image = ZImageModel(z_image_params);
|
||||||
|
z_image.init(params_ctx, tensor_storage_map, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_desc() override {
|
||||||
|
return "z_image";
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||||
|
z_image.get_param_tensors(tensors, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ggml_cgraph* build_graph(struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* timesteps,
|
||||||
|
struct ggml_tensor* context,
|
||||||
|
std::vector<ggml_tensor*> ref_latents = {},
|
||||||
|
bool increase_ref_index = false) {
|
||||||
|
GGML_ASSERT(x->ne[3] == 1);
|
||||||
|
struct ggml_cgraph* gf = new_graph_custom(Z_IMAGE_GRAPH_SIZE);
|
||||||
|
|
||||||
|
x = to_backend(x);
|
||||||
|
context = to_backend(context);
|
||||||
|
timesteps = to_backend(timesteps);
|
||||||
|
|
||||||
|
for (int i = 0; i < ref_latents.size(); i++) {
|
||||||
|
ref_latents[i] = to_backend(ref_latents[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pe_vec = Rope::gen_z_image_pe(x->ne[1],
|
||||||
|
x->ne[0],
|
||||||
|
z_image_params.patch_size,
|
||||||
|
x->ne[3],
|
||||||
|
context->ne[1],
|
||||||
|
SEQ_MULTI_OF,
|
||||||
|
ref_latents,
|
||||||
|
increase_ref_index,
|
||||||
|
z_image_params.theta,
|
||||||
|
z_image_params.axes_dim);
|
||||||
|
int pos_len = pe_vec.size() / z_image_params.axes_dim_sum / 2;
|
||||||
|
// LOG_DEBUG("pos_len %d", pos_len);
|
||||||
|
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, z_image_params.axes_dim_sum / 2, pos_len);
|
||||||
|
// pe->data = pe_vec.data();
|
||||||
|
// print_ggml_tensor(pe, true, "pe");
|
||||||
|
// pe->data = nullptr;
|
||||||
|
set_backend_tensor_data(pe, pe_vec.data());
|
||||||
|
auto runner_ctx = get_context();
|
||||||
|
|
||||||
|
struct ggml_tensor* out = z_image.forward(&runner_ctx,
|
||||||
|
x,
|
||||||
|
timesteps,
|
||||||
|
context,
|
||||||
|
pe,
|
||||||
|
ref_latents);
|
||||||
|
|
||||||
|
ggml_build_forward_expand(gf, out);
|
||||||
|
|
||||||
|
return gf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compute(int n_threads,
|
||||||
|
struct ggml_tensor* x,
|
||||||
|
struct ggml_tensor* timesteps,
|
||||||
|
struct ggml_tensor* context,
|
||||||
|
std::vector<ggml_tensor*> ref_latents = {},
|
||||||
|
bool increase_ref_index = false,
|
||||||
|
struct ggml_tensor** output = nullptr,
|
||||||
|
struct ggml_context* output_ctx = nullptr) {
|
||||||
|
// x: [N, in_channels, h, w]
|
||||||
|
// timesteps: [N, ]
|
||||||
|
// context: [N, max_position, hidden_size]
|
||||||
|
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||||
|
return build_graph(x, timesteps, context, ref_latents, increase_ref_index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
struct ggml_init_params params;
|
||||||
|
params.mem_size = static_cast<size_t>(1024 * 1024) * 1024; // 1GB
|
||||||
|
params.mem_buffer = nullptr;
|
||||||
|
params.no_alloc = false;
|
||||||
|
|
||||||
|
struct ggml_context* work_ctx = ggml_init(params);
|
||||||
|
GGML_ASSERT(work_ctx != nullptr);
|
||||||
|
|
||||||
|
{
|
||||||
|
// auto x = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 16, 16, 16, 1);
|
||||||
|
// ggml_set_f32(x, 0.01f);
|
||||||
|
auto x = load_tensor_from_file(work_ctx, "./z_image_x.bin");
|
||||||
|
print_ggml_tensor(x);
|
||||||
|
|
||||||
|
std::vector<float> timesteps_vec(1, 0.f);
|
||||||
|
auto timesteps = vector_to_ggml_tensor(work_ctx, timesteps_vec);
|
||||||
|
|
||||||
|
// auto context = ggml_new_tensor_3d(work_ctx, GGML_TYPE_F32, 2560, 256, 1);
|
||||||
|
// ggml_set_f32(context, 0.01f);
|
||||||
|
auto context = load_tensor_from_file(work_ctx, "./z_image_context.bin");
|
||||||
|
print_ggml_tensor(context);
|
||||||
|
|
||||||
|
struct ggml_tensor* out = nullptr;
|
||||||
|
|
||||||
|
int t0 = ggml_time_ms();
|
||||||
|
compute(8, x, timesteps, context, {}, false, &out, work_ctx);
|
||||||
|
int t1 = ggml_time_ms();
|
||||||
|
|
||||||
|
print_ggml_tensor(out);
|
||||||
|
LOG_DEBUG("z_image test done in %dms", t1 - t0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_from_file_and_test(const std::string& file_path) {
|
||||||
|
// cuda q8: pass
|
||||||
|
// cuda q8 fa: pass
|
||||||
|
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||||
|
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||||
|
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
||||||
|
|
||||||
|
ModelLoader model_loader;
|
||||||
|
if (!model_loader.init_from_file_and_convert_name(file_path, "model.diffusion_model.")) {
|
||||||
|
LOG_ERROR("init model loader from file failed: '%s'", file_path.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||||
|
if (model_data_type != GGML_TYPE_COUNT) {
|
||||||
|
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||||
|
if (ends_with(name, "weight")) {
|
||||||
|
tensor_storage.expected_type = model_data_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ZImageRunner> z_image = std::make_shared<ZImageRunner>(backend,
|
||||||
|
false,
|
||||||
|
tensor_storage_map,
|
||||||
|
"model.diffusion_model",
|
||||||
|
VERSION_QWEN_IMAGE);
|
||||||
|
|
||||||
|
z_image->alloc_params_buffer();
|
||||||
|
std::map<std::string, ggml_tensor*> tensors;
|
||||||
|
z_image->get_param_tensors(tensors, "model.diffusion_model");
|
||||||
|
|
||||||
|
bool success = model_loader.load_tensors(tensors);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
LOG_ERROR("load tensors from model loader failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("z_image model loaded");
|
||||||
|
z_image->test();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZImage
|
||||||
|
|
||||||
|
#endif // __Z_IMAGE_HPP__
|
||||||