mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-11-11 03:24:30 +00:00
fix: avoid CPU fallback based on backend allocation chunk size (#2294)
This commit is contained in:
1 parent
de00bafc3d
commit
0b3b98d7b8
2 files changed
+15
-11
No files matched your search
@@ -212,6 +212,10 @@ ggml_backend_t GGMLRunner::backend_for_weight(const ggml_tensor* tensor) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool backend_can_allocate_op(ggml_backend_t backend, const ggml_tensor* node) {
|
static bool backend_can_allocate_op(ggml_backend_t backend, const ggml_tensor* node) {
|
||||||
|
// Vulkan reports a preferred allocation chunk size, not a hard tensor limit.
|
||||||
|
if (sd_backend_is(backend, "Vulkan")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
auto buft = ggml_backend_get_default_buffer_type(backend);
|
auto buft = ggml_backend_get_default_buffer_type(backend);
|
||||||
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
||||||
size_t max_size = ggml_backend_buft_get_max_size(buft);
|
size_t max_size = ggml_backend_buft_get_max_size(buft);
|
||||||
@@ -219,6 +223,7 @@ static bool backend_can_allocate_op(ggml_backend_t backend, const ggml_tensor* n
|
|||||||
if (ggml_backend_buft_get_alloc_size(buft, node) > max_size) {
|
if (ggml_backend_buft_get_alloc_size(buft, node) > max_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Cross-backend copies must also fit the destination's allocation limit.
|
||||||
for (auto src : node->src) {
|
for (auto src : node->src) {
|
||||||
if (src != nullptr && ggml_backend_buft_get_alloc_size(buft, src) > max_size) {
|
if (src != nullptr && ggml_backend_buft_get_alloc_size(buft, src) > max_size) {
|
||||||
return false;
|
return false;
|
||||||
@@ -251,8 +256,6 @@ void GGMLRunner::pin_multi_device_nodes(ggml_backend_sched_t sched, ggml_cgraph*
|
|||||||
node->op == GGML_OP_PERMUTE || node->op == GGML_OP_TRANSPOSE) {
|
node->op == GGML_OP_PERMUTE || node->op == GGML_OP_TRANSPOSE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Operation support can allow tensors larger than the backend's allocation limit.
|
|
||||||
// Check inputs too, since cross-backend copies must also fit a single allocation.
|
|
||||||
if (!backend_can_allocate_op(current, node)) {
|
if (!backend_can_allocate_op(current, node)) {
|
||||||
auto cpu = workspace_.cpu_backend();
|
auto cpu = workspace_.cpu_backend();
|
||||||
if (cpu != nullptr && ggml_backend_supports_op(cpu, node)) {
|
if (cpu != nullptr && ggml_backend_supports_op(cpu, node)) {
|
||||||
|
|||||||
@@ -176,12 +176,12 @@ namespace MiniMaxH3 {
|
|||||||
if (ctx->backend != nullptr) {
|
if (ctx->backend != nullptr) {
|
||||||
auto buft = ggml_backend_get_default_buffer_type(ctx->backend);
|
auto buft = ggml_backend_get_default_buffer_type(ctx->backend);
|
||||||
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
||||||
size_t max_size = ggml_backend_buft_get_max_size(buft);
|
size_t chunk_budget = ggml_backend_buft_get_max_size(buft);
|
||||||
max_size -= max_size % alignment;
|
chunk_budget -= chunk_budget % alignment;
|
||||||
// Matmul outputs are F32 even for quantized weights. Split before fc1
|
// Use the backend's preferred allocation size as a conservative chunk budget.
|
||||||
// so its expanded activation never needs an oversized backend buffer.
|
// Matmul outputs are F32 even for quantized weights.
|
||||||
size_t token_bytes = ggml_row_size(GGML_TYPE_F32, std::max(x->ne[0], 2 * ffn_hidden_size)) * x->ne[2] * x->ne[3];
|
size_t token_bytes = ggml_row_size(GGML_TYPE_F32, std::max(x->ne[0], 2 * ffn_hidden_size)) * x->ne[2] * x->ne[3];
|
||||||
chunk_size = static_cast<int64_t>(std::min<size_t>(chunk_size, std::max<size_t>(1, max_size / token_bytes)));
|
chunk_size = static_cast<int64_t>(std::min<size_t>(chunk_size, std::max<size_t>(1, chunk_budget / token_bytes)));
|
||||||
}
|
}
|
||||||
if (chunk_size == x->ne[1]) {
|
if (chunk_size == x->ne[1]) {
|
||||||
return forward_chunk(x);
|
return forward_chunk(x);
|
||||||
@@ -269,10 +269,11 @@ namespace MiniMaxH3 {
|
|||||||
if (ctx->backend != nullptr) {
|
if (ctx->backend != nullptr) {
|
||||||
auto buft = ggml_backend_get_default_buffer_type(ctx->backend);
|
auto buft = ggml_backend_get_default_buffer_type(ctx->backend);
|
||||||
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
size_t alignment = ggml_backend_buft_get_alignment(buft);
|
||||||
size_t max_size = ggml_backend_buft_get_max_size(buft);
|
// This is a conservative chunk budget, not an operation support limit.
|
||||||
max_size -= max_size % alignment;
|
size_t chunk_budget = ggml_backend_buft_get_max_size(buft);
|
||||||
|
chunk_budget -= chunk_budget % alignment;
|
||||||
size_t token_bytes = ggml_row_size(GGML_TYPE_F32, 3 * heads * head_dim) * inputs[0]->ne[2] * inputs[0]->ne[3];
|
size_t token_bytes = ggml_row_size(GGML_TYPE_F32, 3 * heads * head_dim) * inputs[0]->ne[2] * inputs[0]->ne[3];
|
||||||
chunk_size = static_cast<int64_t>(std::min<size_t>(chunk_size, std::max<size_t>(1, max_size / token_bytes)));
|
chunk_size = static_cast<int64_t>(std::min<size_t>(chunk_size, std::max<size_t>(1, chunk_budget / token_bytes)));
|
||||||
}
|
}
|
||||||
if (chunk_size == sequence) {
|
if (chunk_size == sequence) {
|
||||||
ggml_tensor* projected = nullptr;
|
ggml_tensor* projected = nullptr;
|
||||||
@@ -284,7 +285,7 @@ namespace MiniMaxH3 {
|
|||||||
return split_qkv(ctx, projected);
|
return split_qkv(ctx, projected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split Q/K/V before concatenating tokens so the full packed QKV never exceeds the buffer limit.
|
// Split Q/K/V before concatenating tokens to avoid materializing the full packed QKV.
|
||||||
std::vector<ggml_tensor*> chunks[3];
|
std::vector<ggml_tensor*> chunks[3];
|
||||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||||
auto input = inputs[i];
|
auto input = inputs[i];
|
||||||
|
|||||||
Reference in new issue
Block a user