mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-09-25 12:40:41 +00:00
Compare commits
5 Commits
c678dfe704
...
6dcb5bbd42
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dcb5bbd42 | ||
|
|
97d932b8f8 | ||
|
|
78557f88d9 | ||
|
|
2726dd35c2 | ||
|
|
74988b290e |
@ -156,8 +156,11 @@ the runner's graph-cut capacity checks.
|
|||||||
|
|
||||||
Runtime capacity checks also leave 512 MiB of currently free device memory for
|
Runtime capacity checks also leave 512 MiB of currently free device memory for
|
||||||
backend scratch buffers and pipelines, including with explicit backend assignments.
|
backend scratch buffers and pipelines, including with explicit backend assignments.
|
||||||
They cap stale free-memory reports by the device's total memory minus tracked
|
They cap free-memory reports by the device's total memory minus tracked
|
||||||
resident allocations and reject reports that exceed the device's total memory.
|
resident allocations. Vulkan reports exceeding total memory are rejected because
|
||||||
|
its heap-budget subtraction can underflow. Other backends use the cap instead of
|
||||||
|
treating such reports as zero free memory. Failed checks log the reported free and
|
||||||
|
total memory alongside tracked weight and runtime allocations.
|
||||||
|
|
||||||
Components are considered in `diffusion`, `te`, `vae` order so that repeatedly
|
Components are considered in `diffusion`, `te`, `vae` order so that repeatedly
|
||||||
used diffusion weights have priority. Each component's weights use the first
|
used diffusion weights have priority. Each component's weights use the first
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
|
## Video model used in image generation mode
|
||||||
|
|
||||||
|
If generation reports that a model cannot be run with `generate_image()`, add
|
||||||
|
`--mode vid_gen` to the CLI command. `--video-frames` alone does not select video
|
||||||
|
mode. Video models require this mode even when generating a single frame.
|
||||||
|
Library callers must use `generate_video()` for these models; use
|
||||||
|
`sd_ctx_supports_image_generation()` and `sd_ctx_supports_video_generation()` to
|
||||||
|
check the available generation modes.
|
||||||
|
|
||||||
## Completely black or white images or videos / NaNs
|
## Completely black or white images or videos / NaNs
|
||||||
|
|
||||||
Some ggml backends can encounter numerical overflow during inference, producing
|
Some ggml backends can encounter numerical overflow during inference, producing
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# How to Use
|
# How to Use
|
||||||
|
|
||||||
|
Wan models require `-M vid_gen`, including single-frame generation. `--video-frames` alone does not select video mode. Library callers must use `generate_video()` instead of `generate_image()`.
|
||||||
|
|
||||||
## Download weights
|
## Download weights
|
||||||
|
|
||||||
- Download Wan
|
- Download Wan
|
||||||
|
|||||||
@ -1754,7 +1754,7 @@ ArgOptions SDGenerationParams::get_options() {
|
|||||||
on_scm_policy_arg},
|
on_scm_policy_arg},
|
||||||
{"",
|
{"",
|
||||||
"--vae-tile-size",
|
"--vae-tile-size",
|
||||||
"tile size for vae tiling, format [X]x[Y] (default: 32x32)",
|
"tile size for vae tiling in latent units, not image pixels, format [X]x[Y] (default: 32x32)",
|
||||||
on_tile_size_arg},
|
on_tile_size_arg},
|
||||||
{"",
|
{"",
|
||||||
"--vae-relative-tile-size",
|
"--vae-relative-tile-size",
|
||||||
@ -2223,7 +2223,12 @@ bool SDGenerationParams::from_json_str(
|
|||||||
LOG_ERROR("invalid end_image");
|
LOG_ERROR("invalid end_image");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!parse_image_array_json_field(j, "ref_images", 3, width, height, ref_images)) {
|
if (!parse_image_array_json_field(j,
|
||||||
|
"ref_images",
|
||||||
|
3,
|
||||||
|
auto_resize_ref_image ? width : 0,
|
||||||
|
auto_resize_ref_image ? height : 0,
|
||||||
|
ref_images)) {
|
||||||
LOG_ERROR("invalid ref_images");
|
LOG_ERROR("invalid ref_images");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -244,8 +244,12 @@ static bool build_sdapi_img_gen_request(const json& j,
|
|||||||
SDImageOwner image_owner;
|
SDImageOwner image_owner;
|
||||||
if (decode_base64_image(extra_image.get<std::string>(),
|
if (decode_base64_image(extra_image.get<std::string>(),
|
||||||
3,
|
3,
|
||||||
request.gen_params.width_and_height_are_set() ? request.gen_params.width : 0,
|
request.gen_params.auto_resize_ref_image && request.gen_params.width_and_height_are_set()
|
||||||
request.gen_params.width_and_height_are_set() ? request.gen_params.height : 0,
|
? request.gen_params.width
|
||||||
|
: 0,
|
||||||
|
request.gen_params.auto_resize_ref_image && request.gen_params.width_and_height_are_set()
|
||||||
|
? request.gen_params.height
|
||||||
|
: 0,
|
||||||
image_owner)) {
|
image_owner)) {
|
||||||
const sd_image_t& image = image_owner.get();
|
const sd_image_t& image = image_owner.get();
|
||||||
request.gen_params.set_width_and_height_if_unset(image.width, image.height);
|
request.gen_params.set_width_and_height_if_unset(image.width, image.height);
|
||||||
|
|||||||
2
ggml
2
ggml
@ -1 +1 @@
|
|||||||
Subproject commit f583f393cd5dfdc129360bbf75cb3d49ccc837a8
|
Subproject commit 4bf5f6000653b7881d00963cd6ddb665ccd62a8d
|
||||||
@ -2219,7 +2219,10 @@ struct LLMEmbedder : public Conditioner {
|
|||||||
false,
|
false,
|
||||||
deepstack_image_embeds,
|
deepstack_image_embeds,
|
||||||
image_grids);
|
image_grids);
|
||||||
GGML_ASSERT(!hidden_states.empty());
|
if (hidden_states.empty()) {
|
||||||
|
LOG_ERROR("LLM prompt encoding failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
hidden_states = apply_token_weights(std::move(hidden_states), weights);
|
hidden_states = apply_token_weights(std::move(hidden_states), weights);
|
||||||
GGML_ASSERT(hidden_states.shape()[1] > prompt_template_encode_start_idx);
|
GGML_ASSERT(hidden_states.shape()[1] > prompt_template_encode_start_idx);
|
||||||
|
|
||||||
|
|||||||
@ -478,7 +478,11 @@ namespace sd::backend_fit {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool prepare_vae_decode_retry_tiling(sd_tiling_params_t& tiling_params, bool prefer_temporal_tiling) {
|
bool prepare_vae_decode_retry_tiling(sd_tiling_params_t& tiling_params, bool prefer_temporal_tiling, ggml_status status) {
|
||||||
|
// Execution failures can leave the device unusable; tiling only helps with allocation failures.
|
||||||
|
if (status != GGML_STATUS_ALLOC_FAILED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const char* retry_mode = nullptr;
|
const char* retry_mode = nullptr;
|
||||||
if (prefer_temporal_tiling && !tiling_params.temporal_tiling) {
|
if (prefer_temporal_tiling && !tiling_params.temporal_tiling) {
|
||||||
tiling_params.temporal_tiling = true;
|
tiling_params.temporal_tiling = true;
|
||||||
@ -498,7 +502,7 @@ namespace sd::backend_fit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARN("VAE decode failed (likely out of memory); retrying with %s tiling",
|
LOG_WARN("VAE decode ran out of memory; retrying with %s tiling",
|
||||||
retry_mode);
|
retry_mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,8 @@ namespace sd::backend_fit {
|
|||||||
std::string& params_spec);
|
std::string& params_spec);
|
||||||
|
|
||||||
bool prepare_vae_decode_retry_tiling(sd_tiling_params_t& tiling_params,
|
bool prepare_vae_decode_retry_tiling(sd_tiling_params_t& tiling_params,
|
||||||
bool prefer_temporal_tiling);
|
bool prefer_temporal_tiling,
|
||||||
|
ggml_status status);
|
||||||
|
|
||||||
} // namespace sd::backend_fit
|
} // namespace sd::backend_fit
|
||||||
|
|
||||||
|
|||||||
@ -590,6 +590,7 @@ std::optional<sd::Tensor<float>> GGMLRunner::compute(get_graph_cb_t get_graph,
|
|||||||
bool auto_runner_end,
|
bool auto_runner_end,
|
||||||
bool no_return,
|
bool no_return,
|
||||||
const std::function<bool()>& read_outputs) {
|
const std::function<bool()>& read_outputs) {
|
||||||
|
last_compute_status_ = GGML_STATUS_FAILED;
|
||||||
if (graph_active_) {
|
if (graph_active_) {
|
||||||
LOG_ERROR("%s does not support reentrant graph execution", get_desc().c_str());
|
LOG_ERROR("%s does not support reentrant graph execution", get_desc().c_str());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -613,7 +614,9 @@ std::optional<sd::Tensor<float>> GGMLRunner::compute(get_graph_cb_t get_graph,
|
|||||||
GGMLRunner& runner;
|
GGMLRunner& runner;
|
||||||
const bool& success;
|
const bool& success;
|
||||||
~GraphEndGuard() {
|
~GraphEndGuard() {
|
||||||
runner.workspace_.segment_end();
|
if (!runner.workspace_.segment_end()) {
|
||||||
|
runner.last_compute_status_ = GGML_STATUS_FAILED;
|
||||||
|
}
|
||||||
runner.cache_.graph_end(false);
|
runner.cache_.graph_end(false);
|
||||||
runner.cut_cache_.clear();
|
runner.cut_cache_.clear();
|
||||||
runner.free_compute_ctx();
|
runner.free_compute_ctx();
|
||||||
@ -642,6 +645,7 @@ std::optional<sd::Tensor<float>> GGMLRunner::compute(get_graph_cb_t get_graph,
|
|||||||
try {
|
try {
|
||||||
output = execute_graph(graph, n_threads, no_return, read_outputs);
|
output = execute_graph(graph, n_threads, no_return, read_outputs);
|
||||||
} catch (const std::exception& error) {
|
} catch (const std::exception& error) {
|
||||||
|
last_compute_status_ = GGML_STATUS_FAILED;
|
||||||
LOG_ERROR("%s graph execution failed on %s: %s", get_desc().c_str(),
|
LOG_ERROR("%s graph execution failed on %s: %s", get_desc().c_str(),
|
||||||
ggml_backend_name(runtime_backend), error.what());
|
ggml_backend_name(runtime_backend), error.what());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -649,6 +653,7 @@ std::optional<sd::Tensor<float>> GGMLRunner::compute(get_graph_cb_t get_graph,
|
|||||||
success = output.has_value();
|
success = output.has_value();
|
||||||
if (success) {
|
if (success) {
|
||||||
cache_.graph_end(true);
|
cache_.graph_end(true);
|
||||||
|
last_compute_status_ = GGML_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -766,6 +771,7 @@ bool GGMLRunner::execute_segment(ggml_cgraph* graph, int n_threads) {
|
|||||||
}
|
}
|
||||||
workspace_.synchronize();
|
workspace_.synchronize();
|
||||||
if (status != GGML_STATUS_SUCCESS) {
|
if (status != GGML_STATUS_SUCCESS) {
|
||||||
|
last_compute_status_ = status;
|
||||||
LOG_ERROR("%s compute failed: %s", get_desc().c_str(), ggml_status_to_string(status));
|
LOG_ERROR("%s compute failed: %s", get_desc().c_str(), ggml_status_to_string(status));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -818,6 +824,7 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
const auto& cached_plan = resolve_graph_cut_plan(graph);
|
const auto& cached_plan = resolve_graph_cut_plan(graph);
|
||||||
const auto full_measurement = measure(graph, cached_plan.compute_buffer_size);
|
const auto full_measurement = measure(graph, cached_plan.compute_buffer_size);
|
||||||
if (full_measurement.buffers.empty()) {
|
if (full_measurement.buffers.empty()) {
|
||||||
|
last_compute_status_ = GGML_STATUS_ALLOC_FAILED;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
auto manager = residency_manager.lock();
|
auto manager = residency_manager.lock();
|
||||||
@ -888,7 +895,9 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
SegmentGraphBindings& bindings;
|
SegmentGraphBindings& bindings;
|
||||||
ggml_context* context;
|
ggml_context* context;
|
||||||
~SegmentCleanup() {
|
~SegmentCleanup() {
|
||||||
runner.workspace_.segment_end();
|
if (!runner.workspace_.segment_end()) {
|
||||||
|
runner.last_compute_status_ = GGML_STATUS_FAILED;
|
||||||
|
}
|
||||||
bindings.restore();
|
bindings.restore();
|
||||||
weights.segment_end();
|
weights.segment_end();
|
||||||
ggml_free(context);
|
ggml_free(context);
|
||||||
@ -898,6 +907,7 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
|
|
||||||
auto measurement = segmented ? measure(segment_graph, segment.compute_buffer_size) : full_measurement;
|
auto measurement = segmented ? measure(segment_graph, segment.compute_buffer_size) : full_measurement;
|
||||||
if (!workspace_.prepare(measurement)) {
|
if (!workspace_.prepare(measurement)) {
|
||||||
|
last_compute_status_ = GGML_STATUS_ALLOC_FAILED;
|
||||||
return fail_segment("workspace preparation");
|
return fail_segment("workspace preparation");
|
||||||
}
|
}
|
||||||
const size_t cut_bytes = last ? 0 : cut_cache_.estimate_output_bytes(graph, segment);
|
const size_t cut_bytes = last ? 0 : cut_cache_.estimate_output_bytes(graph, segment);
|
||||||
@ -912,7 +922,11 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
sync_runtime_residency();
|
sync_runtime_residency();
|
||||||
requests = memory_requests(measurement.buffers, new_cache_bytes);
|
requests = memory_requests(measurement.buffers, new_cache_bytes);
|
||||||
}
|
}
|
||||||
return weights.ensure_segment_capacity(index, requests);
|
const bool ready = weights.ensure_segment_capacity(index, requests);
|
||||||
|
if (!ready && manager != nullptr) {
|
||||||
|
last_compute_status_ = GGML_STATUS_ALLOC_FAILED;
|
||||||
|
}
|
||||||
|
return ready;
|
||||||
};
|
};
|
||||||
if (!weights.segment_start(index, ensure_capacity)) {
|
if (!weights.segment_start(index, ensure_capacity)) {
|
||||||
return fail_segment("weight preparation");
|
return fail_segment("weight preparation");
|
||||||
@ -921,12 +935,17 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
if (!workspace_.measurement_matches(segment_graph, measurement)) {
|
if (!workspace_.measurement_matches(segment_graph, measurement)) {
|
||||||
measurement = measure(segment_graph, segment.compute_buffer_size);
|
measurement = measure(segment_graph, segment.compute_buffer_size);
|
||||||
}
|
}
|
||||||
if (!workspace_.prepare(measurement) || !ensure_capacity()) {
|
if (!workspace_.prepare(measurement)) {
|
||||||
|
last_compute_status_ = GGML_STATUS_ALLOC_FAILED;
|
||||||
|
return fail_segment("workspace preparation");
|
||||||
|
}
|
||||||
|
if (!ensure_capacity()) {
|
||||||
return fail_segment("workspace capacity check");
|
return fail_segment("workspace capacity check");
|
||||||
}
|
}
|
||||||
if (!workspace_.allocate(segment_graph, [&](ggml_backend_sched_t scheduler, ggml_cgraph* current) {
|
if (!workspace_.allocate(segment_graph, [&](ggml_backend_sched_t scheduler, ggml_cgraph* current) {
|
||||||
pin_multi_device_nodes(scheduler, current);
|
pin_multi_device_nodes(scheduler, current);
|
||||||
})) {
|
})) {
|
||||||
|
last_compute_status_ = GGML_STATUS_ALLOC_FAILED;
|
||||||
return fail_segment("workspace allocation");
|
return fail_segment("workspace allocation");
|
||||||
}
|
}
|
||||||
for (const auto& size : measurement.buffers) {
|
for (const auto& size : measurement.buffers) {
|
||||||
@ -964,6 +983,7 @@ std::optional<Tensor<float>> GGMLRunner::execute_graph(ggml_cgraph* graph, int n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!workspace_.segment_end()) {
|
if (!workspace_.segment_end()) {
|
||||||
|
last_compute_status_ = GGML_STATUS_FAILED;
|
||||||
return fail_segment("workspace synchronization");
|
return fail_segment("workspace synchronization");
|
||||||
}
|
}
|
||||||
// Final outputs and their callbacks may still be views of consumed cuts.
|
// Final outputs and their callbacks may still be views of consumed cuts.
|
||||||
|
|||||||
@ -131,6 +131,7 @@ struct GGMLRunner {
|
|||||||
private:
|
private:
|
||||||
std::map<ggml_backend_t, size_t> logged_compute_bytes_;
|
std::map<ggml_backend_t, size_t> logged_compute_bytes_;
|
||||||
size_t logged_segment_count_ = 0;
|
size_t logged_segment_count_ = 0;
|
||||||
|
ggml_status last_compute_status_ = GGML_STATUS_SUCCESS;
|
||||||
|
|
||||||
sd::ComputeWorkspace::Measurement measure(ggml_cgraph* graph, size_t direct_bytes);
|
sd::ComputeWorkspace::Measurement measure(ggml_cgraph* graph, size_t direct_bytes);
|
||||||
std::vector<DeviceMemoryRequest> memory_requests(const std::vector<sd::BackendBufferSize>& sizes,
|
std::vector<DeviceMemoryRequest> memory_requests(const std::vector<sd::BackendBufferSize>& sizes,
|
||||||
@ -335,6 +336,8 @@ public:
|
|||||||
bool no_return = false,
|
bool no_return = false,
|
||||||
const std::function<bool()>& read_outputs = {});
|
const std::function<bool()>& read_outputs = {});
|
||||||
|
|
||||||
|
ggml_status last_compute_status() const { return last_compute_status_; }
|
||||||
|
|
||||||
void set_flash_attention_enabled(bool enabled) {
|
void set_flash_attention_enabled(bool enabled) {
|
||||||
flash_attn_enabled = enabled;
|
flash_attn_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -252,6 +252,14 @@ static inline bool sd_version_is_sensenova_u1(SDVersion version) {
|
|||||||
return version == VERSION_SENSENOVA_U1_5;
|
return version == VERSION_SENSENOVA_U1_5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool sd_version_supports_video_generation(SDVersion version) {
|
||||||
|
return version == VERSION_SVD || sd_version_is_wan(version) || sd_version_is_hunyuan_video(version) || sd_version_is_lingbot_video(version) || sd_version_is_ltxav(version) || sd_version_is_minimax_h3(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool sd_version_supports_image_generation(SDVersion version) {
|
||||||
|
return !sd_version_supports_video_generation(version);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool sd_version_uses_flux_vae(SDVersion version) {
|
static inline bool sd_version_uses_flux_vae(SDVersion version) {
|
||||||
if (sd_version_is_flux(version) || sd_version_is_z_image(version) || sd_version_is_boogu_image(version) || sd_version_is_longcat(version)) {
|
if (sd_version_is_flux(version) || sd_version_is_z_image(version) || sd_version_is_boogu_image(version) || sd_version_is_longcat(version)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1613,7 +1613,8 @@ void ModelManager::remove_runtime_owner(uintptr_t owner_id) {
|
|||||||
|
|
||||||
ModelManager::CapacityCheck ModelManager::check_capacity(
|
ModelManager::CapacityCheck ModelManager::check_capacity(
|
||||||
const DeviceMemoryRequest& request,
|
const DeviceMemoryRequest& request,
|
||||||
const std::vector<TensorState*>& states) const {
|
const std::vector<TensorState*>& states,
|
||||||
|
bool log_details) const {
|
||||||
CapacityCheck result;
|
CapacityCheck result;
|
||||||
if (request.compute_backend == nullptr || sd_backend_is_cpu(request.compute_backend)) {
|
if (request.compute_backend == nullptr || sd_backend_is_cpu(request.compute_backend)) {
|
||||||
return result;
|
return result;
|
||||||
@ -1631,16 +1632,23 @@ ModelManager::CapacityCheck ModelManager::check_capacity(
|
|||||||
}
|
}
|
||||||
size_t free_bytes = 0, total_bytes = 0;
|
size_t free_bytes = 0, total_bytes = 0;
|
||||||
ggml_backend_dev_memory(device, &free_bytes, &total_bytes);
|
ggml_backend_dev_memory(device, &free_bytes, &total_bytes);
|
||||||
|
const size_t weights_resident = compute_backend_resident_bytes(backend);
|
||||||
|
const size_t other_runtime = other_runtime_resident_bytes(request.owner_id, backend);
|
||||||
|
const size_t resident = add(weights_resident, add(other_runtime, request.runtime_resident_bytes));
|
||||||
|
if (log_details) {
|
||||||
|
LOG_WARN("model manager memory on %s: reported free %.2f MB / total %.2f MB, tracked weights %.2f MB / other runtime %.2f MB / current runtime %.2f MB",
|
||||||
|
ggml_backend_name(backend),
|
||||||
|
free_bytes / (1024.0 * 1024.0), total_bytes / (1024.0 * 1024.0),
|
||||||
|
weights_resident / (1024.0 * 1024.0), other_runtime / (1024.0 * 1024.0),
|
||||||
|
request.runtime_resident_bytes / (1024.0 * 1024.0));
|
||||||
|
}
|
||||||
if (free_bytes == 0 && total_bytes == 0) {
|
if (free_bytes == 0 && total_bytes == 0) {
|
||||||
return SIZE_MAX;
|
return SIZE_MAX;
|
||||||
}
|
}
|
||||||
// Vulkan's heap budget subtraction can underflow when usage exceeds the budget.
|
// Vulkan's heap budget subtraction can underflow when usage exceeds the budget.
|
||||||
if (total_bytes > 0 && free_bytes > total_bytes) {
|
if (total_bytes > 0 && free_bytes > total_bytes && sd_backend_is(backend, "Vulkan")) {
|
||||||
return size_t{0};
|
return size_t{0};
|
||||||
}
|
}
|
||||||
const size_t resident = add(compute_backend_resident_bytes(backend),
|
|
||||||
add(other_runtime_resident_bytes(request.owner_id, backend),
|
|
||||||
request.runtime_resident_bytes));
|
|
||||||
if (total_bytes > 0) {
|
if (total_bytes > 0) {
|
||||||
free_bytes = std::min(free_bytes, resident < total_bytes ? total_bytes - resident : 0);
|
free_bytes = std::min(free_bytes, resident < total_bytes ? total_bytes - resident : 0);
|
||||||
}
|
}
|
||||||
@ -1786,7 +1794,7 @@ bool ModelManager::ensure_compute_backend_capacity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto capacity = check_capacity(request, required_states);
|
const auto capacity = check_capacity(request, required_states, true);
|
||||||
const std::string available_device = capacity.available_device_bytes == SIZE_MAX
|
const std::string available_device = capacity.available_device_bytes == SIZE_MAX
|
||||||
? "unknown"
|
? "unknown"
|
||||||
: sd_format("%.2f MB", capacity.available_device_bytes / (1024.0 * 1024.0));
|
: sd_format("%.2f MB", capacity.available_device_bytes / (1024.0 * 1024.0));
|
||||||
|
|||||||
@ -157,7 +157,8 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
CapacityCheck check_capacity(const DeviceMemoryRequest& request,
|
CapacityCheck check_capacity(const DeviceMemoryRequest& request,
|
||||||
const std::vector<TensorState*>& states) const;
|
const std::vector<TensorState*>& states,
|
||||||
|
bool log_details = false) const;
|
||||||
|
|
||||||
ggml_backend_buffer_type_t params_buffer_type_for(const TensorState& state) const;
|
ggml_backend_buffer_type_t params_buffer_type_for(const TensorState& state) const;
|
||||||
ggml_backend_buffer_type_t split_buffer_type_for(const TensorState& state) const;
|
ggml_backend_buffer_type_t split_buffer_type_for(const TensorState& state) const;
|
||||||
|
|||||||
@ -2766,7 +2766,8 @@ sd::Tensor<float> StableDiffusionGGML::decode_first_stage(const sd::Tensor<float
|
|||||||
auto decoded = first_stage_model->decode(n_threads, latents, vae_tiling_params, decode_video, circular_x, circular_y);
|
auto decoded = first_stage_model->decode(n_threads, latents, vae_tiling_params, decode_video, circular_x, circular_y);
|
||||||
const bool prefer_temporal_tiling = decode_video && first_stage_model->can_temporal_tile_decode();
|
const bool prefer_temporal_tiling = decode_video && first_stage_model->can_temporal_tile_decode();
|
||||||
while (decoded.empty() &&
|
while (decoded.empty() &&
|
||||||
sd::backend_fit::prepare_vae_decode_retry_tiling(vae_tiling_params, prefer_temporal_tiling)) {
|
sd::backend_fit::prepare_vae_decode_retry_tiling(vae_tiling_params, prefer_temporal_tiling,
|
||||||
|
first_stage_model->last_compute_status())) {
|
||||||
decoded = first_stage_model->decode(n_threads, latents, vae_tiling_params, decode_video, circular_x, circular_y);
|
decoded = first_stage_model->decode(n_threads, latents, vae_tiling_params, decode_video, circular_x, circular_y);
|
||||||
}
|
}
|
||||||
return decoded;
|
return decoded;
|
||||||
|
|||||||
@ -789,15 +789,9 @@ namespace sd::pipeline {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiniMax-H3 is video-only. Its denoiser always splits the packed latent into a video and an
|
if (!sd_version_supports_image_generation(sd->version)) {
|
||||||
// audio half, and only generate_video ever computes the audio length, so reaching this
|
LOG_ERROR("%s cannot be run with generate_image(); use generate_video() or --mode vid_gen in the CLI",
|
||||||
// function with an H3 checkpoint is guaranteed to die on
|
model_version_to_str[sd->version]);
|
||||||
// GGML_ASSERT(!audio_input_cache.empty()) with a core dump, after the several minutes it
|
|
||||||
// takes to load the weights, and with nothing in the output pointing at the missing --mode.
|
|
||||||
// (The AnimateDiff path below routes vid_gen back through here, but that is SD1.5 plus a
|
|
||||||
// motion module, never H3.)
|
|
||||||
if (sd_version_is_minimax_h3(sd->version)) {
|
|
||||||
LOG_ERROR("MiniMax-H3 is a video model and cannot be run in img_gen mode; use --mode vid_gen");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -630,14 +630,6 @@ struct sd_ctx_t {
|
|||||||
StableDiffusionGGML* sd = nullptr;
|
StableDiffusionGGML* sd = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool sd_version_supports_video_generation(SDVersion version) {
|
|
||||||
return version == VERSION_SVD || sd_version_is_wan(version) || sd_version_is_hunyuan_video(version) || sd_version_is_lingbot_video(version) || sd_version_is_ltxav(version) || sd_version_is_minimax_h3(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool sd_version_supports_image_generation(SDVersion version) {
|
|
||||||
return !sd_version_supports_video_generation(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params) {
|
sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params) {
|
||||||
sd_ctx_t* sd_ctx = (sd_ctx_t*)malloc(sizeof(sd_ctx_t));
|
sd_ctx_t* sd_ctx = (sd_ctx_t*)malloc(sizeof(sd_ctx_t));
|
||||||
if (sd_ctx == nullptr) {
|
if (sd_ctx == nullptr) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user