perf: cache CPU position embeddings across DiT runners (#2211)

This commit is contained in:
leejet authored and GitHub committed 2026-10-25 05:18:30 +08:00
1 parent a85db96aa5
commit ea209dbfcf
31 files changed
+855 -610

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
# Position embedding cache
`sd::PECache` stores CPU-side `sd::Tensor<float>` data. Each model runner owns
its cache and calls the existing `make_input()` on every graph build. Cache
hits skip PE generation; allocation and upload remain ordinary graph-input
operations. `GGMLRunner` has no PE-specific code or resource hooks.
The cache keeps the most recent key and tensor for each named PE input. A
matching key returns the existing tensor by reference. Changing its parameters
replaces that input's cached result. Different named inputs have independent
storage. Alternating two layouts under the same name recomputes their PE;
there is no LRU, device-buffer cache, memory budget, or graph lifecycle callback.
CPU data lives with the model runner, including across `runner_end()` calls,
and is released when its named entry is replaced or the cache is destroyed.
## Adding a model
Include `core/pe_cache.h` and declare a member:
```cpp
sd::PECache pe_cache_;
```
Construct the key before generating PE and place the generation code in the
lazy callback:
```cpp
sd::PECacheKey key("model.image_pe");
key.add(height).add(width).add(head_dim).add(theta)
.add(circular_x_enabled).add(circular_y_enabled);
auto pe = make_input(pe_cache_.get_or_create(key, [&]() {
auto values = generate_position_embedding(/* existing arguments */);
return sd::Tensor<float>({2, 2, head_dim / 2, token_count}, std::move(values));
}));
```
Keys must cover every variable affecting PE values or shape: geometry, text
length, frequency settings, reference-image ordering and offsets, circular
settings, and video/audio positions or frame rates as applicable.
`add_shape()` records all four ggml dimensions, including trailing singleton
dimensions. `add_shapes()` records an ordered list of reference shapes.
`add(sd::Tensor<T>)` records both shape and values for explicit position inputs.
Keys compare their complete encoded fields rather than a data pointer or hash.
Use distinct names for PE inputs that coexist in a graph, such as Anima's
adapter query and key PE. `make_input()` defers reading the CPU data until graph
execution: do not replace a named entry while an unfinished graph references
it. Adding or updating other named entries does not invalidate its storage.
Return tensor shapes with the contiguous dimension first, and preserve each
model's existing F32 values, layout, and final transformations.
## Current integrations
The cache is used by MiniT2I, the Flux runner and its variants, Flux3, Qwen Image,
Qwen Image 2.1, Z-Image and L2P, Anima, Boogu, ERNIE Image, Fibo2, Ideogram4,
Iris, Krea2, Lens, LLaDA Image, MAGE Flow, Ming Image, MOSS Image, PiD, PixArt,
Wan, Hunyuan Video, LingBot Video, and LTX audio/video.
Position embeddings stored as model weights and graph-side RoPE operations
remain on their existing paths, including MiniMax H3 and SenseNova U1.
+30
View File
@@ -0,0 +1,30 @@
#include "core/pe_cache.h"
namespace sd {
PECacheKey& PECacheKey::add_shape(const ggml_tensor* tensor) {
add(tensor != nullptr);
if (tensor != nullptr) {
for (int i = 0; i < GGML_MAX_DIMS; ++i) {
add(tensor->ne[i]);
}
}
return *this;
}
PECacheKey& PECacheKey::add_shapes(const std::vector<ggml_tensor*>& tensors) {
add(tensors.size());
for (const auto* tensor : tensors) {
add_shape(tensor);
}
return *this;
}
const Tensor<float>& PECache::get_or_create(const PECacheKey& key, const std::function<Tensor<float>()>& build) {
auto entry = entries_.find(key.name());
if (entry != entries_.end() && entry->second.key == key) {
return entry->second.value;
}
auto value = build();
return entries_.insert_or_assign(key.name(), Entry{key, std::move(value)}).first->second.value;
}
}
+82
View File
@@ -0,0 +1,82 @@
#ifndef __SD_CORE_PE_CACHE_H__
#define __SD_CORE_PE_CACHE_H__
#include <functional>
#include <map>
#include <set>
#include <type_traits>
#include "core/tensor.hpp"
#include "ggml.h"
namespace sd {
class PECacheKey {
std::string name_;
std::string fields_;
public:
explicit PECacheKey(std::string name)
: name_(std::move(name)) {}
const std::string& name() const { return name_; }
template <typename T, std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>, int> = 0>
PECacheKey& add(T value) {
if constexpr (std::is_floating_point_v<T>) {
const double field = static_cast<double>(value);
fields_.push_back('f');
fields_.append(reinterpret_cast<const char*>(&field), sizeof(field));
} else {
const uint64_t field = static_cast<uint64_t>(value);
fields_.push_back('i');
fields_.append(reinterpret_cast<const char*>(&field), sizeof(field));
}
return *this;
}
template <typename T>
PECacheKey& add(const std::vector<T>& values) {
fields_.push_back('v');
add(values.size());
for (const auto& value : values) {
add(value);
}
return *this;
}
template <typename T>
PECacheKey& add(const std::set<T>& values) {
return add(std::vector<T>(values.begin(), values.end()));
}
template <typename T>
PECacheKey& add(const Tensor<T>& values) {
add(values.shape());
for (int64_t i = 0; i < values.numel(); ++i) {
add(values.data()[i]);
}
return *this;
}
PECacheKey& add_shape(const ggml_tensor* tensor);
PECacheKey& add_shapes(const std::vector<ggml_tensor*>& tensors);
bool operator==(const PECacheKey& other) const {
return name_ == other.name_ && fields_ == other.fields_;
}
};
class PECache {
struct Entry {
PECacheKey key;
Tensor<float> value;
};
std::map<std::string, Entry> entries_;
public:
const Tensor<float>& get_or_create(const PECacheKey& key, const std::function<Tensor<float>()>& build);
};
}
#endif // __SD_CORE_PE_CACHE_H__
+30 -26
View File
@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -562,10 +563,9 @@ namespace Anima {
}; };
struct AnimaRunner : public DiffusionModelRunner { struct AnimaRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
std::vector<float> image_pe_vec;
std::vector<float> adapter_q_pe_vec;
std::vector<float> adapter_k_pe_vec;
AnimaConfig config; AnimaConfig config;
AnimaNet net; AnimaNet net;
@@ -660,19 +660,23 @@ namespace Anima {
int64_t h_pad = x->ne[1] + pad_h; int64_t h_pad = x->ne[1] + pad_h;
int64_t w_pad = x->ne[0] + pad_w; int64_t w_pad = x->ne[0] + pad_w;
image_pe_vec = finish_rope_pe(gen_anima_image_pe_vec(1, sd::PECacheKey image_pe_key("anima.image_pe");
static_cast<int>(h_pad), image_pe_key.add(h_pad).add(w_pad).add(config.patch_size).add(config.theta).add(config.axes_dim).add(config.head_dim);
static_cast<int>(w_pad), image_pe_key.add_shapes(ref_latents).add(circular_x_enabled).add(circular_y_enabled);
static_cast<int>(config.patch_size), auto image_pe = make_input(pe_cache_.get_or_create(image_pe_key, [&]() {
config.theta, auto image_pe_vec = finish_rope_pe(gen_anima_image_pe_vec(1,
config.axes_dim, static_cast<int>(h_pad),
4.0f, static_cast<int>(w_pad),
4.0f, static_cast<int>(config.patch_size),
1.0f, config.theta,
ref_latents)); config.axes_dim,
int64_t image_pos_len = static_cast<int64_t>(image_pe_vec.size()) / (2 * 2 * (config.head_dim / 2)); 4.0f,
auto image_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, image_pos_len); 4.0f,
set_backend_tensor_data(image_pe, image_pe_vec.data()); 1.0f,
ref_latents));
int64_t image_pos_len = static_cast<int64_t>(image_pe_vec.size()) / (2 * 2 * (config.head_dim / 2));
return sd::Tensor<float>({2, 2, config.head_dim / 2, image_pos_len}, std::move(image_pe_vec));
}));
ggml_tensor* adapter_q_pe = nullptr; ggml_tensor* adapter_q_pe = nullptr;
ggml_tensor* adapter_k_pe = nullptr; ggml_tensor* adapter_k_pe = nullptr;
@@ -680,16 +684,16 @@ namespace Anima {
int64_t target_len = t5_ids->ne[0]; int64_t target_len = t5_ids->ne[0];
int64_t source_len = context->ne[1]; int64_t source_len = context->ne[1];
adapter_q_pe_vec = gen_1d_rope_pe_vec(target_len, 64, 10000.f); sd::PECacheKey q_key("anima.adapter_q_pe");
adapter_k_pe_vec = gen_1d_rope_pe_vec(source_len, 64, 10000.f); q_key.add(target_len);
adapter_q_pe = make_input(pe_cache_.get_or_create(q_key, [&]() {
int64_t target_pos_len = static_cast<int64_t>(adapter_q_pe_vec.size()) / (2 * 2 * 32); return sd::Tensor<float>({2, 2, 32, target_len}, gen_1d_rope_pe_vec(target_len, 64, 10000.f));
int64_t source_pos_len = static_cast<int64_t>(adapter_k_pe_vec.size()) / (2 * 2 * 32); }));
sd::PECacheKey k_key("anima.adapter_k_pe");
adapter_q_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, 32, target_pos_len); k_key.add(source_len);
adapter_k_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, 32, source_pos_len); adapter_k_pe = make_input(pe_cache_.get_or_create(k_key, [&]() {
set_backend_tensor_data(adapter_q_pe, adapter_q_pe_vec.data()); return sd::Tensor<float>({2, 2, 32, source_len}, gen_1d_rope_pe_vec(source_len, 64, 10000.f));
set_backend_tensor_data(adapter_k_pe, adapter_k_pe_vec.data()); }));
} }
auto runner_ctx = get_context(); auto runner_ctx = get_context();
+17 -12
View File
@@ -6,6 +6,7 @@
#include <cmath> #include <cmath>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_runner.h" #include "core/ggml_runner.h"
@@ -759,9 +760,9 @@ namespace Boogu {
} }
struct BooguImageRunner : public DiffusionModelRunner { struct BooguImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
BooguConfig config; BooguConfig config;
BooguImageModel boogu; BooguImageModel boogu;
std::vector<float> pe_vec;
BooguImageRunner(ggml_backend_t backend, BooguImageRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -799,17 +800,21 @@ namespace Boogu {
ref_latents.push_back(make_input(ref_latent_tensor)); ref_latents.push_back(make_input(ref_latent_tensor));
} }
pe_vec = finish_rope_pe(gen_boogu_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("boogu.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size).add_shapes(ref_latents);
static_cast<int>(x->ne[3]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
static_cast<int>(context->ne[1]), auto pe_vec = finish_rope_pe(gen_boogu_pe(static_cast<int>(x->ne[1]),
ref_latents, static_cast<int>(x->ne[0]),
config.theta, config.patch_size,
config.axes_dim)); static_cast<int>(x->ne[3]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(context->ne[1]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ref_latents,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = boogu.forward(&runner_ctx, x, timesteps, context, pe, ref_latents); ggml_tensor* out = boogu.forward(&runner_ctx, x, timesteps, context, pe, ref_latents);
+16 -11
View File
@@ -4,6 +4,7 @@
#include <cinttypes> #include <cinttypes>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
#include "model/diffusion/dit.hpp" #include "model/diffusion/dit.hpp"
@@ -383,9 +384,9 @@ namespace ErnieImage {
}; };
struct ErnieImageRunner : public DiffusionModelRunner { struct ErnieImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
ErnieImageConfig config; ErnieImageConfig config;
ErnieImageModel ernie_image; ErnieImageModel ernie_image;
std::vector<float> pe_vec;
ErnieImageRunner(ggml_backend_t backend, ErnieImageRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -415,16 +416,20 @@ namespace ErnieImage {
GGML_ASSERT(!context_tensor.empty()); GGML_ASSERT(!context_tensor.empty());
ggml_tensor* context = make_input(context_tensor); ggml_tensor* context = make_input(context_tensor);
pe_vec = finish_rope_pe(Rope::gen_ernie_image_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("ernie_image.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size);
static_cast<int>(x->ne[3]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
static_cast<int>(context->ne[1]), auto pe_vec = finish_rope_pe(Rope::gen_ernie_image_pe(static_cast<int>(x->ne[1]),
config.theta, static_cast<int>(x->ne[0]),
config.axes_dim)); config.patch_size,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(x->ne[3]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, config.axes_dim_sum, 1, pos_len, 2); static_cast<int>(context->ne[1]),
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({config.axes_dim_sum, 1, pos_len, 2}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = ernie_image.forward(&runner_ctx, x, timesteps, context, pe); ggml_tensor* out = ernie_image.forward(&runner_ctx, x, timesteps, context, pe);
+25 -17
View File
@@ -1,6 +1,7 @@
#ifndef __SD_MODEL_DIFFUSION_FIBO2_HPP__ #ifndef __SD_MODEL_DIFFUSION_FIBO2_HPP__
#define __SD_MODEL_DIFFUSION_FIBO2_HPP__ #define __SD_MODEL_DIFFUSION_FIBO2_HPP__
#include "core/pe_cache.h"
#include "model/diffusion/z_image.hpp" #include "model/diffusion/z_image.hpp"
// https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_bria_fibo2.py // https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_bria_fibo2.py
@@ -333,9 +334,9 @@ namespace Fibo2 {
}; };
struct Fibo2Runner : public DiffusionModelRunner { struct Fibo2Runner : public DiffusionModelRunner {
sd::PECache pe_cache_;
Fibo2Config config; Fibo2Config config;
Fibo2Model model; Fibo2Model model;
std::vector<float> pe_values;
Fibo2Runner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr) Fibo2Runner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr)
: DiffusionModelRunner(backend, prefix, weight_manager), : DiffusionModelRunner(backend, prefix, weight_manager),
@@ -360,28 +361,35 @@ namespace Fibo2 {
auto x = make_input(*p.x); auto x = make_input(*p.x);
GGML_ASSERT(x->ne[3] == 1 && x->ne[2] == config.channels); GGML_ASSERT(x->ne[3] == 1 && x->ne[2] == config.channels);
int count = config.gist_count(static_cast<int>(p.context->shape()[1])); int count = config.gist_count(static_cast<int>(p.context->shape()[1]));
Rope::Embedding embedding;
for (int i = 0; i < count; ++i) {
embedding.ids.push_back({static_cast<float>(i + 1), 0.f, 0.f});
}
embedding.positions.append_tokens(count);
auto append_image = [&](ggml_tensor* image, int plane) {
auto ids = Rope::gen_flux_img_ids(static_cast<int>(image->ne[1]), static_cast<int>(image->ne[0]),
1, 1, 3, plane, 0, 0, false, &embedding.positions);
embedding.ids.insert(embedding.ids.end(), ids.begin(), ids.end());
};
append_image(x, static_cast<int>(config.max_gist + 1));
std::vector<ggml_tensor*> refs; std::vector<ggml_tensor*> refs;
if (p.ref_latents && p.ref_image_params.pass_to_dit) { if (p.ref_latents && p.ref_image_params.pass_to_dit) {
for (const auto& ref : *p.ref_latents) { for (const auto& ref : *p.ref_latents) {
refs.push_back(make_input(ref)); refs.push_back(make_input(ref));
append_image(refs.back(), static_cast<int>(config.max_gist + 1 + refs.size()));
} }
} }
embedding.values = Rope::embed_nd(embedding.ids, 1, 256.f, {32, 48, 48}, embedding.layout, &embedding.frequencies); sd::PECacheKey pe_key("fibo2.pe");
pe_values = finish_rope_pe(std::move(embedding)); pe_key.add_shape(x).add(count).add(config.max_gist).add_shapes(refs).add(circular_x_enabled);
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, 64, static_cast<int64_t>(pe_values.size() / 256)); pe_key.add(circular_y_enabled);
set_backend_tensor_data(pe, pe_values.data()); auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
Rope::Embedding embedding;
for (int i = 0; i < count; ++i) {
embedding.ids.push_back({static_cast<float>(i + 1), 0.f, 0.f});
}
embedding.positions.append_tokens(count);
auto append_image = [&](ggml_tensor* image, int plane) {
auto ids = Rope::gen_flux_img_ids(static_cast<int>(image->ne[1]), static_cast<int>(image->ne[0]),
1, 1, 3, plane, 0, 0, false, &embedding.positions);
embedding.ids.insert(embedding.ids.end(), ids.begin(), ids.end());
};
append_image(x, static_cast<int>(config.max_gist + 1));
for (size_t i = 0; i < refs.size(); ++i) {
append_image(refs[i], static_cast<int>(config.max_gist + 2 + i));
}
embedding.values = Rope::embed_nd(embedding.ids, 1, 256.f, {32, 48, 48}, embedding.layout, &embedding.frequencies);
auto values = finish_rope_pe(std::move(embedding));
const int64_t tokens = static_cast<int64_t>(values.size() / 256);
return sd::Tensor<float>({2, 2, 64, tokens}, std::move(values));
}));
auto ctx = get_context(); auto ctx = get_context();
auto out = model.forward(&ctx, x, make_input(*p.timesteps), make_input(*p.context), pe, count, refs); auto out = model.forward(&ctx, x, make_input(*p.timesteps), make_input(*p.context), pe, count, refs);
ggml_build_forward_expand(graph, out); ggml_build_forward_expand(graph, out);
+23 -20
View File
@@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "core/ggml_extend_backend.h" #include "core/ggml_extend_backend.h"
#include "core/ggml_tensor_utils.h" #include "core/ggml_tensor_utils.h"
#include "core/pe_cache.h"
#include "core/util.h" #include "core/util.h"
#include "model/adapter/pulid.hpp" #include "model/adapter/pulid.hpp"
@@ -1398,10 +1399,11 @@ namespace Flux {
}; };
struct FluxRunner : public DiffusionModelRunner { struct FluxRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
FluxConfig config; FluxConfig config;
Flux flux; Flux flux;
std::vector<float> pe_vec;
std::vector<float> mod_index_arange_vec; std::vector<float> mod_index_arange_vec;
std::vector<float> dct_vec; std::vector<float> dct_vec;
sd::Tensor<float> guidance_tensor; sd::Tensor<float> guidance_tensor;
@@ -1548,25 +1550,26 @@ namespace Flux {
} else if (version == VERSION_OVIS_IMAGE) { } else if (version == VERSION_OVIS_IMAGE) {
txt_arange_dims = {1, 2}; txt_arange_dims = {1, 2};
} }
pe_vec = finish_rope_pe(Rope::gen_flux_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("flux.pe");
static_cast<int>(x->ne[0]), pe_key.add(version).add_shape(x).add_shape(context).add(config.patch_size).add(txt_arange_dims);
config.patch_size, pe_key.add_shapes(ref_latents).add(ref_index_mode).add(config.ref_index_scale).add(config.theta).add(config.axes_dim);
static_cast<int>(x->ne[3]), pe_key.add(circular_x_enabled).add(circular_y_enabled);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
txt_arange_dims, auto pe_vec = finish_rope_pe(Rope::gen_flux_pe(static_cast<int>(x->ne[1]),
ref_latents, static_cast<int>(x->ne[0]),
ref_index_mode, config.patch_size,
config.ref_index_scale, static_cast<int>(x->ne[3]),
config.theta, static_cast<int>(context->ne[1]),
config.axes_dim, txt_arange_dims,
sd_version_is_longcat(version))); ref_latents,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); ref_index_mode,
// LOG_VERBOSE("pos_len %d", pos_len); config.ref_index_scale,
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); config.theta,
// pe->data = pe_vec.data(); config.axes_dim,
// print_ggml_tensor(pe); sd_version_is_longcat(version)));
// pe->data = nullptr; int64_t pos_len = static_cast<int64_t>(pe_vec.size() / config.axes_dim_sum / 2);
set_backend_tensor_data(pe, pe_vec.data()); return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
if (version == VERSION_CHROMA_RADIANCE) { if (version == VERSION_CHROMA_RADIANCE) {
int patch_size = config.patch_size; int patch_size = config.patch_size;
+29 -21
View File
@@ -1,6 +1,7 @@
#ifndef __SD_MODEL_DIFFUSION_FLUX3_HPP__ #ifndef __SD_MODEL_DIFFUSION_FLUX3_HPP__
#define __SD_MODEL_DIFFUSION_FLUX3_HPP__ #define __SD_MODEL_DIFFUSION_FLUX3_HPP__
#include "core/pe_cache.h"
#include "model/diffusion/flux.hpp" #include "model/diffusion/flux.hpp"
namespace Flux3 { namespace Flux3 {
@@ -183,9 +184,9 @@ namespace Flux3 {
}; };
struct Flux3Runner : public DiffusionModelRunner { struct Flux3Runner : public DiffusionModelRunner {
sd::PECache pe_cache_;
Flux3Config config; Flux3Config config;
Model model; Model model;
std::vector<float> pe_values;
sd::Tensor<float> zero = sd::Tensor<float>::zeros({1}); sd::Tensor<float> zero = sd::Tensor<float>::zeros({1});
Flux3Runner(ggml_backend_t backend, const String2TensorStorage& tensors, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr) Flux3Runner(ggml_backend_t backend, const String2TensorStorage& tensors, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr)
@@ -213,34 +214,41 @@ namespace Flux3 {
auto x = make_input(*params.x); auto x = make_input(*params.x);
auto text = make_input(*params.context); auto text = make_input(*params.context);
GGML_ASSERT(x->ne[3] == 1 && text->ne[2] == 1); GGML_ASSERT(x->ne[3] == 1 && text->ne[2] == 1);
Rope::Embedding embedding; std::vector<ggml_tensor*> refs;
auto append_image = [&](int64_t w, int64_t h, float index) {
embedding.positions.append_image(static_cast<int>(h), static_cast<int>(w), 1, 0.5f, 0.5f);
for (int64_t y = 0; y < h; ++y) {
for (int64_t x = 0; x < w; ++x) {
embedding.ids.push_back({0.f, y * 0.5f, x * 0.5f, index});
}
}
};
append_image(x->ne[0], x->ne[1], 0.f);
ggml_tensor* references = nullptr; ggml_tensor* references = nullptr;
if (params.ref_latents && params.ref_image_params.pass_to_dit) { if (params.ref_latents && params.ref_image_params.pass_to_dit) {
int index = 0;
for (const auto& ref : *params.ref_latents) { for (const auto& ref : *params.ref_latents) {
auto r = make_input(ref); auto r = make_input(ref);
append_image(r->ne[0], r->ne[1], -float(++index)); refs.push_back(r);
r = DiT::patchify(compute_ctx, r, 1, 1); r = DiT::patchify(compute_ctx, r, 1, 1);
references = references ? ggml_concat(compute_ctx, references, r, 1) : r; references = references ? ggml_concat(compute_ctx, references, r, 1) : r;
} }
} }
for (int64_t i = 0; i < text->ne[1]; ++i) { sd::PECacheKey pe_key("flux3.pe");
embedding.ids.push_back({0.f, 0.f, 0.f, static_cast<float>(i)}); pe_key.add_shape(x).add_shape(text).add_shapes(refs).add(circular_x_enabled).add(circular_y_enabled);
} auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
embedding.positions.append_tokens(text->ne[1]); Rope::Embedding embedding;
embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, {32, 32, 32, 32}, embedding.layout, &embedding.frequencies); auto append_image = [&](int64_t w, int64_t h, float index) {
pe_values = finish_rope_pe(std::move(embedding)); embedding.positions.append_image(static_cast<int>(h), static_cast<int>(w), 1, 0.5f, 0.5f);
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, 64, pe_values.size() / 256); for (int64_t y = 0; y < h; ++y) {
set_backend_tensor_data(pe, pe_values.data()); for (int64_t x = 0; x < w; ++x) {
embedding.ids.push_back({0.f, y * 0.5f, x * 0.5f, index});
}
}
};
append_image(x->ne[0], x->ne[1], 0.f);
for (size_t i = 0; i < refs.size(); ++i) {
append_image(refs[i]->ne[0], refs[i]->ne[1], -float(i + 1));
}
for (int64_t i = 0; i < text->ne[1]; ++i) {
embedding.ids.push_back({0.f, 0.f, 0.f, static_cast<float>(i)});
}
embedding.positions.append_tokens(text->ne[1]);
embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, {32, 32, 32, 32}, embedding.layout, &embedding.frequencies);
auto values = finish_rope_pe(std::move(embedding));
const int64_t tokens = static_cast<int64_t>(values.size() / 256);
return sd::Tensor<float>({2, 2, 64, tokens}, std::move(values));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
auto out = model.forward(&runner_ctx, x, text, references, make_input(*params.timesteps), make_input(zero), auto out = model.forward(&runner_ctx, x, text, references, make_input(*params.timesteps), make_input(zero),
config.flow_map ? make_input(*extra->target_timestep) : nullptr, pe); config.flow_map ? make_input(*extra->target_timestep) : nullptr, pe);
+21 -18
View File
@@ -3,6 +3,7 @@
#include <cinttypes> #include <cinttypes>
#include <memory> #include <memory>
#include "core/pe_cache.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
#include "model/diffusion/flux.hpp" #include "model/diffusion/flux.hpp"
@@ -540,10 +541,11 @@ namespace Hunyuan {
}; };
struct HunyuanVideoRunner : public DiffusionModelRunner { struct HunyuanVideoRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
HunyuanVideoConfig config; HunyuanVideoConfig config;
HunyuanVideoModel hunyuan_video; HunyuanVideoModel hunyuan_video;
std::vector<float> pe_vec;
SDVersion version; SDVersion version;
HunyuanVideoRunner(ggml_backend_t backend, HunyuanVideoRunner(ggml_backend_t backend,
@@ -605,23 +607,24 @@ namespace Hunyuan {
if (vision != nullptr) { if (vision != nullptr) {
text_len += static_cast<int>(vision->ne[1]); text_len += static_cast<int>(vision->ne[1]);
} }
pe_vec = Rope::gen_hunyuan_video_pe(static_cast<int>(x->ne[2]), sd::PECacheKey pe_key("hunyuan.pe");
static_cast<int>(x->ne[1]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
static_cast<int>(x->ne[0]), pe_key.add(circular_x_enabled).add(circular_y_enabled).add(std::get<0>(config.patch_size));
std::get<0>(config.patch_size), pe_key.add(std::get<1>(config.patch_size)).add(std::get<2>(config.patch_size)).add(text_len);
std::get<1>(config.patch_size), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
std::get<2>(config.patch_size), auto pe_vec = Rope::gen_hunyuan_video_pe(static_cast<int>(x->ne[2]),
1, static_cast<int>(x->ne[1]),
text_len, static_cast<int>(x->ne[0]),
config.theta, std::get<0>(config.patch_size),
config.axes_dim); std::get<1>(config.patch_size),
int64_t pos_len = static_cast<int64_t>(pe_vec.size() / config.axes_dim_sum / 2); std::get<2>(config.patch_size),
// LOG_VERBOSE("pos_len %d", pos_len); 1,
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); text_len,
// pe->data = pe_vec.data(); config.theta,
// print_ggml_tensor(pe, true, "pe"); config.axes_dim);
// pe->data = nullptr; int64_t pos_len = static_cast<int64_t>(pe_vec.size() / config.axes_dim_sum / 2);
set_backend_tensor_data(pe, pe_vec.data()); return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
+10 -4
View File
@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_graph_cut.h" #include "core/ggml_graph_cut.h"
@@ -422,6 +423,8 @@ namespace Ideogram4 {
}; };
class Ideogram4Runner : public DiffusionModelRunner { class Ideogram4Runner : public DiffusionModelRunner {
sd::PECache pe_cache_;
protected: protected:
bool should_use_uncond_model(const DiffusionParams& diffusion_params) const { bool should_use_uncond_model(const DiffusionParams& diffusion_params) const {
return has_uncond_model && return has_uncond_model &&
@@ -436,7 +439,6 @@ namespace Ideogram4 {
Ideogram4Transformer uncond_model; Ideogram4Transformer uncond_model;
bool has_uncond_model = false; bool has_uncond_model = false;
std::string uncond_prefix; std::string uncond_prefix;
std::vector<float> pe_vec;
std::vector<int32_t> image_indicator_vec; std::vector<int32_t> image_indicator_vec;
Ideogram4Runner(ggml_backend_t backend, Ideogram4Runner(ggml_backend_t backend,
@@ -496,15 +498,19 @@ namespace Ideogram4 {
int64_t head_dim = config.emb_dim / config.num_heads; int64_t head_dim = config.emb_dim / config.num_heads;
auto runner_ctx = get_context(); auto runner_ctx = get_context();
pe_vec = finish_rope_pe(gen_ideogram4_pe(static_cast<int>(grid_h), sd::PECacheKey pe_key("ideogram4.pe");
pe_key.add(grid_h).add(grid_w).add(x->ne[3]).add(context_len).add(head_dim).add(pos_len).add(config.rope_theta);
pe_key.add(config.mrope_section).add(circular_x_enabled).add(circular_y_enabled);
auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
auto pe_vec = finish_rope_pe(gen_ideogram4_pe(static_cast<int>(grid_h),
static_cast<int>(grid_w), static_cast<int>(grid_w),
static_cast<int>(x->ne[3]), static_cast<int>(x->ne[3]),
static_cast<int>(context_len), static_cast<int>(context_len),
static_cast<int>(head_dim), static_cast<int>(head_dim),
static_cast<int>(config.rope_theta), static_cast<int>(config.rope_theta),
config.mrope_section)); config.mrope_section));
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, head_dim / 2, pos_len); return sd::Tensor<float>({2, 2, head_dim / 2, pos_len}, std::move(pe_vec));
set_backend_tensor_data(pe, pe_vec.data()); }));
image_indicator_vec.assign(static_cast<size_t>(pos_len), 1); image_indicator_vec.assign(static_cast<size_t>(pos_len), 1);
for (int64_t i = 0; i < context_len; ++i) { for (int64_t i = 0; i < context_len; ++i) {
+24 -14
View File
@@ -3,6 +3,7 @@
#include <array> #include <array>
#include <stdexcept> #include <stdexcept>
#include "core/pe_cache.h"
#include "model/diffusion/pid.hpp" #include "model/diffusion/pid.hpp"
namespace Iris { namespace Iris {
@@ -382,11 +383,9 @@ namespace Iris {
} }
struct IrisRunner : public DiffusionModelRunner { struct IrisRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
IrisConfig config; IrisConfig config;
IrisModel model; IrisModel model;
std::vector<float> joint_pe_data;
std::vector<float> pixel_pe_data;
std::vector<float> pixel_pos_data;
std::vector<float> text_mask_data; std::vector<float> text_mask_data;
IrisRunner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr) IrisRunner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr)
@@ -418,24 +417,35 @@ namespace Iris {
GGML_ASSERT(h % config.patch_size == 0 && w % config.patch_size == 0); GGML_ASSERT(h % config.patch_size == 0 && w % config.patch_size == 0);
GGML_ASSERT(text->ne[0] == config.text_dim * config.text_layers && text->ne[1] == nt); GGML_ASSERT(text->ne[0] == config.text_dim * config.text_layers && text->ne[1] == nt);
GGML_ASSERT(inputs.y->numel() == nt && x->ne[3] == 1); GGML_ASSERT(inputs.y->numel() == nt && x->ne[3] == 1);
joint_pe_data = Pid::make_rope_1d(nt, static_cast<int>(config.head_dim), 10000.f); sd::PECacheKey joint_key("iris.joint_pe");
auto img = image_rope(h / config.patch_size, w / config.patch_size, config.head_dim); joint_key.add(h).add(w).add(nt).add(config.patch_size).add(config.head_dim);
joint_pe_data.insert(joint_pe_data.end(), img.begin(), img.end()); auto pe = make_input(pe_cache_.get_or_create(joint_key, [&]() {
pixel_pe_data = image_rope(h / config.patch_size, w / config.patch_size, config.pixel_attn_dim / config.pixel_heads); auto values = Pid::make_rope_1d(nt, static_cast<int>(config.head_dim), 10000.f);
pixel_pos_data = Pid::make_pixel_abs_pos(h, w, static_cast<int>(config.pixel_dim)); auto img = image_rope(h / config.patch_size, w / config.patch_size, config.head_dim);
values.insert(values.end(), img.begin(), img.end());
const int64_t tokens = nt + static_cast<int64_t>(img.size() / (2 * config.head_dim));
return sd::Tensor<float>({2, 2, config.head_dim / 2, tokens}, std::move(values));
}));
sd::PECacheKey pixel_key("iris.pixel_pe");
pixel_key.add(h).add(w).add(config.patch_size).add(config.pixel_attn_dim).add(config.pixel_heads);
auto pp = make_input(pe_cache_.get_or_create(pixel_key, [&]() {
return sd::Tensor<float>({2, 2, config.pixel_attn_dim / config.pixel_heads / 2,
(h / config.patch_size) * (w / config.patch_size)},
image_rope(h / config.patch_size, w / config.patch_size, config.pixel_attn_dim / config.pixel_heads));
}));
sd::PECacheKey pos_key("iris.pixel_pos");
pos_key.add(h).add(w).add(config.pixel_dim);
auto pos = make_input(pe_cache_.get_or_create(pos_key, [&]() {
return sd::Tensor<float>({config.pixel_dim, h * w, 1},
Pid::make_pixel_abs_pos(h, w, static_cast<int>(config.pixel_dim)));
}));
text_mask_data.resize(nt * nt); text_mask_data.resize(nt * nt);
for (int q = 0; q < nt; ++q) { for (int q = 0; q < nt; ++q) {
for (int k = 0; k < nt; ++k) { for (int k = 0; k < nt; ++k) {
text_mask_data[q * nt + k] = inputs.y->values()[k] != 0.f || q == k ? 0.f : -INFINITY; text_mask_data[q * nt + k] = inputs.y->values()[k] != 0.f || q == k ? 0.f : -INFINITY;
} }
} }
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, nt + img.size() / (2 * config.head_dim));
auto pp = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.pixel_attn_dim / config.pixel_heads / 2, (h / config.patch_size) * (w / config.patch_size));
auto pos = ggml_new_tensor_3d(compute_ctx, GGML_TYPE_F32, config.pixel_dim, h * w, 1);
auto mask = ggml_new_tensor_2d(compute_ctx, GGML_TYPE_F32, nt, nt); auto mask = ggml_new_tensor_2d(compute_ctx, GGML_TYPE_F32, nt, nt);
set_backend_tensor_data(pe, joint_pe_data.data());
set_backend_tensor_data(pp, pixel_pe_data.data());
set_backend_tensor_data(pos, pixel_pos_data.data());
set_backend_tensor_data(mask, text_mask_data.data()); set_backend_tensor_data(mask, text_mask_data.data());
auto ctx = get_context(); auto ctx = get_context();
auto out = model.forward(&ctx, x, t, text, mask, pe, pp, pos); auto out = model.forward(&ctx, x, t, text, mask, pe, pp, pos);
+19 -13
View File
@@ -11,6 +11,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_graph_cut.h" #include "core/ggml_graph_cut.h"
@@ -714,9 +715,9 @@ namespace Krea2 {
} }
struct Krea2Runner : public DiffusionModelRunner { struct Krea2Runner : public DiffusionModelRunner {
sd::PECache pe_cache_;
Krea2Config config; Krea2Config config;
Krea2Model model; Krea2Model model;
std::vector<float> pe_vec;
Krea2Runner(ggml_backend_t backend, Krea2Runner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -754,18 +755,23 @@ namespace Krea2 {
ref_latents.push_back(make_input(ref_latent_tensor)); ref_latents.push_back(make_input(ref_latent_tensor));
} }
pe_vec = finish_rope_pe(gen_krea2_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("krea2.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size).add_shapes(ref_latents);
static_cast<int>(x->ne[3]), pe_key.add(ref_image_params.ref_index_mode);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
config.theta, auto pe_vec = finish_rope_pe(gen_krea2_pe(static_cast<int>(x->ne[1]),
config.axes_dim, static_cast<int>(x->ne[0]),
ref_latents, config.patch_size,
ref_image_params.ref_index_mode)); static_cast<int>(x->ne[3]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(context->ne[1]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); config.theta,
set_backend_tensor_data(pe, pe_vec.data()); config.axes_dim,
ref_latents,
ref_image_params.ref_index_mode));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = model.forward(&runner_ctx, x, timesteps, context, pe, ref_latents, ref_image_params.force_ref_timestep_zero); ggml_tensor* out = model.forward(&runner_ctx, x, timesteps, context, pe, ref_latents, ref_image_params.force_ref_timestep_zero);
+15 -10
View File
@@ -4,6 +4,7 @@
#include <cinttypes> #include <cinttypes>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -352,9 +353,9 @@ namespace Lens {
}; };
struct LensRunner : public DiffusionModelRunner { struct LensRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
LensConfig config; LensConfig config;
LensModel lens; LensModel lens;
std::vector<float> pe_vec;
LensRunner(ggml_backend_t backend, LensRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -384,15 +385,19 @@ namespace Lens {
GGML_ASSERT(!context_tensor.empty()); GGML_ASSERT(!context_tensor.empty());
ggml_tensor* context = make_input(context_tensor); ggml_tensor* context = make_input(context_tensor);
pe_vec = finish_rope_pe(Rope::gen_lens_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("lens.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
static_cast<int>(x->ne[3]), pe_key.add(circular_x_enabled).add(circular_y_enabled);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
config.theta, auto pe_vec = finish_rope_pe(Rope::gen_lens_pe(static_cast<int>(x->ne[1]),
config.axes_dim)); static_cast<int>(x->ne[0]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(x->ne[3]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); static_cast<int>(context->ne[1]),
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = lens.forward(&runner_ctx, x, timesteps, context, pe); ggml_tensor* out = lens.forward(&runner_ctx, x, timesteps, context, pe);
+19 -14
View File
@@ -9,6 +9,7 @@
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/util.h" #include "core/util.h"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -606,9 +607,9 @@ namespace LingBotVideo {
}; };
struct LingBotVideoRunner : public DiffusionModelRunner { struct LingBotVideoRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
LingBotVideoConfig config; LingBotVideoConfig config;
LingBotVideoModel lingbot_video; LingBotVideoModel lingbot_video;
std::vector<float> pe_vec;
LingBotVideoRunner(ggml_backend_t backend, LingBotVideoRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -647,19 +648,23 @@ namespace LingBotVideo {
int64_t T = x->ne[2]; int64_t T = x->ne[2];
int64_t N = x_tensor.shape()[4]; int64_t N = x_tensor.shape()[4];
GGML_ASSERT(N == 1); GGML_ASSERT(N == 1);
pe_vec = Rope::gen_lingbot_video_pe(static_cast<int>(T), sd::PECacheKey pe_key("lingbot_video.pe");
static_cast<int>(H), pe_key.add(T).add(H).add(W).add(N).add_shape(context).add(config.patch_t).add(config.patch_h).add(config.patch_w);
static_cast<int>(W), pe_key.add(config.rope_theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_t, auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
config.patch_h, auto pe_vec = Rope::gen_lingbot_video_pe(static_cast<int>(T),
config.patch_w, static_cast<int>(H),
static_cast<int>(N), static_cast<int>(W),
static_cast<int>(context->ne[1]), config.patch_t,
config.rope_theta, config.patch_h,
config.axes_dim); config.patch_w,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(N),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); static_cast<int>(context->ne[1]),
set_backend_tensor_data(pe, pe_vec.data()); config.rope_theta,
config.axes_dim);
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = lingbot_video.forward(&runner_ctx, x, timesteps, context, pe); ggml_tensor* out = lingbot_video.forward(&runner_ctx, x, timesteps, context, pe);
+33 -23
View File
@@ -3,6 +3,7 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_runner.h" #include "core/ggml_runner.h"
@@ -379,10 +380,11 @@ namespace LLaDAImage {
}; };
struct LLaDAImageRunner : public DiffusionModelRunner { struct LLaDAImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
LLaDAImageConfig config; LLaDAImageConfig config;
LLaDAImageModel llada_image; LLaDAImageModel llada_image;
std::vector<float> pe_vec;
LLaDAImageRunner(ggml_backend_t backend, LLaDAImageRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -412,17 +414,21 @@ namespace LLaDAImage {
GGML_ASSERT(!context_tensor.empty()); GGML_ASSERT(!context_tensor.empty());
ggml_tensor* context = make_input(context_tensor); ggml_tensor* context = make_input(context_tensor);
pe_vec = finish_rope_pe(Rope::gen_llada_image_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("llada_image.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size);
static_cast<int>(x->ne[3]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
static_cast<int>(context->ne[1]), auto pe_vec = finish_rope_pe(Rope::gen_llada_image_pe(static_cast<int>(x->ne[1]),
ZImage::SEQ_MULTI_OF, static_cast<int>(x->ne[0]),
config.theta, config.patch_size,
config.axes_dim)); static_cast<int>(x->ne[3]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(context->ne[1]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ZImage::SEQ_MULTI_OF,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = llada_image.forward(&runner_ctx, x, timesteps, context, pe); ggml_tensor* out = llada_image.forward(&runner_ctx, x, timesteps, context, pe);
@@ -459,17 +465,21 @@ namespace LLaDAImage {
ggml_tensor* source = make_input(source_tensor); ggml_tensor* source = make_input(source_tensor);
GGML_ASSERT(x->ne[3] == 1); GGML_ASSERT(x->ne[3] == 1);
pe_vec = finish_rope_pe(Rope::gen_llada_image_edit_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("llada_image.pe1");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size).add_shape(semantic);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
semantic != nullptr ? static_cast<int>(semantic->ne[1]) : 0, auto pe_vec = finish_rope_pe(Rope::gen_llada_image_edit_pe(static_cast<int>(x->ne[1]),
ZImage::SEQ_MULTI_OF, static_cast<int>(x->ne[0]),
config.theta, config.patch_size,
config.axes_dim)); static_cast<int>(context->ne[1]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); semantic != nullptr ? static_cast<int>(semantic->ne[1]) : 0,
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ZImage::SEQ_MULTI_OF,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
int64_t W = x->ne[0]; int64_t W = x->ne[0];
+107 -83
View File
@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "core/ggml_extend_backend.h" #include "core/ggml_extend_backend.h"
#include "core/ggml_tensor_utils.h" #include "core/ggml_tensor_utils.h"
#include "core/pe_cache.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -1736,14 +1737,9 @@ namespace LTXV {
}; };
struct LTXAVRunner : public DiffusionModelRunner { struct LTXAVRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
LTXAVConfig config; LTXAVConfig config;
LTXAVModelBlock model; LTXAVModelBlock model;
std::vector<float> video_pe_vec;
std::vector<float> audio_pe_vec;
std::vector<float> video_cross_pe_vec;
std::vector<float> audio_cross_pe_vec;
std::vector<float> connector_pe_vec;
std::vector<float> audio_connector_pe_vec;
sd::Tensor<float> vx_input_cache; sd::Tensor<float> vx_input_cache;
sd::Tensor<float> ax_input_cache; sd::Tensor<float> ax_input_cache;
@@ -1853,79 +1849,101 @@ namespace LTXV {
float video_frame_rate = frame_rate > 0.f ? frame_rate : 24.f; float video_frame_rate = frame_rate > 0.f ? frame_rate : 24.f;
int64_t video_token_count = vx->ne[0] * vx->ne[1] * vx->ne[2]; int64_t video_token_count = vx->ne[0] * vx->ne[1] * vx->ne[2];
bool has_video_positions = !video_positions_tensor.empty(); bool has_video_positions = !video_positions_tensor.empty();
if (has_video_positions) { sd::PECacheKey video_pe_key("ltxav_video_pe");
GGML_ASSERT(video_positions_tensor.shape()[2] == video_token_count); video_pe_key.add_shape(vx).add(video_frame_rate).add(video_positions_tensor).add(config.positional_embedding_theta);
video_pe_vec = build_video_rope_matrix_from_positions(video_positions_tensor, video_pe_key.add(config.causal_temporal_positioning).add(config.use_middle_indices_grid).add(config.hidden_size);
static_cast<int>(config.hidden_size), video_pe_key.add(config.num_attention_heads).add(config.attention_head_dim).add(config.positional_embedding_max_pos);
static_cast<int>(config.num_attention_heads), video_pe_key.add(std::get<0>(config.vae_scale_factors)).add(std::get<1>(config.vae_scale_factors));
config.positional_embedding_theta, video_pe_key.add(std::get<2>(config.vae_scale_factors));
config.positional_embedding_max_pos, auto video_pe = make_input(pe_cache_.get_or_create(video_pe_key, [&]() {
config.use_middle_indices_grid); std::vector<float> video_pe_vec;
} else { if (has_video_positions) {
video_pe_vec = build_video_rope_matrix(vx->ne[0], GGML_ASSERT(video_positions_tensor.shape()[2] == video_token_count);
vx->ne[1], video_pe_vec = build_video_rope_matrix_from_positions(video_positions_tensor,
vx->ne[2], static_cast<int>(config.hidden_size),
static_cast<int>(config.hidden_size), static_cast<int>(config.num_attention_heads),
static_cast<int>(config.num_attention_heads), config.positional_embedding_theta,
video_frame_rate, config.positional_embedding_max_pos,
config.positional_embedding_theta, config.use_middle_indices_grid);
config.positional_embedding_max_pos, } else {
config.vae_scale_factors, video_pe_vec = build_video_rope_matrix(vx->ne[0],
config.causal_temporal_positioning, vx->ne[1],
config.use_middle_indices_grid); vx->ne[2],
} static_cast<int>(config.hidden_size),
auto video_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.attention_head_dim / 2, video_token_count * config.num_attention_heads); static_cast<int>(config.num_attention_heads),
ggml_set_name(video_pe, "ltxav_video_pe"); video_frame_rate,
set_backend_tensor_data(video_pe, video_pe_vec.data()); config.positional_embedding_theta,
config.positional_embedding_max_pos,
config.vae_scale_factors,
config.causal_temporal_positioning,
config.use_middle_indices_grid);
}
return sd::Tensor<float>({2, 2, config.attention_head_dim / 2, video_token_count * config.num_attention_heads}, std::move(video_pe_vec));
}));
ggml_tensor* audio_pe = nullptr; ggml_tensor* audio_pe = nullptr;
ggml_tensor* video_cross_pe = nullptr; ggml_tensor* video_cross_pe = nullptr;
ggml_tensor* audio_cross_pe = nullptr; ggml_tensor* audio_cross_pe = nullptr;
if (ax != nullptr && ggml_nelements(ax) > 0 && ax->ne[1] > 0) { if (ax != nullptr && ggml_nelements(ax) > 0 && ax->ne[1] > 0) {
audio_pe_vec = build_audio_rope_matrix(ax->ne[1], sd::PECacheKey audio_pe_key("ltxav_audio_pe");
static_cast<int>(config.audio_hidden_size), audio_pe_key.add(ax->ne[1]).add(config.audio_hidden_size).add(config.audio_num_attention_heads);
static_cast<int>(config.audio_num_attention_heads), audio_pe_key.add(config.audio_attention_head_dim).add(config.positional_embedding_theta);
config.positional_embedding_theta, audio_pe_key.add(config.audio_positional_embedding_max_pos[0]).add(config.use_middle_indices_grid);
config.audio_positional_embedding_max_pos[0], audio_pe = make_input(pe_cache_.get_or_create(audio_pe_key, [&]() {
config.use_middle_indices_grid); auto audio_pe_vec = build_audio_rope_matrix(ax->ne[1],
audio_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.audio_attention_head_dim / 2, ax->ne[1] * config.audio_num_attention_heads); static_cast<int>(config.audio_hidden_size),
ggml_set_name(audio_pe, "ltxav_audio_pe"); static_cast<int>(config.audio_num_attention_heads),
set_backend_tensor_data(audio_pe, audio_pe_vec.data()); config.positional_embedding_theta,
config.audio_positional_embedding_max_pos[0],
config.use_middle_indices_grid);
return sd::Tensor<float>({2, 2, config.audio_attention_head_dim / 2, ax->ne[1] * config.audio_num_attention_heads}, std::move(audio_pe_vec));
}));
int temporal_max_pos = std::max(config.positional_embedding_max_pos[0], config.audio_positional_embedding_max_pos[0]); int temporal_max_pos = std::max(config.positional_embedding_max_pos[0], config.audio_positional_embedding_max_pos[0]);
if (has_video_positions) { sd::PECacheKey video_cross_pe_key("ltxav_video_cross_pe");
video_cross_pe_vec = build_video_temporal_rope_matrix_from_positions(video_positions_tensor, video_cross_pe_key.add_shape(vx).add(video_frame_rate).add(video_positions_tensor);
static_cast<int>(config.audio_cross_attention_dim), video_cross_pe_key.add(config.positional_embedding_theta).add(config.causal_temporal_positioning);
static_cast<int>(config.audio_num_attention_heads), video_cross_pe_key.add(config.use_middle_indices_grid).add(config.audio_cross_attention_dim);
config.positional_embedding_theta, video_cross_pe_key.add(config.audio_num_attention_heads).add(config.audio_attention_head_dim);
temporal_max_pos, video_cross_pe_key.add(temporal_max_pos).add(std::get<0>(config.vae_scale_factors));
true); video_cross_pe = make_input(pe_cache_.get_or_create(video_cross_pe_key, [&]() {
} else { std::vector<float> video_cross_pe_vec;
video_cross_pe_vec = build_video_temporal_rope_matrix(vx->ne[0], if (has_video_positions) {
vx->ne[1], video_cross_pe_vec = build_video_temporal_rope_matrix_from_positions(video_positions_tensor,
vx->ne[2], static_cast<int>(config.audio_cross_attention_dim),
static_cast<int>(config.audio_cross_attention_dim), static_cast<int>(config.audio_num_attention_heads),
static_cast<int>(config.audio_num_attention_heads), config.positional_embedding_theta,
video_frame_rate, temporal_max_pos,
config.positional_embedding_theta, true);
temporal_max_pos, } else {
std::get<0>(config.vae_scale_factors), video_cross_pe_vec = build_video_temporal_rope_matrix(vx->ne[0],
config.causal_temporal_positioning, vx->ne[1],
true); vx->ne[2],
} static_cast<int>(config.audio_cross_attention_dim),
video_cross_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.audio_attention_head_dim / 2, video_token_count * config.audio_num_attention_heads); static_cast<int>(config.audio_num_attention_heads),
ggml_set_name(video_cross_pe, "ltxav_video_cross_pe"); video_frame_rate,
set_backend_tensor_data(video_cross_pe, video_cross_pe_vec.data()); config.positional_embedding_theta,
temporal_max_pos,
std::get<0>(config.vae_scale_factors),
config.causal_temporal_positioning,
true);
}
return sd::Tensor<float>({2, 2, config.audio_attention_head_dim / 2, video_token_count * config.audio_num_attention_heads}, std::move(video_cross_pe_vec));
}));
audio_cross_pe_vec = build_audio_rope_matrix(ax->ne[1], sd::PECacheKey audio_cross_pe_key("ltxav_audio_cross_pe");
static_cast<int>(config.audio_cross_attention_dim), audio_cross_pe_key.add(ax->ne[1]).add(config.audio_cross_attention_dim).add(config.audio_num_attention_heads);
static_cast<int>(config.audio_num_attention_heads), audio_cross_pe_key.add(config.audio_attention_head_dim).add(config.positional_embedding_theta);
config.positional_embedding_theta, audio_cross_pe_key.add(temporal_max_pos);
temporal_max_pos, audio_cross_pe = make_input(pe_cache_.get_or_create(audio_cross_pe_key, [&]() {
true); auto audio_cross_pe_vec = build_audio_rope_matrix(ax->ne[1],
audio_cross_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.audio_attention_head_dim / 2, ax->ne[1] * config.audio_num_attention_heads); static_cast<int>(config.audio_cross_attention_dim),
ggml_set_name(audio_cross_pe, "ltxav_audio_cross_pe"); static_cast<int>(config.audio_num_attention_heads),
set_backend_tensor_data(audio_cross_pe, audio_cross_pe_vec.data()); config.positional_embedding_theta,
temporal_max_pos,
true);
return sd::Tensor<float>({2, 2, config.audio_attention_head_dim / 2, ax->ne[1] * config.audio_num_attention_heads}, std::move(audio_cross_pe_vec));
}));
} }
bool needs_video_connector_pe = bool needs_video_connector_pe =
@@ -1941,10 +1959,13 @@ namespace LTXV {
int64_t target_len = std::max<int64_t>(1024, seq_len); int64_t target_len = std::max<int64_t>(1024, seq_len);
int64_t duplications = (target_len + config.connector_num_registers - 1) / config.connector_num_registers; int64_t duplications = (target_len + config.connector_num_registers - 1) / config.connector_num_registers;
int64_t full_len = seq_len + duplications * config.connector_num_registers - seq_len; int64_t full_len = seq_len + duplications * config.connector_num_registers - seq_len;
connector_pe_vec = build_1d_rope_matrix(full_len, static_cast<int>(config.connector_hidden_size), static_cast<int>(config.connector_num_heads), 10000.f, 4096.f, true); sd::PECacheKey video_connector_pe_key("ltxav_video_connector_pe");
video_connector_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.connector_head_dim / 2, full_len * config.connector_num_heads); video_connector_pe_key.add(full_len).add(config.connector_hidden_size).add(config.connector_num_heads);
ggml_set_name(video_connector_pe, "ltxav_video_connector_pe"); video_connector_pe_key.add(config.connector_head_dim);
set_backend_tensor_data(video_connector_pe, connector_pe_vec.data()); video_connector_pe = make_input(pe_cache_.get_or_create(video_connector_pe_key, [&]() {
auto connector_pe_vec = build_1d_rope_matrix(full_len, static_cast<int>(config.connector_hidden_size), static_cast<int>(config.connector_num_heads), 10000.f, 4096.f, true);
return sd::Tensor<float>({2, 2, config.connector_head_dim / 2, full_len * config.connector_num_heads}, std::move(connector_pe_vec));
}));
} }
bool run_audio_context = bool run_audio_context =
@@ -1961,14 +1982,17 @@ namespace LTXV {
context->ne[1] < 1024)); context->ne[1] < 1024));
ggml_tensor* audio_connector_pe = nullptr; ggml_tensor* audio_connector_pe = nullptr;
if (needs_audio_connector_pe) { if (needs_audio_connector_pe) {
int64_t seq_len = context->ne[1]; int64_t seq_len = context->ne[1];
int64_t target_len = std::max<int64_t>(1024, seq_len); int64_t target_len = std::max<int64_t>(1024, seq_len);
int64_t duplications = (target_len + config.audio_connector_num_registers - 1) / config.audio_connector_num_registers; int64_t duplications = (target_len + config.audio_connector_num_registers - 1) / config.audio_connector_num_registers;
int64_t full_len = seq_len + duplications * config.audio_connector_num_registers - seq_len; int64_t full_len = seq_len + duplications * config.audio_connector_num_registers - seq_len;
audio_connector_pe_vec = build_1d_rope_matrix(full_len, static_cast<int>(config.audio_connector_hidden_size), static_cast<int>(config.audio_connector_num_heads), 10000.f, 4096.f, true); sd::PECacheKey audio_connector_pe_key("ltxav_audio_connector_pe");
audio_connector_pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.audio_connector_head_dim / 2, full_len * config.audio_connector_num_heads); audio_connector_pe_key.add(full_len).add(config.audio_connector_hidden_size).add(config.audio_connector_num_heads);
ggml_set_name(audio_connector_pe, "ltxav_audio_connector_pe"); audio_connector_pe_key.add(config.audio_connector_head_dim);
set_backend_tensor_data(audio_connector_pe, audio_connector_pe_vec.data()); audio_connector_pe = make_input(pe_cache_.get_or_create(audio_connector_pe_key, [&]() {
auto audio_connector_pe_vec = build_1d_rope_matrix(full_len, static_cast<int>(config.audio_connector_hidden_size), static_cast<int>(config.audio_connector_num_heads), 10000.f, 4096.f, true);
return sd::Tensor<float>({2, 2, config.audio_connector_head_dim / 2, full_len * config.audio_connector_num_heads}, std::move(audio_connector_pe_vec));
}));
} }
auto runner_ctx = get_context(); auto runner_ctx = get_context();
+17 -11
View File
@@ -3,6 +3,7 @@
#include <cmath> #include <cmath>
#include <memory> #include <memory>
#include "core/pe_cache.h"
#include "model/diffusion/qwen_image.hpp" #include "model/diffusion/qwen_image.hpp"
@@ -57,11 +58,12 @@ namespace MageFlow {
}; };
struct MageFlowRunner : public DiffusionModelRunner { struct MageFlowRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
Qwen::QwenImageConfig config; Qwen::QwenImageConfig config;
Qwen::QwenImageModel mage_flow; Qwen::QwenImageModel mage_flow;
std::shared_ptr<MageFlowTimestepProjEmbeddings> time_text_embed; std::shared_ptr<MageFlowTimestepProjEmbeddings> time_text_embed;
std::vector<float> pe_vec;
MageFlowRunner(ggml_backend_t backend, MageFlowRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -110,16 +112,20 @@ namespace MageFlow {
} }
int batch_size = static_cast<int>(x->ne[3]); int batch_size = static_cast<int>(x->ne[3]);
pe_vec = finish_rope_pe(Rope::gen_mage_flow_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("mage_flow.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
batch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(batch_size).add_shapes(ref_latents);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
ref_latents, auto pe_vec = finish_rope_pe(Rope::gen_mage_flow_pe(static_cast<int>(x->ne[1]),
config.theta, static_cast<int>(x->ne[0]),
config.axes_dim)); batch_size,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(context->ne[1]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ref_latents,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
time_text_embed->prepare(timesteps_tensor); time_text_embed->prepare(timesteps_tensor);
auto runner_ctx = get_context(); auto runner_ctx = get_context();
+19 -14
View File
@@ -1,6 +1,7 @@
#ifndef __SD_MODEL_DIFFUSION_MING_IMAGE_HPP__ #ifndef __SD_MODEL_DIFFUSION_MING_IMAGE_HPP__
#define __SD_MODEL_DIFFUSION_MING_IMAGE_HPP__ #define __SD_MODEL_DIFFUSION_MING_IMAGE_HPP__
#include "core/pe_cache.h"
#include "z_image.hpp" #include "z_image.hpp"
namespace MingImage { namespace MingImage {
@@ -72,9 +73,9 @@ namespace MingImage {
}; };
struct MingImageRunner : DiffusionModelRunner { struct MingImageRunner : DiffusionModelRunner {
sd::PECache pe_cache_;
MingImageConfig config; MingImageConfig config;
MingImageModel model; MingImageModel model;
std::vector<float> pe_values;
MingImageRunner(ggml_backend_t backend, const String2TensorStorage& tensors, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr) MingImageRunner(ggml_backend_t backend, const String2TensorStorage& tensors, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr)
: DiffusionModelRunner(backend, prefix, weight_manager), : DiffusionModelRunner(backend, prefix, weight_manager),
@@ -109,19 +110,23 @@ namespace MingImage {
const int64_t n_txt = context->ne[1] + direct->ne[1]; const int64_t n_txt = context->ne[1] + direct->ne[1];
const int64_t n_img = ((x->ne[0] + config.patch_size - 1) / config.patch_size) * const int64_t n_img = ((x->ne[0] + config.patch_size - 1) / config.patch_size) *
((x->ne[1] + config.patch_size - 1) / config.patch_size); ((x->ne[1] + config.patch_size - 1) / config.patch_size);
auto padded = finish_rope_pe(Rope::gen_z_image_pe( sd::PECacheKey pe_key("ming_image.pe");
static_cast<int>(x->ne[1]), static_cast<int>(x->ne[0]), config.patch_size, 1, pe_key.add_shape(x).add(n_txt).add(config.patch_size).add(config.theta).add(config.axes_dim);
static_cast<int>(n_txt), ZImage::SEQ_MULTI_OF, {}, Rope::RefIndexMode::FIXED, pe_key.add(config.axes_dim_sum).add(circular_x_enabled).add(circular_y_enabled);
config.theta, config.axes_dim)); auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
// Zero-masked alignment tokens cannot affect valid queries. Omit them while auto padded = finish_rope_pe(Rope::gen_z_image_pe(
// retaining the padded caption length used to position image tokens. static_cast<int>(x->ne[1]), static_cast<int>(x->ne[0]), config.patch_size, 1,
const size_t stride = config.axes_dim_sum * 2; static_cast<int>(n_txt), ZImage::SEQ_MULTI_OF, {}, Rope::RefIndexMode::FIXED,
const int64_t padded_txt = n_txt + Rope::bound_mod(static_cast<int>(n_txt), ZImage::SEQ_MULTI_OF); config.theta, config.axes_dim));
pe_values.assign(padded.begin(), padded.begin() + n_txt * stride); // Zero-masked alignment tokens cannot affect valid queries. Omit them while
pe_values.insert(pe_values.end(), padded.begin() + padded_txt * stride, // retaining the padded caption length used to position image tokens.
padded.begin() + (padded_txt + n_img) * stride); const size_t stride = config.axes_dim_sum * 2;
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, n_txt + n_img); const int64_t padded_txt = n_txt + Rope::bound_mod(static_cast<int>(n_txt), ZImage::SEQ_MULTI_OF);
set_backend_tensor_data(pe, pe_values.data()); std::vector<float> pe_values(padded.begin(), padded.begin() + n_txt * stride);
pe_values.insert(pe_values.end(), padded.begin() + padded_txt * stride,
padded.begin() + (padded_txt + n_img) * stride);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, n_txt + n_img}, std::move(pe_values));
}));
auto ctx = get_context(); auto ctx = get_context();
auto out = model.forward(&ctx, x, t, context, direct, pe); auto out = model.forward(&ctx, x, t, context, direct, pe);
ggml_build_forward_expand(gf, out); ggml_build_forward_expand(gf, out);
+23 -87
View File
@@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_runner.h" #include "core/ggml_runner.h"
@@ -473,20 +474,9 @@ namespace MiniT2I {
}; };
struct MiniT2IRunner : public DiffusionModelRunner { struct MiniT2IRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
MiniT2IConfig config; MiniT2IConfig config;
MMJiT model; MMJiT model;
ggml_context* position_cache_ctx = nullptr;
ggml_backend_buffer_t position_cache_buffer = nullptr;
ggml_tensor* cached_pos_embed = nullptr;
ggml_tensor* cached_txt_pe = nullptr;
ggml_tensor* cached_joint_pe = nullptr;
int64_t cached_img_side = -1;
int64_t cached_txt_len = -1;
int64_t cached_hidden_size = -1;
int64_t cached_head_dim = -1;
bool cached_circular_x = false;
bool cached_circular_y = false;
MiniT2IRunner(ggml_backend_t backend, MiniT2IRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
const std::string prefix = "", const std::string prefix = "",
@@ -497,10 +487,6 @@ namespace MiniT2I {
model.init(params_ctx, tensor_storage_map, this->prefix); model.init(params_ctx, tensor_storage_map, this->prefix);
} }
~MiniT2IRunner() override {
free_position_cache();
}
std::string get_desc() override { std::string get_desc() override {
return "MiniT2I"; return "MiniT2I";
} }
@@ -509,75 +495,6 @@ namespace MiniT2I {
model.get_param_tensors(tensors, prefix); model.get_param_tensors(tensors, prefix);
} }
void free_position_cache() {
if (position_cache_buffer != nullptr) {
ggml_backend_buffer_free(position_cache_buffer);
position_cache_buffer = nullptr;
}
if (position_cache_ctx != nullptr) {
ggml_free(position_cache_ctx);
position_cache_ctx = nullptr;
}
cached_pos_embed = nullptr;
cached_txt_pe = nullptr;
cached_joint_pe = nullptr;
cached_img_side = -1;
cached_txt_len = -1;
cached_hidden_size = -1;
cached_head_dim = -1;
}
void ensure_position_cache(int64_t img_side, int64_t txt_len) {
if (cached_img_side == img_side &&
cached_txt_len == txt_len &&
cached_hidden_size == config.hidden_size &&
cached_head_dim == config.head_dim &&
cached_circular_x == circular_x_enabled &&
cached_circular_y == circular_y_enabled &&
cached_pos_embed != nullptr &&
cached_txt_pe != nullptr &&
cached_joint_pe != nullptr) {
return;
}
free_position_cache();
auto pos_embed_vec = make_2d_sincos_pos_embed(static_cast<int>(img_side), static_cast<int>(config.hidden_size));
auto txt_pe_vec = make_text_rope(static_cast<int>(txt_len), static_cast<int>(config.head_dim));
auto img_pe_vec = finish_rope_pe(make_vision_rope(static_cast<int>(img_side), static_cast<int>(config.head_dim)));
auto joint_pe_vec = txt_pe_vec;
joint_pe_vec.insert(joint_pe_vec.end(), img_pe_vec.begin(), img_pe_vec.end());
ggml_init_params params;
params.mem_size = static_cast<size_t>(3 * ggml_tensor_overhead());
params.mem_buffer = nullptr;
params.no_alloc = true;
position_cache_ctx = ggml_init(params);
GGML_ASSERT(position_cache_ctx != nullptr);
cached_pos_embed = ggml_new_tensor_3d(position_cache_ctx, GGML_TYPE_F32, config.hidden_size, img_side * img_side, 1);
ggml_set_name(cached_pos_embed, "minit2i.pos_embed");
cached_txt_pe = ggml_new_tensor_4d(position_cache_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, txt_len);
ggml_set_name(cached_txt_pe, "minit2i.txt_pe");
cached_joint_pe = ggml_new_tensor_4d(position_cache_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, txt_len + img_side * img_side);
ggml_set_name(cached_joint_pe, "minit2i.joint_pe");
position_cache_buffer = ggml_backend_alloc_ctx_tensors(position_cache_ctx, runtime_backend);
GGML_ASSERT(position_cache_buffer != nullptr);
ggml_backend_buffer_set_usage(position_cache_buffer, GGML_BACKEND_BUFFER_USAGE_WEIGHTS);
ggml_backend_tensor_set(cached_pos_embed, pos_embed_vec.data(), 0, ggml_nbytes(cached_pos_embed));
ggml_backend_tensor_set(cached_txt_pe, txt_pe_vec.data(), 0, ggml_nbytes(cached_txt_pe));
ggml_backend_tensor_set(cached_joint_pe, joint_pe_vec.data(), 0, ggml_nbytes(cached_joint_pe));
ggml_backend_synchronize(runtime_backend);
cached_img_side = img_side;
cached_txt_len = txt_len;
cached_hidden_size = config.hidden_size;
cached_head_dim = config.head_dim;
cached_circular_x = circular_x_enabled;
cached_circular_y = circular_y_enabled;
}
ggml_cgraph* build_graph(const sd::Tensor<float>& x_tensor, ggml_cgraph* build_graph(const sd::Tensor<float>& x_tensor,
const sd::Tensor<float>& timesteps_tensor, const sd::Tensor<float>& timesteps_tensor,
const sd::Tensor<float>& context_tensor, const sd::Tensor<float>& context_tensor,
@@ -592,10 +509,29 @@ namespace MiniT2I {
int64_t H = x->ne[1]; int64_t H = x->ne[1];
int64_t img_side = H / config.patch_size; int64_t img_side = H / config.patch_size;
int64_t txt_len = context->ne[1]; int64_t txt_len = context->ne[1];
ensure_position_cache(img_side, txt_len); sd::PECacheKey pos_key("minit2i.pos_embed");
pos_key.add(img_side).add(config.hidden_size);
auto pos_embed = make_input(pe_cache_.get_or_create(pos_key, [&]() {
return sd::Tensor<float>({config.hidden_size, img_side * img_side, 1},
make_2d_sincos_pos_embed(static_cast<int>(img_side), static_cast<int>(config.hidden_size)));
}));
sd::PECacheKey txt_key("minit2i.txt_pe");
txt_key.add(txt_len).add(config.head_dim);
auto txt_pe = make_input(pe_cache_.get_or_create(txt_key, [&]() {
return sd::Tensor<float>({2, 2, config.head_dim / 2, txt_len},
make_text_rope(static_cast<int>(txt_len), static_cast<int>(config.head_dim)));
}));
sd::PECacheKey joint_key("minit2i.joint_pe");
joint_key.add(img_side).add(txt_len).add(config.head_dim).add(circular_x_enabled).add(circular_y_enabled);
auto joint_pe = make_input(pe_cache_.get_or_create(joint_key, [&]() {
auto values = make_text_rope(static_cast<int>(txt_len), static_cast<int>(config.head_dim));
auto image = finish_rope_pe(make_vision_rope(static_cast<int>(img_side), static_cast<int>(config.head_dim)));
values.insert(values.end(), image.begin(), image.end());
return sd::Tensor<float>({2, 2, config.head_dim / 2, txt_len + img_side * img_side}, std::move(values));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
auto out = model.forward(&runner_ctx, x, context, mask, cached_pos_embed, cached_txt_pe, cached_joint_pe); auto out = model.forward(&runner_ctx, x, context, mask, pos_embed, txt_pe, joint_pe);
ggml_build_forward_expand(gf, out); ggml_build_forward_expand(gf, out);
return gf; return gf;
} }
+1 -1
View File
@@ -173,7 +173,7 @@ struct MingImageDiffusionExtra {
struct ZImageDiffusionExtra { struct ZImageDiffusionExtra {
const sd::Tensor<float>* control_latent = nullptr; const sd::Tensor<float>* control_latent = nullptr;
float strength = 1.f; float strength = 1.f;
}; };
using DiffusionExtraParams = std::variant<std::monostate, using DiffusionExtraParams = std::variant<std::monostate,
+23 -18
View File
@@ -3,6 +3,7 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
#include "core/pe_cache.h"
#include "model/common/ggml_block.hpp" #include "model/common/ggml_block.hpp"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -193,9 +194,10 @@ namespace MOSSImage {
}; };
struct MOSSImageRunner : public DiffusionModelRunner { struct MOSSImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
MOSSImageConfig config; MOSSImageConfig config;
Model model; Model model;
std::vector<float> pe_data, time_data; std::vector<float> time_data;
MOSSImageRunner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr) MOSSImageRunner(ggml_backend_t backend, const String2TensorStorage& weights, const std::string& prefix, std::shared_ptr<RunnerWeightManager> weight_manager = nullptr)
: DiffusionModelRunner(backend, prefix, weight_manager), config(MOSSImageConfig::detect_from_weights(weights, prefix)), model(config) { : DiffusionModelRunner(backend, prefix, weight_manager), config(MOSSImageConfig::detect_from_weights(weights, prefix)), model(config) {
@@ -224,31 +226,34 @@ namespace MOSSImage {
auto text = make_input(*inputs.context); auto text = make_input(*inputs.context);
GGML_ASSERT(x->ne[3] == 1 && x->ne[2] == config.channels && text->ne[0] == config.text_dim); GGML_ASSERT(x->ne[3] == 1 && x->ne[2] == config.channels && text->ne[0] == config.text_dim);
int64_t h = x->ne[1], w = x->ne[0], nt = text->ne[1]; int64_t h = x->ne[1], w = x->ne[0], nt = text->ne[1];
Rope::Embedding embedding; sd::PECacheKey pe_key("moss_image.pe");
embedding.positions.append_image(static_cast<int>(h), static_cast<int>(w)); pe_key.add(h).add(w).add(nt).add(config.head_dim).add(circular_x_enabled).add(circular_y_enabled);
embedding.positions.images.back().height_axis = 2; auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
embedding.positions.images.back().width_axis = 3; Rope::Embedding embedding;
embedding.positions.append_tokens(nt); embedding.positions.append_image(static_cast<int>(h), static_cast<int>(w));
for (int64_t token = 0; token < h * w + nt; ++token) { embedding.positions.images.back().height_axis = 2;
float pos[4] = {0.f, float(token - h * w), 0.f, 0.f}; embedding.positions.images.back().width_axis = 3;
if (token < h * w) { embedding.positions.append_tokens(nt);
pos[1] = float(nt); for (int64_t token = 0; token < h * w + nt; ++token) {
pos[2] = float(token / w) - float(h - 1) / 2.f; float pos[4] = {0.f, float(token - h * w), 0.f, 0.f};
pos[3] = float(token % w) - float(w - 1) / 2.f; if (token < h * w) {
pos[1] = float(nt);
pos[2] = float(token / w) - float(h - 1) / 2.f;
pos[3] = float(token % w) - float(w - 1) / 2.f;
}
embedding.ids.push_back({pos[0], pos[1], pos[2], pos[3]});
} }
embedding.ids.push_back({pos[0], pos[1], pos[2], pos[3]}); embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, std::vector<int>(4, static_cast<int>(config.head_dim / 4)), embedding.layout, &embedding.frequencies);
} auto values = finish_rope_pe(std::move(embedding));
embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, std::vector<int>(4, static_cast<int>(config.head_dim / 4)), embedding.layout, &embedding.frequencies); return sd::Tensor<float>({2, 2, config.head_dim / 2, h * w + nt}, std::move(values));
pe_data = finish_rope_pe(std::move(embedding)); }));
time_data.resize(config.freq_dim); time_data.resize(config.freq_dim);
for (int64_t i = 0; i < config.freq_dim / 2; ++i) { for (int64_t i = 0; i < config.freq_dim / 2; ++i) {
double angle = inputs.timesteps->values()[0] * std::pow(10000.0, -double(i) / double(config.freq_dim / 2)); double angle = inputs.timesteps->values()[0] * std::pow(10000.0, -double(i) / double(config.freq_dim / 2));
time_data[i] = float(std::cos(angle)); time_data[i] = float(std::cos(angle));
time_data[i + config.freq_dim / 2] = float(std::sin(angle)); time_data[i + config.freq_dim / 2] = float(std::sin(angle));
} }
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, h * w + nt);
auto time = ggml_new_tensor_3d(compute_ctx, GGML_TYPE_F32, config.freq_dim, 1, 1); auto time = ggml_new_tensor_3d(compute_ctx, GGML_TYPE_F32, config.freq_dim, 1, 1);
set_backend_tensor_data(pe, pe_data.data());
set_backend_tensor_data(time, time_data.data()); set_backend_tensor_data(time, time_data.data());
auto ctx = get_context(); auto ctx = get_context();
ggml_build_forward_expand(gf, model.forward(&ctx, x, time, text, pe, skip)); ggml_build_forward_expand(gf, model.forward(&ctx, x, time, text, pe, skip));
+45 -51
View File
@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_runner.h" #include "core/ggml_runner.h"
@@ -822,12 +823,9 @@ namespace Pid {
}; };
struct PiDRunner : public DiffusionModelRunner { struct PiDRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
PixelDiTConfig config; PixelDiTConfig config;
PixelDiT model; PixelDiT model;
std::vector<float> pos_img_vec;
std::vector<float> pos_txt_vec;
std::vector<float> pixel_pos_vec;
std::vector<float> pixel_pos_comp_vec;
PiDRunner(ggml_backend_t backend, PiDRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map, const String2TensorStorage& tensor_storage_map,
@@ -867,57 +865,53 @@ namespace Pid {
int64_t Hs = Hp / config.patch_size; int64_t Hs = Hp / config.patch_size;
int64_t Ws = Wp / config.patch_size; int64_t Ws = Wp / config.patch_size;
pos_img_vec = finish_rope_pe(make_rope_2d(static_cast<int>(Hs), sd::PECacheKey pos_img_key("pid.pos_img");
static_cast<int>(Ws), pos_img_key.add(Hs).add(Ws).add(config.hidden_size).add(config.num_groups).add(config.rope_ref_grid_h);
static_cast<int>(config.hidden_size / config.num_groups), pos_img_key.add(config.rope_ref_grid_w).add(circular_x_enabled).add(circular_y_enabled);
10000.f, auto pos_img = make_input(pe_cache_.get_or_create(pos_img_key, [&]() {
16.f, auto pos_img_vec = finish_rope_pe(make_rope_2d(static_cast<int>(Hs),
static_cast<int>(config.rope_ref_grid_h), static_cast<int>(Ws),
static_cast<int>(config.rope_ref_grid_w))); static_cast<int>(config.hidden_size / config.num_groups),
auto pos_img = ggml_new_tensor_4d(compute_ctx, 10000.f,
GGML_TYPE_F32, 16.f,
2, static_cast<int>(config.rope_ref_grid_h),
2, static_cast<int>(config.rope_ref_grid_w)));
config.hidden_size / config.num_groups / 2, return sd::Tensor<float>({2, 2, config.hidden_size / config.num_groups / 2, Hs * Ws}, std::move(pos_img_vec));
Hs * Ws); }));
set_backend_tensor_data(pos_img, pos_img_vec.data());
int64_t Ltxt = std::min<int64_t>(context->ne[1], config.txt_max_length); int64_t Ltxt = std::min<int64_t>(context->ne[1], config.txt_max_length);
pos_txt_vec = make_rope_1d(static_cast<int>(Ltxt), sd::PECacheKey pos_txt_key("pid.pos_txt");
static_cast<int>(config.hidden_size / config.num_groups), pos_txt_key.add(Ltxt).add(config.hidden_size).add(config.num_groups).add(config.text_rope_theta);
config.text_rope_theta); auto pos_txt = make_input(pe_cache_.get_or_create(pos_txt_key, [&]() {
auto pos_txt = ggml_new_tensor_4d(compute_ctx, auto pos_txt_vec = make_rope_1d(static_cast<int>(Ltxt),
GGML_TYPE_F32, static_cast<int>(config.hidden_size / config.num_groups),
2, config.text_rope_theta);
2, return sd::Tensor<float>({2, 2, config.hidden_size / config.num_groups / 2, Ltxt}, std::move(pos_txt_vec));
config.hidden_size / config.num_groups / 2, }));
Ltxt);
set_backend_tensor_data(pos_txt, pos_txt_vec.data());
pixel_pos_vec = make_pixel_abs_pos(static_cast<int>(Hp), sd::PECacheKey pixel_pos_key("pid.pixel_pos");
static_cast<int>(Wp), pixel_pos_key.add(Hp).add(Wp).add(config.pixel_hidden_size);
static_cast<int>(config.pixel_hidden_size)); auto pixel_pos = make_input(pe_cache_.get_or_create(pixel_pos_key, [&]() {
auto pixel_pos = ggml_new_tensor_3d(compute_ctx, auto pixel_pos_vec = make_pixel_abs_pos(static_cast<int>(Hp),
GGML_TYPE_F32, static_cast<int>(Wp),
config.pixel_hidden_size, static_cast<int>(config.pixel_hidden_size));
Wp * Hp, return sd::Tensor<float>({config.pixel_hidden_size, Wp * Hp, 1}, std::move(pixel_pos_vec));
1); }));
set_backend_tensor_data(pixel_pos, pixel_pos_vec.data());
pixel_pos_comp_vec = finish_rope_pe(make_rope_2d(static_cast<int>(Hs), sd::PECacheKey pixel_pos_comp_key("pid.pixel_pos_comp");
static_cast<int>(Ws), pixel_pos_comp_key.add(Hs).add(Ws).add(config.pixel_attn_hidden_size).add(config.pixel_num_groups);
static_cast<int>(config.pixel_attn_hidden_size / config.pixel_num_groups), pixel_pos_comp_key.add(config.rope_ref_grid_h).add(config.rope_ref_grid_w).add(circular_x_enabled);
10000.f, pixel_pos_comp_key.add(circular_y_enabled);
16.f, auto pixel_pos_comp = make_input(pe_cache_.get_or_create(pixel_pos_comp_key, [&]() {
static_cast<int>(config.rope_ref_grid_h), auto pixel_pos_comp_vec = finish_rope_pe(make_rope_2d(static_cast<int>(Hs),
static_cast<int>(config.rope_ref_grid_w))); static_cast<int>(Ws),
auto pixel_pos_comp = ggml_new_tensor_4d(compute_ctx, static_cast<int>(config.pixel_attn_hidden_size / config.pixel_num_groups),
GGML_TYPE_F32, 10000.f,
2, 16.f,
2, static_cast<int>(config.rope_ref_grid_h),
config.pixel_attn_hidden_size / config.pixel_num_groups / 2, static_cast<int>(config.rope_ref_grid_w)));
Hs * Ws); return sd::Tensor<float>({2, 2, config.pixel_attn_hidden_size / config.pixel_num_groups / 2, Hs * Ws}, std::move(pixel_pos_comp_vec));
set_backend_tensor_data(pixel_pos_comp, pixel_pos_comp_vec.data()); }));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
auto out = model.forward(&runner_ctx, auto out = model.forward(&runner_ctx,
+9 -5
View File
@@ -5,6 +5,7 @@
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
#include <vector> #include <vector>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_runner.h" #include "core/ggml_runner.h"
@@ -295,9 +296,9 @@ namespace PixArt {
}; };
struct PixArtRunner : public DiffusionModelRunner { struct PixArtRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
PixArtConfig config; PixArtConfig config;
PixArtModel model; PixArtModel model;
std::vector<float> pos_vec;
PixArtRunner(ggml_backend_t backend, PixArtRunner(ggml_backend_t backend,
const String2TensorStorage& tensor_storage_map = {}, const String2TensorStorage& tensor_storage_map = {},
@@ -357,10 +358,13 @@ namespace PixArt {
int64_t wp = W / config.patch_size; int64_t wp = W / config.patch_size;
int64_t hp = H / config.patch_size; int64_t hp = H / config.patch_size;
pos_vec = gen_2d_sincos_pos_embed(config.hidden_size, hp, wp, sd::PECacheKey pos_key("pixart.pos");
config.pos_embed_base_size, config.interpolation_scale); pos_key.add(hp).add(wp).add(config.hidden_size).add(config.pos_embed_base_size).add(config.interpolation_scale);
auto pos = ggml_new_tensor_3d(compute_ctx, GGML_TYPE_F32, config.hidden_size, wp * hp, 1); auto pos = make_input(pe_cache_.get_or_create(pos_key, [&]() {
set_backend_tensor_data(pos, pos_vec.data()); auto pos_vec = gen_2d_sincos_pos_embed(config.hidden_size, hp, wp,
config.pos_embed_base_size, config.interpolation_scale);
return sd::Tensor<float>({config.hidden_size, wp * hp, 1}, std::move(pos_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = model.forward(&runner_ctx, x, timesteps, context, pos, context_mask); ggml_tensor* out = model.forward(&runner_ctx, x, timesteps, context, pos, context_mask);
+21 -18
View File
@@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include "core/ggml_extend_backend.h" #include "core/ggml_extend_backend.h"
#include "core/ggml_tensor_utils.h" #include "core/ggml_tensor_utils.h"
#include "core/pe_cache.h"
#include "core/util.h" #include "core/util.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
@@ -561,10 +562,11 @@ namespace Qwen {
}; };
struct QwenImageRunner : public DiffusionModelRunner { struct QwenImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
QwenImageConfig config; QwenImageConfig config;
QwenImageModel qwen_image; QwenImageModel qwen_image;
std::vector<float> pe_vec;
std::vector<float> modulate_index_vec; std::vector<float> modulate_index_vec;
std::vector<int32_t> additional_t_cond_vec; std::vector<int32_t> additional_t_cond_vec;
SDVersion version; SDVersion version;
@@ -635,23 +637,24 @@ namespace Qwen {
ref_index_mode = Rope::RefIndexMode::DECREASE; ref_index_mode = Rope::RefIndexMode::DECREASE;
} }
pe_vec = finish_rope_pe(Rope::gen_qwen_image_pe(time_len, sd::PECacheKey pe_key("qwen_image.pe");
static_cast<int>(x->ne[1]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
static_cast<int>(x->ne[0]), pe_key.add(circular_x_enabled).add(circular_y_enabled).add(time_len).add(batch_size).add(config.patch_size);
config.patch_size, pe_key.add_shapes(ref_latents).add(ref_index_mode);
batch_size, auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
static_cast<int>(context->ne[1]), auto pe_vec = finish_rope_pe(Rope::gen_qwen_image_pe(time_len,
ref_latents, static_cast<int>(x->ne[1]),
ref_index_mode, static_cast<int>(x->ne[0]),
config.theta, config.patch_size,
config.axes_dim)); batch_size,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(context->ne[1]),
// LOG_VERBOSE("pos_len %d", pos_len); ref_latents,
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ref_index_mode,
// pe->data = pe_vec.data(); config.theta,
// print_ggml_tensor(pe, true, "pe"); config.axes_dim));
// pe->data = nullptr; int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
set_backend_tensor_data(pe, pe_vec.data()); return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
ggml_tensor* modulate_index = nullptr; ggml_tensor* modulate_index = nullptr;
if (config.zero_cond_t) { if (config.zero_cond_t) {
+27 -18
View File
@@ -1,6 +1,7 @@
#ifndef __SD_MODEL_DIFFUSION_QWEN_IMAGE_2_1_H__ #ifndef __SD_MODEL_DIFFUSION_QWEN_IMAGE_2_1_H__
#define __SD_MODEL_DIFFUSION_QWEN_IMAGE_2_1_H__ #define __SD_MODEL_DIFFUSION_QWEN_IMAGE_2_1_H__
#include "core/pe_cache.h"
#include "model/diffusion/qwen_image.hpp" #include "model/diffusion/qwen_image.hpp"
namespace Qwen { namespace Qwen {
@@ -370,9 +371,9 @@ namespace Qwen {
}; };
struct QwenImage21Runner : public DiffusionModelRunner { struct QwenImage21Runner : public DiffusionModelRunner {
sd::PECache pe_cache_;
QwenImage21Config config; QwenImage21Config config;
QwenImage21Model model; QwenImage21Model model;
std::vector<float> pe_data;
std::vector<sd::Tensor<float>> mask_data; std::vector<sd::Tensor<float>> mask_data;
ggml_type prefix_cache_type = GGML_TYPE_COUNT; ggml_type prefix_cache_type = GGML_TYPE_COUNT;
bool prefix_cache_enabled = true; bool prefix_cache_enabled = true;
@@ -504,20 +505,7 @@ namespace Qwen {
if (prefix_cache_type == GGML_TYPE_COUNT && active_cache.type == GGML_TYPE_F16) { if (prefix_cache_type == GGML_TYPE_COUNT && active_cache.type == GGML_TYPE_F16) {
checked_cache.flash_attn_used = &flash_attn_used; checked_cache.flash_attn_used = &flash_attn_used;
} }
const bool cached = active_cache.mode == QwenImage21PrefixCache::Mode::REUSE; const bool cached = active_cache.mode == QwenImage21PrefixCache::Mode::REUSE;
const auto first_position = layout.positions.begin() + (cached ? layout.prefix_length : 0);
Rope::Embedding embedding;
embedding.ids.assign(first_position, layout.positions.end());
const size_t offset = cached ? static_cast<size_t>(layout.prefix_length) : 0;
embedding.positions.token_count = embedding.ids.size();
for (auto region : layout.rope_layout.images) {
if (region.begin >= offset) {
region.begin -= offset;
embedding.positions.images.push_back(region);
}
}
embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, config.axes_dim, embedding.layout, &embedding.frequencies);
pe_data = finish_rope_pe(std::move(embedding));
mask_data.clear(); mask_data.clear();
if (!cached) { if (!cached) {
for (const auto& segment : layout.segments) { for (const auto& segment : layout.segments) {
@@ -535,9 +523,30 @@ namespace Qwen {
} }
auto build = [&]() { auto build = [&]() {
auto graph = new_graph_custom(QWEN_IMAGE_GRAPH_SIZE * 2); auto graph = new_graph_custom(QWEN_IMAGE_GRAPH_SIZE * 2);
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.head_dim / 2, sd::PECacheKey pe_key("qwen_image_2_1.pe");
layout.positions.size() - (cached ? layout.prefix_length : 0)); pe_key.add(layout.positions).add(cached).add(layout.prefix_length).add(config.axes_dim).add(config.head_dim);
set_backend_tensor_data(pe, pe_data.data()); pe_key.add(circular_x_enabled).add(circular_y_enabled);
for (const auto& region : layout.rope_layout.images) {
pe_key.add(region.begin).add(region.count).add(region.height_period).add(region.width_period);
pe_key.add(region.height_axis).add(region.width_axis);
}
auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
const auto first_position = layout.positions.begin() + (cached ? layout.prefix_length : 0);
Rope::Embedding embedding;
embedding.ids.assign(first_position, layout.positions.end());
const size_t offset = cached ? static_cast<size_t>(layout.prefix_length) : 0;
embedding.positions.token_count = embedding.ids.size();
for (auto region : layout.rope_layout.images) {
if (region.begin >= offset) {
region.begin -= offset;
embedding.positions.images.push_back(region);
}
}
embedding.values = Rope::embed_nd(embedding.ids, 1, 10000.f, config.axes_dim, embedding.layout, &embedding.frequencies);
auto values = finish_rope_pe(std::move(embedding));
const int64_t tokens = static_cast<int64_t>(layout.positions.size()) - (cached ? layout.prefix_length : 0);
return sd::Tensor<float>({2, 2, config.head_dim / 2, tokens}, std::move(values));
}));
std::vector<ggml_tensor*> masks, ref_inputs; std::vector<ggml_tensor*> masks, ref_inputs;
for (const auto& mask : mask_data) { for (const auto& mask : mask_data) {
masks.push_back(mask.empty() ? nullptr : make_input(mask)); masks.push_back(mask.empty() ? nullptr : make_input(mask));
+28 -27
View File
@@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include "core/ggml_extend_backend.h" #include "core/ggml_extend_backend.h"
#include "core/ggml_tensor_utils.h" #include "core/ggml_tensor_utils.h"
#include "core/pe_cache.h"
#include "model/common/block.hpp" #include "model/common/block.hpp"
#include "model/common/rope.hpp" #include "model/common/rope.hpp"
@@ -885,11 +886,12 @@ namespace WAN {
}; };
struct WanRunner : public DiffusionModelRunner { struct WanRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
std::string desc = "wan"; std::string desc = "wan";
WanConfig config; WanConfig config;
Wan wan; Wan wan;
std::vector<float> pe_vec;
SDVersion version; SDVersion version;
WanRunner(ggml_backend_t backend, WanRunner(ggml_backend_t backend,
@@ -1000,37 +1002,36 @@ namespace WAN {
ggml_tensor* audio_embed = make_optional_input(audio_embed_tensor); ggml_tensor* audio_embed = make_optional_input(audio_embed_tensor);
ggml_tensor* ref_latent = make_optional_input(ref_latent_tensor); ggml_tensor* ref_latent = make_optional_input(ref_latent_tensor);
pe_vec = Rope::gen_wan_pe(static_cast<int>(x->ne[2]), sd::PECacheKey pe_key("wan.pe");
static_cast<int>(x->ne[1]), pe_key.add_shape(x).add_shape(ref_latent).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
static_cast<int>(x->ne[0]), pe_key.add(std::get<0>(config.patch_size)).add(std::get<1>(config.patch_size)).add(std::get<2>(config.patch_size));
std::get<0>(config.patch_size), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
std::get<1>(config.patch_size), auto pe_vec = Rope::gen_wan_pe(static_cast<int>(x->ne[2]),
std::get<2>(config.patch_size), static_cast<int>(x->ne[1]),
1, static_cast<int>(x->ne[0]),
config.theta,
config.axes_dim);
if (ref_latent != nullptr) {
// Match S2V's reference-frame temporal offset.
int t_start = std::max(30, static_cast<int>(x->ne[2]) + 9);
auto ref_pe = Rope::gen_wan_pe(static_cast<int>(ref_latent->ne[2]),
static_cast<int>(ref_latent->ne[1]),
static_cast<int>(ref_latent->ne[0]),
std::get<0>(config.patch_size), std::get<0>(config.patch_size),
std::get<1>(config.patch_size), std::get<1>(config.patch_size),
std::get<2>(config.patch_size), std::get<2>(config.patch_size),
1, 1,
config.theta, config.theta,
config.axes_dim, config.axes_dim);
t_start); if (ref_latent != nullptr) {
pe_vec.insert(pe_vec.end(), ref_pe.begin(), ref_pe.end()); int t_start = std::max(30, static_cast<int>(x->ne[2]) + 9);
} auto ref_pe = Rope::gen_wan_pe(static_cast<int>(ref_latent->ne[2]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); static_cast<int>(ref_latent->ne[1]),
// LOG_VERBOSE("pos_len %d", pos_len); static_cast<int>(ref_latent->ne[0]),
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); std::get<0>(config.patch_size),
// pe->data = pe_vec.data(); std::get<1>(config.patch_size),
// print_ggml_tensor(pe); std::get<2>(config.patch_size),
// pe->data = nullptr; 1,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim,
t_start);
pe_vec.insert(pe_vec.end(), ref_pe.begin(), ref_pe.end());
}
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
if (c_concat != nullptr) { if (c_concat != nullptr) {
x = ggml_concat(compute_ctx, x, c_concat, 3); x = ggml_concat(compute_ctx, x, c_concat, 3);
+56 -53
View File
@@ -3,6 +3,7 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
#include "core/pe_cache.h"
#include "core/ggml_extend.h" #include "core/ggml_extend.h"
#include "core/ggml_extend_backend.h" #include "core/ggml_extend_backend.h"
@@ -23,10 +24,10 @@
#endif #endif
namespace ZImage { namespace ZImage {
constexpr int Z_IMAGE_GRAPH_SIZE = 24576; constexpr int Z_IMAGE_GRAPH_SIZE = 24576;
constexpr int ADALN_EMBED_DIM = 256; constexpr int ADALN_EMBED_DIM = 256;
constexpr int SEQ_MULTI_OF = 32; constexpr int SEQ_MULTI_OF = 32;
constexpr int CONTROL_IN_CHANNELS = 33; constexpr int CONTROL_IN_CHANNELS = 33;
struct ZImageConfig { struct ZImageConfig {
int patch_size = 2; int patch_size = 2;
@@ -649,15 +650,15 @@ namespace ZImage {
for (int i = 0; i < control_num_refiner_layers; i++) { for (int i = 0; i < control_num_refiner_layers; i++) {
std::string name = "control_noise_refiner." + std::to_string(i); std::string name = "control_noise_refiner." + std::to_string(i);
auto block = std::make_shared<ZImageControlTransformerBlock>(i, auto block = std::make_shared<ZImageControlTransformerBlock>(i,
config.hidden_size, config.hidden_size,
config.head_dim, config.head_dim,
config.num_heads, config.num_heads,
config.num_kv_heads, config.num_kv_heads,
config.multiple_of, config.multiple_of,
config.ffn_dim_multiplier, config.ffn_dim_multiplier,
config.norm_eps, config.norm_eps,
config.qk_norm, config.qk_norm,
tensor_storage_map.find(name + ".before_proj.weight") != tensor_storage_map.end()); tensor_storage_map.find(name + ".before_proj.weight") != tensor_storage_map.end());
control_blocks[name] = block; control_blocks[name] = block;
} }
@@ -665,15 +666,15 @@ namespace ZImage {
for (int i = 0; i < control_num_layers; i++) { for (int i = 0; i < control_num_layers; i++) {
std::string name = "control_layers." + std::to_string(i); std::string name = "control_layers." + std::to_string(i);
auto block = std::make_shared<ZImageControlTransformerBlock>(i, auto block = std::make_shared<ZImageControlTransformerBlock>(i,
config.hidden_size, config.hidden_size,
config.head_dim, config.head_dim,
config.num_heads, config.num_heads,
config.num_kv_heads, config.num_kv_heads,
config.multiple_of, config.multiple_of,
config.ffn_dim_multiplier, config.ffn_dim_multiplier,
config.norm_eps, config.norm_eps,
config.qk_norm, config.qk_norm,
tensor_storage_map.find(name + ".before_proj.weight") != tensor_storage_map.end()); tensor_storage_map.find(name + ".before_proj.weight") != tensor_storage_map.end());
control_blocks[name] = block; control_blocks[name] = block;
} }
@@ -705,7 +706,7 @@ namespace ZImage {
if (n_pad_token > 0) { if (n_pad_token > 0) {
auto img_pad_token = params["x_pad_token"]; auto img_pad_token = params["x_pad_token"];
auto ctrl_pad_tokens = ggml_repeat_4d(ctx->ggml_ctx, img_pad_token, img_pad_token->ne[0], n_pad_token, N, 1); auto ctrl_pad_tokens = ggml_repeat_4d(ctx->ggml_ctx, img_pad_token, img_pad_token->ne[0], n_pad_token, N, 1);
c = ggml_concat(ctx->ggml_ctx, c, ctrl_pad_tokens, 1); c = ggml_concat(ctx->ggml_ctx, c, ctrl_pad_tokens, 1);
} }
for (int i = 0; i < control_num_refiner_layers; i++) { for (int i = 0; i < control_num_refiner_layers; i++) {
@@ -755,7 +756,7 @@ namespace ZImage {
for (int i = 0; i < control_num_layers; i++) { for (int i = 0; i < control_num_layers; i++) {
auto block = std::dynamic_pointer_cast<ZImageControlTransformerBlock>(control_blocks["control_layers." + std::to_string(i)]); auto block = std::dynamic_pointer_cast<ZImageControlTransformerBlock>(control_blocks["control_layers." + std::to_string(i)]);
auto out = block->forward(ctx, ctrl_unified, pe, unified_c, t_emb); auto out = block->forward(ctx, ctrl_unified, pe, unified_c, t_emb);
ctrl_unified = out.second; ctrl_unified = out.second;
main_hints.push_back(ggml_ext_scale(ctx->ggml_ctx, out.first, strength)); main_hints.push_back(ggml_ext_scale(ctx->ggml_ctx, out.first, strength));
sd::ggml_graph_cut::mark_graph_cut(ctrl_unified, "z_image.control.layers." + std::to_string(i), "control"); sd::ggml_graph_cut::mark_graph_cut(ctrl_unified, "z_image.control.layers." + std::to_string(i), "control");
@@ -769,8 +770,8 @@ namespace ZImage {
ggml_tensor* timestep, ggml_tensor* timestep,
ggml_tensor* context, ggml_tensor* context,
ggml_tensor* pe, ggml_tensor* pe,
ggml_tensor* control = nullptr, ggml_tensor* control = nullptr,
float strength = 0.f) { float strength = 0.f) {
auto x_embedder = std::dynamic_pointer_cast<Linear>(blocks["x_embedder"]); auto x_embedder = std::dynamic_pointer_cast<Linear>(blocks["x_embedder"]);
auto t_embedder = std::dynamic_pointer_cast<TimestepEmbedder>(blocks["t_embedder"]); auto t_embedder = std::dynamic_pointer_cast<TimestepEmbedder>(blocks["t_embedder"]);
auto cap_embedder_0 = std::dynamic_pointer_cast<RMSNorm>(blocks["cap_embedder.0"]); auto cap_embedder_0 = std::dynamic_pointer_cast<RMSNorm>(blocks["cap_embedder.0"]);
@@ -869,7 +870,7 @@ namespace ZImage {
ggml_tensor* context, ggml_tensor* context,
ggml_tensor* pe, ggml_tensor* pe,
std::vector<ggml_tensor*> ref_latents = {}, std::vector<ggml_tensor*> ref_latents = {},
ggml_tensor* control_latent = nullptr, ggml_tensor* control_latent = nullptr,
float control_strength = 0.f) { float control_strength = 0.f) {
// Forward pass of DiT. // Forward pass of DiT.
// x: [N, C, H, W] // x: [N, C, H, W]
@@ -916,10 +917,11 @@ namespace ZImage {
}; };
struct ZImageRunner : public DiffusionModelRunner { struct ZImageRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
public: public:
ZImageConfig config; ZImageConfig config;
ZImageModel z_image; ZImageModel z_image;
std::vector<float> pe_vec;
std::vector<float> timestep_vec; std::vector<float> timestep_vec;
SDVersion version; SDVersion version;
@@ -953,10 +955,10 @@ namespace ZImage {
ggml_cgraph* build_graph(const sd::Tensor<float>& x_tensor, ggml_cgraph* build_graph(const sd::Tensor<float>& x_tensor,
const sd::Tensor<float>& timesteps_tensor, const sd::Tensor<float>& timesteps_tensor,
const sd::Tensor<float>& context_tensor, const sd::Tensor<float>& context_tensor,
const std::vector<sd::Tensor<float>>& ref_latents_tensor = {}, const std::vector<sd::Tensor<float>>& ref_latents_tensor = {},
Rope::RefIndexMode ref_index_mode = Rope::RefIndexMode::FIXED, Rope::RefIndexMode ref_index_mode = Rope::RefIndexMode::FIXED,
const sd::Tensor<float>& control_latent_tensor = {}, const sd::Tensor<float>& control_latent_tensor = {},
float control_strength = 0.f) { float control_strength = 0.f) {
ggml_cgraph* gf = new_graph_custom(Z_IMAGE_GRAPH_SIZE); ggml_cgraph* gf = new_graph_custom(Z_IMAGE_GRAPH_SIZE);
ggml_tensor* x = make_input(x_tensor); ggml_tensor* x = make_input(x_tensor);
ggml_tensor* timesteps = make_input(timesteps_tensor); ggml_tensor* timesteps = make_input(timesteps_tensor);
@@ -971,23 +973,24 @@ namespace ZImage {
ggml_tensor* control_latent = make_optional_input(control_latent_tensor); ggml_tensor* control_latent = make_optional_input(control_latent_tensor);
pe_vec = finish_rope_pe(Rope::gen_z_image_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("z_image.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size).add_shapes(ref_latents);
static_cast<int>(x->ne[3]), pe_key.add(ref_index_mode);
static_cast<int>(context->ne[1]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
SEQ_MULTI_OF, auto pe_vec = finish_rope_pe(Rope::gen_z_image_pe(static_cast<int>(x->ne[1]),
ref_latents, static_cast<int>(x->ne[0]),
ref_index_mode, config.patch_size,
config.theta, static_cast<int>(x->ne[3]),
config.axes_dim)); static_cast<int>(context->ne[1]),
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); SEQ_MULTI_OF,
// LOG_VERBOSE("pos_len %d", pos_len); ref_latents,
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); ref_index_mode,
// pe->data = pe_vec.data(); config.theta,
// print_ggml_tensor(pe, true, "pe"); config.axes_dim));
// pe->data = nullptr; int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
set_backend_tensor_data(pe, pe_vec.data()); return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto runner_ctx = get_context(); auto runner_ctx = get_context();
ggml_tensor* out = z_image.forward(&runner_ctx, ggml_tensor* out = z_image.forward(&runner_ctx,
@@ -1011,7 +1014,7 @@ namespace ZImage {
const std::vector<sd::Tensor<float>>& ref_latents = {}, const std::vector<sd::Tensor<float>>& ref_latents = {},
Rope::RefIndexMode ref_index_mode = Rope::RefIndexMode::FIXED, Rope::RefIndexMode ref_index_mode = Rope::RefIndexMode::FIXED,
const sd::Tensor<float>& control_latent = {}, const sd::Tensor<float>& control_latent = {},
float control_strength = 0.f) { float control_strength = 0.f) {
// x: [N, in_channels, h, w] // x: [N, in_channels, h, w]
// timesteps: [N, ] // timesteps: [N, ]
// context: [N, max_position, hidden_size] // context: [N, max_position, hidden_size]
@@ -1029,10 +1032,10 @@ namespace ZImage {
static const std::vector<sd::Tensor<float>> empty_ref_latents; static const std::vector<sd::Tensor<float>> empty_ref_latents;
static const sd::Tensor<float> empty_control_latent; static const sd::Tensor<float> empty_control_latent;
const auto* z_image_extra = std::get_if<ZImageDiffusionExtra>(&diffusion_params.extra); const auto* z_image_extra = std::get_if<ZImageDiffusionExtra>(&diffusion_params.extra);
const sd::Tensor<float>& control_latent = (z_image_extra != nullptr && z_image_extra->control_latent != nullptr) ? *z_image_extra->control_latent const sd::Tensor<float>& control_latent = (z_image_extra != nullptr && z_image_extra->control_latent != nullptr) ? *z_image_extra->control_latent
: empty_control_latent; : empty_control_latent;
float control_strength = z_image_extra != nullptr ? z_image_extra->strength : 0.f; float control_strength = z_image_extra != nullptr ? z_image_extra->strength : 0.f;
return compute(n_threads, return compute(n_threads,
*diffusion_params.x, *diffusion_params.x,
+19 -14
View File
@@ -2,6 +2,7 @@
#define __SD_MODEL_DIFFUSION_Z_IMAGE_L2P_HPP__ #define __SD_MODEL_DIFFUSION_Z_IMAGE_L2P_HPP__
#include <cmath> #include <cmath>
#include "core/pe_cache.h"
#include "z_image.hpp" #include "z_image.hpp"
@@ -183,9 +184,9 @@ namespace ZImageL2P {
}; };
struct ZImageL2PRunner : public DiffusionModelRunner { struct ZImageL2PRunner : public DiffusionModelRunner {
sd::PECache pe_cache_;
ZImageL2PConfig config; ZImageL2PConfig config;
ZImageL2PModel model; ZImageL2PModel model;
std::vector<float> pe_vec;
ZImageL2PRunner(ggml_backend_t backend, ZImageL2PRunner(ggml_backend_t backend,
const String2TensorStorage& tensors, const String2TensorStorage& tensors,
@@ -221,19 +222,23 @@ namespace ZImageL2P {
auto context = make_input(*inputs.context); auto context = make_input(*inputs.context);
GGML_ASSERT(x->ne[3] == 1); GGML_ASSERT(x->ne[3] == 1);
GGML_ASSERT(x->ne[0] % config.patch_size == 0 && x->ne[1] % config.patch_size == 0); GGML_ASSERT(x->ne[0] % config.patch_size == 0 && x->ne[1] % config.patch_size == 0);
pe_vec = finish_rope_pe(Rope::gen_z_image_pe(static_cast<int>(x->ne[1]), sd::PECacheKey pe_key("z_image_l2p.pe");
static_cast<int>(x->ne[0]), pe_key.add_shape(x).add_shape(context).add(config.theta).add(config.axes_dim).add(config.axes_dim_sum);
config.patch_size, pe_key.add(circular_x_enabled).add(circular_y_enabled).add(config.patch_size);
static_cast<int>(x->ne[3]), auto pe = make_input(pe_cache_.get_or_create(pe_key, [&]() {
static_cast<int>(context->ne[1]), auto pe_vec = finish_rope_pe(Rope::gen_z_image_pe(static_cast<int>(x->ne[1]),
ZImage::SEQ_MULTI_OF, static_cast<int>(x->ne[0]),
{}, config.patch_size,
Rope::RefIndexMode::FIXED, static_cast<int>(x->ne[3]),
config.theta, static_cast<int>(context->ne[1]),
config.axes_dim)); ZImage::SEQ_MULTI_OF,
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2); {},
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, config.axes_dim_sum / 2, pos_len); Rope::RefIndexMode::FIXED,
set_backend_tensor_data(pe, pe_vec.data()); config.theta,
config.axes_dim));
int pos_len = static_cast<int>(pe_vec.size() / config.axes_dim_sum / 2);
return sd::Tensor<float>({2, 2, config.axes_dim_sum / 2, pos_len}, std::move(pe_vec));
}));
auto ctx = get_context(); auto ctx = get_context();
auto out = model.forward(&ctx, x, t, context, pe); auto out = model.forward(&ctx, x, t, context, pe);
ggml_build_forward_expand(gf, out); ggml_build_forward_expand(gf, out);
+2 -2
View File
@@ -1150,8 +1150,8 @@ bool StableDiffusionGGML::build_control_net_runner() {
return false; return false;
} }
ModelManager::ResidencyMode residency_mode = backend_manager.params_backend_is_disk(SDBackendModule::DIFFUSION) ModelManager::ResidencyMode residency_mode = backend_manager.params_backend_is_disk(SDBackendModule::DIFFUSION)
? ModelManager::ResidencyMode::Disk ? ModelManager::ResidencyMode::Disk
: ModelManager::ResidencyMode::ParamBackend; : ModelManager::ResidencyMode::ParamBackend;
return model_manager->register_param_tensors(ModelComponent::ControlNet, return model_manager->register_param_tensors(ModelComponent::ControlNet,
std::move(control_tensors), std::move(control_tensors),
residency_mode, residency_mode,
+5 -5
View File
@@ -130,15 +130,15 @@ namespace sd::pipeline {
} }
// TAE encode already returns the latent; KL/Flux VAE returns a mean/logvar pair. // TAE encode already returns the latent; KL/Flux VAE returns a mean/logvar pair.
sd::Tensor<float> ctrl_latent = sd->first_stage_model->get_desc() == "taesd" sd::Tensor<float> ctrl_latent = sd->first_stage_model->get_desc() == "taesd"
? vae_output ? vae_output
: sd::ops::chunk(vae_output, 2, 2)[0]; : sd::ops::chunk(vae_output, 2, 2)[0];
ctrl_latent = sd->first_stage_model->vae_to_diffusion_latents(ctrl_latent); ctrl_latent = sd->first_stage_model->vae_to_diffusion_latents(ctrl_latent);
if (ctrl_latent.empty() || ctrl_latent.dim() != 4 || ctrl_latent.shape()[2] > 33) { if (ctrl_latent.empty() || ctrl_latent.dim() != 4 || ctrl_latent.shape()[2] > 33) {
LOG_ERROR("failed to encode control image"); LOG_ERROR("failed to encode control image");
return {}; return {};
} }
std::vector<int64_t> padded_shape = ctrl_latent.shape(); std::vector<int64_t> padded_shape = ctrl_latent.shape();
padded_shape[2] = 33; padded_shape[2] = 33;
sd::Tensor<float> padded(padded_shape); sd::Tensor<float> padded(padded_shape);
sd::ops::slice_assign(&padded, 2, 0, ctrl_latent.shape()[2], ctrl_latent); sd::ops::slice_assign(&padded, 2, 0, ctrl_latent.shape()[2], ctrl_latent);
return padded; return padded;
@@ -1028,7 +1028,7 @@ namespace sd::pipeline {
std::vector<int64_t> ctrl_shape = latents.control_image.shape(); std::vector<int64_t> ctrl_shape = latents.control_image.shape();
ctrl_shape[0] = hires_latent_w; ctrl_shape[0] = hires_latent_w;
ctrl_shape[1] = hires_latent_h; ctrl_shape[1] = hires_latent_h;
hires_control_image = sd::ops::interpolate(latents.control_image, ctrl_shape, sd::ops::InterpolateMode::Bicubic); hires_control_image = sd::ops::interpolate(latents.control_image, ctrl_shape, sd::ops::InterpolateMode::Bicubic);
} }
} else { } else {
hires_control_image = latents.control_image; hires_control_image = latents.control_image;