feat: optimize cfg special cases with guidance schdeule (#2033)

This commit is contained in:
stduhpf 2026-09-24 19:10:22 +02:00 committed by GitHub
parent 88411ef1e0
commit caa111adf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 88 additions and 27 deletions

View File

@ -2441,6 +2441,7 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
timesteps_tensor, timesteps_tensor,
cond, cond,
&controls); &controls);
bool uncond_controls_ready = false;
static const std::vector<sd::Tensor<float>> empty_ref_latents; static const std::vector<sd::Tensor<float>> empty_ref_latents;
bool uncond_without_ref_latents = !img_uncond.empty() && bool uncond_without_ref_latents = !img_uncond.empty() &&
@ -2530,6 +2531,17 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
return std::move(cached_output); return std::move(cached_output);
} }
// A re-enabled condition can miss the cache even when the positive pass was reused.
if (!uncond_controls_ready && !uncond.empty() &&
(&condition == &uncond || &condition == &img_uncond)) {
compute_sample_controls(control_image,
noised_input,
timesteps_tensor,
uncond,
&controls);
uncond_controls_ready = true;
}
for (const auto& extension : generation_extensions) { for (const auto& extension : generation_extensions) {
extension->before_diffusion(diffusion_params, step); extension->before_diffusion(diffusion_params, step);
} }
@ -2569,41 +2581,69 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
} }
} }
float effective_guidance_scale = guidance_schedule.empty()
? cfg_scale
: guidance_schedule[guidance_schedule.size() - 1 - step];
float image_guidance_scale = img_cfg_scale;
constexpr float kEpsilon = 1e-5f;
bool skip_uncond = false;
if (!uncond.empty() && !needs_uncond_denoised && !use_apg_guidance) {
if (!img_uncond.empty()) {
skip_uncond = std::abs(image_guidance_scale - effective_guidance_scale) < kEpsilon;
} else {
skip_uncond = std::abs(effective_guidance_scale - 1.0f) < kEpsilon;
}
}
bool skip_img_uncond = false;
if (!img_uncond.empty() && !needs_uncond_denoised && !use_apg_guidance) {
if (!uncond.empty()) {
skip_img_uncond = std::abs(image_guidance_scale - 1.0f) < kEpsilon;
} else {
skip_img_uncond = std::abs(effective_guidance_scale - 1.0f) < kEpsilon;
}
}
cond_out = run_condition(*positive_condition, c_concat_override); cond_out = run_condition(*positive_condition, c_concat_override);
if (cond_out.empty()) { if (cond_out.empty()) {
return {}; return {};
} }
if (!uncond.empty()) { if (!uncond.empty()) {
if (!step_cache.is_step_skipped()) { if (!skip_uncond) {
compute_sample_controls(control_image, const std::vector<int>* uncond_skip_layers = nullptr;
noised_input, if (is_skiplayer_step && slg_uncond) {
timesteps_tensor, LOG_VERBOSE("Skipping layers at uncond step %d\n", step);
uncond, uncond_skip_layers = &skip_layer_guidance.layers();
&controls); }
} uncond_out = run_condition(uncond,
const std::vector<int>* uncond_skip_layers = nullptr; uncond.c_concat.empty() ? nullptr : &uncond.c_concat,
if (is_skiplayer_step && slg_uncond) { uncond_skip_layers,
LOG_VERBOSE("Skipping layers at uncond step %d\n", step); nullptr,
uncond_skip_layers = &skip_layer_guidance.layers(); true);
} if (uncond_out.empty()) {
uncond_out = run_condition(uncond, return {};
uncond.c_concat.empty() ? nullptr : &uncond.c_concat, }
uncond_skip_layers, } else {
nullptr, step_cache.invalidate_condition(&uncond);
true);
if (uncond_out.empty()) {
return {};
} }
} }
if (!img_uncond.empty()) { if (!img_uncond.empty()) {
img_uncond_out = run_condition(img_uncond, if (!skip_img_uncond) {
img_uncond.c_concat.empty() ? nullptr : &img_uncond.c_concat, img_uncond_out = run_condition(img_uncond,
nullptr, img_uncond.c_concat.empty() ? nullptr : &img_uncond.c_concat,
uncond_without_ref_latents ? &empty_ref_latents : nullptr, nullptr,
true); uncond_without_ref_latents ? &empty_ref_latents : nullptr,
if (img_uncond_out.empty()) { true);
return {}; if (img_uncond_out.empty()) {
return {};
}
} else {
step_cache.invalidate_condition(&img_uncond);
} }
} }
sd::guidance::GuidanceInput guidance_input; sd::guidance::GuidanceInput guidance_input;
@ -2613,7 +2653,7 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
guidance_input.pred_uncond = uncond_out.empty() ? nullptr : &uncond_out; guidance_input.pred_uncond = uncond_out.empty() ? nullptr : &uncond_out;
guidance_input.pred_img_uncond = img_uncond_out.empty() ? nullptr : &img_uncond_out; guidance_input.pred_img_uncond = img_uncond_out.empty() ? nullptr : &img_uncond_out;
sd::guidance::GuiderOutput guided = guidance_schedule.empty() ? primary_guidance.forward(guidance_input, {}) : primary_guidance.forward(guidance_input, {}, guidance_schedule[guidance_schedule.size() - 1 - step]); sd::guidance::GuiderOutput guided = primary_guidance.forward(guidance_input, {}, effective_guidance_scale);
if (guided.pred.empty()) { if (guided.pred.empty()) {
return {}; return {};
} }

View File

@ -275,6 +275,26 @@ namespace sd_sample {
} }
} }
void SampleStepCacheDispatcher::invalidate_condition(const void* condition) {
if (condition == nullptr) {
return;
}
switch (runtime.mode) {
case SampleCacheMode::EASYCACHE:
runtime.easycache.cache_diffs.erase(condition);
break;
case SampleCacheMode::UCACHE:
runtime.ucache.cache_diffs.erase(condition);
break;
case SampleCacheMode::CACHEDIT:
runtime.cachedit.cache_diffs.erase(condition);
break;
case SampleCacheMode::NONE:
break;
}
}
bool SampleStepCacheDispatcher::is_step_skipped() const { bool SampleStepCacheDispatcher::is_step_skipped() const {
switch (runtime.mode) { switch (runtime.mode) {
case SampleCacheMode::EASYCACHE: case SampleCacheMode::EASYCACHE:

View File

@ -46,6 +46,7 @@ namespace sd_sample {
bool before_condition(const void* condition, const sd::Tensor<float>& input, sd::Tensor<float>* output); bool before_condition(const void* condition, const sd::Tensor<float>& input, sd::Tensor<float>* output);
void after_condition(const void* condition, const sd::Tensor<float>& input, const sd::Tensor<float>& output); void after_condition(const void* condition, const sd::Tensor<float>& input, const sd::Tensor<float>& output);
void invalidate_condition(const void* condition);
bool is_step_skipped() const; bool is_step_skipped() const;
}; };