mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-10-18 05:50:10 +08:00
Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45c46779af | ||
|
|
869d023416 | ||
|
|
e9bc3b6c06 | ||
|
|
b542894fb9 | ||
|
|
5498cc0d67 | ||
|
|
aa2b8e0ca5 | ||
|
|
a14e2b321d | ||
|
|
28ffb6c13d | ||
|
|
b88cc32346 | ||
|
|
f532972d60 | ||
|
|
d5b05f70c6 | ||
|
|
6d6dc1b8ed | ||
|
|
199e675cc7 | ||
|
|
742a7333c3 | ||
|
|
e8eb3791c8 | ||
|
|
aa44e06890 | ||
|
|
6448430dbb | ||
|
|
347710f68f | ||
|
|
59ebdf0bb5 | ||
|
|
4ffcbcaed7 | ||
|
|
694f0d9235 | ||
|
|
8ecdf053ac | ||
|
|
ee89afc878 | ||
|
|
d2d3944f50 | ||
|
|
0fa3e1a383 | ||
|
|
c2d8ffc22c | ||
|
|
fb748bb8a4 | ||
|
|
8f6c5c217b |
+102
-18
@@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
- name: Get commit hash
|
||||
id: commit
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.event.inputs.create_release == 'true' }}
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: pr-mpt/actions-commit-hash@v2
|
||||
|
||||
- name: Fetch system info
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
|
||||
- name: Get commit hash
|
||||
id: commit
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.event.inputs.create_release == 'true' }}
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: pr-mpt/actions-commit-hash@v2
|
||||
|
||||
- name: Fetch system info
|
||||
@@ -164,8 +164,6 @@ jobs:
|
||||
defines: "-DGGML_NATIVE=OFF -DGGML_AVX512=ON -DGGML_AVX=ON -DGGML_AVX2=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||
- build: "cuda12"
|
||||
defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES=90;89;86;80;75"
|
||||
# - build: "rocm5.5"
|
||||
# defines: '-G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSD_HIPBLAS=ON -DCMAKE_BUILD_TYPE=Release -DAMDGPU_TARGETS="gfx1100;gfx1102;gfx1030" -DSD_BUILD_SHARED_LIBS=ON'
|
||||
- build: 'vulkan'
|
||||
defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON"
|
||||
steps:
|
||||
@@ -184,22 +182,9 @@ jobs:
|
||||
method: "network"
|
||||
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]'
|
||||
|
||||
- name: Install rocm-toolkit
|
||||
id: rocm-toolkit
|
||||
if: ${{ matrix.build == 'rocm5.5' }}
|
||||
uses: Cyberhan123/rocm-toolkit@v0.1.0
|
||||
with:
|
||||
rocm: "5.5.0"
|
||||
|
||||
- name: Install Ninja
|
||||
id: install-ninja
|
||||
if: ${{ matrix.build == 'rocm5.5' }}
|
||||
uses: urkle/action-get-ninja@v1
|
||||
with:
|
||||
version: 1.11.1
|
||||
- name: Install Vulkan SDK
|
||||
id: get_vulkan
|
||||
if: ${{ matrix.build == 'vulkan' }} https://sdk.lunarg.com/sdk/download/1.4.328.1/windows/vulkansdk-windows-X64-1.4.328.1.exe
|
||||
if: ${{ matrix.build == 'vulkan' }}
|
||||
run: |
|
||||
curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe"
|
||||
& "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install
|
||||
@@ -277,6 +262,104 @@ jobs:
|
||||
path: |
|
||||
sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip
|
||||
|
||||
windows-latest-cmake-hip:
|
||||
runs-on: windows-2022
|
||||
|
||||
env:
|
||||
HIPSDK_INSTALLER_VERSION: "25.Q3"
|
||||
GPU_TARGETS: "gfx1151;gfx1200;gfx1201;gfx1100;gfx1101;gfx1102;gfx1030;gfx1031;gfx1032"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache ROCm Installation
|
||||
id: cache-rocm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: C:\Program Files\AMD\ROCm
|
||||
key: rocm-${{ env.HIPSDK_INSTALLER_VERSION }}-${{ runner.os }}
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.16
|
||||
with:
|
||||
key: windows-latest-cmake-hip-${{ env.HIPSDK_INSTALLER_VERSION }}-x64
|
||||
evict-old-files: 1d
|
||||
|
||||
- name: Install ROCm
|
||||
if: steps.cache-rocm.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
write-host "Downloading AMD HIP SDK Installer"
|
||||
Invoke-WebRequest -Uri "https://download.amd.com/developer/eula/rocm-hub/AMD-Software-PRO-Edition-${{ env.HIPSDK_INSTALLER_VERSION }}-WinSvr2022-For-HIP.exe" -OutFile "${env:RUNNER_TEMP}\rocm-install.exe"
|
||||
write-host "Installing AMD HIP SDK"
|
||||
$proc = Start-Process "${env:RUNNER_TEMP}\rocm-install.exe" -ArgumentList '-install' -NoNewWindow -PassThru
|
||||
$completed = $proc.WaitForExit(600000)
|
||||
if (-not $completed) {
|
||||
Write-Error "ROCm installation timed out after 10 minutes. Killing the process"
|
||||
$proc.Kill()
|
||||
exit 1
|
||||
}
|
||||
if ($proc.ExitCode -ne 0) {
|
||||
Write-Error "ROCm installation failed with exit code $($proc.ExitCode)"
|
||||
exit 1
|
||||
}
|
||||
write-host "Completed AMD HIP SDK installation"
|
||||
|
||||
- name: Verify ROCm
|
||||
run: |
|
||||
# Find and test ROCm installation
|
||||
$clangPath = Get-ChildItem 'C:\Program Files\AMD\ROCm\*\bin\clang.exe' | Select-Object -First 1
|
||||
if (-not $clangPath) {
|
||||
Write-Error "ROCm installation not found"
|
||||
exit 1
|
||||
}
|
||||
& $clangPath.FullName --version
|
||||
# Set HIP_PATH environment variable for later steps
|
||||
echo "HIP_PATH=$(Resolve-Path 'C:\Program Files\AMD\ROCm\*\bin\clang.exe' | split-path | split-path)" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
$env:CMAKE_PREFIX_PATH="${env:HIP_PATH}"
|
||||
cmake .. `
|
||||
-G "Unix Makefiles" `
|
||||
-DSD_HIPBLAS=ON `
|
||||
-DSD_BUILD_SHARED_LIBS=ON `
|
||||
-DGGML_NATIVE=OFF `
|
||||
-DCMAKE_C_COMPILER=clang `
|
||||
-DCMAKE_CXX_COMPILER=clang++ `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
-DGPU_TARGETS="${{ env.GPU_TARGETS }}"
|
||||
cmake --build . --config Release --parallel ${env:NUMBER_OF_PROCESSORS}
|
||||
|
||||
- name: Get commit hash
|
||||
id: commit
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: pr-mpt/actions-commit-hash@v2
|
||||
|
||||
- name: Pack artifacts
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
run: |
|
||||
md "build\bin\rocblas\library\"
|
||||
md "build\bin\hipblaslt\library"
|
||||
cp "${env:HIP_PATH}\bin\hipblas.dll" "build\bin\"
|
||||
cp "${env:HIP_PATH}\bin\hipblaslt.dll" "build\bin\"
|
||||
cp "${env:HIP_PATH}\bin\rocblas.dll" "build\bin\"
|
||||
cp "${env:HIP_PATH}\bin\rocblas\library\*" "build\bin\rocblas\library\"
|
||||
cp "${env:HIP_PATH}\bin\hipblaslt\library\*" "build\bin\hipblaslt\library\"
|
||||
7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-x64.zip .\build\bin\*
|
||||
|
||||
- name: Upload artifacts
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-x64.zip
|
||||
path: |
|
||||
sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-x64.zip
|
||||
|
||||
release:
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
|
||||
@@ -286,6 +369,7 @@ jobs:
|
||||
- ubuntu-latest-cmake
|
||||
- macOS-latest-cmake
|
||||
- windows-latest-cmake
|
||||
- windows-latest-cmake-hip
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -12,3 +12,4 @@ test/
|
||||
output*.png
|
||||
models*
|
||||
*.log
|
||||
preview.png
|
||||
|
||||
@@ -81,7 +81,9 @@ API and command-line option may change frequently.***
|
||||
- [`DPM++ 2M v2`](https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/8457)
|
||||
- `DPM++ 2S a`
|
||||
- [`LCM`](https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/13952)
|
||||
- Cross-platform reproducibility (`--rng cuda`, consistent with the `stable-diffusion-webui GPU RNG`)
|
||||
- Cross-platform reproducibility
|
||||
- `--rng cuda`, default, consistent with the `stable-diffusion-webui GPU RNG`
|
||||
- `--rng cpu`, consistent with the `comfyui RNG`
|
||||
- Embedds generation parameters into png output as webui-compatible text string
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -476,11 +476,12 @@ protected:
|
||||
public:
|
||||
CLIPLayer(int64_t d_model,
|
||||
int64_t n_head,
|
||||
int64_t intermediate_size)
|
||||
int64_t intermediate_size,
|
||||
bool proj_in = false)
|
||||
: d_model(d_model),
|
||||
n_head(n_head),
|
||||
intermediate_size(intermediate_size) {
|
||||
blocks["self_attn"] = std::shared_ptr<GGMLBlock>(new MultiheadAttention(d_model, n_head, true, true));
|
||||
blocks["self_attn"] = std::shared_ptr<GGMLBlock>(new MultiheadAttention(d_model, n_head, true, true, proj_in));
|
||||
|
||||
blocks["layer_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(d_model));
|
||||
blocks["layer_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(d_model));
|
||||
@@ -509,11 +510,12 @@ public:
|
||||
CLIPEncoder(int64_t n_layer,
|
||||
int64_t d_model,
|
||||
int64_t n_head,
|
||||
int64_t intermediate_size)
|
||||
int64_t intermediate_size,
|
||||
bool proj_in = false)
|
||||
: n_layer(n_layer) {
|
||||
for (int i = 0; i < n_layer; i++) {
|
||||
std::string name = "layers." + std::to_string(i);
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(new CLIPLayer(d_model, n_head, intermediate_size));
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(new CLIPLayer(d_model, n_head, intermediate_size, proj_in));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,10 +551,10 @@ protected:
|
||||
int64_t num_positions;
|
||||
bool force_clip_f32;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type token_wtype = GGML_TYPE_F32;
|
||||
if (!force_clip_f32) {
|
||||
token_wtype = get_type(prefix + "token_embedding.weight", tensor_types, GGML_TYPE_F32);
|
||||
token_wtype = get_type(prefix + "token_embedding.weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
if (!support_get_rows(token_wtype)) {
|
||||
token_wtype = GGML_TYPE_F32;
|
||||
}
|
||||
@@ -605,7 +607,8 @@ protected:
|
||||
int64_t image_size;
|
||||
int64_t num_patches;
|
||||
int64_t num_positions;
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type patch_wtype = GGML_TYPE_F16;
|
||||
enum ggml_type class_wtype = GGML_TYPE_F32;
|
||||
enum ggml_type position_wtype = GGML_TYPE_F32;
|
||||
@@ -668,7 +671,7 @@ enum CLIPVersion {
|
||||
|
||||
class CLIPTextModel : public GGMLBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
if (version == OPEN_CLIP_VIT_BIGG_14) {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["text_projection"] = ggml_new_tensor_2d(ctx, wtype, projection_dim, hidden_size);
|
||||
@@ -689,7 +692,8 @@ public:
|
||||
|
||||
CLIPTextModel(CLIPVersion version = OPENAI_CLIP_VIT_L_14,
|
||||
bool with_final_ln = true,
|
||||
bool force_clip_f32 = false)
|
||||
bool force_clip_f32 = false,
|
||||
bool proj_in = false)
|
||||
: version(version), with_final_ln(with_final_ln) {
|
||||
if (version == OPEN_CLIP_VIT_H_14) {
|
||||
hidden_size = 1024;
|
||||
@@ -704,7 +708,7 @@ public:
|
||||
}
|
||||
|
||||
blocks["embeddings"] = std::shared_ptr<GGMLBlock>(new CLIPEmbeddings(hidden_size, vocab_size, n_token, force_clip_f32));
|
||||
blocks["encoder"] = std::shared_ptr<GGMLBlock>(new CLIPEncoder(n_layer, hidden_size, n_head, intermediate_size));
|
||||
blocks["encoder"] = std::shared_ptr<GGMLBlock>(new CLIPEncoder(n_layer, hidden_size, n_head, intermediate_size, proj_in));
|
||||
blocks["final_layer_norm"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size));
|
||||
}
|
||||
|
||||
@@ -758,7 +762,7 @@ public:
|
||||
int32_t n_layer = 24;
|
||||
|
||||
public:
|
||||
CLIPVisionModel(CLIPVersion version = OPENAI_CLIP_VIT_L_14) {
|
||||
CLIPVisionModel(CLIPVersion version = OPENAI_CLIP_VIT_L_14, bool proj_in = false) {
|
||||
if (version == OPEN_CLIP_VIT_H_14) {
|
||||
hidden_size = 1280;
|
||||
intermediate_size = 5120;
|
||||
@@ -773,7 +777,7 @@ public:
|
||||
|
||||
blocks["embeddings"] = std::shared_ptr<GGMLBlock>(new CLIPVisionEmbeddings(hidden_size, num_channels, patch_size, image_size));
|
||||
blocks["pre_layernorm"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size));
|
||||
blocks["encoder"] = std::shared_ptr<GGMLBlock>(new CLIPEncoder(n_layer, hidden_size, n_head, intermediate_size));
|
||||
blocks["encoder"] = std::shared_ptr<GGMLBlock>(new CLIPEncoder(n_layer, hidden_size, n_head, intermediate_size, proj_in));
|
||||
blocks["post_layernorm"] = std::shared_ptr<GGMLBlock>(new LayerNorm(hidden_size));
|
||||
}
|
||||
|
||||
@@ -811,8 +815,8 @@ protected:
|
||||
int64_t out_features;
|
||||
bool transpose_weight;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
if (transpose_weight) {
|
||||
params["weight"] = ggml_new_tensor_2d(ctx, wtype, out_features, in_features);
|
||||
} else {
|
||||
@@ -845,7 +849,8 @@ public:
|
||||
|
||||
public:
|
||||
CLIPVisionModelProjection(CLIPVersion version = OPENAI_CLIP_VIT_L_14,
|
||||
bool transpose_proj_w = false) {
|
||||
bool transpose_proj_w = false,
|
||||
bool proj_in = false) {
|
||||
if (version == OPEN_CLIP_VIT_H_14) {
|
||||
hidden_size = 1280;
|
||||
projection_dim = 1024;
|
||||
@@ -853,7 +858,7 @@ public:
|
||||
hidden_size = 1664;
|
||||
}
|
||||
|
||||
blocks["vision_model"] = std::shared_ptr<GGMLBlock>(new CLIPVisionModel(version));
|
||||
blocks["vision_model"] = std::shared_ptr<GGMLBlock>(new CLIPVisionModel(version, proj_in));
|
||||
blocks["visual_projection"] = std::shared_ptr<GGMLBlock>(new CLIPProjection(hidden_size, projection_dim, transpose_proj_w));
|
||||
}
|
||||
|
||||
@@ -881,13 +886,24 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
|
||||
CLIPTextModelRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
CLIPVersion version = OPENAI_CLIP_VIT_L_14,
|
||||
bool with_final_ln = true,
|
||||
bool force_clip_f32 = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), model(version, with_final_ln, force_clip_f32) {
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
bool proj_in = false;
|
||||
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (!starts_with(name, prefix)) {
|
||||
continue;
|
||||
}
|
||||
if (contains(name, "self_attn.in_proj")) {
|
||||
proj_in = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
model = CLIPTextModel(version, with_final_ln, force_clip_f32, proj_in);
|
||||
model.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -920,7 +936,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
size_t max_token_idx = 0,
|
||||
bool return_pooled = false,
|
||||
int clip_skip = -1) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph(compute_ctx);
|
||||
struct ggml_cgraph* gf = new_graph_custom(2048);
|
||||
|
||||
input_ids = to_backend(input_ids);
|
||||
|
||||
|
||||
+69
-36
@@ -182,31 +182,21 @@ protected:
|
||||
int64_t dim_in;
|
||||
int64_t dim_out;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "proj.weight", tensor_types, GGML_TYPE_F32);
|
||||
enum ggml_type bias_wtype = GGML_TYPE_F32;
|
||||
params["proj.weight"] = ggml_new_tensor_2d(ctx, wtype, dim_in, dim_out * 2);
|
||||
params["proj.bias"] = ggml_new_tensor_1d(ctx, bias_wtype, dim_out * 2);
|
||||
}
|
||||
|
||||
public:
|
||||
GEGLU(int64_t dim_in, int64_t dim_out)
|
||||
: dim_in(dim_in), dim_out(dim_out) {}
|
||||
: dim_in(dim_in), dim_out(dim_out) {
|
||||
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Linear(dim_in, dim_out * 2));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) override {
|
||||
// x: [ne3, ne2, ne1, dim_in]
|
||||
// return: [ne3, ne2, ne1, dim_out]
|
||||
struct ggml_tensor* w = params["proj.weight"];
|
||||
struct ggml_tensor* b = params["proj.bias"];
|
||||
auto proj = std::dynamic_pointer_cast<Linear>(blocks["proj"]);
|
||||
|
||||
auto x_w = ggml_view_2d(ctx->ggml_ctx, w, w->ne[0], w->ne[1] / 2, w->nb[1], 0); // [dim_out, dim_in]
|
||||
auto x_b = ggml_view_1d(ctx->ggml_ctx, b, b->ne[0] / 2, 0); // [dim_out, dim_in]
|
||||
auto gate_w = ggml_view_2d(ctx->ggml_ctx, w, w->ne[0], w->ne[1] / 2, w->nb[1], w->nb[1] * w->ne[1] / 2); // [dim_out, ]
|
||||
auto gate_b = ggml_view_1d(ctx->ggml_ctx, b, b->ne[0] / 2, b->nb[0] * b->ne[0] / 2); // [dim_out, ]
|
||||
|
||||
auto x_in = x;
|
||||
x = ggml_ext_linear(ctx->ggml_ctx, x_in, x_w, x_b); // [ne3, ne2, ne1, dim_out]
|
||||
auto gate = ggml_ext_linear(ctx->ggml_ctx, x_in, gate_w, gate_b); // [ne3, ne2, ne1, dim_out]
|
||||
x = proj->forward(ctx, x); // [ne3, ne2, ne1, dim_out*2]
|
||||
auto x_vec = ggml_ext_chunk(ctx->ggml_ctx, x, 2, 0);
|
||||
x = x_vec[0]; // [ne3, ne2, ne1, dim_out]
|
||||
auto gate = x_vec[1]; // [ne3, ne2, ne1, dim_out]
|
||||
|
||||
gate = ggml_gelu_inplace(ctx->ggml_ctx, gate);
|
||||
|
||||
@@ -252,14 +242,18 @@ public:
|
||||
}
|
||||
|
||||
// net_1 is nn.Dropout(), skip for inference
|
||||
float scale = 1.f;
|
||||
bool force_prec_f32 = false;
|
||||
float scale = 1.f;
|
||||
if (precision_fix) {
|
||||
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 Vulkan without enabling force_prec_f32,
|
||||
// or when using CUDA but the weights are k-quants.
|
||||
blocks["net.2"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, dim_out, true, false, false, scale));
|
||||
blocks["net.2"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, dim_out, true, false, force_prec_f32, scale));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||
@@ -408,30 +402,56 @@ protected:
|
||||
int64_t d_head;
|
||||
int64_t depth = 1; // 1
|
||||
int64_t context_dim = 768; // hidden_size, 1024 for VERSION_SD2
|
||||
bool use_linear = false;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") {
|
||||
auto iter = tensor_storage_map.find(prefix + "proj_out.weight");
|
||||
if (iter != tensor_storage_map.end()) {
|
||||
int64_t inner_dim = n_head * d_head;
|
||||
if (iter->second.n_dims == 4 && use_linear) {
|
||||
use_linear = false;
|
||||
blocks["proj_in"] = std::make_shared<Conv2d>(in_channels, inner_dim, std::pair{1, 1});
|
||||
blocks["proj_out"] = std::make_shared<Conv2d>(inner_dim, in_channels, std::pair{1, 1});
|
||||
} else if (iter->second.n_dims == 2 && !use_linear) {
|
||||
use_linear = true;
|
||||
blocks["proj_in"] = std::make_shared<Linear>(in_channels, inner_dim);
|
||||
blocks["proj_out"] = std::make_shared<Linear>(inner_dim, in_channels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SpatialTransformer(int64_t in_channels,
|
||||
int64_t n_head,
|
||||
int64_t d_head,
|
||||
int64_t depth,
|
||||
int64_t context_dim)
|
||||
int64_t context_dim,
|
||||
bool use_linear)
|
||||
: in_channels(in_channels),
|
||||
n_head(n_head),
|
||||
d_head(d_head),
|
||||
depth(depth),
|
||||
context_dim(context_dim) {
|
||||
// We will convert unet transformer linear to conv2d 1x1 when loading the weights, so use_linear is always False
|
||||
context_dim(context_dim),
|
||||
use_linear(use_linear) {
|
||||
// disable_self_attn is always False
|
||||
int64_t inner_dim = n_head * d_head; // in_channels
|
||||
blocks["norm"] = std::shared_ptr<GGMLBlock>(new GroupNorm32(in_channels));
|
||||
blocks["proj_in"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, inner_dim, {1, 1}));
|
||||
if (use_linear) {
|
||||
blocks["proj_in"] = std::shared_ptr<GGMLBlock>(new Linear(in_channels, inner_dim));
|
||||
} else {
|
||||
blocks["proj_in"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, inner_dim, {1, 1}));
|
||||
}
|
||||
|
||||
for (int i = 0; i < depth; i++) {
|
||||
std::string name = "transformer_blocks." + std::to_string(i);
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(new BasicTransformerBlock(inner_dim, n_head, d_head, context_dim, false));
|
||||
}
|
||||
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Conv2d(inner_dim, in_channels, {1, 1}));
|
||||
if (use_linear) {
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, in_channels));
|
||||
} else {
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Conv2d(inner_dim, in_channels, {1, 1}));
|
||||
}
|
||||
}
|
||||
|
||||
virtual struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||
@@ -440,8 +460,8 @@ public:
|
||||
// x: [N, in_channels, h, w]
|
||||
// context: [N, max_position(aka n_token), hidden_size(aka context_dim)]
|
||||
auto norm = std::dynamic_pointer_cast<GroupNorm32>(blocks["norm"]);
|
||||
auto proj_in = std::dynamic_pointer_cast<Conv2d>(blocks["proj_in"]);
|
||||
auto proj_out = std::dynamic_pointer_cast<Conv2d>(blocks["proj_out"]);
|
||||
auto proj_in = std::dynamic_pointer_cast<UnaryBlock>(blocks["proj_in"]);
|
||||
auto proj_out = std::dynamic_pointer_cast<UnaryBlock>(blocks["proj_out"]);
|
||||
|
||||
auto x_in = x;
|
||||
int64_t n = x->ne[3];
|
||||
@@ -450,10 +470,15 @@ public:
|
||||
int64_t inner_dim = n_head * d_head;
|
||||
|
||||
x = norm->forward(ctx, x);
|
||||
x = proj_in->forward(ctx, x); // [N, inner_dim, h, w]
|
||||
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 2, 0, 3)); // [N, h, w, inner_dim]
|
||||
x = ggml_reshape_3d(ctx->ggml_ctx, x, inner_dim, w * h, n); // [N, h * w, inner_dim]
|
||||
if (use_linear) {
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 2, 0, 3)); // [N, h, w, inner_dim]
|
||||
x = ggml_reshape_3d(ctx->ggml_ctx, x, inner_dim, w * h, n); // [N, h * w, inner_dim]
|
||||
x = proj_in->forward(ctx, x); // [N, inner_dim, h, w]
|
||||
} else {
|
||||
x = proj_in->forward(ctx, x); // [N, inner_dim, h, w]
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 2, 0, 3)); // [N, h, w, inner_dim]
|
||||
x = ggml_reshape_3d(ctx->ggml_ctx, x, inner_dim, w * h, n); // [N, h * w, inner_dim]
|
||||
}
|
||||
|
||||
for (int i = 0; i < depth; i++) {
|
||||
std::string name = "transformer_blocks." + std::to_string(i);
|
||||
@@ -462,11 +487,19 @@ public:
|
||||
x = transformer_block->forward(ctx, x, context);
|
||||
}
|
||||
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); // [N, inner_dim, h * w]
|
||||
x = ggml_reshape_4d(ctx->ggml_ctx, x, w, h, inner_dim, n); // [N, inner_dim, h, w]
|
||||
if (use_linear) {
|
||||
// proj_out
|
||||
x = proj_out->forward(ctx, x); // [N, in_channels, h, w]
|
||||
|
||||
// proj_out
|
||||
x = proj_out->forward(ctx, x); // [N, in_channels, h, w]
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); // [N, inner_dim, h * w]
|
||||
x = ggml_reshape_4d(ctx->ggml_ctx, x, w, h, inner_dim, n); // [N, inner_dim, h, w]
|
||||
} else {
|
||||
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); // [N, inner_dim, h * w]
|
||||
x = ggml_reshape_4d(ctx->ggml_ctx, x, w, h, inner_dim, n); // [N, inner_dim, h, w]
|
||||
|
||||
// proj_out
|
||||
x = proj_out->forward(ctx, x); // [N, in_channels, h, w]
|
||||
}
|
||||
|
||||
x = ggml_add(ctx->ggml_ctx, x, x_in);
|
||||
return x;
|
||||
@@ -475,7 +508,7 @@ public:
|
||||
|
||||
class AlphaBlender : public GGMLBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, std::string prefix = "") override {
|
||||
// Get the type of the "mix_factor" tensor from the input tensors map with the specified prefix
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["mix_factor"] = ggml_new_tensor_1d(ctx, wtype, 1);
|
||||
|
||||
+117
-31
@@ -34,6 +34,7 @@ struct Conditioner {
|
||||
virtual void free_params_buffer() = 0;
|
||||
virtual void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) = 0;
|
||||
virtual size_t get_params_buffer_size() = 0;
|
||||
virtual void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) {}
|
||||
virtual std::tuple<SDCondition, std::vector<bool>> get_learned_condition_with_trigger(ggml_context* work_ctx,
|
||||
int n_threads,
|
||||
const ConditionerParams& conditioner_params) {
|
||||
@@ -63,19 +64,19 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
||||
|
||||
FrozenCLIPEmbedderWithCustomWords(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string& embd_dir,
|
||||
SDVersion version = VERSION_SD1,
|
||||
PMVersion pv = PM_VERSION_1)
|
||||
: version(version), pm_version(pv), tokenizer(sd_version_is_sd2(version) ? 0 : 49407), embd_dir(embd_dir) {
|
||||
bool force_clip_f32 = embd_dir.size() > 0;
|
||||
if (sd_version_is_sd1(version)) {
|
||||
text_model = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "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)) {
|
||||
text_model = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "cond_stage_model.transformer.text_model", OPEN_CLIP_VIT_H_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", OPEN_CLIP_VIT_H_14, true, force_clip_f32);
|
||||
} else if (sd_version_is_sdxl(version)) {
|
||||
text_model = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "cond_stage_model.transformer.text_model", OPENAI_CLIP_VIT_L_14, false, force_clip_f32);
|
||||
text_model2 = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "cond_stage_model.1.transformer.text_model", OPEN_CLIP_VIT_BIGG_14, false, 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, false, force_clip_f32);
|
||||
text_model2 = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "cond_stage_model.1.transformer.text_model", OPEN_CLIP_VIT_BIGG_14, false, force_clip_f32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +109,17 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
text_model->set_weight_adapter(adapter);
|
||||
if (sd_version_is_sdxl(version)) {
|
||||
text_model2->set_weight_adapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
bool load_embedding(std::string embd_name, std::string embd_path, std::vector<int32_t>& bpe_tokens) {
|
||||
// the order matters
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(embd_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(embd_path)) {
|
||||
LOG_ERROR("embedding '%s' failed", embd_name.c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -270,13 +278,30 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
||||
const std::string& curr_text = item.first;
|
||||
float curr_weight = item.second;
|
||||
// printf(" %s: %f \n", curr_text.c_str(), curr_weight);
|
||||
int32_t clean_index = 0;
|
||||
if (curr_text == "BREAK" && curr_weight == -1.0f) {
|
||||
// Pad token array up to chunk size at this point.
|
||||
// TODO: This is a hardcoded chunk_len, like in stable-diffusion.cpp, make it a parameter for the future?
|
||||
// Also, this is 75 instead of 77 to leave room for BOS and EOS tokens.
|
||||
int padding_size = 75 - (tokens_acc % 75);
|
||||
for (int j = 0; j < padding_size; j++) {
|
||||
clean_input_ids.push_back(tokenizer.EOS_TOKEN_ID);
|
||||
clean_index++;
|
||||
}
|
||||
|
||||
// After padding, continue to the next iteration to process the following text as a new segment
|
||||
tokens.insert(tokens.end(), clean_input_ids.begin(), clean_input_ids.end());
|
||||
weights.insert(weights.end(), padding_size, curr_weight);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Regular token, process normally
|
||||
std::vector<int> curr_tokens = tokenizer.encode(curr_text, on_new_token_cb);
|
||||
int32_t clean_index = 0;
|
||||
for (uint32_t i = 0; i < curr_tokens.size(); i++) {
|
||||
int token_id = curr_tokens[i];
|
||||
if (token_id == image_token)
|
||||
if (token_id == image_token) {
|
||||
class_token_index.push_back(clean_index - 1);
|
||||
else {
|
||||
} else {
|
||||
clean_input_ids.push_back(token_id);
|
||||
clean_index++;
|
||||
}
|
||||
@@ -379,6 +404,22 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
||||
for (const auto& item : parsed_attention) {
|
||||
const std::string& curr_text = item.first;
|
||||
float curr_weight = item.second;
|
||||
|
||||
if (curr_text == "BREAK" && curr_weight == -1.0f) {
|
||||
// Pad token array up to chunk size at this point.
|
||||
// TODO: This is a hardcoded chunk_len, like in stable-diffusion.cpp, make it a parameter for the future?
|
||||
// Also, this is 75 instead of 77 to leave room for BOS and EOS tokens.
|
||||
size_t current_size = tokens.size();
|
||||
size_t padding_size = (75 - (current_size % 75)) % 75; // Ensure no negative padding
|
||||
|
||||
if (padding_size > 0) {
|
||||
LOG_DEBUG("BREAK token encountered, padding current chunk by %zu tokens.", padding_size);
|
||||
tokens.insert(tokens.end(), padding_size, tokenizer.EOS_TOKEN_ID);
|
||||
weights.insert(weights.end(), padding_size, 1.0f);
|
||||
}
|
||||
continue; // Skip to the next item after handling BREAK
|
||||
}
|
||||
|
||||
std::vector<int> curr_tokens = tokenizer.encode(curr_text, on_new_token_cb);
|
||||
tokens.insert(tokens.end(), curr_tokens.begin(), curr_tokens.end());
|
||||
weights.insert(weights.end(), curr_tokens.size(), curr_weight);
|
||||
@@ -623,9 +664,21 @@ struct FrozenCLIPVisionEmbedder : public GGMLRunner {
|
||||
|
||||
FrozenCLIPVisionEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {})
|
||||
: vision_model(OPEN_CLIP_VIT_H_14), GGMLRunner(backend, offload_params_to_cpu) {
|
||||
vision_model.init(params_ctx, tensor_types, "cond_stage_model.transformer");
|
||||
const String2TensorStorage& tensor_storage_map = {})
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
std::string prefix = "cond_stage_model.transformer";
|
||||
bool proj_in = false;
|
||||
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (!starts_with(name, prefix)) {
|
||||
continue;
|
||||
}
|
||||
if (contains(name, "self_attn.in_proj")) {
|
||||
proj_in = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vision_model = CLIPVisionModelProjection(OPEN_CLIP_VIT_H_14, false, proj_in);
|
||||
vision_model.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -673,12 +726,12 @@ struct SD3CLIPEmbedder : public Conditioner {
|
||||
|
||||
SD3CLIPEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {})
|
||||
const String2TensorStorage& tensor_storage_map = {})
|
||||
: clip_g_tokenizer(0) {
|
||||
bool use_clip_l = false;
|
||||
bool use_clip_g = false;
|
||||
bool use_t5 = false;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
if (pair.first.find("text_encoders.clip_l") != std::string::npos) {
|
||||
use_clip_l = true;
|
||||
} else if (pair.first.find("text_encoders.clip_g") != std::string::npos) {
|
||||
@@ -692,13 +745,13 @@ struct SD3CLIPEmbedder : public Conditioner {
|
||||
return;
|
||||
}
|
||||
if (use_clip_l) {
|
||||
clip_l = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.clip_l.transformer.text_model", OPENAI_CLIP_VIT_L_14, false);
|
||||
clip_l = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.clip_l.transformer.text_model", OPENAI_CLIP_VIT_L_14, false);
|
||||
}
|
||||
if (use_clip_g) {
|
||||
clip_g = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.clip_g.transformer.text_model", OPEN_CLIP_VIT_BIGG_14, false);
|
||||
clip_g = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.clip_g.transformer.text_model", OPEN_CLIP_VIT_BIGG_14, false);
|
||||
}
|
||||
if (use_t5) {
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.t5xxl.transformer");
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.t5xxl.transformer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -752,6 +805,18 @@ struct SD3CLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (clip_l) {
|
||||
clip_l->set_weight_adapter(adapter);
|
||||
}
|
||||
if (clip_g) {
|
||||
clip_g->set_weight_adapter(adapter);
|
||||
}
|
||||
if (t5) {
|
||||
t5->set_weight_adapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::vector<int>, std::vector<float>>> tokenize(std::string text,
|
||||
size_t max_length = 0,
|
||||
bool padding = false) {
|
||||
@@ -1082,10 +1147,10 @@ struct FluxCLIPEmbedder : public Conditioner {
|
||||
|
||||
FluxCLIPEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {}) {
|
||||
const String2TensorStorage& tensor_storage_map = {}) {
|
||||
bool use_clip_l = false;
|
||||
bool use_t5 = false;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
if (pair.first.find("text_encoders.clip_l") != std::string::npos) {
|
||||
use_clip_l = true;
|
||||
} else if (pair.first.find("text_encoders.t5xxl") != std::string::npos) {
|
||||
@@ -1099,12 +1164,12 @@ struct FluxCLIPEmbedder : public Conditioner {
|
||||
}
|
||||
|
||||
if (use_clip_l) {
|
||||
clip_l = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.clip_l.transformer.text_model", OPENAI_CLIP_VIT_L_14, true);
|
||||
clip_l = std::make_shared<CLIPTextModelRunner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.clip_l.transformer.text_model", OPENAI_CLIP_VIT_L_14, true);
|
||||
} else {
|
||||
LOG_WARN("clip_l text encoder not found! Prompt adherence might be degraded.");
|
||||
}
|
||||
if (use_t5) {
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.t5xxl.transformer");
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.t5xxl.transformer");
|
||||
} else {
|
||||
LOG_WARN("t5xxl text encoder not found! Prompt adherence might be degraded.");
|
||||
}
|
||||
@@ -1148,6 +1213,15 @@ struct FluxCLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) {
|
||||
if (clip_l) {
|
||||
clip_l->set_weight_adapter(adapter);
|
||||
}
|
||||
if (t5) {
|
||||
t5->set_weight_adapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::vector<int>, std::vector<float>>> tokenize(std::string text,
|
||||
size_t max_length = 0,
|
||||
bool padding = false) {
|
||||
@@ -1342,13 +1416,13 @@ struct T5CLIPEmbedder : public Conditioner {
|
||||
|
||||
T5CLIPEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
bool use_mask = false,
|
||||
int mask_pad = 1,
|
||||
bool is_umt5 = false)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
bool use_mask = false,
|
||||
int mask_pad = 1,
|
||||
bool is_umt5 = false)
|
||||
: use_mask(use_mask), mask_pad(mask_pad), t5_tokenizer(is_umt5) {
|
||||
bool use_t5 = false;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
if (pair.first.find("text_encoders.t5xxl") != std::string::npos) {
|
||||
use_t5 = true;
|
||||
}
|
||||
@@ -1358,7 +1432,7 @@ struct T5CLIPEmbedder : public Conditioner {
|
||||
LOG_WARN("IMPORTANT NOTICE: No text encoders provided, cannot process prompts!");
|
||||
return;
|
||||
} else {
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_types, "text_encoders.t5xxl.transformer", is_umt5);
|
||||
t5 = std::make_shared<T5Runner>(backend, offload_params_to_cpu, tensor_storage_map, "text_encoders.t5xxl.transformer", is_umt5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,6 +1462,12 @@ struct T5CLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (t5) {
|
||||
t5->set_weight_adapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<std::vector<int>, std::vector<float>, std::vector<float>> tokenize(std::string text,
|
||||
size_t max_length = 0,
|
||||
bool padding = false) {
|
||||
@@ -1549,12 +1629,12 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
||||
|
||||
Qwen2_5_VLCLIPEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
bool enable_vision = false) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
bool enable_vision = false) {
|
||||
qwenvl = std::make_shared<Qwen::Qwen2_5_VLRunner>(backend,
|
||||
offload_params_to_cpu,
|
||||
tensor_types,
|
||||
tensor_storage_map,
|
||||
"text_encoders.qwen2vl",
|
||||
enable_vision);
|
||||
}
|
||||
@@ -1577,6 +1657,12 @@ struct Qwen2_5_VLCLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (qwenvl) {
|
||||
qwenvl->set_weight_adapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<std::vector<int>, std::vector<float>> tokenize(std::string text,
|
||||
size_t max_length = 0,
|
||||
size_t system_prompt_length = 0,
|
||||
|
||||
+7
-6
@@ -27,6 +27,7 @@ protected:
|
||||
int num_heads = 8;
|
||||
int num_head_channels = -1; // channels // num_heads
|
||||
int context_dim = 768; // 1024 for VERSION_SD2, 2048 for VERSION_SDXL
|
||||
bool use_linear_projection = false;
|
||||
|
||||
public:
|
||||
int model_channels = 320;
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
int64_t d_head,
|
||||
int64_t depth,
|
||||
int64_t context_dim) -> SpatialTransformer* {
|
||||
return new SpatialTransformer(in_channels, n_head, d_head, depth, context_dim);
|
||||
return new SpatialTransformer(in_channels, n_head, d_head, depth, context_dim, use_linear_projection);
|
||||
};
|
||||
|
||||
auto make_zero_conv = [&](int64_t channels) {
|
||||
@@ -318,10 +319,10 @@ struct ControlNet : public GGMLRunner {
|
||||
|
||||
ControlNet(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
SDVersion version = VERSION_SD1)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
SDVersion version = VERSION_SD1)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), control_net(version) {
|
||||
control_net.init(params_ctx, tensor_types, "");
|
||||
control_net.init(params_ctx, tensor_storage_map, "");
|
||||
}
|
||||
|
||||
~ControlNet() override {
|
||||
@@ -379,7 +380,7 @@ struct ControlNet : public GGMLRunner {
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y = nullptr) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, CONTROL_NET_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(CONTROL_NET_GRAPH_SIZE);
|
||||
|
||||
x = to_backend(x);
|
||||
if (guided_hint_cached) {
|
||||
@@ -441,7 +442,7 @@ struct ControlNet : public GGMLRunner {
|
||||
std::set<std::string> ignore_tensors;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path)) {
|
||||
LOG_ERROR("init control net model loader from file failed: '%s'", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
+81
-21
@@ -11,14 +11,13 @@
|
||||
#define TIMESTEPS 1000
|
||||
#define FLUX_TIMESTEPS 1000
|
||||
|
||||
struct SigmaSchedule {
|
||||
int version = 0;
|
||||
struct SigmaScheduler {
|
||||
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;
|
||||
};
|
||||
|
||||
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> 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> 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
|
||||
*/
|
||||
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 {
|
||||
const std::vector<float> noise_levels[] = {
|
||||
/* SD1.5 */
|
||||
@@ -169,19 +171,19 @@ struct AYSSchedule : SigmaSchedule {
|
||||
std::vector<float> results(n + 1);
|
||||
|
||||
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 */
|
||||
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];
|
||||
} 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];
|
||||
} else if (version == VERSION_SVD) {
|
||||
LOG_INFO("AYS using SVD noise levels");
|
||||
LOG_INFO("AYS_SCHEDULER using SVD noise levels");
|
||||
inputs = noise_levels[2];
|
||||
} else {
|
||||
LOG_ERROR("Version not compatible with AYS scheduler");
|
||||
LOG_ERROR("Version not compatible with AYS_SCHEDULER scheduler");
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -203,7 +205,7 @@ struct AYSSchedule : SigmaSchedule {
|
||||
/*
|
||||
* 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 {
|
||||
if (sigma_max <= 0.0f) {
|
||||
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> result;
|
||||
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 {
|
||||
// These *COULD* be function arguments here,
|
||||
// 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> result_sigmas;
|
||||
|
||||
@@ -299,8 +318,8 @@ struct SimpleSchedule : SigmaSchedule {
|
||||
}
|
||||
};
|
||||
|
||||
// Close to Beta Schedule, but increadably simple in code.
|
||||
struct SmoothStepSchedule : SigmaSchedule {
|
||||
// Close to Beta Scheduler, but increadably simple in code.
|
||||
struct SmoothStepScheduler : SigmaScheduler {
|
||||
static constexpr float smoothstep(float x) {
|
||||
return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
@@ -329,7 +348,6 @@ struct SmoothStepSchedule : SigmaSchedule {
|
||||
};
|
||||
|
||||
struct Denoiser {
|
||||
std::shared_ptr<SigmaSchedule> scheduler = std::make_shared<DiscreteSchedule>();
|
||||
virtual float sigma_min() = 0;
|
||||
virtual float sigma_max() = 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* 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, scheduler_t scheduler_type, SDVersion version) {
|
||||
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);
|
||||
}
|
||||
};
|
||||
@@ -426,7 +487,6 @@ struct EDMVDenoiser : public CompVisVDenoiser {
|
||||
|
||||
EDMVDenoiser(float min_sigma = 0.002, float max_sigma = 120.0)
|
||||
: min_sigma(min_sigma), max_sigma(max_sigma) {
|
||||
scheduler = std::make_shared<ExponentialSchedule>();
|
||||
}
|
||||
|
||||
float t_to_sigma(float t) override {
|
||||
@@ -1109,7 +1169,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
// end beta) (which unfortunately k-diffusion's data
|
||||
// structure hides from the denoiser), and the sigmas are
|
||||
// also needed to invert the behavior of CompVisDenoiser
|
||||
// (k-diffusion's LMSDiscreteScheduler)
|
||||
// (k-diffusion's LMSDiscreteSchedulerr)
|
||||
float beta_start = 0.00085f;
|
||||
float beta_end = 0.0120f;
|
||||
std::vector<double> alphas_cumprod;
|
||||
@@ -1137,7 +1197,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
|
||||
for (int i = 0; i < steps; i++) {
|
||||
// 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
|
||||
// 2. Most variables below follow Diffusers naming
|
||||
//
|
||||
|
||||
+40
-19
@@ -35,8 +35,9 @@ struct DiffusionModel {
|
||||
virtual void free_compute_buffer() = 0;
|
||||
virtual void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) = 0;
|
||||
virtual size_t get_params_buffer_size() = 0;
|
||||
virtual int64_t get_adm_in_channels() = 0;
|
||||
virtual void set_flash_attn_enabled(bool enabled) = 0;
|
||||
virtual void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter){};
|
||||
virtual int64_t get_adm_in_channels() = 0;
|
||||
virtual void set_flash_attn_enabled(bool enabled) = 0;
|
||||
};
|
||||
|
||||
struct UNetModel : public DiffusionModel {
|
||||
@@ -44,9 +45,9 @@ struct UNetModel : public DiffusionModel {
|
||||
|
||||
UNetModel(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
SDVersion version = VERSION_SD1)
|
||||
: unet(backend, offload_params_to_cpu, tensor_types, "model.diffusion_model", version) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
SDVersion version = VERSION_SD1)
|
||||
: unet(backend, offload_params_to_cpu, tensor_storage_map, "model.diffusion_model", version) {
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -73,6 +74,10 @@ struct UNetModel : public DiffusionModel {
|
||||
return unet.get_params_buffer_size();
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
unet.set_weight_adapter(adapter);
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() override {
|
||||
return unet.unet.adm_in_channels;
|
||||
}
|
||||
@@ -102,8 +107,8 @@ struct MMDiTModel : public DiffusionModel {
|
||||
|
||||
MMDiTModel(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {})
|
||||
: mmdit(backend, offload_params_to_cpu, tensor_types, "model.diffusion_model") {
|
||||
const String2TensorStorage& tensor_storage_map = {})
|
||||
: mmdit(backend, offload_params_to_cpu, tensor_storage_map, "model.diffusion_model") {
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -130,6 +135,10 @@ struct MMDiTModel : public DiffusionModel {
|
||||
return mmdit.get_params_buffer_size();
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
mmdit.set_weight_adapter(adapter);
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768 + 1280;
|
||||
}
|
||||
@@ -158,10 +167,10 @@ struct FluxModel : public DiffusionModel {
|
||||
|
||||
FluxModel(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
SDVersion version = VERSION_FLUX,
|
||||
bool use_mask = false)
|
||||
: flux(backend, offload_params_to_cpu, tensor_types, "model.diffusion_model", version, use_mask) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
SDVersion version = VERSION_FLUX,
|
||||
bool use_mask = false)
|
||||
: flux(backend, offload_params_to_cpu, tensor_storage_map, "model.diffusion_model", version, use_mask) {
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -188,6 +197,10 @@ struct FluxModel : public DiffusionModel {
|
||||
return flux.get_params_buffer_size();
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
flux.set_weight_adapter(adapter);
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
@@ -221,10 +234,10 @@ struct WanModel : public DiffusionModel {
|
||||
|
||||
WanModel(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "model.diffusion_model",
|
||||
SDVersion version = VERSION_WAN2)
|
||||
: prefix(prefix), wan(backend, offload_params_to_cpu, tensor_types, prefix, version) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "model.diffusion_model",
|
||||
SDVersion version = VERSION_WAN2)
|
||||
: prefix(prefix), wan(backend, offload_params_to_cpu, tensor_storage_map, prefix, version) {
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -251,6 +264,10 @@ struct WanModel : public DiffusionModel {
|
||||
return wan.get_params_buffer_size();
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
wan.set_weight_adapter(adapter);
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
@@ -283,10 +300,10 @@ struct QwenImageModel : public DiffusionModel {
|
||||
|
||||
QwenImageModel(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "model.diffusion_model",
|
||||
SDVersion version = VERSION_QWEN_IMAGE)
|
||||
: prefix(prefix), qwen_image(backend, offload_params_to_cpu, tensor_types, prefix, version) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "model.diffusion_model",
|
||||
SDVersion version = VERSION_QWEN_IMAGE)
|
||||
: prefix(prefix), qwen_image(backend, offload_params_to_cpu, tensor_storage_map, prefix, version) {
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -313,6 +330,10 @@ struct QwenImageModel : public DiffusionModel {
|
||||
return qwen_image.get_params_buffer_size();
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
qwen_image.set_weight_adapter(adapter);
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
|
||||
+50
-37
@@ -1,40 +1,66 @@
|
||||
# Running distilled models: SSD1B and SD1.x with tiny U-Nets
|
||||
# Running distilled models: SSD1B and SDx.x with tiny U-Nets
|
||||
|
||||
## Preface
|
||||
## Preface
|
||||
|
||||
This kind of models have a reduced U-Net part.
|
||||
Unlike other SDXL models the U-Net of SSD1B has only one middle block and lesser attention layers in up and down blocks, resulting in relatively smaller files. Running these models saves more than 33% of the time. For more details, refer to Segmind's paper on https://arxiv.org/abs/2401.02677v1 .
|
||||
Unlike other SD 1.x models Tiny-UNet models consist of only 6 U-Net blocks, resulting in relatively smaller files (approximately 1 GB). Running these models saves almost 50% of the time. For more details, refer to the paper: https://arxiv.org/pdf/2305.15798.pdf .
|
||||
These models feature a reduced U-Net architecture. Unlike standard SDXL models, the SSD-1B U-Net contains only one middle block and fewer attention layers in its up- and down-blocks, resulting in significantly smaller file sizes. Using these models can reduce inference time by more than 33%. For more details, refer to Segmind's paper: https://arxiv.org/abs/2401.02677v1.
|
||||
Similarly, SD1.x- and SD2.x-style models with a tiny U-Net consist of only 6 U-Net blocks, leading to very small files and time savings of up to 50%. For more information, see the paper: https://arxiv.org/pdf/2305.15798.pdf.
|
||||
|
||||
## SSD1B
|
||||
|
||||
Unfortunately not all of this models follow the standard model parameter naming mapping.
|
||||
Anyway there are some very useful SSD1B models available online, such as:
|
||||
Note that not all of these models follow the standard parameter naming conventions. However, several useful SSD-1B models are available online, such as:
|
||||
|
||||
* https://huggingface.co/segmind/SSD-1B/resolve/main/SSD-1B-A1111.safetensors
|
||||
* https://huggingface.co/hassenhamdi/SSD-1B-fp8_e4m3fn/resolve/main/SSD-1B_fp8_e4m3fn.safetensors
|
||||
* https://huggingface.co/hassenhamdi/SSD-1B-fp8_e4m3fn/resolve/main/SSD-1B_fp8_e4m3fn.safetensors
|
||||
|
||||
Also there are useful LORAs available:
|
||||
Useful LoRAs are also available:
|
||||
|
||||
* https://huggingface.co/seungminh/lora-swarovski-SSD-1B/resolve/main/pytorch_lora_weights.safetensors
|
||||
* https://huggingface.co/kylielee505/mylcmlorassd/resolve/main/pytorch_lora_weights.safetensors
|
||||
* https://huggingface.co/kylielee505/mylcmlorassd/resolve/main/pytorch_lora_weights.safetensors
|
||||
|
||||
You can use this files **out-of-the-box** - unlike models in next section.
|
||||
These files can be used out-of-the-box, unlike the models described in the next section.
|
||||
|
||||
|
||||
## SD1.x with tiny U-Nets
|
||||
## SD1.x, SD2.x with tiny U-Nets
|
||||
|
||||
There are some Tiny SD 1.x models available online, such as:
|
||||
These models require conversion before use. You will need a Python script provided by the diffusers team, available on GitHub:
|
||||
|
||||
* https://raw.githubusercontent.com/huggingface/diffusers/refs/heads/main/scripts/convert_diffusers_to_original_stable_diffusion.py
|
||||
|
||||
### SD2.x
|
||||
|
||||
NotaAI provides the following model online:
|
||||
|
||||
* https://huggingface.co/nota-ai/bk-sdm-v2-tiny
|
||||
|
||||
Creating a .safetensors file involves two steps. First, run this short Python script to download the model from Hugging Face:
|
||||
|
||||
```python
|
||||
from diffusers import StableDiffusionPipeline
|
||||
pipe = StableDiffusionPipeline.from_pretrained("nota-ai/bk-sdm-v2-tiny",cache_dir="./")
|
||||
```
|
||||
|
||||
Second, create the .safetensors file by running:
|
||||
|
||||
```bash
|
||||
python convert_diffusers_to_original_stable_diffusion.py \
|
||||
--model_path models--nota-ai--bk-sdm-v2-tiny/snapshots/68277af553777858cd47e133f92e4db47321bc74 \
|
||||
--checkpoint_path bk-sdm-v2-tiny.safetensors --half --use_safetensors
|
||||
```
|
||||
|
||||
This will generate the **file bk-sdm-v2-tiny.safetensors**, which is now ready for use with sd.cpp.
|
||||
|
||||
### SD1.x
|
||||
|
||||
Several Tiny SD 1.x models are available online, such as:
|
||||
|
||||
* https://huggingface.co/segmind/tiny-sd
|
||||
* https://huggingface.co/segmind/portrait-finetuned
|
||||
* https://huggingface.co/nota-ai/bk-sdm-tiny
|
||||
|
||||
These models need some conversion, for example because partially tensors are **non contiguous** stored. To create a usable checkpoint file, follow these **easy** steps:
|
||||
These models also require conversion, partly because some tensors are stored in a non-contiguous manner. To create a usable checkpoint file, follow these simple steps:
|
||||
Download and prepare the model using Python:
|
||||
|
||||
### Download model from Hugging Face
|
||||
|
||||
Download the model using Python on your computer, for example this way:
|
||||
##### Download the model using Python on your computer, for example this way:
|
||||
|
||||
```python
|
||||
import torch
|
||||
@@ -46,35 +72,22 @@ for param in unet.parameters():
|
||||
pipe.save_pretrained("segmindtiny-sd", safe_serialization=True)
|
||||
```
|
||||
|
||||
### Convert that to a ckpt file
|
||||
|
||||
To convert the downloaded model to a checkpoint file, you need another Python script. Download the conversion script from here:
|
||||
|
||||
* https://raw.githubusercontent.com/huggingface/diffusers/refs/heads/main/scripts/convert_diffusers_to_original_stable_diffusion.py
|
||||
|
||||
|
||||
### Run convert script
|
||||
|
||||
Now, run that conversion script:
|
||||
##### Run the conversion script:
|
||||
|
||||
```bash
|
||||
python convert_diffusers_to_original_stable_diffusion.py \
|
||||
--model_path ./segmindtiny-sd \
|
||||
--checkpoint_path ./segmind_tiny-sd.ckpt --half
|
||||
--model_path ./segmindtiny-sd \
|
||||
--checkpoint_path ./segmind_tiny-sd.ckpt --half
|
||||
```
|
||||
|
||||
The file **segmind_tiny-sd.ckpt** will be generated and is now ready to use with sd.cpp
|
||||
|
||||
You can follow a similar process for other models mentioned above from Hugging Face.
|
||||
The file segmind_tiny-sd.ckpt will be generated and is now ready for use with sd.cpp. You can follow a similar process for the other models mentioned above.
|
||||
|
||||
|
||||
### Another ckpt file on the net
|
||||
|
||||
There is another model file available online:
|
||||
### Another available .ckpt file:
|
||||
|
||||
* https://huggingface.co/ClashSAN/small-sd/resolve/main/tinySDdistilled.ckpt
|
||||
|
||||
If you want to use that, you have to adjust some **non-contiguous tensors** first:
|
||||
|
||||
To use this file, you must first adjust its non-contiguous tensors:
|
||||
|
||||
```python
|
||||
import torch
|
||||
|
||||
+9
-32
@@ -12,38 +12,15 @@ Here's a simple example:
|
||||
|
||||
`../models/marblesh.safetensors` or `../models/marblesh.ckpt` will be applied to the model
|
||||
|
||||
# Support matrix
|
||||
# Lora Apply Mode
|
||||
|
||||
> ℹ️ CUDA `get_rows` support is defined here:
|
||||
> [ggml-org/ggml/src/ggml-cuda/getrows.cu#L156](https://github.com/ggml-org/ggml/blob/7dee1d6a1e7611f238d09be96738388da97c88ed/src/ggml-cuda/getrows.cu#L156)
|
||||
> Currently only the basic types + Q4/Q5/Q8 are implemented. K-quants are **not** supported.
|
||||
There are two ways to apply LoRA: **immediately** and **at_runtime**. You can specify it using the `--lora-apply-mode` parameter.
|
||||
|
||||
NOTE: The other backends may have different support.
|
||||
By default, the mode is selected automatically:
|
||||
|
||||
* If the model weights contain any quantized parameters, the **at_runtime** mode is used;
|
||||
* Otherwise, the **immediately** mode is 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.
|
||||
In contrast, the **at_runtime** mode provides better compatibility and higher precision, but inference may be slower and memory usage may be higher in some cases.
|
||||
|
||||
| Quant / Type | CUDA | Vulkan |
|
||||
|--------------|------|--------|
|
||||
| F32 | ✔️ | ✔️ |
|
||||
| F16 | ✔️ | ✔️ |
|
||||
| BF16 | ✔️ | ✔️ |
|
||||
| I32 | ✔️ | ❌ |
|
||||
| Q4_0 | ✔️ | ✔️ |
|
||||
| Q4_1 | ✔️ | ✔️ |
|
||||
| Q5_0 | ✔️ | ✔️ |
|
||||
| Q5_1 | ✔️ | ✔️ |
|
||||
| Q8_0 | ✔️ | ✔️ |
|
||||
| Q2_K | ❌ | ❌ |
|
||||
| Q3_K | ❌ | ❌ |
|
||||
| Q4_K | ❌ | ❌ |
|
||||
| Q5_K | ❌ | ❌ |
|
||||
| Q6_K | ❌ | ❌ |
|
||||
| Q8_K | ❌ | ❌ |
|
||||
| IQ1_S | ❌ | ✔️ |
|
||||
| IQ1_M | ❌ | ✔️ |
|
||||
| IQ2_XXS | ❌ | ✔️ |
|
||||
| IQ2_XS | ❌ | ✔️ |
|
||||
| IQ2_S | ❌ | ✔️ |
|
||||
| IQ3_XXS | ❌ | ✔️ |
|
||||
| IQ3_S | ❌ | ✔️ |
|
||||
| IQ4_XS | ❌ | ✔️ |
|
||||
| IQ4_NL | ❌ | ✔️ |
|
||||
| MXFP4 | ❌ | ✔️ |
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ Running PMV2 is now a two-step process:
|
||||
```
|
||||
python face_detect.py input_image_dir
|
||||
```
|
||||
An ```id_embeds.safetensors``` file will be generated in ```input_images_dir```
|
||||
An ```id_embeds.bin``` file will be generated in ```input_images_dir```
|
||||
|
||||
**Note: this step is only needed to run once; the same ```id_embeds``` can be reused**
|
||||
|
||||
@@ -48,6 +48,6 @@ An ```id_embeds.safetensors``` file will be generated in ```input_images_dir```
|
||||
|
||||
You can download ```photomaker-v2.safetensors``` from [here](https://huggingface.co/bssrdf/PhotoMakerV2)
|
||||
|
||||
- All the command line parameters from Version 1 remain the same for Version 2
|
||||
- All the command line parameters from Version 1 remain the same for Version 2 plus one extra pointing to a valid ```id_embeds``` file: --pm-id-embed-path [path_to__id_embeds.bin]
|
||||
|
||||
|
||||
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "denoiser.hpp"
|
||||
#include "ggml_extend.hpp"
|
||||
|
||||
struct EasyCacheConfig {
|
||||
bool enabled = false;
|
||||
float reuse_threshold = 0.2f;
|
||||
float start_percent = 0.15f;
|
||||
float end_percent = 0.95f;
|
||||
};
|
||||
|
||||
struct EasyCacheCacheEntry {
|
||||
std::vector<float> diff;
|
||||
};
|
||||
|
||||
struct EasyCacheState {
|
||||
EasyCacheConfig config;
|
||||
Denoiser* denoiser = nullptr;
|
||||
float start_sigma = std::numeric_limits<float>::max();
|
||||
float end_sigma = 0.0f;
|
||||
bool initialized = false;
|
||||
bool initial_step = true;
|
||||
bool skip_current_step = false;
|
||||
bool step_active = false;
|
||||
const SDCondition* anchor_condition = nullptr;
|
||||
std::unordered_map<const SDCondition*, EasyCacheCacheEntry> cache_diffs;
|
||||
std::vector<float> prev_input;
|
||||
std::vector<float> prev_output;
|
||||
float output_prev_norm = 0.0f;
|
||||
bool has_prev_input = false;
|
||||
bool has_prev_output = false;
|
||||
bool has_output_prev_norm = false;
|
||||
bool has_relative_transformation_rate = false;
|
||||
float relative_transformation_rate = 0.0f;
|
||||
float cumulative_change_rate = 0.0f;
|
||||
float last_input_change = 0.0f;
|
||||
bool has_last_input_change = false;
|
||||
int total_steps_skipped = 0;
|
||||
int current_step_index = -1;
|
||||
|
||||
void reset_runtime() {
|
||||
initial_step = true;
|
||||
skip_current_step = false;
|
||||
step_active = false;
|
||||
anchor_condition = nullptr;
|
||||
cache_diffs.clear();
|
||||
prev_input.clear();
|
||||
prev_output.clear();
|
||||
output_prev_norm = 0.0f;
|
||||
has_prev_input = false;
|
||||
has_prev_output = false;
|
||||
has_output_prev_norm = false;
|
||||
has_relative_transformation_rate = false;
|
||||
relative_transformation_rate = 0.0f;
|
||||
cumulative_change_rate = 0.0f;
|
||||
last_input_change = 0.0f;
|
||||
has_last_input_change = false;
|
||||
total_steps_skipped = 0;
|
||||
current_step_index = -1;
|
||||
}
|
||||
|
||||
void init(const EasyCacheConfig& cfg, Denoiser* d) {
|
||||
config = cfg;
|
||||
denoiser = d;
|
||||
initialized = cfg.enabled && d != nullptr;
|
||||
reset_runtime();
|
||||
if (initialized) {
|
||||
start_sigma = percent_to_sigma(config.start_percent);
|
||||
end_sigma = percent_to_sigma(config.end_percent);
|
||||
}
|
||||
}
|
||||
|
||||
bool enabled() const {
|
||||
return initialized && config.enabled;
|
||||
}
|
||||
|
||||
float percent_to_sigma(float percent) const {
|
||||
if (!denoiser) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (percent <= 0.0f) {
|
||||
return std::numeric_limits<float>::max();
|
||||
}
|
||||
if (percent >= 1.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
float t = (1.0f - percent) * (TIMESTEPS - 1);
|
||||
return denoiser->t_to_sigma(t);
|
||||
}
|
||||
|
||||
void begin_step(int step_index, float sigma) {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
if (step_index == current_step_index) {
|
||||
return;
|
||||
}
|
||||
current_step_index = step_index;
|
||||
skip_current_step = false;
|
||||
has_last_input_change = false;
|
||||
step_active = false;
|
||||
if (sigma > start_sigma) {
|
||||
return;
|
||||
}
|
||||
if (!(sigma > end_sigma)) {
|
||||
return;
|
||||
}
|
||||
step_active = true;
|
||||
}
|
||||
|
||||
bool step_is_active() const {
|
||||
return enabled() && step_active;
|
||||
}
|
||||
|
||||
bool is_step_skipped() const {
|
||||
return enabled() && step_active && skip_current_step;
|
||||
}
|
||||
|
||||
bool has_cache(const SDCondition* cond) const {
|
||||
auto it = cache_diffs.find(cond);
|
||||
return it != cache_diffs.end() && !it->second.diff.empty();
|
||||
}
|
||||
|
||||
void update_cache(const SDCondition* cond, ggml_tensor* input, ggml_tensor* output) {
|
||||
EasyCacheCacheEntry& entry = cache_diffs[cond];
|
||||
size_t ne = static_cast<size_t>(ggml_nelements(output));
|
||||
entry.diff.resize(ne);
|
||||
float* out_data = (float*)output->data;
|
||||
float* in_data = (float*)input->data;
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
entry.diff[i] = out_data[i] - in_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
void apply_cache(const SDCondition* cond, ggml_tensor* input, ggml_tensor* output) {
|
||||
auto it = cache_diffs.find(cond);
|
||||
if (it == cache_diffs.end() || it->second.diff.empty()) {
|
||||
return;
|
||||
}
|
||||
copy_ggml_tensor(output, input);
|
||||
float* out_data = (float*)output->data;
|
||||
const std::vector<float>& diff = it->second.diff;
|
||||
for (size_t i = 0; i < diff.size(); ++i) {
|
||||
out_data[i] += diff[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool before_condition(const SDCondition* cond,
|
||||
ggml_tensor* input,
|
||||
ggml_tensor* output,
|
||||
float sigma,
|
||||
int step_index) {
|
||||
if (!enabled() || step_index < 0) {
|
||||
return false;
|
||||
}
|
||||
if (step_index != current_step_index) {
|
||||
begin_step(step_index, sigma);
|
||||
}
|
||||
if (!step_active) {
|
||||
return false;
|
||||
}
|
||||
if (initial_step) {
|
||||
anchor_condition = cond;
|
||||
initial_step = false;
|
||||
}
|
||||
bool is_anchor = (cond == anchor_condition);
|
||||
if (skip_current_step) {
|
||||
if (has_cache(cond)) {
|
||||
apply_cache(cond, input, output);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!is_anchor) {
|
||||
return false;
|
||||
}
|
||||
if (!has_prev_input || !has_prev_output || !has_cache(cond)) {
|
||||
return false;
|
||||
}
|
||||
size_t ne = static_cast<size_t>(ggml_nelements(input));
|
||||
if (prev_input.size() != ne) {
|
||||
return false;
|
||||
}
|
||||
float* input_data = (float*)input->data;
|
||||
last_input_change = 0.0f;
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
last_input_change += std::fabs(input_data[i] - prev_input[i]);
|
||||
}
|
||||
if (ne > 0) {
|
||||
last_input_change /= static_cast<float>(ne);
|
||||
}
|
||||
has_last_input_change = true;
|
||||
|
||||
if (has_output_prev_norm && has_relative_transformation_rate && last_input_change > 0.0f && output_prev_norm > 0.0f) {
|
||||
float approx_output_change_rate = (relative_transformation_rate * last_input_change) / output_prev_norm;
|
||||
cumulative_change_rate += approx_output_change_rate;
|
||||
if (cumulative_change_rate < config.reuse_threshold) {
|
||||
skip_current_step = true;
|
||||
total_steps_skipped++;
|
||||
apply_cache(cond, input, output);
|
||||
return true;
|
||||
} else {
|
||||
cumulative_change_rate = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void after_condition(const SDCondition* cond, ggml_tensor* input, ggml_tensor* output) {
|
||||
if (!step_is_active()) {
|
||||
return;
|
||||
}
|
||||
update_cache(cond, input, output);
|
||||
if (cond != anchor_condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t ne = static_cast<size_t>(ggml_nelements(input));
|
||||
float* in_data = (float*)input->data;
|
||||
prev_input.resize(ne);
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
prev_input[i] = in_data[i];
|
||||
}
|
||||
has_prev_input = true;
|
||||
|
||||
float* out_data = (float*)output->data;
|
||||
float output_change = 0.0f;
|
||||
if (has_prev_output && prev_output.size() == ne) {
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
output_change += std::fabs(out_data[i] - prev_output[i]);
|
||||
}
|
||||
if (ne > 0) {
|
||||
output_change /= static_cast<float>(ne);
|
||||
}
|
||||
}
|
||||
|
||||
prev_output.resize(ne);
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
prev_output[i] = out_data[i];
|
||||
}
|
||||
has_prev_output = true;
|
||||
|
||||
float mean_abs = 0.0f;
|
||||
for (size_t i = 0; i < ne; ++i) {
|
||||
mean_abs += std::fabs(out_data[i]);
|
||||
}
|
||||
output_prev_norm = (ne > 0) ? (mean_abs / static_cast<float>(ne)) : 0.0f;
|
||||
has_output_prev_norm = output_prev_norm > 0.0f;
|
||||
|
||||
if (has_last_input_change && last_input_change > 0.0f && output_change > 0.0f) {
|
||||
float rate = output_change / last_input_change;
|
||||
if (std::isfinite(rate)) {
|
||||
relative_transformation_rate = rate;
|
||||
has_relative_transformation_rate = true;
|
||||
}
|
||||
}
|
||||
cumulative_change_rate = 0.0f;
|
||||
has_last_input_change = false;
|
||||
}
|
||||
};
|
||||
+3
-3
@@ -156,7 +156,7 @@ struct ESRGAN : public GGMLRunner {
|
||||
|
||||
ESRGAN(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {})
|
||||
const String2TensorStorage& tensor_storage_map = {})
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
// rrdb_net will be created in load_from_file
|
||||
}
|
||||
@@ -169,7 +169,7 @@ struct ESRGAN : public GGMLRunner {
|
||||
LOG_INFO("loading esrgan from '%s'", file_path.c_str());
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path)) {
|
||||
LOG_ERROR("init esrgan model loader from file failed: '%s'", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -344,7 +344,7 @@ struct ESRGAN : public GGMLRunner {
|
||||
if (!rrdb_net)
|
||||
return nullptr;
|
||||
constexpr int kGraphNodes = 1 << 16; // 65k
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, kGraphNodes, /*grads*/ false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(kGraphNodes);
|
||||
x = to_backend(x);
|
||||
|
||||
auto runner_ctx = get_context();
|
||||
|
||||
+18
-4
@@ -32,6 +32,8 @@ Options:
|
||||
-o, --output <string> path to write result image to (default: ./output.png)
|
||||
-p, --prompt <string> the prompt to render
|
||||
-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
|
||||
@@ -48,6 +50,8 @@ Options:
|
||||
--fps <int> fps (default: 24)
|
||||
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for NitroSD-Realism around 250 and 500 for
|
||||
NitroSD-Vibrant
|
||||
--preview-interval <int> interval in denoising steps between consecutive updates of the image preview file (default is 1, meaning updating at
|
||||
every step)
|
||||
--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)
|
||||
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
||||
@@ -86,16 +90,25 @@ Options:
|
||||
--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).
|
||||
--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], default: cuda
|
||||
--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)
|
||||
--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)
|
||||
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow]
|
||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple], default:
|
||||
discrete
|
||||
--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, lcm],
|
||||
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,
|
||||
ddim_trailing, tcd] default: euler for Flux/SD3/Wan, euler_a otherwise
|
||||
@@ -107,4 +120,5 @@ Options:
|
||||
--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)
|
||||
```
|
||||
|
||||
+262
-40
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@@ -46,6 +47,13 @@ const char* modes_str[] = {
|
||||
};
|
||||
#define SD_ALL_MODES_STR "img_gen, vid_gen, convert, upscale"
|
||||
|
||||
const char* previews_str[] = {
|
||||
"none",
|
||||
"proj",
|
||||
"tae",
|
||||
"vae",
|
||||
};
|
||||
|
||||
enum SDMode {
|
||||
IMG_GEN,
|
||||
VID_GEN,
|
||||
@@ -98,26 +106,30 @@ struct SDParams {
|
||||
std::vector<int> high_noise_skip_layers = {7, 8, 9};
|
||||
sd_sample_params_t high_noise_sample_params;
|
||||
|
||||
std::string easycache_option;
|
||||
sd_easycache_params_t easycache_params;
|
||||
|
||||
float moe_boundary = 0.875f;
|
||||
int video_frames = 1;
|
||||
int fps = 16;
|
||||
float vace_strength = 1.f;
|
||||
|
||||
float strength = 0.75f;
|
||||
float control_strength = 0.9f;
|
||||
rng_type_t rng_type = CUDA_RNG;
|
||||
int64_t seed = 42;
|
||||
bool verbose = false;
|
||||
bool offload_params_to_cpu = false;
|
||||
bool control_net_cpu = false;
|
||||
bool clip_on_cpu = false;
|
||||
bool vae_on_cpu = false;
|
||||
bool diffusion_flash_attn = false;
|
||||
bool diffusion_conv_direct = false;
|
||||
bool vae_conv_direct = false;
|
||||
bool canny_preprocess = false;
|
||||
bool color = false;
|
||||
int upscale_repeats = 1;
|
||||
float strength = 0.75f;
|
||||
float control_strength = 0.9f;
|
||||
rng_type_t rng_type = CUDA_RNG;
|
||||
rng_type_t sampler_rng_type = RNG_TYPE_COUNT;
|
||||
int64_t seed = 42;
|
||||
bool verbose = false;
|
||||
bool offload_params_to_cpu = false;
|
||||
bool control_net_cpu = false;
|
||||
bool clip_on_cpu = false;
|
||||
bool vae_on_cpu = false;
|
||||
bool diffusion_flash_attn = false;
|
||||
bool diffusion_conv_direct = false;
|
||||
bool vae_conv_direct = false;
|
||||
bool canny_preprocess = false;
|
||||
bool color = false;
|
||||
int upscale_repeats = 1;
|
||||
|
||||
// Photo Maker
|
||||
std::string photo_maker_path;
|
||||
@@ -130,15 +142,23 @@ struct SDParams {
|
||||
int chroma_t5_mask_pad = 1;
|
||||
float flow_shift = INFINITY;
|
||||
|
||||
prediction_t prediction = DEFAULT_PRED;
|
||||
prediction_t prediction = DEFAULT_PRED;
|
||||
lora_apply_mode_t lora_apply_mode = LORA_APPLY_AUTO;
|
||||
|
||||
sd_tiling_params_t vae_tiling_params = {false, 0, 0, 0.5f, 0.0f, 0.0f};
|
||||
bool force_sdxl_vae_conv_scale = false;
|
||||
|
||||
preview_t preview_method = PREVIEW_NONE;
|
||||
int preview_interval = 1;
|
||||
std::string preview_path = "preview.png";
|
||||
bool taesd_preview = false;
|
||||
bool preview_noisy = false;
|
||||
|
||||
SDParams() {
|
||||
sd_sample_params_init(&sample_params);
|
||||
sd_sample_params_init(&high_noise_sample_params);
|
||||
high_noise_sample_params.sample_steps = -1;
|
||||
sd_easycache_params_init(&easycache_params);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -196,9 +216,11 @@ void print_params(SDParams params) {
|
||||
printf(" high_noise_sample_params: %s\n", SAFE_STR(high_noise_sample_params_str));
|
||||
printf(" moe_boundary: %.3f\n", params.moe_boundary);
|
||||
printf(" prediction: %s\n", sd_prediction_name(params.prediction));
|
||||
printf(" lora_apply_mode: %s\n", sd_lora_apply_mode_name(params.lora_apply_mode));
|
||||
printf(" flow_shift: %.2f\n", params.flow_shift);
|
||||
printf(" strength(img2img): %.2f\n", params.strength);
|
||||
printf(" rng: %s\n", sd_rng_type_name(params.rng_type));
|
||||
printf(" sampler rng: %s\n", sd_rng_type_name(params.sampler_rng_type));
|
||||
printf(" seed: %zd\n", params.seed);
|
||||
printf(" batch_count: %d\n", params.batch_count);
|
||||
printf(" vae_tiling: %s\n", params.vae_tiling_params.enabled ? "true" : "false");
|
||||
@@ -208,8 +230,15 @@ void print_params(SDParams params) {
|
||||
printf(" chroma_use_t5_mask: %s\n", params.chroma_use_t5_mask ? "true" : "false");
|
||||
printf(" chroma_t5_mask_pad: %d\n", params.chroma_t5_mask_pad);
|
||||
printf(" video_frames: %d\n", params.video_frames);
|
||||
printf(" easycache: %s (threshold=%.3f, start=%.2f, end=%.2f)\n",
|
||||
params.easycache_params.enabled ? "enabled" : "disabled",
|
||||
params.easycache_params.reuse_threshold,
|
||||
params.easycache_params.start_percent,
|
||||
params.easycache_params.end_percent);
|
||||
printf(" vace_strength: %.2f\n", params.vace_strength);
|
||||
printf(" fps: %d\n", params.fps);
|
||||
printf(" preview_mode: %s (%s)\n", previews_str[params.preview_method], params.preview_noisy ? "noisy" : "denoised");
|
||||
printf(" preview_interval: %d\n", params.preview_interval);
|
||||
free(sample_params_str);
|
||||
free(high_noise_sample_params_str);
|
||||
}
|
||||
@@ -589,6 +618,10 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"--negative-prompt",
|
||||
"the negative prompt (default: \"\")",
|
||||
¶ms.negative_prompt},
|
||||
{"",
|
||||
"--preview-path",
|
||||
"path to write preview image to (default: ./preview.png)",
|
||||
¶ms.preview_path},
|
||||
{"",
|
||||
"--upscale-model",
|
||||
"path to esrgan model.",
|
||||
@@ -647,6 +680,10 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"shift timestep for NitroFusion models (default: 0). "
|
||||
"recommended N for NitroSD-Realism around 250 and 500 for NitroSD-Vibrant",
|
||||
¶ms.sample_params.shifted_timestep},
|
||||
{"",
|
||||
"--preview-interval",
|
||||
"interval in denoising steps between consecutive updates of the image preview file (default is 1, meaning updating at every step)",
|
||||
¶ms.preview_interval},
|
||||
};
|
||||
|
||||
options.float_options = {
|
||||
@@ -801,7 +838,14 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"--disable-auto-resize-ref-image",
|
||||
"disable auto resize of ref images",
|
||||
false, ¶ms.auto_resize_ref_image},
|
||||
};
|
||||
{"",
|
||||
"--taesd-preview-only",
|
||||
std::string("prevents usage of taesd for decoding the final image. (for use with --preview ") + previews_str[PREVIEW_TAE] + ")",
|
||||
true, ¶ms.taesd_preview},
|
||||
{"",
|
||||
"--preview-noisy",
|
||||
"enables previewing noisy inputs of the models rather than the denoised outputs",
|
||||
true, ¶ms.preview_noisy}};
|
||||
|
||||
auto on_mode_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
@@ -854,28 +898,28 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_schedule_arg = [&](int argc, const char** argv, int index) {
|
||||
auto on_sampler_rng_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
}
|
||||
const char* arg = argv[index];
|
||||
params.sample_params.scheduler = str_to_schedule(arg);
|
||||
if (params.sample_params.scheduler == SCHEDULE_COUNT) {
|
||||
fprintf(stderr, "error: invalid scheduler %s\n",
|
||||
const char* arg = argv[index];
|
||||
params.sampler_rng_type = str_to_rng_type(arg);
|
||||
if (params.sampler_rng_type == RNG_TYPE_COUNT) {
|
||||
fprintf(stderr, "error: invalid sampler rng type %s\n",
|
||||
arg);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_high_noise_schedule_arg = [&](int argc, const char** argv, int index) {
|
||||
auto on_scheduler_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
}
|
||||
const char* arg = argv[index];
|
||||
params.high_noise_sample_params.scheduler = str_to_schedule(arg);
|
||||
if (params.high_noise_sample_params.scheduler == SCHEDULE_COUNT) {
|
||||
fprintf(stderr, "error: invalid high noise scheduler %s\n",
|
||||
const char* arg = argv[index];
|
||||
params.sample_params.scheduler = str_to_scheduler(arg);
|
||||
if (params.sample_params.scheduler == SCHEDULER_COUNT) {
|
||||
fprintf(stderr, "error: invalid scheduler %s\n",
|
||||
arg);
|
||||
return -1;
|
||||
}
|
||||
@@ -896,6 +940,20 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_lora_apply_mode_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
}
|
||||
const char* arg = argv[index];
|
||||
params.lora_apply_mode = str_to_lora_apply_mode(arg);
|
||||
if (params.lora_apply_mode == LORA_APPLY_MODE_COUNT) {
|
||||
fprintf(stderr, "error: invalid lora apply model %s\n",
|
||||
arg);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_sample_method_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
@@ -1046,6 +1104,58 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_preview_arg = [&](int argc, const char** argv, int index) {
|
||||
if (++index >= argc) {
|
||||
return -1;
|
||||
}
|
||||
const char* preview = argv[index];
|
||||
int preview_method = -1;
|
||||
for (int m = 0; m < PREVIEW_COUNT; m++) {
|
||||
if (!strcmp(preview, previews_str[m])) {
|
||||
preview_method = m;
|
||||
}
|
||||
}
|
||||
if (preview_method == -1) {
|
||||
fprintf(stderr, "error: preview method %s\n",
|
||||
preview);
|
||||
return -1;
|
||||
}
|
||||
params.preview_method = (preview_t)preview_method;
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto on_easycache_arg = [&](int argc, const char** argv, int index) {
|
||||
const std::string default_values = "0.2,0.15,0.95";
|
||||
auto looks_like_value = [](const std::string& token) {
|
||||
if (token.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (token[0] != '-') {
|
||||
return true;
|
||||
}
|
||||
if (token.size() == 1) {
|
||||
return false;
|
||||
}
|
||||
unsigned char next = static_cast<unsigned char>(token[1]);
|
||||
return std::isdigit(next) || token[1] == '.';
|
||||
};
|
||||
|
||||
std::string option_value;
|
||||
int consumed = 0;
|
||||
if (index + 1 < argc) {
|
||||
std::string next_arg = argv[index + 1];
|
||||
if (looks_like_value(next_arg)) {
|
||||
option_value = argv_to_utf8(index + 1, argv);
|
||||
consumed = 1;
|
||||
}
|
||||
}
|
||||
if (option_value.empty()) {
|
||||
option_value = default_values;
|
||||
}
|
||||
params.easycache_option = option_value;
|
||||
return consumed;
|
||||
};
|
||||
|
||||
options.manual_options = {
|
||||
{"-M",
|
||||
"--mode",
|
||||
@@ -1058,8 +1168,12 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
on_type_arg},
|
||||
{"",
|
||||
"--rng",
|
||||
"RNG, one of [std_default, cuda], default: cuda",
|
||||
"RNG, one of [std_default, cuda, cpu], default: cuda(sd-webui), cpu(comfyui)",
|
||||
on_rng_arg},
|
||||
{"",
|
||||
"--sampler-rng",
|
||||
"sampler RNG, one of [std_default, cuda, cpu]. If not specified, use --rng",
|
||||
on_sampler_rng_arg},
|
||||
{"-s",
|
||||
"--seed",
|
||||
"RNG seed (default: 42, use random seed for < 0)",
|
||||
@@ -1073,10 +1187,18 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"--prediction",
|
||||
"prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow]",
|
||||
on_prediction_arg},
|
||||
{"",
|
||||
"--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.",
|
||||
on_lora_apply_mode_arg},
|
||||
{"",
|
||||
"--scheduler",
|
||||
"denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple], default: discrete",
|
||||
on_schedule_arg},
|
||||
"denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple, lcm], default: discrete",
|
||||
on_scheduler_arg},
|
||||
{"",
|
||||
"--skip-layers",
|
||||
"layers to skip for SLG steps (default: [7,8,9])",
|
||||
@@ -1086,10 +1208,6 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"(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",
|
||||
on_high_noise_sample_method_arg},
|
||||
{"",
|
||||
"--high-noise-scheduler",
|
||||
"(high noise) denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple], default: discrete",
|
||||
on_high_noise_schedule_arg},
|
||||
{"",
|
||||
"--high-noise-skip-layers",
|
||||
"(high noise) layers to skip for SLG steps (default: [7,8,9])",
|
||||
@@ -1110,6 +1228,14 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
"--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)",
|
||||
on_relative_tile_size_arg},
|
||||
{"",
|
||||
"--preview",
|
||||
std::string("preview method. must be one of the following [") + previews_str[0] + ", " + previews_str[1] + ", " + previews_str[2] + ", " + previews_str[3] + "] (default is " + previews_str[PREVIEW_NONE] + ")\n",
|
||||
on_preview_arg},
|
||||
{"",
|
||||
"--easycache",
|
||||
"enable EasyCache for DiT models with optional \"threshold,start_percent,end_percent\" (default: 0.2,0.15,0.95)",
|
||||
on_easycache_arg},
|
||||
};
|
||||
|
||||
if (!parse_options(argc, argv, options)) {
|
||||
@@ -1117,6 +1243,59 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!params.easycache_option.empty()) {
|
||||
float values[3] = {0.0f, 0.0f, 0.0f};
|
||||
std::stringstream ss(params.easycache_option);
|
||||
std::string token;
|
||||
int idx = 0;
|
||||
while (std::getline(ss, token, ',')) {
|
||||
auto trim = [](std::string& s) {
|
||||
const char* whitespace = " \t\r\n";
|
||||
auto start = s.find_first_not_of(whitespace);
|
||||
if (start == std::string::npos) {
|
||||
s.clear();
|
||||
return;
|
||||
}
|
||||
auto end = s.find_last_not_of(whitespace);
|
||||
s = s.substr(start, end - start + 1);
|
||||
};
|
||||
trim(token);
|
||||
if (token.empty()) {
|
||||
fprintf(stderr, "error: invalid easycache option '%s'\n", params.easycache_option.c_str());
|
||||
exit(1);
|
||||
}
|
||||
if (idx >= 3) {
|
||||
fprintf(stderr, "error: easycache expects exactly 3 comma-separated values (threshold,start,end)\n");
|
||||
exit(1);
|
||||
}
|
||||
try {
|
||||
values[idx] = std::stof(token);
|
||||
} catch (const std::exception&) {
|
||||
fprintf(stderr, "error: invalid easycache value '%s'\n", token.c_str());
|
||||
exit(1);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
if (idx != 3) {
|
||||
fprintf(stderr, "error: easycache expects exactly 3 comma-separated values (threshold,start,end)\n");
|
||||
exit(1);
|
||||
}
|
||||
if (values[0] < 0.0f) {
|
||||
fprintf(stderr, "error: easycache threshold must be non-negative\n");
|
||||
exit(1);
|
||||
}
|
||||
if (values[1] < 0.0f || values[1] >= 1.0f || values[2] <= 0.0f || values[2] > 1.0f || values[1] >= values[2]) {
|
||||
fprintf(stderr, "error: easycache start/end percents must satisfy 0.0 <= start < end <= 1.0\n");
|
||||
exit(1);
|
||||
}
|
||||
params.easycache_params.enabled = true;
|
||||
params.easycache_params.reuse_threshold = values[0];
|
||||
params.easycache_params.start_percent = values[1];
|
||||
params.easycache_params.end_percent = values[2];
|
||||
} else {
|
||||
params.easycache_params.enabled = false;
|
||||
}
|
||||
|
||||
if (params.n_threads <= 0) {
|
||||
params.n_threads = get_num_physical_cores();
|
||||
}
|
||||
@@ -1163,10 +1342,6 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (params.mode != CONVERT && params.tensor_type_rules.size() > 0) {
|
||||
fprintf(stderr, "warning: --tensor-type-rules is currently supported only for conversion\n");
|
||||
}
|
||||
|
||||
if (params.mode == VID_GEN && params.video_frames <= 0) {
|
||||
fprintf(stderr, "warning: --video-frames must be at least 1\n");
|
||||
exit(1);
|
||||
@@ -1245,9 +1420,12 @@ std::string get_image_params(SDParams params, int64_t seed) {
|
||||
parameter_string += "Size: " + std::to_string(params.width) + "x" + std::to_string(params.height) + ", ";
|
||||
parameter_string += "Model: " + sd_basename(params.model_path) + ", ";
|
||||
parameter_string += "RNG: " + std::string(sd_rng_type_name(params.rng_type)) + ", ";
|
||||
if (params.sampler_rng_type != RNG_TYPE_COUNT) {
|
||||
parameter_string += "Sampler RNG: " + std::string(sd_rng_type_name(params.sampler_rng_type)) + ", ";
|
||||
}
|
||||
parameter_string += "Sampler: " + std::string(sd_sample_method_name(params.sample_params.sample_method));
|
||||
if (params.sample_params.scheduler != DEFAULT) {
|
||||
parameter_string += " " + std::string(sd_schedule_name(params.sample_params.scheduler));
|
||||
if (params.sample_params.scheduler != SCHEDULER_COUNT) {
|
||||
parameter_string += " " + std::string(sd_scheduler_name(params.sample_params.scheduler));
|
||||
}
|
||||
parameter_string += ", ";
|
||||
for (const auto& te : {params.clip_l_path, params.clip_g_path, params.t5xxl_path, params.qwen2vl_path, params.qwen2vl_vision_path}) {
|
||||
@@ -1452,15 +1630,49 @@ bool load_images_from_dir(const std::string dir,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string preview_path;
|
||||
float preview_fps;
|
||||
|
||||
void step_callback(int step, int frame_count, sd_image_t* image, bool is_noisy) {
|
||||
(void)step;
|
||||
(void)is_noisy;
|
||||
// is_noisy is set to true if the preview corresponds to noisy latents, false if it's denoised latents
|
||||
// unused in this app, it will either be always noisy or always denoised here
|
||||
if (frame_count == 1) {
|
||||
stbi_write_png(preview_path.c_str(), image->width, image->height, image->channel, image->data, 0);
|
||||
} else {
|
||||
create_mjpg_avi_from_sd_images(preview_path.c_str(), image, frame_count, preview_fps);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
SDParams params;
|
||||
parse_args(argc, argv, params);
|
||||
preview_path = params.preview_path;
|
||||
if (params.video_frames > 4) {
|
||||
size_t last_dot_pos = params.preview_path.find_last_of(".");
|
||||
std::string base_path = params.preview_path;
|
||||
std::string file_ext = "";
|
||||
if (last_dot_pos != std::string::npos) { // filename has extension
|
||||
base_path = params.preview_path.substr(0, last_dot_pos);
|
||||
file_ext = params.preview_path.substr(last_dot_pos);
|
||||
std::transform(file_ext.begin(), file_ext.end(), file_ext.begin(), ::tolower);
|
||||
}
|
||||
if (file_ext == ".png") {
|
||||
preview_path = base_path + ".avi";
|
||||
}
|
||||
}
|
||||
preview_fps = params.fps;
|
||||
if (params.preview_method == PREVIEW_PROJ)
|
||||
preview_fps /= 4.0f;
|
||||
|
||||
params.sample_params.guidance.slg.layers = params.skip_layers.data();
|
||||
params.sample_params.guidance.slg.layer_count = params.skip_layers.size();
|
||||
params.high_noise_sample_params.guidance.slg.layers = params.high_noise_skip_layers.data();
|
||||
params.high_noise_sample_params.guidance.slg.layer_count = params.high_noise_skip_layers.size();
|
||||
|
||||
sd_set_log_callback(sd_log_cb, (void*)¶ms);
|
||||
sd_set_preview_callback((sd_preview_cb_t)step_callback, params.preview_method, params.preview_interval, !params.preview_noisy, params.preview_noisy);
|
||||
|
||||
if (params.verbose) {
|
||||
print_params(params);
|
||||
@@ -1643,17 +1855,21 @@ int main(int argc, const char* argv[]) {
|
||||
params.lora_model_dir.c_str(),
|
||||
params.embedding_dir.c_str(),
|
||||
params.photo_maker_path.c_str(),
|
||||
params.tensor_type_rules.c_str(),
|
||||
vae_decode_only,
|
||||
true,
|
||||
params.n_threads,
|
||||
params.wtype,
|
||||
params.rng_type,
|
||||
params.sampler_rng_type,
|
||||
params.prediction,
|
||||
params.lora_apply_mode,
|
||||
params.offload_params_to_cpu,
|
||||
params.clip_on_cpu,
|
||||
params.control_net_cpu,
|
||||
params.vae_on_cpu,
|
||||
params.diffusion_flash_attn,
|
||||
params.taesd_preview,
|
||||
params.diffusion_conv_direct,
|
||||
params.vae_conv_direct,
|
||||
params.force_sdxl_vae_conv_scale,
|
||||
@@ -1690,6 +1906,10 @@ int main(int argc, const char* argv[]) {
|
||||
params.sample_params.sample_method = sd_get_default_sample_method(sd_ctx);
|
||||
}
|
||||
|
||||
if (params.sample_params.scheduler == SCHEDULER_COUNT) {
|
||||
params.sample_params.scheduler = sd_get_default_scheduler(sd_ctx);
|
||||
}
|
||||
|
||||
if (params.mode == IMG_GEN) {
|
||||
sd_img_gen_params_t img_gen_params = {
|
||||
params.prompt.c_str(),
|
||||
@@ -1716,6 +1936,7 @@ int main(int argc, const char* argv[]) {
|
||||
params.pm_style_strength,
|
||||
}, // pm_params
|
||||
params.vae_tiling_params,
|
||||
params.easycache_params,
|
||||
};
|
||||
|
||||
results = generate_image(sd_ctx, &img_gen_params);
|
||||
@@ -1738,6 +1959,7 @@ int main(int argc, const char* argv[]) {
|
||||
params.seed,
|
||||
params.video_frames,
|
||||
params.vace_strength,
|
||||
params.easycache_params,
|
||||
};
|
||||
|
||||
results = generate_video(sd_ctx, &vid_gen_params, &num_results);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Flux {
|
||||
int64_t hidden_size;
|
||||
float eps;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
ggml_type wtype = GGML_TYPE_F32;
|
||||
params["scale"] = ggml_new_tensor_1d(ctx, wtype, hidden_size);
|
||||
}
|
||||
@@ -1115,10 +1115,10 @@ namespace Flux {
|
||||
|
||||
FluxRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_FLUX,
|
||||
bool use_mask = false)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_FLUX,
|
||||
bool use_mask = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), version(version), use_mask(use_mask) {
|
||||
flux_params.version = version;
|
||||
flux_params.guidance_embed = false;
|
||||
@@ -1134,7 +1134,7 @@ namespace Flux {
|
||||
flux_params.in_channels = 3;
|
||||
flux_params.patch_size = 16;
|
||||
}
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (!starts_with(tensor_name, prefix))
|
||||
continue;
|
||||
@@ -1172,7 +1172,7 @@ namespace Flux {
|
||||
}
|
||||
|
||||
flux = Flux(flux_params);
|
||||
flux.init(params_ctx, tensor_types, prefix);
|
||||
flux.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -1243,7 +1243,7 @@ namespace Flux {
|
||||
bool increase_ref_index = false,
|
||||
std::vector<int> skip_layers = {}) {
|
||||
GGML_ASSERT(x->ne[3] == 1);
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, FLUX_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(FLUX_GRAPH_SIZE);
|
||||
|
||||
struct ggml_tensor* mod_index_arange = nullptr;
|
||||
struct ggml_tensor* dct = nullptr; // for chroma radiance
|
||||
@@ -1398,22 +1398,21 @@ namespace Flux {
|
||||
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "model.diffusion_model.")) {
|
||||
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_types = model_loader.tensor_storages_types;
|
||||
for (auto& item : tensor_types) {
|
||||
// LOG_DEBUG("%s %u", item.first.c_str(), item.second);
|
||||
if (ends_with(item.first, "weight")) {
|
||||
// item.second = model_data_type;
|
||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (ends_with(name, "weight")) {
|
||||
tensor_storage.expected_type = model_data_type;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<FluxRunner> flux = std::make_shared<FluxRunner>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
tensor_storage_map,
|
||||
"model.diffusion_model",
|
||||
VERSION_CHROMA_RADIANCE,
|
||||
false);
|
||||
|
||||
+191
-44
@@ -875,7 +875,7 @@ __STATIC_INLINE__ void sd_tiling_non_square(ggml_tensor* input,
|
||||
ggml_tensor* input_tile = ggml_new_tensor_4d(tiles_ctx, GGML_TYPE_F32, input_tile_size_x, input_tile_size_y, input->ne[2], input->ne[3]);
|
||||
ggml_tensor* output_tile = ggml_new_tensor_4d(tiles_ctx, GGML_TYPE_F32, output_tile_size_x, output_tile_size_y, output->ne[2], output->ne[3]);
|
||||
int num_tiles = num_tiles_x * num_tiles_y;
|
||||
LOG_INFO("processing %i tiles", num_tiles);
|
||||
LOG_DEBUG("processing %i tiles", num_tiles);
|
||||
pretty_progress(0, num_tiles, 0.0f);
|
||||
int tile_count = 1;
|
||||
bool last_y = false, last_x = false;
|
||||
@@ -959,12 +959,15 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_ext_linear(struct ggml_context* ctx,
|
||||
int64_t ne3 = x->ne[3];
|
||||
x = ggml_reshape_2d(ctx, x, x->ne[0], x->ne[1] * x->ne[2] * x->ne[3]);
|
||||
x = ggml_mul_mat(ctx, w, x);
|
||||
x = ggml_reshape_4d(ctx, x, x->ne[0], x->ne[1] / ne2 / ne3, ne2, ne3);
|
||||
if (force_prec_f32) {
|
||||
ggml_mul_mat_set_prec(x, GGML_PREC_F32);
|
||||
}
|
||||
x = ggml_reshape_4d(ctx, x, x->ne[0], x->ne[1] / ne2 / ne3, ne2, ne3);
|
||||
} else {
|
||||
x = ggml_mul_mat(ctx, w, x);
|
||||
}
|
||||
if (force_prec_f32) {
|
||||
ggml_mul_mat_set_prec(x, GGML_PREC_F32);
|
||||
if (force_prec_f32) {
|
||||
ggml_mul_mat_set_prec(x, GGML_PREC_F32);
|
||||
}
|
||||
}
|
||||
if (scale != 1.f) {
|
||||
x = ggml_scale(ctx, x, 1.f / scale);
|
||||
@@ -994,6 +997,9 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_ext_conv_2d(struct ggml_context* ctx,
|
||||
if (scale != 1.f) {
|
||||
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) {
|
||||
x = ggml_conv_2d_direct(ctx, w, x, s0, s1, p0, p1, d0, d1);
|
||||
} else {
|
||||
@@ -1119,6 +1125,18 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_ext_ones(struct ggml_context* ctx,
|
||||
return ggml_ext_full(ctx, 1.f, ne0, ne1, ne2, ne3);
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ ggml_tensor* ggml_ext_cast_f32(ggml_context* ctx, ggml_tensor* a) {
|
||||
auto out = ggml_reshape_2d(ctx, a, 1, ggml_nelements(a));
|
||||
ggml_tensor* one = ggml_ext_ones(ctx, 1, 1, 1, 1); // [1,]
|
||||
if (ggml_is_transposed(out)) {
|
||||
out = ggml_mul_mat(ctx, one, out);
|
||||
} else {
|
||||
out = ggml_mul_mat(ctx, out, one);
|
||||
}
|
||||
out = ggml_reshape(ctx, out, a);
|
||||
return out;
|
||||
}
|
||||
|
||||
// q: [N * n_head, n_token, d_head]
|
||||
// k: [N * n_head, n_k, d_head]
|
||||
// v: [N * n_head, d_head, n_k]
|
||||
@@ -1460,13 +1478,43 @@ __STATIC_INLINE__ size_t ggml_tensor_num(ggml_context* ctx) {
|
||||
#define MAX_PARAMS_TENSOR_NUM 32768
|
||||
#define MAX_GRAPH_SIZE 327680
|
||||
|
||||
typedef std::map<std::string, enum ggml_type> String2GGMLType;
|
||||
struct WeightAdapter {
|
||||
struct ForwardParams {
|
||||
enum class op_type_t {
|
||||
OP_LINEAR,
|
||||
OP_CONV2D,
|
||||
} op_type;
|
||||
struct {
|
||||
bool force_prec_f32 = false;
|
||||
float scale = 1.f;
|
||||
} linear;
|
||||
struct {
|
||||
int s0 = 1;
|
||||
int s1 = 1;
|
||||
int p0 = 0;
|
||||
int p1 = 0;
|
||||
int d0 = 1;
|
||||
int d1 = 1;
|
||||
bool direct = false;
|
||||
float scale = 1.f;
|
||||
} conv2d;
|
||||
};
|
||||
virtual ggml_tensor* patch_weight(ggml_context* ctx, ggml_tensor* weight, const std::string& weight_name) = 0;
|
||||
virtual ggml_tensor* forward_with_lora(ggml_context* ctx,
|
||||
ggml_tensor* x,
|
||||
ggml_tensor* w,
|
||||
ggml_tensor* b,
|
||||
const std::string& prefix,
|
||||
ForwardParams forward_params) = 0;
|
||||
virtual size_t get_extra_graph_size() = 0;
|
||||
};
|
||||
|
||||
struct GGMLRunnerContext {
|
||||
ggml_backend_t backend = nullptr;
|
||||
ggml_context* ggml_ctx = nullptr;
|
||||
bool flash_attn_enabled = false;
|
||||
bool conv2d_direct_enabled = false;
|
||||
ggml_backend_t backend = nullptr;
|
||||
ggml_context* ggml_ctx = nullptr;
|
||||
bool flash_attn_enabled = false;
|
||||
bool conv2d_direct_enabled = false;
|
||||
std::shared_ptr<WeightAdapter> weight_adapter = nullptr;
|
||||
};
|
||||
|
||||
struct GGMLRunner {
|
||||
@@ -1488,6 +1536,8 @@ protected:
|
||||
struct ggml_context* compute_ctx = nullptr;
|
||||
struct ggml_gallocr* compute_allocr = nullptr;
|
||||
|
||||
std::shared_ptr<WeightAdapter> weight_adapter = nullptr;
|
||||
|
||||
std::vector<float> one_vec = {1.f};
|
||||
ggml_tensor* one_tensor = nullptr;
|
||||
|
||||
@@ -1567,11 +1617,20 @@ protected:
|
||||
ggml_build_forward_expand(gf, one_tensor);
|
||||
}
|
||||
|
||||
struct ggml_cgraph* new_graph_custom(size_t graph_size) {
|
||||
if (weight_adapter) {
|
||||
graph_size += weight_adapter->get_extra_graph_size();
|
||||
}
|
||||
return ggml_new_graph_custom(compute_ctx, graph_size, false);
|
||||
}
|
||||
|
||||
struct ggml_cgraph* get_compute_graph(get_graph_cb_t get_graph) {
|
||||
prepare_build_in_tensor_before();
|
||||
struct ggml_cgraph* gf = get_graph();
|
||||
auto result = ggml_graph_node(gf, -1);
|
||||
ggml_set_name(result, final_result_name.c_str());
|
||||
if (ggml_graph_n_nodes(gf) > 0) {
|
||||
auto result = ggml_graph_node(gf, -1);
|
||||
ggml_set_name(result, final_result_name.c_str());
|
||||
}
|
||||
prepare_build_in_tensor_after(gf);
|
||||
return gf;
|
||||
}
|
||||
@@ -1760,6 +1819,7 @@ public:
|
||||
runner_ctx.backend = runtime_backend;
|
||||
runner_ctx.flash_attn_enabled = flash_attn_enabled;
|
||||
runner_ctx.conv2d_direct_enabled = conv2d_direct_enabled;
|
||||
runner_ctx.weight_adapter = weight_adapter;
|
||||
return runner_ctx;
|
||||
}
|
||||
|
||||
@@ -1891,6 +1951,10 @@ public:
|
||||
void set_conv2d_direct_enabled(bool enabled) {
|
||||
conv2d_direct_enabled = enabled;
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) {
|
||||
weight_adapter = adapter;
|
||||
}
|
||||
};
|
||||
|
||||
class GGMLBlock {
|
||||
@@ -1900,30 +1964,36 @@ protected:
|
||||
GGMLBlockMap blocks;
|
||||
ParameterMap params;
|
||||
|
||||
ggml_type get_type(const std::string& name, const String2GGMLType& tensor_types, ggml_type default_type) {
|
||||
auto iter = tensor_types.find(name);
|
||||
if (iter != tensor_types.end()) {
|
||||
return iter->second;
|
||||
ggml_type get_type(const std::string& name, const String2TensorStorage& tensor_storage_map, ggml_type default_type) {
|
||||
ggml_type wtype = default_type;
|
||||
auto iter = tensor_storage_map.find(name);
|
||||
if (iter != tensor_storage_map.end()) {
|
||||
const TensorStorage& tensor_storage = iter->second;
|
||||
if (tensor_storage.expected_type != GGML_TYPE_COUNT) {
|
||||
wtype = tensor_storage.expected_type;
|
||||
} else {
|
||||
wtype = tensor_storage.type;
|
||||
}
|
||||
}
|
||||
return default_type;
|
||||
return wtype;
|
||||
}
|
||||
|
||||
void init_blocks(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_blocks(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") {
|
||||
for (auto& pair : blocks) {
|
||||
auto& block = pair.second;
|
||||
block->init(ctx, tensor_types, prefix + pair.first);
|
||||
block->init(ctx, tensor_storage_map, prefix + pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {}
|
||||
virtual void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") {}
|
||||
|
||||
public:
|
||||
void init(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") {
|
||||
void init(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, std::string prefix = "") {
|
||||
if (prefix.size() > 0) {
|
||||
prefix = prefix + ".";
|
||||
}
|
||||
init_blocks(ctx, tensor_types, prefix);
|
||||
init_params(ctx, tensor_types, prefix);
|
||||
init_params(ctx, tensor_storage_map, prefix);
|
||||
init_blocks(ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
size_t get_params_num() {
|
||||
@@ -2000,9 +2070,11 @@ protected:
|
||||
bool force_f32;
|
||||
bool force_prec_f32;
|
||||
float scale;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
if (in_features % ggml_blck_size(wtype) != 0 || force_f32) {
|
||||
wtype = GGML_TYPE_F32;
|
||||
}
|
||||
@@ -2033,6 +2105,13 @@ public:
|
||||
if (bias) {
|
||||
b = params["bias"];
|
||||
}
|
||||
if (ctx->weight_adapter) {
|
||||
WeightAdapter::ForwardParams forward_params;
|
||||
forward_params.op_type = WeightAdapter::ForwardParams::op_type_t::OP_LINEAR;
|
||||
forward_params.linear.force_prec_f32 = force_prec_f32;
|
||||
forward_params.linear.scale = scale;
|
||||
return ctx->weight_adapter->forward_with_lora(ctx->ggml_ctx, x, w, b, prefix, forward_params);
|
||||
}
|
||||
return ggml_ext_linear(ctx->ggml_ctx, x, w, b, force_prec_f32, scale);
|
||||
}
|
||||
};
|
||||
@@ -2049,8 +2128,8 @@ class Embedding : public UnaryBlock {
|
||||
protected:
|
||||
int64_t embedding_dim;
|
||||
int64_t num_embeddings;
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
if (!support_get_rows(wtype)) {
|
||||
wtype = GGML_TYPE_F32;
|
||||
}
|
||||
@@ -2092,8 +2171,10 @@ protected:
|
||||
std::pair<int, int> dilation;
|
||||
bool bias;
|
||||
float scale = 1.f;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map, const std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
enum ggml_type wtype = GGML_TYPE_F16;
|
||||
params["weight"] = ggml_new_tensor_4d(ctx, wtype, kernel_size.second, kernel_size.first, in_channels, out_channels);
|
||||
if (bias) {
|
||||
@@ -2132,6 +2213,19 @@ public:
|
||||
if (bias) {
|
||||
b = params["bias"];
|
||||
}
|
||||
if (ctx->weight_adapter) {
|
||||
WeightAdapter::ForwardParams forward_params;
|
||||
forward_params.op_type = WeightAdapter::ForwardParams::op_type_t::OP_CONV2D;
|
||||
forward_params.conv2d.s0 = stride.second;
|
||||
forward_params.conv2d.s1 = stride.first;
|
||||
forward_params.conv2d.p0 = padding.second;
|
||||
forward_params.conv2d.p1 = padding.first;
|
||||
forward_params.conv2d.d0 = dilation.second;
|
||||
forward_params.conv2d.d1 = dilation.first;
|
||||
forward_params.conv2d.direct = ctx->conv2d_direct_enabled;
|
||||
forward_params.conv2d.scale = scale;
|
||||
return ctx->weight_adapter->forward_with_lora(ctx->ggml_ctx, x, w, b, prefix, forward_params);
|
||||
}
|
||||
return ggml_ext_conv_2d(ctx->ggml_ctx,
|
||||
x,
|
||||
w,
|
||||
@@ -2157,7 +2251,7 @@ protected:
|
||||
int64_t dilation;
|
||||
bool bias;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = GGML_TYPE_F16;
|
||||
params["weight"] = ggml_new_tensor_4d(ctx, wtype, 1, kernel_size, in_channels, out_channels); // 5d => 4d
|
||||
if (bias) {
|
||||
@@ -2203,8 +2297,10 @@ protected:
|
||||
std::tuple<int, int, int> padding;
|
||||
std::tuple<int, int, int> dilation;
|
||||
bool bias;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map, const std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
enum ggml_type wtype = GGML_TYPE_F16;
|
||||
params["weight"] = ggml_new_tensor_4d(ctx,
|
||||
wtype,
|
||||
@@ -2236,8 +2332,17 @@ public:
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* w = params["weight"];
|
||||
struct ggml_tensor* b = nullptr;
|
||||
if (ctx->weight_adapter) {
|
||||
w = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, w, prefix + "weight");
|
||||
if (w->type != GGML_TYPE_F16) {
|
||||
w = ggml_cast(ctx->ggml_ctx, w, GGML_TYPE_F16);
|
||||
}
|
||||
}
|
||||
if (bias) {
|
||||
b = params["bias"];
|
||||
if (ctx->weight_adapter) {
|
||||
b = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, b, prefix + "bias");
|
||||
}
|
||||
}
|
||||
return ggml_ext_conv_3d(ctx->ggml_ctx, x, w, b, in_channels,
|
||||
std::get<2>(stride), std::get<1>(stride), std::get<0>(stride),
|
||||
@@ -2252,8 +2357,10 @@ protected:
|
||||
float eps;
|
||||
bool elementwise_affine;
|
||||
bool bias;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
if (elementwise_affine) {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["weight"] = ggml_new_tensor_1d(ctx, wtype, normalized_shape);
|
||||
@@ -2280,8 +2387,14 @@ public:
|
||||
|
||||
if (elementwise_affine) {
|
||||
w = params["weight"];
|
||||
if (ctx->weight_adapter) {
|
||||
w = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, w, prefix + "weight");
|
||||
}
|
||||
if (bias) {
|
||||
b = params["bias"];
|
||||
if (ctx->weight_adapter) {
|
||||
b = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, b, prefix + "bias");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ggml_ext_layer_norm(ctx->ggml_ctx, x, w, b, eps);
|
||||
@@ -2294,8 +2407,10 @@ protected:
|
||||
int64_t num_channels;
|
||||
float eps;
|
||||
bool affine;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
if (affine) {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
enum ggml_type bias_wtype = GGML_TYPE_F32;
|
||||
@@ -2320,6 +2435,10 @@ public:
|
||||
if (affine) {
|
||||
w = params["weight"];
|
||||
b = params["bias"];
|
||||
if (ctx->weight_adapter) {
|
||||
w = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, w, prefix + "weight");
|
||||
b = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, b, prefix + "bias");
|
||||
}
|
||||
}
|
||||
return ggml_ext_group_norm(ctx->ggml_ctx, x, w, b, num_groups);
|
||||
}
|
||||
@@ -2335,8 +2454,10 @@ class RMSNorm : public UnaryBlock {
|
||||
protected:
|
||||
int64_t hidden_size;
|
||||
float eps;
|
||||
std::string prefix;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, std::string prefix = "") override {
|
||||
this->prefix = prefix;
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["weight"] = ggml_new_tensor_1d(ctx, wtype, hidden_size);
|
||||
}
|
||||
@@ -2349,8 +2470,11 @@ public:
|
||||
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* w = params["weight"];
|
||||
x = ggml_rms_norm(ctx->ggml_ctx, x, eps);
|
||||
x = ggml_mul_inplace(ctx->ggml_ctx, x, w);
|
||||
if (ctx->weight_adapter) {
|
||||
w = ctx->weight_adapter->patch_weight(ctx->ggml_ctx, w, prefix + "weight");
|
||||
}
|
||||
x = ggml_rms_norm(ctx->ggml_ctx, x, eps);
|
||||
x = ggml_mul_inplace(ctx->ggml_ctx, x, w);
|
||||
return x;
|
||||
}
|
||||
};
|
||||
@@ -2359,9 +2483,11 @@ class MultiheadAttention : public GGMLBlock {
|
||||
protected:
|
||||
int64_t embed_dim;
|
||||
int64_t n_head;
|
||||
bool proj_in;
|
||||
std::string q_proj_name;
|
||||
std::string k_proj_name;
|
||||
std::string v_proj_name;
|
||||
std::string in_proj_name;
|
||||
std::string out_proj_name;
|
||||
|
||||
public:
|
||||
@@ -2369,19 +2495,27 @@ public:
|
||||
int64_t n_head,
|
||||
bool qkv_proj_bias = true,
|
||||
bool out_proj_bias = true,
|
||||
bool proj_in = false,
|
||||
std::string q_proj_name = "q_proj",
|
||||
std::string k_proj_name = "k_proj",
|
||||
std::string v_proj_name = "v_proj",
|
||||
std::string in_proj_name = "in_proj",
|
||||
std::string out_proj_name = "out_proj")
|
||||
: embed_dim(embed_dim),
|
||||
n_head(n_head),
|
||||
proj_in(proj_in),
|
||||
q_proj_name(q_proj_name),
|
||||
k_proj_name(k_proj_name),
|
||||
v_proj_name(v_proj_name),
|
||||
in_proj_name(in_proj_name),
|
||||
out_proj_name(out_proj_name) {
|
||||
blocks[q_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
blocks[k_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
blocks[v_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
if (proj_in) {
|
||||
blocks[in_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim * 3, qkv_proj_bias));
|
||||
} else {
|
||||
blocks[q_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
blocks[k_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
blocks[v_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, qkv_proj_bias));
|
||||
}
|
||||
blocks[out_proj_name] = std::shared_ptr<GGMLBlock>(new Linear(embed_dim, embed_dim, out_proj_bias));
|
||||
}
|
||||
|
||||
@@ -2389,14 +2523,27 @@ public:
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx,
|
||||
struct ggml_tensor* x,
|
||||
bool mask = false) {
|
||||
auto q_proj = std::dynamic_pointer_cast<Linear>(blocks[q_proj_name]);
|
||||
auto k_proj = std::dynamic_pointer_cast<Linear>(blocks[k_proj_name]);
|
||||
auto v_proj = std::dynamic_pointer_cast<Linear>(blocks[v_proj_name]);
|
||||
auto out_proj = std::dynamic_pointer_cast<Linear>(blocks[out_proj_name]);
|
||||
|
||||
struct ggml_tensor* q = q_proj->forward(ctx, x);
|
||||
struct ggml_tensor* k = k_proj->forward(ctx, x);
|
||||
struct ggml_tensor* v = v_proj->forward(ctx, x);
|
||||
ggml_tensor* q;
|
||||
ggml_tensor* k;
|
||||
ggml_tensor* v;
|
||||
if (proj_in) {
|
||||
auto in_proj = std::dynamic_pointer_cast<Linear>(blocks[in_proj_name]);
|
||||
auto qkv = in_proj->forward(ctx, x);
|
||||
auto qkv_vec = split_qkv(ctx->ggml_ctx, qkv);
|
||||
q = qkv_vec[0];
|
||||
k = qkv_vec[1];
|
||||
v = qkv_vec[2];
|
||||
} else {
|
||||
auto q_proj = std::dynamic_pointer_cast<Linear>(blocks[q_proj_name]);
|
||||
auto k_proj = std::dynamic_pointer_cast<Linear>(blocks[k_proj_name]);
|
||||
auto v_proj = std::dynamic_pointer_cast<Linear>(blocks[v_proj_name]);
|
||||
|
||||
q = q_proj->forward(ctx, x);
|
||||
k = k_proj->forward(ctx, x);
|
||||
v = v_proj->forward(ctx, x);
|
||||
}
|
||||
|
||||
x = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, n_head, nullptr, mask); // [N, n_token, embed_dim]
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "ggml.h"
|
||||
|
||||
const float wan_21_latent_rgb_proj[16][3] = {
|
||||
{0.015123f, -0.148418f, 0.479828f},
|
||||
{0.003652f, -0.010680f, -0.037142f},
|
||||
{0.212264f, 0.063033f, 0.016779f},
|
||||
{0.232999f, 0.406476f, 0.220125f},
|
||||
{-0.051864f, -0.082384f, -0.069396f},
|
||||
{0.085005f, -0.161492f, 0.010689f},
|
||||
{-0.245369f, -0.506846f, -0.117010f},
|
||||
{-0.151145f, 0.017721f, 0.007207f},
|
||||
{-0.293239f, -0.207936f, -0.421135f},
|
||||
{-0.187721f, 0.050783f, 0.177649f},
|
||||
{-0.013067f, 0.265964f, 0.166578f},
|
||||
{0.028327f, 0.109329f, 0.108642f},
|
||||
{-0.205343f, 0.043991f, 0.148914f},
|
||||
{0.014307f, -0.048647f, -0.007219f},
|
||||
{0.217150f, 0.053074f, 0.319923f},
|
||||
{0.155357f, 0.083156f, 0.064780f}};
|
||||
float wan_21_latent_rgb_bias[3] = {-0.270270f, -0.234976f, -0.456853f};
|
||||
|
||||
const float wan_22_latent_rgb_proj[48][3] = {
|
||||
{0.017126f, -0.027230f, -0.019257f},
|
||||
{-0.113739f, -0.028715f, -0.022885f},
|
||||
{-0.000106f, 0.021494f, 0.004629f},
|
||||
{-0.013273f, -0.107137f, -0.033638f},
|
||||
{-0.000381f, 0.000279f, 0.025877f},
|
||||
{-0.014216f, -0.003975f, 0.040528f},
|
||||
{0.001638f, -0.000748f, 0.011022f},
|
||||
{0.029238f, -0.006697f, 0.035933f},
|
||||
{0.021641f, -0.015874f, 0.040531f},
|
||||
{-0.101984f, -0.070160f, -0.028855f},
|
||||
{0.033207f, -0.021068f, 0.002663f},
|
||||
{-0.104711f, 0.121673f, 0.102981f},
|
||||
{0.082647f, -0.004991f, 0.057237f},
|
||||
{-0.027375f, 0.031581f, 0.006868f},
|
||||
{-0.045434f, 0.029444f, 0.019287f},
|
||||
{-0.046572f, -0.012537f, 0.006675f},
|
||||
{0.074709f, 0.033690f, 0.025289f},
|
||||
{-0.008251f, -0.002745f, -0.006999f},
|
||||
{0.012685f, -0.061856f, -0.048658f},
|
||||
{0.042304f, -0.007039f, 0.000295f},
|
||||
{-0.007644f, -0.060843f, -0.033142f},
|
||||
{0.159909f, 0.045628f, 0.367541f},
|
||||
{0.095171f, 0.086438f, 0.010271f},
|
||||
{0.006812f, 0.019643f, 0.029637f},
|
||||
{0.003467f, -0.010705f, 0.014252f},
|
||||
{-0.099681f, -0.066272f, -0.006243f},
|
||||
{0.047357f, 0.037040f, 0.000185f},
|
||||
{-0.041797f, -0.089225f, -0.032257f},
|
||||
{0.008928f, 0.017028f, 0.018684f},
|
||||
{-0.042255f, 0.016045f, 0.006849f},
|
||||
{0.011268f, 0.036462f, 0.037387f},
|
||||
{0.011553f, -0.016375f, -0.048589f},
|
||||
{0.046266f, -0.027189f, 0.056979f},
|
||||
{0.009640f, -0.017576f, 0.030324f},
|
||||
{-0.045794f, -0.036083f, -0.010616f},
|
||||
{0.022418f, 0.039783f, -0.032939f},
|
||||
{-0.052714f, -0.015525f, 0.007438f},
|
||||
{0.193004f, 0.223541f, 0.264175f},
|
||||
{-0.059406f, -0.008188f, 0.022867f},
|
||||
{-0.156742f, -0.263791f, -0.007385f},
|
||||
{-0.015717f, 0.016570f, 0.033969f},
|
||||
{0.037969f, 0.109835f, 0.200449f},
|
||||
{-0.000782f, -0.009566f, -0.008058f},
|
||||
{0.010709f, 0.052960f, -0.044195f},
|
||||
{0.017271f, 0.045839f, 0.034569f},
|
||||
{0.009424f, 0.013088f, -0.001714f},
|
||||
{-0.024805f, -0.059378f, -0.033756f},
|
||||
{-0.078293f, 0.029070f, 0.026129f}};
|
||||
float wan_22_latent_rgb_bias[3] = {0.013160f, -0.096492f, -0.071323f};
|
||||
|
||||
const float flux_latent_rgb_proj[16][3] = {
|
||||
{-0.041168f, 0.019917f, 0.097253f},
|
||||
{0.028096f, 0.026730f, 0.129576f},
|
||||
{0.065618f, -0.067950f, -0.014651f},
|
||||
{-0.012998f, -0.014762f, 0.081251f},
|
||||
{0.078567f, 0.059296f, -0.024687f},
|
||||
{-0.015987f, -0.003697f, 0.005012f},
|
||||
{0.033605f, 0.138999f, 0.068517f},
|
||||
{-0.024450f, -0.063567f, -0.030101f},
|
||||
{-0.040194f, -0.016710f, 0.127185f},
|
||||
{0.112681f, 0.088764f, -0.041940f},
|
||||
{-0.023498f, 0.093664f, 0.025543f},
|
||||
{0.082899f, 0.048320f, 0.007491f},
|
||||
{0.075712f, 0.074139f, 0.081965f},
|
||||
{-0.143501f, 0.018263f, -0.136138f},
|
||||
{-0.025767f, -0.082035f, -0.040023f},
|
||||
{-0.111849f, -0.055589f, -0.032361f}};
|
||||
float flux_latent_rgb_bias[3] = {0.024600f, -0.006937f, -0.008089f};
|
||||
|
||||
// This one was taken straight from
|
||||
// https://github.com/Stability-AI/sd3.5/blob/8565799a3b41eb0c7ba976d18375f0f753f56402/sd3_impls.py#L288-L303
|
||||
// (MiT Licence)
|
||||
const float sd3_latent_rgb_proj[16][3] = {
|
||||
{-0.0645f, 0.0177f, 0.1052f},
|
||||
{0.0028f, 0.0312f, 0.0650f},
|
||||
{0.1848f, 0.0762f, 0.0360f},
|
||||
{0.0944f, 0.0360f, 0.0889f},
|
||||
{0.0897f, 0.0506f, -0.0364f},
|
||||
{-0.0020f, 0.1203f, 0.0284f},
|
||||
{0.0855f, 0.0118f, 0.0283f},
|
||||
{-0.0539f, 0.0658f, 0.1047f},
|
||||
{-0.0057f, 0.0116f, 0.0700f},
|
||||
{-0.0412f, 0.0281f, -0.0039f},
|
||||
{0.1106f, 0.1171f, 0.1220f},
|
||||
{-0.0248f, 0.0682f, -0.0481f},
|
||||
{0.0815f, 0.0846f, 0.1207f},
|
||||
{-0.0120f, -0.0055f, -0.0867f},
|
||||
{-0.0749f, -0.0634f, -0.0456f},
|
||||
{-0.1418f, -0.1457f, -0.1259f},
|
||||
};
|
||||
float sd3_latent_rgb_bias[3] = {0, 0, 0};
|
||||
|
||||
const float sdxl_latent_rgb_proj[4][3] = {
|
||||
{0.258303f, 0.277640f, 0.329699f},
|
||||
{-0.299701f, 0.105446f, 0.014194f},
|
||||
{0.050522f, 0.186163f, -0.143257f},
|
||||
{-0.211938f, -0.149892f, -0.080036f}};
|
||||
float sdxl_latent_rgb_bias[3] = {0.144381f, -0.033313f, 0.007061f};
|
||||
|
||||
const float sd_latent_rgb_proj[4][3] = {
|
||||
{0.337366f, 0.216344f, 0.257386f},
|
||||
{0.165636f, 0.386828f, 0.046994f},
|
||||
{-0.267803f, 0.237036f, 0.223517f},
|
||||
{-0.178022f, -0.200862f, -0.678514f}};
|
||||
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) {
|
||||
size_t buffer_head = 0;
|
||||
for (int k = 0; k < frames; k++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
size_t latent_id = (i * latents->nb[0] + j * latents->nb[1] + k * latents->nb[2]);
|
||||
float r = 0, g = 0, b = 0;
|
||||
if (latent_rgb_proj != nullptr) {
|
||||
for (int d = 0; d < dim; d++) {
|
||||
float value = *(float*)((char*)latents->data + latent_id + d * latents->nb[ggml_n_dims(latents) - 1]);
|
||||
r += value * latent_rgb_proj[d][0];
|
||||
g += value * latent_rgb_proj[d][1];
|
||||
b += value * latent_rgb_proj[d][2];
|
||||
}
|
||||
} else {
|
||||
// interpret first 3 channels as RGB
|
||||
r = *(float*)((char*)latents->data + latent_id + 0 * latents->nb[ggml_n_dims(latents) - 1]);
|
||||
g = *(float*)((char*)latents->data + latent_id + 1 * latents->nb[ggml_n_dims(latents) - 1]);
|
||||
b = *(float*)((char*)latents->data + latent_id + 2 * latents->nb[ggml_n_dims(latents) - 1]);
|
||||
}
|
||||
if (latent_rgb_bias != nullptr) {
|
||||
// bias
|
||||
r += latent_rgb_bias[0];
|
||||
g += latent_rgb_bias[1];
|
||||
b += latent_rgb_bias[2];
|
||||
}
|
||||
// change range
|
||||
r = r * .5f + .5f;
|
||||
g = g * .5f + .5f;
|
||||
b = b * .5f + .5f;
|
||||
|
||||
// clamp rgb values to [0,1] range
|
||||
r = r >= 0 ? r <= 1 ? r : 1 : 0;
|
||||
g = g >= 0 ? g <= 1 ? g : 1 : 0;
|
||||
b = b >= 0 ? b <= 1 ? b : 1 : 0;
|
||||
|
||||
buffer[buffer_head++] = (uint8_t)(r * 255);
|
||||
buffer[buffer_head++] = (uint8_t)(g * 255);
|
||||
buffer[buffer_head++] = (uint8_t)(b * 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,13 +633,13 @@ protected:
|
||||
int64_t hidden_size;
|
||||
std::string qk_norm;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, std::string prefix = "") override {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["pos_embed"] = ggml_new_tensor_3d(ctx, wtype, hidden_size, num_patchs, 1);
|
||||
}
|
||||
|
||||
public:
|
||||
MMDiT(const String2GGMLType& tensor_types = {}) {
|
||||
MMDiT(const String2TensorStorage& tensor_storage_map = {}) {
|
||||
// input_size is always None
|
||||
// learn_sigma is always False
|
||||
// register_length is alwalys 0
|
||||
@@ -652,8 +652,7 @@ public:
|
||||
// pos_embed_offset is not used
|
||||
// context_embedder_config is always {'target': 'torch.nn.Linear', 'params': {'in_features': 4096, 'out_features': 1536}}
|
||||
|
||||
// read tensors from tensor_types
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find("model.diffusion_model.") == std::string::npos)
|
||||
continue;
|
||||
@@ -852,10 +851,10 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
|
||||
MMDiTRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "")
|
||||
: GGMLRunner(backend, offload_params_to_cpu), mmdit(tensor_types) {
|
||||
mmdit.init(params_ctx, tensor_types, prefix);
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "")
|
||||
: GGMLRunner(backend, offload_params_to_cpu), mmdit(tensor_storage_map) {
|
||||
mmdit.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -871,7 +870,7 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y,
|
||||
std::vector<int> skip_layers = std::vector<int>()) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, MMDIT_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(MMDIT_GRAPH_SIZE);
|
||||
|
||||
x = to_backend(x);
|
||||
context = to_backend(context);
|
||||
@@ -962,7 +961,7 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
mmdit->get_param_tensors(tensors, "model.diffusion_model");
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path)) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", file_path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ggml.h"
|
||||
#include "gguf.h"
|
||||
#include "json.hpp"
|
||||
#include "ordered_map.hpp"
|
||||
#include "zip.h"
|
||||
|
||||
#define SD_MAX_DIMS 5
|
||||
@@ -26,6 +27,7 @@ enum SDVersion {
|
||||
VERSION_SD1_TINY_UNET,
|
||||
VERSION_SD2,
|
||||
VERSION_SD2_INPAINT,
|
||||
VERSION_SD2_TINY_UNET,
|
||||
VERSION_SDXL,
|
||||
VERSION_SDXL_INPAINT,
|
||||
VERSION_SDXL_PIX2PIX,
|
||||
@@ -52,7 +54,7 @@ static inline bool sd_version_is_sd1(SDVersion version) {
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_sd2(SDVersion version) {
|
||||
if (version == VERSION_SD2 || version == VERSION_SD2_INPAINT) {
|
||||
if (version == VERSION_SD2 || version == VERSION_SD2_INPAINT || version == VERSION_SD2_TINY_UNET) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -65,6 +67,15 @@ static inline bool sd_version_is_sdxl(SDVersion version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_unet(SDVersion version) {
|
||||
if (sd_version_is_sd1(version) ||
|
||||
sd_version_is_sd2(version) ||
|
||||
sd_version_is_sdxl(version)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_sd3(SDVersion version) {
|
||||
if (version == VERSION_SD3) {
|
||||
return true;
|
||||
@@ -98,7 +109,11 @@ static inline bool sd_version_is_qwen_image(SDVersion version) {
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_inpaint(SDVersion version) {
|
||||
if (version == VERSION_SD1_INPAINT || version == VERSION_SD2_INPAINT || version == VERSION_SDXL_INPAINT || version == VERSION_FLUX_FILL || version == VERSION_FLEX_2) {
|
||||
if (version == VERSION_SD1_INPAINT ||
|
||||
version == VERSION_SD2_INPAINT ||
|
||||
version == VERSION_SDXL_INPAINT ||
|
||||
version == VERSION_FLUX_FILL ||
|
||||
version == VERSION_FLEX_2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -134,6 +149,7 @@ enum PMVersion {
|
||||
struct TensorStorage {
|
||||
std::string name;
|
||||
ggml_type type = GGML_TYPE_F32;
|
||||
ggml_type expected_type = GGML_TYPE_COUNT;
|
||||
bool is_bf16 = false;
|
||||
bool is_f8_e4m3 = false;
|
||||
bool is_f8_e5m2 = false;
|
||||
@@ -242,12 +258,15 @@ struct TensorStorage {
|
||||
|
||||
typedef std::function<bool(const TensorStorage&, ggml_tensor**)> on_new_tensor_cb_t;
|
||||
|
||||
typedef std::map<std::string, enum ggml_type> String2GGMLType;
|
||||
typedef OrderedMap<std::string, TensorStorage> String2TensorStorage;
|
||||
|
||||
class ModelLoader {
|
||||
protected:
|
||||
SDVersion version_ = VERSION_COUNT;
|
||||
std::vector<std::string> file_paths_;
|
||||
std::vector<TensorStorage> tensor_storages;
|
||||
String2TensorStorage tensor_storage_map;
|
||||
|
||||
void add_tensor_storage(const TensorStorage& tensor_storage);
|
||||
|
||||
bool parse_data_pkl(uint8_t* buffer,
|
||||
size_t buffer_size,
|
||||
@@ -262,16 +281,18 @@ protected:
|
||||
bool init_from_diffusers_file(const std::string& file_path, const std::string& prefix = "");
|
||||
|
||||
public:
|
||||
String2GGMLType tensor_storages_types;
|
||||
|
||||
bool init_from_file(const std::string& file_path, const std::string& prefix = "");
|
||||
bool model_is_unet();
|
||||
void convert_tensors_name();
|
||||
bool init_from_file_and_convert_name(const std::string& file_path,
|
||||
const std::string& prefix = "",
|
||||
SDVersion version = VERSION_COUNT);
|
||||
SDVersion get_sd_version();
|
||||
std::map<ggml_type, uint32_t> get_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_conditioner_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_diffusion_model_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_vae_wtype_stat();
|
||||
void set_wtype_override(ggml_type wtype, std::string prefix = "");
|
||||
String2TensorStorage& get_tensor_storage_map() { return tensor_storage_map; }
|
||||
void set_wtype_override(ggml_type wtype, std::string tensor_type_rules = "");
|
||||
bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads = 0);
|
||||
bool load_tensors(std::map<std::string, struct ggml_tensor*>& tensors,
|
||||
std::set<std::string> ignore_tensors = {},
|
||||
@@ -279,8 +300,8 @@ public:
|
||||
|
||||
std::vector<std::string> get_tensor_names() const {
|
||||
std::vector<std::string> names;
|
||||
for (const auto& ts : tensor_storages) {
|
||||
names.push_back(ts.name);
|
||||
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
names.push_back(name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
+1058
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
#ifndef __NAME_CONVERSTION_H__
|
||||
#define __NAME_CONVERSTION_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "model.h"
|
||||
|
||||
bool is_cond_stage_model_name(const std::string& name);
|
||||
bool is_diffusion_model_name(const std::string& name);
|
||||
bool is_first_stage_model_name(const std::string& name);
|
||||
|
||||
std::string convert_tensor_name(std::string name, SDVersion version);
|
||||
|
||||
#endif // __NAME_CONVERSTION_H__
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
#ifndef __ORDERED_MAP_HPP__
|
||||
#define __ORDERED_MAP_HPP__
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
template <typename Key, typename T>
|
||||
class OrderedMap {
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = std::pair<const Key, T>;
|
||||
using list_type = std::list<value_type>;
|
||||
using size_type = typename list_type::size_type;
|
||||
using difference_type = typename list_type::difference_type;
|
||||
using iterator = typename list_type::iterator;
|
||||
using const_iterator = typename list_type::const_iterator;
|
||||
|
||||
private:
|
||||
list_type data_;
|
||||
std::unordered_map<Key, iterator> index_;
|
||||
|
||||
public:
|
||||
// --- constructors ---
|
||||
OrderedMap() = default;
|
||||
|
||||
OrderedMap(std::initializer_list<value_type> init) {
|
||||
for (const auto& kv : init)
|
||||
insert(kv);
|
||||
}
|
||||
|
||||
OrderedMap(const OrderedMap&) = default;
|
||||
OrderedMap(OrderedMap&&) noexcept = default;
|
||||
OrderedMap& operator=(const OrderedMap&) = default;
|
||||
OrderedMap& operator=(OrderedMap&&) noexcept = default;
|
||||
|
||||
// --- element access ---
|
||||
T& at(const Key& key) {
|
||||
auto it = index_.find(key);
|
||||
if (it == index_.end())
|
||||
throw std::out_of_range("OrderedMap::at: key not found");
|
||||
return it->second->second;
|
||||
}
|
||||
|
||||
const T& at(const Key& key) const {
|
||||
auto it = index_.find(key);
|
||||
if (it == index_.end())
|
||||
throw std::out_of_range("OrderedMap::at: key not found");
|
||||
return it->second->second;
|
||||
}
|
||||
|
||||
T& operator[](const Key& key) {
|
||||
auto it = index_.find(key);
|
||||
if (it == index_.end()) {
|
||||
data_.emplace_back(key, T{});
|
||||
auto iter = std::prev(data_.end());
|
||||
index_[key] = iter;
|
||||
return iter->second;
|
||||
}
|
||||
return it->second->second;
|
||||
}
|
||||
|
||||
// --- iterators ---
|
||||
iterator begin() noexcept { return data_.begin(); }
|
||||
const_iterator begin() const noexcept { return data_.begin(); }
|
||||
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||
|
||||
iterator end() noexcept { return data_.end(); }
|
||||
const_iterator end() const noexcept { return data_.end(); }
|
||||
const_iterator cend() const noexcept { return data_.cend(); }
|
||||
|
||||
// --- capacity ---
|
||||
bool empty() const noexcept { return data_.empty(); }
|
||||
size_type size() const noexcept { return data_.size(); }
|
||||
|
||||
// --- modifiers ---
|
||||
void clear() noexcept {
|
||||
data_.clear();
|
||||
index_.clear();
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& value) {
|
||||
auto it = index_.find(value.first);
|
||||
if (it != index_.end()) {
|
||||
return {it->second, false};
|
||||
}
|
||||
data_.push_back(value);
|
||||
auto iter = std::prev(data_.end());
|
||||
index_[value.first] = iter;
|
||||
return {iter, true};
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value) {
|
||||
auto it = index_.find(value.first);
|
||||
if (it != index_.end()) {
|
||||
return {it->second, false};
|
||||
}
|
||||
data_.push_back(std::move(value));
|
||||
auto iter = std::prev(data_.end());
|
||||
index_[iter->first] = iter;
|
||||
return {iter, true};
|
||||
}
|
||||
|
||||
void erase(const Key& key) {
|
||||
auto it = index_.find(key);
|
||||
if (it != index_.end()) {
|
||||
data_.erase(it->second);
|
||||
index_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {
|
||||
index_.erase(pos->first);
|
||||
return data_.erase(pos);
|
||||
}
|
||||
|
||||
// --- lookup ---
|
||||
size_type count(const Key& key) const {
|
||||
return index_.count(key);
|
||||
}
|
||||
|
||||
iterator find(const Key& key) {
|
||||
auto it = index_.find(key);
|
||||
if (it == index_.end())
|
||||
return data_.end();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const {
|
||||
auto it = index_.find(key);
|
||||
if (it == index_.end())
|
||||
return data_.end();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool contains(const Key& key) const {
|
||||
return index_.find(key) != index_.end();
|
||||
}
|
||||
|
||||
// --- comparison ---
|
||||
bool operator==(const OrderedMap& other) const {
|
||||
return data_ == other.data_;
|
||||
}
|
||||
|
||||
bool operator!=(const OrderedMap& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::pair<iterator, bool> emplace(Args&&... args) {
|
||||
value_type value(std::forward<Args>(args)...);
|
||||
auto it = index_.find(value.first);
|
||||
if (it != index_.end()) {
|
||||
return {it->second, false};
|
||||
}
|
||||
data_.push_back(std::move(value));
|
||||
auto iter = std::prev(data_.end());
|
||||
index_[iter->first] = iter;
|
||||
return {iter, true};
|
||||
}
|
||||
|
||||
void swap(OrderedMap& other) noexcept {
|
||||
data_.swap(other.data_);
|
||||
index_.swap(other.index_);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __ORDERED_MAP_HPP__
|
||||
@@ -412,7 +412,7 @@ public:
|
||||
public:
|
||||
PhotoMakerIDEncoder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
SDVersion version = VERSION_SDXL,
|
||||
PMVersion pm_v = PM_VERSION_1,
|
||||
@@ -422,9 +422,9 @@ public:
|
||||
pm_version(pm_v),
|
||||
style_strength(sty) {
|
||||
if (pm_version == PM_VERSION_1) {
|
||||
id_encoder.init(params_ctx, tensor_types, prefix);
|
||||
id_encoder.init(params_ctx, tensor_storage_map, prefix);
|
||||
} else if (pm_version == PM_VERSION_2) {
|
||||
id_encoder2.init(params_ctx, tensor_types, prefix);
|
||||
id_encoder2.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ struct PhotoMakerIDEmbed : public GGMLRunner {
|
||||
const std::string& file_path = "",
|
||||
const std::string& prefix = "")
|
||||
: file_path(file_path), GGMLRunner(backend, offload_params_to_cpu), model_loader(ml) {
|
||||
if (!model_loader->init_from_file(file_path, prefix)) {
|
||||
if (!model_loader->init_from_file_and_convert_name(file_path, prefix)) {
|
||||
load_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-15
@@ -94,10 +94,14 @@ namespace Qwen {
|
||||
blocks["norm_added_q"] = std::shared_ptr<GGMLBlock>(new RMSNorm(dim_head, eps));
|
||||
blocks["norm_added_k"] = std::shared_ptr<GGMLBlock>(new RMSNorm(dim_head, eps));
|
||||
|
||||
float scale = 1.f / 32.f;
|
||||
float scale = 1.f / 32.f;
|
||||
bool force_prec_f32 = false;
|
||||
#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 (not all prompts).
|
||||
blocks["to_out.0"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_dim, out_bias, false, false, scale));
|
||||
blocks["to_out.0"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_dim, out_bias, false, force_prec_f32, scale));
|
||||
// to_out.1 is nn.Dropout
|
||||
|
||||
blocks["to_add_out"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_context_dim, out_bias, false, false, scale));
|
||||
@@ -502,12 +506,12 @@ namespace Qwen {
|
||||
|
||||
QwenImageRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_QWEN_IMAGE)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_QWEN_IMAGE)
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
qwen_image_params.num_layers = 0;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find(prefix) == std::string::npos)
|
||||
continue;
|
||||
@@ -526,7 +530,7 @@ namespace Qwen {
|
||||
}
|
||||
LOG_INFO("qwen_image_params.num_layers: %ld", qwen_image_params.num_layers);
|
||||
qwen_image = QwenImageModel(qwen_image_params);
|
||||
qwen_image.init(params_ctx, tensor_types, prefix);
|
||||
qwen_image.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -543,7 +547,7 @@ namespace Qwen {
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false) {
|
||||
GGML_ASSERT(x->ne[3] == 1);
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, QWEN_IMAGE_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(QWEN_IMAGE_GRAPH_SIZE);
|
||||
|
||||
x = to_backend(x);
|
||||
context = to_backend(context);
|
||||
@@ -644,22 +648,21 @@ namespace Qwen {
|
||||
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "model.diffusion_model.")) {
|
||||
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_types = model_loader.tensor_storages_types;
|
||||
for (auto& item : tensor_types) {
|
||||
// LOG_DEBUG("%s %u", item.first.c_str(), item.second);
|
||||
if (ends_with(item.first, "weight")) {
|
||||
item.second = model_data_type;
|
||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (ends_with(name, "weight")) {
|
||||
tensor_storage.expected_type = model_data_type;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<QwenImageRunner> qwen_image = std::make_shared<QwenImageRunner>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
tensor_storage_map,
|
||||
"model.diffusion_model",
|
||||
VERSION_QWEN_IMAGE);
|
||||
|
||||
|
||||
+14
-15
@@ -910,13 +910,13 @@ namespace Qwen {
|
||||
|
||||
Qwen2_5_VLRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
bool enable_vision_ = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), enable_vision(enable_vision_) {
|
||||
bool have_vision_weight = false;
|
||||
bool llama_cpp_style = false;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find(prefix) == std::string::npos)
|
||||
continue;
|
||||
@@ -940,7 +940,7 @@ namespace Qwen {
|
||||
}
|
||||
}
|
||||
model = Qwen2_5_VL(params, enable_vision, llama_cpp_style);
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
model.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -1049,7 +1049,7 @@ namespace Qwen {
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_encode_image_graph(struct ggml_tensor* image) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, QWENVL_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(QWENVL_GRAPH_SIZE);
|
||||
|
||||
GGML_ASSERT(image->ne[1] % (params.vision.patch_size * params.vision.spatial_merge_size) == 0);
|
||||
GGML_ASSERT(image->ne[0] % (params.vision.patch_size * params.vision.spatial_merge_size) == 0);
|
||||
@@ -1188,10 +1188,10 @@ namespace Qwen {
|
||||
|
||||
Qwen2_5_VLEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
bool enable_vision = false)
|
||||
: model(backend, offload_params_to_cpu, tensor_types, prefix, enable_vision) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
bool enable_vision = false)
|
||||
: model(backend, offload_params_to_cpu, tensor_storage_map, prefix, enable_vision) {
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||
@@ -1342,22 +1342,21 @@ namespace Qwen {
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "qwen2vl.")) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path, "qwen2vl.")) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", file_path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto tensor_types = model_loader.tensor_storages_types;
|
||||
for (auto& item : tensor_types) {
|
||||
// LOG_DEBUG("%s %u", item.first.c_str(), item.second);
|
||||
if (ends_with(item.first, "weight")) {
|
||||
item.second = model_data_type;
|
||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (ends_with(name, "weight")) {
|
||||
tensor_storage.expected_type = model_data_type;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Qwen2_5_VLEmbedder> qwenvl = std::make_shared<Qwen2_5_VLEmbedder>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
tensor_storage_map,
|
||||
"qwen2vl",
|
||||
true);
|
||||
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#ifndef __RNG_MT19937_HPP__
|
||||
#define __RNG_MT19937_HPP__
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "rng.hpp"
|
||||
|
||||
// RNG imitiating torch cpu randn on CPU.
|
||||
// Port from pytorch, original license: https://github.com/pytorch/pytorch/blob/d01a7b0241ed1c4cded7e7ca097249feb343f072/LICENSE
|
||||
// Ref: https://github.com/pytorch/pytorch/blob/d01a7b0241ed1c4cded7e7ca097249feb343f072/aten/src/ATen/core/TransformationHelper.h, for uniform_real
|
||||
// Ref: https://github.com/pytorch/pytorch/blob/d01a7b0241ed1c4cded7e7ca097249feb343f072/aten/src/ATen/native/cpu/DistributionTemplates.h, for normal_kernel/normal_fill/normal_fill_16
|
||||
// Ref: https://github.com/pytorch/pytorch/blob/d01a7b0241ed1c4cded7e7ca097249feb343f072/aten/src/ATen/core/MT19937RNGEngine.h, for mt19937_engine
|
||||
// Ref: https://github.com/pytorch/pytorch/blob/d01a7b0241ed1c4cded7e7ca097249feb343f072/aten/src/ATen/core/DistributionsHelper.h, for uniform_real_distribution/normal_distribution
|
||||
class MT19937RNG : public RNG {
|
||||
static const int N = 624;
|
||||
static const int M = 397;
|
||||
static const uint32_t MATRIX_A = 0x9908b0dfU;
|
||||
static const uint32_t UMASK = 0x80000000U;
|
||||
static const uint32_t LMASK = 0x7fffffffU;
|
||||
|
||||
struct State {
|
||||
uint64_t seed_;
|
||||
int left_;
|
||||
bool seeded_;
|
||||
uint32_t next_;
|
||||
std::array<uint32_t, N> state_;
|
||||
bool has_next_gauss = false;
|
||||
double next_gauss = 0.0f;
|
||||
};
|
||||
|
||||
State s;
|
||||
|
||||
uint32_t mix_bits(uint32_t u, uint32_t v) { return (u & UMASK) | (v & LMASK); }
|
||||
uint32_t twist(uint32_t u, uint32_t v) { return (mix_bits(u, v) >> 1) ^ ((v & 1) ? MATRIX_A : 0); }
|
||||
void next_state() {
|
||||
uint32_t* p = s.state_.data();
|
||||
s.left_ = N;
|
||||
s.next_ = 0;
|
||||
for (int j = N - M + 1; --j; p++)
|
||||
p[0] = p[M] ^ twist(p[0], p[1]);
|
||||
for (int j = M; --j; p++)
|
||||
p[0] = p[M - N] ^ twist(p[0], p[1]);
|
||||
p[0] = p[M - N] ^ twist(p[0], s.state_[0]);
|
||||
}
|
||||
|
||||
uint32_t rand_uint32() {
|
||||
if (--s.left_ == 0)
|
||||
next_state();
|
||||
uint32_t y = s.state_[s.next_++];
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680U;
|
||||
y ^= (y << 15) & 0xefc60000U;
|
||||
y ^= (y >> 18);
|
||||
return y;
|
||||
}
|
||||
|
||||
uint64_t rand_uint64() {
|
||||
uint64_t high = (uint64_t)rand_uint32();
|
||||
uint64_t low = (uint64_t)rand_uint32();
|
||||
return (high << 32) | low;
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
T uniform_real(V val, T from, T to) {
|
||||
constexpr auto MASK = static_cast<V>((static_cast<uint64_t>(1) << std::numeric_limits<T>::digits) - 1);
|
||||
constexpr auto DIVISOR = static_cast<T>(1) / (static_cast<uint64_t>(1) << std::numeric_limits<T>::digits);
|
||||
T x = (val & MASK) * DIVISOR;
|
||||
return (x * (to - from) + from);
|
||||
}
|
||||
|
||||
double normal_double_value(double mean, double std) {
|
||||
if (s.has_next_gauss) {
|
||||
s.has_next_gauss = false;
|
||||
return s.next_gauss;
|
||||
}
|
||||
double u1 = uniform_real(rand_uint64(), 0., 1.); // double
|
||||
double u2 = uniform_real(rand_uint64(), 0., 1.); // double
|
||||
|
||||
double r = std::sqrt(-2.0 * std::log1p(-u2));
|
||||
double theta = 2.0 * 3.14159265358979323846 * u1;
|
||||
double value = r * std::cos(theta) * std + mean;
|
||||
s.next_gauss = r * std::sin(theta) * std + mean;
|
||||
s.has_next_gauss = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
void normal_fill_16(float* data, float mean, float std) {
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
float u1 = 1.0f - data[j];
|
||||
float u2 = data[j + 8];
|
||||
float r = std::sqrt(-2.0f * std::log(u1));
|
||||
float theta = 2.0f * 3.14159265358979323846 * u2;
|
||||
data[j] = r * std::cos(theta) * std + mean;
|
||||
data[j + 8] = r * std::sin(theta) * std + mean;
|
||||
}
|
||||
}
|
||||
|
||||
void randn(float* data, int64_t size, float mean = 0.0f, float std = 1.0f) {
|
||||
if (size >= 16) {
|
||||
for (int64_t i = 0; i < size; i++) {
|
||||
data[i] = uniform_real(rand_uint32(), 0.f, 1.f);
|
||||
}
|
||||
for (int64_t i = 0; i < size - 15; i += 16) {
|
||||
normal_fill_16(data + i, mean, std);
|
||||
}
|
||||
if (size % 16 != 0) {
|
||||
// Recompute the last 16 values.
|
||||
data = data + size - 16;
|
||||
for (int64_t i = 0; i < 16; i++) {
|
||||
data[i] = uniform_real(rand_uint32(), 0.f, 1.f);
|
||||
}
|
||||
normal_fill_16(data, mean, std);
|
||||
}
|
||||
} else {
|
||||
// Strange handling, hard to understand, but keeping it consistent with PyTorch.
|
||||
for (int64_t i = 0; i < size; i++) {
|
||||
data[i] = (float)normal_double_value(mean, std);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
MT19937RNG(uint64_t seed = 0) { manual_seed(seed); }
|
||||
|
||||
void manual_seed(uint64_t seed) override {
|
||||
s.seed_ = seed;
|
||||
s.seeded_ = true;
|
||||
s.state_[0] = (uint32_t)(seed & 0xffffffffU);
|
||||
for (int j = 1; j < N; j++) {
|
||||
uint32_t prev = s.state_[j - 1];
|
||||
s.state_[j] = 1812433253U * (prev ^ (prev >> 30)) + j;
|
||||
}
|
||||
s.left_ = 1;
|
||||
s.next_ = 0;
|
||||
s.has_next_gauss = false;
|
||||
}
|
||||
|
||||
std::vector<float> randn(uint32_t n) override {
|
||||
std::vector<float> out;
|
||||
out.resize(n);
|
||||
randn((float*)out.data(), out.size());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __RNG_MT19937_HPP__
|
||||
+749
-190
File diff suppressed because it is too large
Load Diff
+52
-13
@@ -31,6 +31,7 @@ extern "C" {
|
||||
enum rng_type_t {
|
||||
STD_DEFAULT_RNG,
|
||||
CUDA_RNG,
|
||||
CPU_RNG,
|
||||
RNG_TYPE_COUNT
|
||||
};
|
||||
|
||||
@@ -52,16 +53,16 @@ enum sample_method_t {
|
||||
};
|
||||
|
||||
enum scheduler_t {
|
||||
DEFAULT,
|
||||
DISCRETE,
|
||||
KARRAS,
|
||||
EXPONENTIAL,
|
||||
AYS,
|
||||
GITS,
|
||||
SGM_UNIFORM,
|
||||
SIMPLE,
|
||||
SMOOTHSTEP,
|
||||
SCHEDULE_COUNT
|
||||
DISCRETE_SCHEDULER,
|
||||
KARRAS_SCHEDULER,
|
||||
EXPONENTIAL_SCHEDULER,
|
||||
AYS_SCHEDULER,
|
||||
GITS_SCHEDULER,
|
||||
SGM_UNIFORM_SCHEDULER,
|
||||
SIMPLE_SCHEDULER,
|
||||
SMOOTHSTEP_SCHEDULER,
|
||||
LCM_SCHEDULER,
|
||||
SCHEDULER_COUNT
|
||||
};
|
||||
|
||||
enum prediction_t {
|
||||
@@ -126,6 +127,21 @@ enum sd_log_level_t {
|
||||
SD_LOG_ERROR
|
||||
};
|
||||
|
||||
enum preview_t {
|
||||
PREVIEW_NONE,
|
||||
PREVIEW_PROJ,
|
||||
PREVIEW_TAE,
|
||||
PREVIEW_VAE,
|
||||
PREVIEW_COUNT
|
||||
};
|
||||
|
||||
enum lora_apply_mode_t {
|
||||
LORA_APPLY_AUTO,
|
||||
LORA_APPLY_IMMEDIATELY,
|
||||
LORA_APPLY_AT_RUNTIME,
|
||||
LORA_APPLY_MODE_COUNT,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
int tile_size_x;
|
||||
@@ -151,17 +167,21 @@ typedef struct {
|
||||
const char* lora_model_dir;
|
||||
const char* embedding_dir;
|
||||
const char* photo_maker_path;
|
||||
const char* tensor_type_rules;
|
||||
bool vae_decode_only;
|
||||
bool free_params_immediately;
|
||||
int n_threads;
|
||||
enum sd_type_t wtype;
|
||||
enum rng_type_t rng_type;
|
||||
enum rng_type_t sampler_rng_type;
|
||||
enum prediction_t prediction;
|
||||
enum lora_apply_mode_t lora_apply_mode;
|
||||
bool offload_params_to_cpu;
|
||||
bool keep_clip_on_cpu;
|
||||
bool keep_control_net_on_cpu;
|
||||
bool keep_vae_on_cpu;
|
||||
bool diffusion_flash_attn;
|
||||
bool tae_preview_only;
|
||||
bool diffusion_conv_direct;
|
||||
bool vae_conv_direct;
|
||||
bool force_sdxl_vae_conv_scale;
|
||||
@@ -209,6 +229,13 @@ typedef struct {
|
||||
float style_strength;
|
||||
} sd_pm_params_t; // photo maker
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
float reuse_threshold;
|
||||
float start_percent;
|
||||
float end_percent;
|
||||
} sd_easycache_params_t;
|
||||
|
||||
typedef struct {
|
||||
const char* prompt;
|
||||
const char* negative_prompt;
|
||||
@@ -229,6 +256,7 @@ typedef struct {
|
||||
float control_strength;
|
||||
sd_pm_params_t pm_params;
|
||||
sd_tiling_params_t vae_tiling_params;
|
||||
sd_easycache_params_t easycache;
|
||||
} sd_img_gen_params_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -248,15 +276,18 @@ typedef struct {
|
||||
int64_t seed;
|
||||
int video_frames;
|
||||
float vace_strength;
|
||||
sd_easycache_params_t easycache;
|
||||
} sd_vid_gen_params_t;
|
||||
|
||||
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_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);
|
||||
|
||||
SD_API void sd_set_log_callback(sd_log_cb_t sd_log_cb, void* data);
|
||||
SD_API void sd_set_progress_callback(sd_progress_cb_t cb, void* data);
|
||||
SD_API void sd_set_preview_callback(sd_preview_cb_t cb, enum preview_t mode, int interval, bool denoised, bool noisy);
|
||||
SD_API int32_t get_num_physical_cores();
|
||||
SD_API const char* sd_get_system_info();
|
||||
|
||||
@@ -266,21 +297,29 @@ 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 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 const char* sd_schedule_name(enum scheduler_t scheduler);
|
||||
SD_API enum scheduler_t str_to_schedule(const char* str);
|
||||
SD_API const char* sd_scheduler_name(enum scheduler_t scheduler);
|
||||
SD_API enum scheduler_t str_to_scheduler(const char* str);
|
||||
SD_API const char* sd_prediction_name(enum prediction_t prediction);
|
||||
SD_API enum prediction_t str_to_prediction(const char* str);
|
||||
SD_API const char* sd_preview_name(enum preview_t preview);
|
||||
SD_API enum preview_t str_to_preview(const char* str);
|
||||
SD_API const char* sd_lora_apply_mode_name(enum lora_apply_mode_t mode);
|
||||
SD_API enum lora_apply_mode_t str_to_lora_apply_mode(const char* str);
|
||||
|
||||
SD_API void sd_easycache_params_init(sd_easycache_params_t* easycache_params);
|
||||
|
||||
SD_API void sd_ctx_params_init(sd_ctx_params_t* sd_ctx_params);
|
||||
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 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 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 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);
|
||||
|
||||
@@ -461,7 +461,7 @@ protected:
|
||||
int64_t hidden_size;
|
||||
float eps;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["weight"] = ggml_new_tensor_1d(ctx, wtype, hidden_size);
|
||||
}
|
||||
@@ -759,7 +759,7 @@ struct T5Runner : public GGMLRunner {
|
||||
|
||||
T5Runner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
bool is_umt5 = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
@@ -768,7 +768,7 @@ struct T5Runner : public GGMLRunner {
|
||||
params.relative_attention = false;
|
||||
}
|
||||
model = T5(params);
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
model.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -905,10 +905,10 @@ struct T5Embedder {
|
||||
|
||||
T5Embedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
bool is_umt5 = false)
|
||||
: model(backend, offload_params_to_cpu, tensor_types, prefix, is_umt5), tokenizer(is_umt5) {
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
bool is_umt5 = false)
|
||||
: model(backend, offload_params_to_cpu, tensor_storage_map, prefix, is_umt5), tokenizer(is_umt5) {
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||
@@ -1004,20 +1004,19 @@ struct T5Embedder {
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path)) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", file_path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto tensor_types = model_loader.tensor_storages_types;
|
||||
for (auto& item : tensor_types) {
|
||||
// LOG_DEBUG("%s %u", item.first.c_str(), item.second);
|
||||
if (ends_with(item.first, "weight")) {
|
||||
item.second = model_data_type;
|
||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (ends_with(name, "weight")) {
|
||||
tensor_storage.expected_type = model_data_type;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<T5Embedder> t5 = std::make_shared<T5Embedder>(backend, false, tensor_types, "", true);
|
||||
std::shared_ptr<T5Embedder> t5 = std::make_shared<T5Embedder>(backend, false, tensor_storage_map, "", true);
|
||||
|
||||
t5->alloc_params_buffer();
|
||||
std::map<std::string, ggml_tensor*> tensors;
|
||||
|
||||
@@ -197,14 +197,14 @@ struct TinyAutoEncoder : public GGMLRunner {
|
||||
|
||||
TinyAutoEncoder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
bool decoder_only = true,
|
||||
SDVersion version = VERSION_SD1)
|
||||
: decode_only(decoder_only),
|
||||
taesd(decoder_only, version),
|
||||
GGMLRunner(backend, offload_params_to_cpu) {
|
||||
taesd.init(params_ctx, tensor_types, prefix);
|
||||
taesd.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -222,7 +222,7 @@ struct TinyAutoEncoder : public GGMLRunner {
|
||||
}
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path)) {
|
||||
LOG_ERROR("init taesd model loader from file failed: '%s'", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/*==================================================== UnetModel =====================================================*/
|
||||
|
||||
#define UNET_GRAPH_SIZE 10240
|
||||
#define UNET_GRAPH_SIZE 102400
|
||||
|
||||
class SpatialVideoTransformer : public SpatialTransformer {
|
||||
protected:
|
||||
@@ -20,9 +20,10 @@ public:
|
||||
int64_t d_head,
|
||||
int64_t depth,
|
||||
int64_t context_dim,
|
||||
bool use_linear,
|
||||
int64_t time_depth = 1,
|
||||
int64_t max_time_embed_period = 10000)
|
||||
: SpatialTransformer(in_channels, n_head, d_head, depth, context_dim),
|
||||
: SpatialTransformer(in_channels, n_head, d_head, depth, context_dim, use_linear),
|
||||
max_time_embed_period(max_time_embed_period) {
|
||||
// We will convert unet transformer linear to conv2d 1x1 when loading the weights, so use_linear is always False
|
||||
// use_spatial_context is always True
|
||||
@@ -178,17 +179,20 @@ protected:
|
||||
int num_heads = 8;
|
||||
int num_head_channels = -1; // channels // num_heads
|
||||
int context_dim = 768; // 1024 for VERSION_SD2, 2048 for VERSION_SDXL
|
||||
bool use_linear_projection = false;
|
||||
bool tiny_unet = false;
|
||||
|
||||
public:
|
||||
int model_channels = 320;
|
||||
int adm_in_channels = 2816; // only for VERSION_SDXL/SVD
|
||||
|
||||
UnetModelBlock(SDVersion version = VERSION_SD1, const String2GGMLType& tensor_types = {})
|
||||
UnetModelBlock(SDVersion version = VERSION_SD1, const String2TensorStorage& tensor_storage_map = {})
|
||||
: version(version) {
|
||||
if (sd_version_is_sd2(version)) {
|
||||
context_dim = 1024;
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
context_dim = 1024;
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
use_linear_projection = true;
|
||||
} else if (sd_version_is_sdxl(version)) {
|
||||
context_dim = 2048;
|
||||
attention_resolutions = {4, 2};
|
||||
@@ -196,22 +200,26 @@ public:
|
||||
transformer_depth = {1, 2, 10};
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
use_linear_projection = true;
|
||||
} else if (version == VERSION_SVD) {
|
||||
in_channels = 8;
|
||||
out_channels = 4;
|
||||
context_dim = 1024;
|
||||
adm_in_channels = 768;
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
} else if (version == VERSION_SD1_TINY_UNET) {
|
||||
num_res_blocks = 1;
|
||||
channel_mult = {1, 2, 4};
|
||||
in_channels = 8;
|
||||
out_channels = 4;
|
||||
context_dim = 1024;
|
||||
adm_in_channels = 768;
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
use_linear_projection = true;
|
||||
}
|
||||
if (sd_version_is_inpaint(version)) {
|
||||
in_channels = 9;
|
||||
} else if (sd_version_is_unet_edit(version)) {
|
||||
in_channels = 8;
|
||||
}
|
||||
if (version == VERSION_SD1_TINY_UNET || version == VERSION_SD2_TINY_UNET) {
|
||||
num_res_blocks = 1;
|
||||
channel_mult = {1, 2, 4};
|
||||
tiny_unet = true;
|
||||
}
|
||||
|
||||
// dims is always 2
|
||||
// use_temporal_attention is always True for SVD
|
||||
@@ -249,9 +257,9 @@ public:
|
||||
int64_t depth,
|
||||
int64_t context_dim) -> SpatialTransformer* {
|
||||
if (version == VERSION_SVD) {
|
||||
return new SpatialVideoTransformer(in_channels, n_head, d_head, depth, context_dim);
|
||||
return new SpatialVideoTransformer(in_channels, n_head, d_head, depth, context_dim, use_linear_projection);
|
||||
} else {
|
||||
return new SpatialTransformer(in_channels, n_head, d_head, depth, context_dim);
|
||||
return new SpatialTransformer(in_channels, n_head, d_head, depth, context_dim, use_linear_projection);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -285,7 +293,7 @@ public:
|
||||
context_dim));
|
||||
}
|
||||
input_block_chans.push_back(ch);
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
if (tiny_unet) {
|
||||
input_block_idx++;
|
||||
}
|
||||
}
|
||||
@@ -306,7 +314,7 @@ public:
|
||||
d_head = num_head_channels;
|
||||
n_head = ch / d_head;
|
||||
}
|
||||
if (version != VERSION_SD1_TINY_UNET) {
|
||||
if (!tiny_unet) {
|
||||
blocks["middle_block.0"] = std::shared_ptr<GGMLBlock>(get_resblock(ch, time_embed_dim, ch));
|
||||
if (version != VERSION_SDXL_SSD1B) {
|
||||
blocks["middle_block.1"] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch,
|
||||
@@ -353,7 +361,7 @@ public:
|
||||
}
|
||||
|
||||
if (i > 0 && j == num_res_blocks) {
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
if (tiny_unet) {
|
||||
output_block_idx++;
|
||||
if (output_block_idx == 2) {
|
||||
up_sample_idx = 1;
|
||||
@@ -490,7 +498,7 @@ public:
|
||||
}
|
||||
hs.push_back(h);
|
||||
}
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
if (tiny_unet) {
|
||||
input_block_idx++;
|
||||
}
|
||||
if (i != len_mults - 1) {
|
||||
@@ -507,7 +515,7 @@ public:
|
||||
// [N, 4*model_channels, h/8, w/8]
|
||||
|
||||
// middle_block
|
||||
if (version != VERSION_SD1_TINY_UNET) {
|
||||
if (!tiny_unet) {
|
||||
h = resblock_forward("middle_block.0", ctx, h, emb, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
if (version != VERSION_SDXL_SSD1B) {
|
||||
h = attention_layer_forward("middle_block.1", ctx, h, context, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
@@ -549,7 +557,7 @@ public:
|
||||
}
|
||||
|
||||
if (i > 0 && j == num_res_blocks) {
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
if (tiny_unet) {
|
||||
output_block_idx++;
|
||||
if (output_block_idx == 2) {
|
||||
up_sample_idx = 1;
|
||||
@@ -581,11 +589,11 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
|
||||
UNetModelRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
SDVersion version = VERSION_SD1)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), unet(version, tensor_types) {
|
||||
unet.init(params_ctx, tensor_types, prefix);
|
||||
: GGMLRunner(backend, offload_params_to_cpu), unet(version, tensor_storage_map) {
|
||||
unet.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -604,7 +612,7 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, UNET_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(UNET_GRAPH_SIZE);
|
||||
|
||||
if (num_video_frames == -1) {
|
||||
num_video_frames = x->ne[3];
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ struct UpscalerGGML {
|
||||
backend = ggml_backend_sycl_init(0);
|
||||
#endif
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(esrgan_path)) {
|
||||
if (!model_loader.init_from_file_and_convert_name(esrgan_path)) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", esrgan_path.c_str());
|
||||
}
|
||||
model_loader.set_wtype_override(model_data_type);
|
||||
@@ -51,7 +51,7 @@ struct UpscalerGGML {
|
||||
backend = ggml_backend_cpu_init();
|
||||
}
|
||||
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.tensor_storages_types);
|
||||
esrgan_upscaler = std::make_shared<ESRGAN>(backend, offload_params_to_cpu, model_loader.get_tensor_storage_map());
|
||||
if (direct) {
|
||||
esrgan_upscaler->set_conv2d_direct_enabled(true);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -185,6 +186,12 @@ int32_t get_num_physical_cores() {
|
||||
static sd_progress_cb_t sd_progress_cb = nullptr;
|
||||
void* sd_progress_cb_data = nullptr;
|
||||
|
||||
static sd_preview_cb_t sd_preview_cb = nullptr;
|
||||
preview_t sd_preview_mode = PREVIEW_NONE;
|
||||
int sd_preview_interval = 1;
|
||||
bool sd_preview_denoised = true;
|
||||
bool sd_preview_noisy = false;
|
||||
|
||||
std::u32string utf8_to_utf32(const std::string& utf8_str) {
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||||
return converter.from_bytes(utf8_str);
|
||||
@@ -328,6 +335,37 @@ void sd_set_progress_callback(sd_progress_cb_t cb, void* data) {
|
||||
sd_progress_cb = cb;
|
||||
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) {
|
||||
sd_preview_cb = cb;
|
||||
sd_preview_mode = mode;
|
||||
sd_preview_interval = interval;
|
||||
sd_preview_denoised = denoised;
|
||||
sd_preview_noisy = noisy;
|
||||
}
|
||||
|
||||
sd_preview_cb_t sd_get_preview_callback() {
|
||||
return sd_preview_cb;
|
||||
}
|
||||
|
||||
preview_t sd_get_preview_mode() {
|
||||
return sd_preview_mode;
|
||||
}
|
||||
int sd_get_preview_interval() {
|
||||
return sd_preview_interval;
|
||||
}
|
||||
bool sd_should_preview_denoised() {
|
||||
return sd_preview_denoised;
|
||||
}
|
||||
bool sd_should_preview_noisy() {
|
||||
return sd_preview_noisy;
|
||||
}
|
||||
|
||||
sd_progress_cb_t sd_get_progress_callback() {
|
||||
return sd_progress_cb;
|
||||
}
|
||||
void* sd_get_progress_callback_data() {
|
||||
return sd_progress_cb_data;
|
||||
}
|
||||
const char* sd_get_system_info() {
|
||||
static char buffer[1024];
|
||||
std::stringstream ss;
|
||||
@@ -510,6 +548,8 @@ sd_image_f32_t clip_preprocess(sd_image_f32_t image, int target_width, int targe
|
||||
// (abc) - increases attention to abc by a multiplier of 1.1
|
||||
// (abc:3.12) - increases attention to abc by a multiplier of 3.12
|
||||
// [abc] - decreases attention to abc by a multiplier of 1.1
|
||||
// BREAK - separates the prompt into conceptually distinct parts for sequential processing
|
||||
// B - internal helper pattern; prevents 'B' in 'BREAK' from being consumed as normal text
|
||||
// \( - literal character '('
|
||||
// \[ - literal character '['
|
||||
// \) - literal character ')'
|
||||
@@ -545,7 +585,7 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
float round_bracket_multiplier = 1.1f;
|
||||
float square_bracket_multiplier = 1 / 1.1f;
|
||||
|
||||
std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|[^\\()\[\]:]+|:)");
|
||||
std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]+|:|\bB)");
|
||||
std::regex re_break(R"(\s*\bBREAK\b\s*)");
|
||||
|
||||
auto multiply_range = [&](int start_position, float multiplier) {
|
||||
@@ -554,7 +594,7 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
}
|
||||
};
|
||||
|
||||
std::smatch m;
|
||||
std::smatch m, m2;
|
||||
std::string remaining_text = text;
|
||||
|
||||
while (std::regex_search(remaining_text, m, re_attention)) {
|
||||
@@ -578,6 +618,8 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
square_brackets.pop_back();
|
||||
} else if (text == "\\(") {
|
||||
res.push_back({text.substr(1), 1.0f});
|
||||
} else if (std::regex_search(text, m2, re_break)) {
|
||||
res.push_back({"BREAK", -1.0f});
|
||||
} else {
|
||||
res.push_back({text, 1.0f});
|
||||
}
|
||||
@@ -608,4 +650,4 @@ std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::str
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,15 @@ std::string trim(const std::string& s);
|
||||
|
||||
std::vector<std::pair<std::string, float>> parse_prompt_attention(const std::string& text);
|
||||
|
||||
sd_progress_cb_t sd_get_progress_callback();
|
||||
void* sd_get_progress_callback_data();
|
||||
|
||||
sd_preview_cb_t sd_get_preview_callback();
|
||||
preview_t sd_get_preview_mode();
|
||||
int sd_get_preview_interval();
|
||||
bool sd_should_preview_denoised();
|
||||
bool sd_should_preview_noisy();
|
||||
|
||||
#define LOG_DEBUG(format, ...) log_printf(SD_LOG_DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
#define LOG_INFO(format, ...) log_printf(SD_LOG_INFO, __FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
#define LOG_WARN(format, ...) log_printf(SD_LOG_WARN, __FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
@@ -64,25 +64,51 @@ public:
|
||||
class AttnBlock : public UnaryBlock {
|
||||
protected:
|
||||
int64_t in_channels;
|
||||
bool use_linear;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") {
|
||||
auto iter = tensor_storage_map.find(prefix + "proj_out.weight");
|
||||
if (iter != tensor_storage_map.end()) {
|
||||
if (iter->second.n_dims == 4 && use_linear) {
|
||||
use_linear = false;
|
||||
blocks["q"] = std::make_shared<Conv2d>(in_channels, in_channels, std::pair{1, 1});
|
||||
blocks["k"] = std::make_shared<Conv2d>(in_channels, in_channels, std::pair{1, 1});
|
||||
blocks["v"] = std::make_shared<Conv2d>(in_channels, in_channels, std::pair{1, 1});
|
||||
blocks["proj_out"] = std::make_shared<Conv2d>(in_channels, in_channels, std::pair{1, 1});
|
||||
} else if (iter->second.n_dims == 2 && !use_linear) {
|
||||
use_linear = true;
|
||||
blocks["q"] = std::make_shared<Linear>(in_channels, in_channels);
|
||||
blocks["k"] = std::make_shared<Linear>(in_channels, in_channels);
|
||||
blocks["v"] = std::make_shared<Linear>(in_channels, in_channels);
|
||||
blocks["proj_out"] = std::make_shared<Linear>(in_channels, in_channels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AttnBlock(int64_t in_channels)
|
||||
: in_channels(in_channels) {
|
||||
AttnBlock(int64_t in_channels, bool use_linear)
|
||||
: in_channels(in_channels), use_linear(use_linear) {
|
||||
blocks["norm"] = std::shared_ptr<GGMLBlock>(new GroupNorm32(in_channels));
|
||||
blocks["q"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
blocks["k"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
blocks["v"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
if (use_linear) {
|
||||
blocks["q"] = std::shared_ptr<GGMLBlock>(new Linear(in_channels, in_channels));
|
||||
blocks["k"] = std::shared_ptr<GGMLBlock>(new Linear(in_channels, in_channels));
|
||||
blocks["v"] = std::shared_ptr<GGMLBlock>(new Linear(in_channels, in_channels));
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Linear(in_channels, in_channels));
|
||||
} else {
|
||||
blocks["q"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
blocks["k"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
blocks["v"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(GGMLRunnerContext* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, in_channels, h, w]
|
||||
auto norm = std::dynamic_pointer_cast<GroupNorm32>(blocks["norm"]);
|
||||
auto q_proj = std::dynamic_pointer_cast<Conv2d>(blocks["q"]);
|
||||
auto k_proj = std::dynamic_pointer_cast<Conv2d>(blocks["k"]);
|
||||
auto v_proj = std::dynamic_pointer_cast<Conv2d>(blocks["v"]);
|
||||
auto proj_out = std::dynamic_pointer_cast<Conv2d>(blocks["proj_out"]);
|
||||
auto q_proj = std::dynamic_pointer_cast<UnaryBlock>(blocks["q"]);
|
||||
auto k_proj = std::dynamic_pointer_cast<UnaryBlock>(blocks["k"]);
|
||||
auto v_proj = std::dynamic_pointer_cast<UnaryBlock>(blocks["v"]);
|
||||
auto proj_out = std::dynamic_pointer_cast<UnaryBlock>(blocks["proj_out"]);
|
||||
|
||||
auto h_ = norm->forward(ctx, x);
|
||||
|
||||
@@ -91,23 +117,44 @@ public:
|
||||
const int64_t h = h_->ne[1];
|
||||
const int64_t w = h_->ne[0];
|
||||
|
||||
auto q = q_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
q = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, q, 1, 2, 0, 3)); // [N, h, w, in_channels]
|
||||
q = ggml_reshape_3d(ctx->ggml_ctx, q, c, h * w, n); // [N, h * w, in_channels]
|
||||
ggml_tensor* q;
|
||||
ggml_tensor* k;
|
||||
ggml_tensor* v;
|
||||
if (use_linear) {
|
||||
h_ = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, h_, 1, 2, 0, 3)); // [N, h, w, in_channels]
|
||||
h_ = ggml_reshape_3d(ctx->ggml_ctx, h_, c, h * w, n); // [N, h * w, in_channels]
|
||||
|
||||
auto k = k_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
k = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, k, 1, 2, 0, 3)); // [N, h, w, in_channels]
|
||||
k = ggml_reshape_3d(ctx->ggml_ctx, k, c, h * w, n); // [N, h * w, in_channels]
|
||||
q = q_proj->forward(ctx, h_); // [N, h * w, in_channels]
|
||||
k = k_proj->forward(ctx, h_); // [N, h * w, in_channels]
|
||||
v = v_proj->forward(ctx, h_); // [N, h * w, in_channels]
|
||||
|
||||
auto v = v_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
v = ggml_reshape_3d(ctx->ggml_ctx, v, h * w, c, n); // [N, in_channels, h * w]
|
||||
v = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, v, 1, 0, 2, 3)); // [N, in_channels, h * w]
|
||||
} else {
|
||||
q = q_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
q = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, q, 1, 2, 0, 3)); // [N, h, w, in_channels]
|
||||
q = ggml_reshape_3d(ctx->ggml_ctx, q, c, h * w, n); // [N, h * w, in_channels]
|
||||
|
||||
k = k_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
k = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, k, 1, 2, 0, 3)); // [N, h, w, in_channels]
|
||||
k = ggml_reshape_3d(ctx->ggml_ctx, k, c, h * w, n); // [N, h * w, in_channels]
|
||||
|
||||
v = v_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
v = ggml_reshape_3d(ctx->ggml_ctx, v, h * w, c, n); // [N, in_channels, h * w]
|
||||
}
|
||||
|
||||
h_ = ggml_ext_attention(ctx->ggml_ctx, q, k, v, false); // [N, h * w, in_channels]
|
||||
|
||||
h_ = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, h_, 1, 0, 2, 3)); // [N, in_channels, h * w]
|
||||
h_ = ggml_reshape_4d(ctx->ggml_ctx, h_, w, h, c, n); // [N, in_channels, h, w]
|
||||
if (use_linear) {
|
||||
h_ = proj_out->forward(ctx, h_); // [N, h * w, in_channels]
|
||||
|
||||
h_ = proj_out->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
h_ = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, h_, 1, 0, 2, 3)); // [N, in_channels, h * w]
|
||||
h_ = ggml_reshape_4d(ctx->ggml_ctx, h_, w, h, c, n); // [N, in_channels, h, w]
|
||||
} else {
|
||||
h_ = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, h_, 1, 0, 2, 3)); // [N, in_channels, h * w]
|
||||
h_ = ggml_reshape_4d(ctx->ggml_ctx, h_, w, h, c, n); // [N, in_channels, h, w]
|
||||
|
||||
h_ = proj_out->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
}
|
||||
|
||||
h_ = ggml_add(ctx->ggml_ctx, h_, x);
|
||||
return h_;
|
||||
@@ -163,8 +210,8 @@ public:
|
||||
|
||||
class VideoResnetBlock : public ResnetBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "mix_factor", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "mix_factor", tensor_storage_map, GGML_TYPE_F32);
|
||||
params["mix_factor"] = ggml_new_tensor_1d(ctx, wtype, 1);
|
||||
}
|
||||
|
||||
@@ -233,7 +280,8 @@ public:
|
||||
int num_res_blocks,
|
||||
int in_channels,
|
||||
int z_channels,
|
||||
bool double_z = true)
|
||||
bool double_z = true,
|
||||
bool use_linear_projection = false)
|
||||
: ch(ch),
|
||||
ch_mult(ch_mult),
|
||||
num_res_blocks(num_res_blocks),
|
||||
@@ -264,7 +312,7 @@ public:
|
||||
}
|
||||
|
||||
blocks["mid.block_1"] = std::shared_ptr<GGMLBlock>(new ResnetBlock(block_in, block_in));
|
||||
blocks["mid.attn_1"] = std::shared_ptr<GGMLBlock>(new AttnBlock(block_in));
|
||||
blocks["mid.attn_1"] = std::shared_ptr<GGMLBlock>(new AttnBlock(block_in, use_linear_projection));
|
||||
blocks["mid.block_2"] = std::shared_ptr<GGMLBlock>(new ResnetBlock(block_in, block_in));
|
||||
|
||||
blocks["norm_out"] = std::shared_ptr<GGMLBlock>(new GroupNorm32(block_in));
|
||||
@@ -351,8 +399,9 @@ public:
|
||||
std::vector<int> ch_mult,
|
||||
int num_res_blocks,
|
||||
int z_channels,
|
||||
bool video_decoder = false,
|
||||
int video_kernel_size = 3)
|
||||
bool use_linear_projection = false,
|
||||
bool video_decoder = false,
|
||||
int video_kernel_size = 3)
|
||||
: ch(ch),
|
||||
out_ch(out_ch),
|
||||
ch_mult(ch_mult),
|
||||
@@ -366,7 +415,7 @@ public:
|
||||
blocks["conv_in"] = std::shared_ptr<GGMLBlock>(new Conv2d(z_channels, block_in, {3, 3}, {1, 1}, {1, 1}));
|
||||
|
||||
blocks["mid.block_1"] = get_resnet_block(block_in, block_in);
|
||||
blocks["mid.attn_1"] = std::shared_ptr<GGMLBlock>(new AttnBlock(block_in));
|
||||
blocks["mid.attn_1"] = std::shared_ptr<GGMLBlock>(new AttnBlock(block_in, use_linear_projection));
|
||||
blocks["mid.block_2"] = get_resnet_block(block_in, block_in);
|
||||
|
||||
for (int i = num_resolutions - 1; i >= 0; i--) {
|
||||
@@ -454,9 +503,10 @@ protected:
|
||||
} dd_config;
|
||||
|
||||
public:
|
||||
AutoencodingEngine(bool decode_only = true,
|
||||
bool use_video_decoder = false,
|
||||
SDVersion version = VERSION_SD1)
|
||||
AutoencodingEngine(SDVersion version = VERSION_SD1,
|
||||
bool decode_only = true,
|
||||
bool use_linear_projection = false,
|
||||
bool use_video_decoder = false)
|
||||
: decode_only(decode_only), use_video_decoder(use_video_decoder) {
|
||||
if (sd_version_is_dit(version)) {
|
||||
dd_config.z_channels = 16;
|
||||
@@ -470,6 +520,7 @@ public:
|
||||
dd_config.ch_mult,
|
||||
dd_config.num_res_blocks,
|
||||
dd_config.z_channels,
|
||||
use_linear_projection,
|
||||
use_video_decoder));
|
||||
if (use_quant) {
|
||||
blocks["post_quant_conv"] = std::shared_ptr<GGMLBlock>(new Conv2d(dd_config.z_channels,
|
||||
@@ -482,7 +533,8 @@ public:
|
||||
dd_config.num_res_blocks,
|
||||
dd_config.in_channels,
|
||||
dd_config.z_channels,
|
||||
dd_config.double_z));
|
||||
dd_config.double_z,
|
||||
use_linear_projection));
|
||||
if (use_quant) {
|
||||
int factor = dd_config.double_z ? 2 : 1;
|
||||
|
||||
@@ -562,13 +614,26 @@ struct AutoEncoderKL : public VAE {
|
||||
|
||||
AutoEncoderKL(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const String2TensorStorage& tensor_storage_map,
|
||||
const std::string prefix,
|
||||
bool decode_only = false,
|
||||
bool use_video_decoder = false,
|
||||
SDVersion version = VERSION_SD1)
|
||||
: decode_only(decode_only), ae(decode_only, use_video_decoder, version), VAE(backend, offload_params_to_cpu) {
|
||||
ae.init(params_ctx, tensor_types, prefix);
|
||||
: decode_only(decode_only), VAE(backend, offload_params_to_cpu) {
|
||||
bool use_linear_projection = false;
|
||||
for (const auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (!starts_with(name, prefix)) {
|
||||
continue;
|
||||
}
|
||||
if (ends_with(name, "attn_1.proj_out.weight")) {
|
||||
if (tensor_storage.n_dims == 2) {
|
||||
use_linear_projection = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ae = AutoencodingEngine(version, decode_only, use_linear_projection, use_video_decoder);
|
||||
ae.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
void set_conv2d_scale(float scale) override {
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace WAN {
|
||||
std::tuple<int, int, int> dilation;
|
||||
bool bias;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
params["weight"] = ggml_new_tensor_4d(ctx,
|
||||
GGML_TYPE_F16,
|
||||
std::get<2>(kernel_size),
|
||||
@@ -87,9 +87,14 @@ namespace WAN {
|
||||
protected:
|
||||
int64_t dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
ggml_type wtype = GGML_TYPE_F32;
|
||||
params["gamma"] = ggml_new_tensor_1d(ctx, wtype, dim);
|
||||
auto iter = tensor_storage_map.find(prefix + "gamma");
|
||||
if (iter != tensor_storage_map.end()) {
|
||||
params["gamma"] = ggml_new_tensor(ctx, wtype, iter->second.n_dims, &iter->second.ne[0]);
|
||||
} else {
|
||||
params["gamma"] = ggml_new_tensor_1d(ctx, wtype, dim);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -101,6 +106,7 @@ namespace WAN {
|
||||
// assert N == 1
|
||||
|
||||
struct ggml_tensor* w = params["gamma"];
|
||||
w = ggml_reshape_1d(ctx->ggml_ctx, w, ggml_nelements(w));
|
||||
auto h = ggml_ext_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, x, 3, 0, 1, 2)); // [ID, IH, IW, N*IC]
|
||||
h = ggml_rms_norm(ctx->ggml_ctx, h, 1e-12);
|
||||
h = ggml_mul(ctx->ggml_ctx, h, w);
|
||||
@@ -1110,12 +1116,12 @@ namespace WAN {
|
||||
|
||||
WanVAERunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
bool decode_only = false,
|
||||
SDVersion version = VERSION_WAN2)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
bool decode_only = false,
|
||||
SDVersion version = VERSION_WAN2)
|
||||
: decode_only(decode_only), ae(decode_only, version == VERSION_WAN2_2_TI2V), VAE(backend, offload_params_to_cpu) {
|
||||
ae.init(params_ctx, tensor_types, prefix);
|
||||
ae.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -1127,7 +1133,7 @@ namespace WAN {
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* z, bool decode_graph) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, 10240 * z->ne[2], false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(10240 * z->ne[2]);
|
||||
|
||||
z = to_backend(z);
|
||||
|
||||
@@ -1141,7 +1147,7 @@ namespace WAN {
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_graph_partial(struct ggml_tensor* z, bool decode_graph, int64_t i) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, 20480, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(20480);
|
||||
|
||||
ae.clear_cache();
|
||||
|
||||
@@ -1256,7 +1262,7 @@ namespace WAN {
|
||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
std::shared_ptr<WanVAERunner> vae = std::make_shared<WanVAERunner>(backend, false, String2GGMLType{}, "", false, VERSION_WAN2_2_TI2V);
|
||||
std::shared_ptr<WanVAERunner> vae = std::make_shared<WanVAERunner>(backend, false, String2TensorStorage{}, "", false, VERSION_WAN2_2_TI2V);
|
||||
{
|
||||
LOG_INFO("loading from '%s'", file_path.c_str());
|
||||
|
||||
@@ -1265,7 +1271,7 @@ namespace WAN {
|
||||
vae->get_param_tensors(tensors, "first_stage_model");
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "vae.")) {
|
||||
if (!model_loader.init_from_file_and_convert_name(file_path, "vae.")) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", file_path.c_str());
|
||||
return;
|
||||
}
|
||||
@@ -1494,8 +1500,8 @@ namespace WAN {
|
||||
protected:
|
||||
int dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 6, 1);
|
||||
}
|
||||
|
||||
@@ -1582,8 +1588,8 @@ namespace WAN {
|
||||
class VaceWanAttentionBlock : public WanAttentionBlock {
|
||||
protected:
|
||||
int block_id;
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 6, 1);
|
||||
}
|
||||
|
||||
@@ -1634,8 +1640,8 @@ namespace WAN {
|
||||
protected:
|
||||
int dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 2, 1);
|
||||
}
|
||||
|
||||
@@ -1681,7 +1687,7 @@ namespace WAN {
|
||||
int in_dim;
|
||||
int flf_pos_embed_token_number;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
void init_params(struct ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
|
||||
if (flf_pos_embed_token_number > 0) {
|
||||
params["emb_pos"] = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, in_dim, flf_pos_embed_token_number, 1);
|
||||
}
|
||||
@@ -2015,12 +2021,12 @@ namespace WAN {
|
||||
|
||||
WanRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_WAN2)
|
||||
const String2TensorStorage& tensor_storage_map = {},
|
||||
const std::string prefix = "",
|
||||
SDVersion version = VERSION_WAN2)
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
wan_params.num_layers = 0;
|
||||
for (auto pair : tensor_types) {
|
||||
for (auto pair : tensor_storage_map) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find(prefix) == std::string::npos)
|
||||
continue;
|
||||
@@ -2069,15 +2075,19 @@ namespace WAN {
|
||||
wan_params.text_len = 512;
|
||||
} else {
|
||||
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 {
|
||||
desc = "Wan2.1-T2V-1.3B";
|
||||
desc = "Wan2.1-T2V-1.3B";
|
||||
wan_params.in_dim = 16;
|
||||
}
|
||||
wan_params.dim = 1536;
|
||||
wan_params.eps = 1e-06;
|
||||
wan_params.ffn_dim = 8960;
|
||||
wan_params.freq_dim = 256;
|
||||
wan_params.in_dim = 16;
|
||||
wan_params.num_heads = 12;
|
||||
wan_params.out_dim = 16;
|
||||
wan_params.text_len = 512;
|
||||
@@ -2117,7 +2127,7 @@ namespace WAN {
|
||||
LOG_INFO("%s", desc.c_str());
|
||||
|
||||
wan = Wan(wan_params);
|
||||
wan.init(params_ctx, tensor_types, prefix);
|
||||
wan.init(params_ctx, tensor_storage_map, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
@@ -2136,7 +2146,7 @@ namespace WAN {
|
||||
struct ggml_tensor* time_dim_concat = nullptr,
|
||||
struct ggml_tensor* vace_context = nullptr,
|
||||
float vace_strength = 1.f) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, WAN_GRAPH_SIZE, false);
|
||||
struct ggml_cgraph* gf = new_graph_custom(WAN_GRAPH_SIZE);
|
||||
|
||||
x = to_backend(x);
|
||||
timesteps = to_backend(timesteps);
|
||||
@@ -2249,22 +2259,21 @@ namespace WAN {
|
||||
LOG_INFO("loading from '%s'", file_path.c_str());
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "model.diffusion_model.")) {
|
||||
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_types = model_loader.tensor_storages_types;
|
||||
for (auto& item : tensor_types) {
|
||||
// LOG_DEBUG("%s %u", item.first.c_str(), item.second);
|
||||
if (ends_with(item.first, "weight")) {
|
||||
item.second = model_data_type;
|
||||
auto& tensor_storage_map = model_loader.get_tensor_storage_map();
|
||||
for (auto& [name, tensor_storage] : tensor_storage_map) {
|
||||
if (ends_with(name, "weight")) {
|
||||
tensor_storage.expected_type = model_data_type;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<WanRunner> wan = std::make_shared<WanRunner>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
tensor_storage_map,
|
||||
"model.diffusion_model",
|
||||
VERSION_WAN2_2_TI2V);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user