mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-06-25 15:46:40 +00:00
Compare commits
No commits in common. "1d6cb0f8c33ddadf1bff8aff40ec2e5b1ccb4940" and "f16a110f8776398ef23a2a6b7b57522c2471637a" have entirely different histories.
1d6cb0f8c3
...
f16a110f87
@ -750,7 +750,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
gen_params.pm_id_embed_path.c_str(),
|
gen_params.pm_id_embed_path.c_str(),
|
||||||
gen_params.pm_style_strength,
|
gen_params.pm_style_strength,
|
||||||
}, // pm_params
|
}, // pm_params
|
||||||
gen_params.vae_tiling_params,
|
ctx_params.vae_tiling_params,
|
||||||
gen_params.cache_params,
|
gen_params.cache_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -776,7 +776,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
gen_params.seed,
|
gen_params.seed,
|
||||||
gen_params.video_frames,
|
gen_params.video_frames,
|
||||||
gen_params.vace_strength,
|
gen_params.vace_strength,
|
||||||
gen_params.vae_tiling_params,
|
ctx_params.vae_tiling_params,
|
||||||
gen_params.cache_params,
|
gen_params.cache_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -475,6 +475,7 @@ struct SDContextParams {
|
|||||||
prediction_t prediction = PREDICTION_COUNT;
|
prediction_t prediction = PREDICTION_COUNT;
|
||||||
lora_apply_mode_t lora_apply_mode = LORA_APPLY_AUTO;
|
lora_apply_mode_t lora_apply_mode = LORA_APPLY_AUTO;
|
||||||
|
|
||||||
|
sd_tiling_params_t vae_tiling_params = {false, 0, 0, 0.5f, 0.0f, 0.0f};
|
||||||
bool force_sdxl_vae_conv_scale = false;
|
bool force_sdxl_vae_conv_scale = false;
|
||||||
|
|
||||||
float flow_shift = INFINITY;
|
float flow_shift = INFINITY;
|
||||||
@ -575,9 +576,18 @@ struct SDContextParams {
|
|||||||
&chroma_t5_mask_pad},
|
&chroma_t5_mask_pad},
|
||||||
};
|
};
|
||||||
|
|
||||||
options.float_options = {};
|
options.float_options = {
|
||||||
|
{"",
|
||||||
|
"--vae-tile-overlap",
|
||||||
|
"tile overlap for vae tiling, in fraction of tile size (default: 0.5)",
|
||||||
|
&vae_tiling_params.target_overlap},
|
||||||
|
};
|
||||||
|
|
||||||
options.bool_options = {
|
options.bool_options = {
|
||||||
|
{"",
|
||||||
|
"--vae-tiling",
|
||||||
|
"process vae in tiles to reduce memory usage",
|
||||||
|
true, &vae_tiling_params.enabled},
|
||||||
{"",
|
{"",
|
||||||
"--force-sdxl-vae-conv-scale",
|
"--force-sdxl-vae-conv-scale",
|
||||||
"force use of conv scale on sdxl vae",
|
"force use of conv scale on sdxl vae",
|
||||||
@ -714,6 +724,52 @@ struct SDContextParams {
|
|||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto on_tile_size_arg = [&](int argc, const char** argv, int index) {
|
||||||
|
if (++index >= argc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::string tile_size_str = argv[index];
|
||||||
|
size_t x_pos = tile_size_str.find('x');
|
||||||
|
try {
|
||||||
|
if (x_pos != std::string::npos) {
|
||||||
|
std::string tile_x_str = tile_size_str.substr(0, x_pos);
|
||||||
|
std::string tile_y_str = tile_size_str.substr(x_pos + 1);
|
||||||
|
vae_tiling_params.tile_size_x = std::stoi(tile_x_str);
|
||||||
|
vae_tiling_params.tile_size_y = std::stoi(tile_y_str);
|
||||||
|
} else {
|
||||||
|
vae_tiling_params.tile_size_x = vae_tiling_params.tile_size_y = std::stoi(tile_size_str);
|
||||||
|
}
|
||||||
|
} catch (const std::invalid_argument&) {
|
||||||
|
return -1;
|
||||||
|
} catch (const std::out_of_range&) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto on_relative_tile_size_arg = [&](int argc, const char** argv, int index) {
|
||||||
|
if (++index >= argc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::string rel_size_str = argv[index];
|
||||||
|
size_t x_pos = rel_size_str.find('x');
|
||||||
|
try {
|
||||||
|
if (x_pos != std::string::npos) {
|
||||||
|
std::string rel_x_str = rel_size_str.substr(0, x_pos);
|
||||||
|
std::string rel_y_str = rel_size_str.substr(x_pos + 1);
|
||||||
|
vae_tiling_params.rel_size_x = std::stof(rel_x_str);
|
||||||
|
vae_tiling_params.rel_size_y = std::stof(rel_y_str);
|
||||||
|
} else {
|
||||||
|
vae_tiling_params.rel_size_x = vae_tiling_params.rel_size_y = std::stof(rel_size_str);
|
||||||
|
}
|
||||||
|
} catch (const std::invalid_argument&) {
|
||||||
|
return -1;
|
||||||
|
} catch (const std::out_of_range&) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
options.manual_options = {
|
options.manual_options = {
|
||||||
{"",
|
{"",
|
||||||
"--type",
|
"--type",
|
||||||
@ -740,6 +796,14 @@ struct SDContextParams {
|
|||||||
"but it usually offers faster inference speed and, in some cases, lower memory usage. "
|
"but it usually offers faster inference speed and, in some cases, lower memory usage. "
|
||||||
"The at_runtime mode, on the other hand, is exactly the opposite.",
|
"The at_runtime mode, on the other hand, is exactly the opposite.",
|
||||||
on_lora_apply_mode_arg},
|
on_lora_apply_mode_arg},
|
||||||
|
{"",
|
||||||
|
"--vae-tile-size",
|
||||||
|
"tile size for vae tiling, format [X]x[Y] (default: 32x32)",
|
||||||
|
on_tile_size_arg},
|
||||||
|
{"",
|
||||||
|
"--vae-relative-tile-size",
|
||||||
|
"relative tile size for vae tiling, format [X]x[Y], in fraction of image size if < 1, in number of tiles per dim if >=1 (overrides --vae-tile-size)",
|
||||||
|
on_relative_tile_size_arg},
|
||||||
};
|
};
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
@ -853,6 +917,13 @@ struct SDContextParams {
|
|||||||
<< " chroma_t5_mask_pad: " << chroma_t5_mask_pad << ",\n"
|
<< " chroma_t5_mask_pad: " << chroma_t5_mask_pad << ",\n"
|
||||||
<< " prediction: " << sd_prediction_name(prediction) << ",\n"
|
<< " prediction: " << sd_prediction_name(prediction) << ",\n"
|
||||||
<< " lora_apply_mode: " << sd_lora_apply_mode_name(lora_apply_mode) << ",\n"
|
<< " lora_apply_mode: " << sd_lora_apply_mode_name(lora_apply_mode) << ",\n"
|
||||||
|
<< " vae_tiling_params: { "
|
||||||
|
<< vae_tiling_params.enabled << ", "
|
||||||
|
<< vae_tiling_params.tile_size_x << ", "
|
||||||
|
<< vae_tiling_params.tile_size_y << ", "
|
||||||
|
<< vae_tiling_params.target_overlap << ", "
|
||||||
|
<< vae_tiling_params.rel_size_x << ", "
|
||||||
|
<< vae_tiling_params.rel_size_y << " },\n"
|
||||||
<< " force_sdxl_vae_conv_scale: " << (force_sdxl_vae_conv_scale ? "true" : "false") << "\n"
|
<< " force_sdxl_vae_conv_scale: " << (force_sdxl_vae_conv_scale ? "true" : "false") << "\n"
|
||||||
<< "}";
|
<< "}";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
@ -990,8 +1061,6 @@ struct SDGenerationParams {
|
|||||||
|
|
||||||
int64_t seed = 42;
|
int64_t seed = 42;
|
||||||
|
|
||||||
sd_tiling_params_t vae_tiling_params = {false, 0, 0, 0.5f, 0.0f, 0.0f};
|
|
||||||
|
|
||||||
// Photo Maker
|
// Photo Maker
|
||||||
std::string pm_id_images_dir;
|
std::string pm_id_images_dir;
|
||||||
std::string pm_id_embed_path;
|
std::string pm_id_embed_path;
|
||||||
@ -1182,10 +1251,6 @@ struct SDGenerationParams {
|
|||||||
"--vace-strength",
|
"--vace-strength",
|
||||||
"wan vace strength",
|
"wan vace strength",
|
||||||
&vace_strength},
|
&vace_strength},
|
||||||
{"",
|
|
||||||
"--vae-tile-overlap",
|
|
||||||
"tile overlap for vae tiling, in fraction of tile size (default: 0.5)",
|
|
||||||
&vae_tiling_params.target_overlap},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.bool_options = {
|
options.bool_options = {
|
||||||
@ -1199,10 +1264,6 @@ struct SDGenerationParams {
|
|||||||
"disable auto resize of ref images",
|
"disable auto resize of ref images",
|
||||||
false,
|
false,
|
||||||
&auto_resize_ref_image},
|
&auto_resize_ref_image},
|
||||||
{"",
|
|
||||||
"--vae-tiling",
|
|
||||||
"process vae in tiles to reduce memory usage",
|
|
||||||
true, &vae_tiling_params.enabled},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto on_seed_arg = [&](int argc, const char** argv, int index) {
|
auto on_seed_arg = [&](int argc, const char** argv, int index) {
|
||||||
@ -1399,52 +1460,6 @@ struct SDGenerationParams {
|
|||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto on_tile_size_arg = [&](int argc, const char** argv, int index) {
|
|
||||||
if (++index >= argc) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
std::string tile_size_str = argv[index];
|
|
||||||
size_t x_pos = tile_size_str.find('x');
|
|
||||||
try {
|
|
||||||
if (x_pos != std::string::npos) {
|
|
||||||
std::string tile_x_str = tile_size_str.substr(0, x_pos);
|
|
||||||
std::string tile_y_str = tile_size_str.substr(x_pos + 1);
|
|
||||||
vae_tiling_params.tile_size_x = std::stoi(tile_x_str);
|
|
||||||
vae_tiling_params.tile_size_y = std::stoi(tile_y_str);
|
|
||||||
} else {
|
|
||||||
vae_tiling_params.tile_size_x = vae_tiling_params.tile_size_y = std::stoi(tile_size_str);
|
|
||||||
}
|
|
||||||
} catch (const std::invalid_argument&) {
|
|
||||||
return -1;
|
|
||||||
} catch (const std::out_of_range&) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto on_relative_tile_size_arg = [&](int argc, const char** argv, int index) {
|
|
||||||
if (++index >= argc) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
std::string rel_size_str = argv[index];
|
|
||||||
size_t x_pos = rel_size_str.find('x');
|
|
||||||
try {
|
|
||||||
if (x_pos != std::string::npos) {
|
|
||||||
std::string rel_x_str = rel_size_str.substr(0, x_pos);
|
|
||||||
std::string rel_y_str = rel_size_str.substr(x_pos + 1);
|
|
||||||
vae_tiling_params.rel_size_x = std::stof(rel_x_str);
|
|
||||||
vae_tiling_params.rel_size_y = std::stof(rel_y_str);
|
|
||||||
} else {
|
|
||||||
vae_tiling_params.rel_size_x = vae_tiling_params.rel_size_y = std::stof(rel_size_str);
|
|
||||||
}
|
|
||||||
} catch (const std::invalid_argument&) {
|
|
||||||
return -1;
|
|
||||||
} catch (const std::out_of_range&) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
options.manual_options = {
|
options.manual_options = {
|
||||||
{"-s",
|
{"-s",
|
||||||
"--seed",
|
"--seed",
|
||||||
@ -1496,14 +1511,6 @@ struct SDGenerationParams {
|
|||||||
"--scm-policy",
|
"--scm-policy",
|
||||||
"SCM policy: 'dynamic' (default) or 'static'",
|
"SCM policy: 'dynamic' (default) or 'static'",
|
||||||
on_scm_policy_arg},
|
on_scm_policy_arg},
|
||||||
{"",
|
|
||||||
"--vae-tile-size",
|
|
||||||
"tile size for vae tiling, format [X]x[Y] (default: 32x32)",
|
|
||||||
on_tile_size_arg},
|
|
||||||
{"",
|
|
||||||
"--vae-relative-tile-size",
|
|
||||||
"relative tile size for vae tiling, format [X]x[Y], in fraction of image size if < 1, in number of tiles per dim if >=1 (overrides --vae-tile-size)",
|
|
||||||
on_relative_tile_size_arg},
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1939,13 +1946,6 @@ struct SDGenerationParams {
|
|||||||
<< " seed: " << seed << ",\n"
|
<< " seed: " << seed << ",\n"
|
||||||
<< " upscale_repeats: " << upscale_repeats << ",\n"
|
<< " upscale_repeats: " << upscale_repeats << ",\n"
|
||||||
<< " upscale_tile_size: " << upscale_tile_size << ",\n"
|
<< " upscale_tile_size: " << upscale_tile_size << ",\n"
|
||||||
<< " vae_tiling_params: { "
|
|
||||||
<< vae_tiling_params.enabled << ", "
|
|
||||||
<< vae_tiling_params.tile_size_x << ", "
|
|
||||||
<< vae_tiling_params.tile_size_y << ", "
|
|
||||||
<< vae_tiling_params.target_overlap << ", "
|
|
||||||
<< vae_tiling_params.rel_size_x << ", "
|
|
||||||
<< vae_tiling_params.rel_size_y << " },\n"
|
|
||||||
<< "}";
|
<< "}";
|
||||||
free(sample_params_str);
|
free(sample_params_str);
|
||||||
free(high_noise_sample_params_str);
|
free(high_noise_sample_params_str);
|
||||||
|
|||||||
@ -273,20 +273,55 @@ struct LoraEntry {
|
|||||||
std::string fullpath;
|
std::string fullpath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServerRuntime {
|
void free_results(sd_image_t* result_images, int num_results) {
|
||||||
sd_ctx_t* sd_ctx;
|
if (result_images) {
|
||||||
std::mutex* sd_ctx_mutex;
|
for (int i = 0; i < num_results; ++i) {
|
||||||
const SDSvrParams* svr_params;
|
if (result_images[i].data) {
|
||||||
const SDContextParams* ctx_params;
|
stbi_image_free(result_images[i].data);
|
||||||
const SDGenerationParams* default_gen_params;
|
result_images[i].data = nullptr;
|
||||||
std::vector<LoraEntry>* lora_cache;
|
}
|
||||||
std::mutex* lora_mutex;
|
}
|
||||||
};
|
}
|
||||||
|
free(result_images);
|
||||||
|
}
|
||||||
|
|
||||||
void refresh_lora_cache(ServerRuntime& rt) {
|
int main(int argc, const char** argv) {
|
||||||
|
if (argc > 1 && std::string(argv[1]) == "--version") {
|
||||||
|
std::cout << version_string() << "\n";
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
SDSvrParams svr_params;
|
||||||
|
SDContextParams ctx_params;
|
||||||
|
SDGenerationParams default_gen_params;
|
||||||
|
parse_args(argc, argv, svr_params, ctx_params, default_gen_params);
|
||||||
|
|
||||||
|
sd_set_log_callback(sd_log_cb, (void*)&svr_params);
|
||||||
|
log_verbose = svr_params.verbose;
|
||||||
|
log_color = svr_params.color;
|
||||||
|
|
||||||
|
LOG_DEBUG("version: %s", version_string().c_str());
|
||||||
|
LOG_DEBUG("%s", sd_get_system_info());
|
||||||
|
LOG_DEBUG("%s", svr_params.to_string().c_str());
|
||||||
|
LOG_DEBUG("%s", ctx_params.to_string().c_str());
|
||||||
|
LOG_DEBUG("%s", default_gen_params.to_string().c_str());
|
||||||
|
|
||||||
|
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(false, false, false);
|
||||||
|
sd_ctx_t* sd_ctx = new_sd_ctx(&sd_ctx_params);
|
||||||
|
|
||||||
|
if (sd_ctx == nullptr) {
|
||||||
|
LOG_ERROR("new_sd_ctx_t failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex sd_ctx_mutex;
|
||||||
|
|
||||||
|
std::vector<LoraEntry> lora_cache;
|
||||||
|
std::mutex lora_mutex;
|
||||||
|
|
||||||
|
auto refresh_lora_cache = [&]() {
|
||||||
std::vector<LoraEntry> new_cache;
|
std::vector<LoraEntry> new_cache;
|
||||||
|
|
||||||
fs::path lora_dir = rt.ctx_params->lora_model_dir;
|
fs::path lora_dir = ctx_params.lora_model_dir;
|
||||||
if (fs::exists(lora_dir) && fs::is_directory(lora_dir)) {
|
if (fs::exists(lora_dir) && fs::is_directory(lora_dir)) {
|
||||||
auto is_lora_ext = [](const fs::path& p) {
|
auto is_lora_ext = [](const fs::path& p) {
|
||||||
auto ext = p.extension().string();
|
auto ext = p.extension().string();
|
||||||
@ -318,35 +353,47 @@ void refresh_lora_cache(ServerRuntime& rt) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*rt.lora_mutex);
|
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||||
*rt.lora_cache = std::move(new_cache);
|
lora_cache = std::move(new_cache);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::string get_lora_full_path(ServerRuntime& rt, const std::string& path) {
|
auto get_lora_full_path = [&](const std::string& path) -> std::string {
|
||||||
std::lock_guard<std::mutex> lock(*rt.lora_mutex);
|
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||||
auto it = std::find_if(rt.lora_cache->begin(), rt.lora_cache->end(),
|
auto it = std::find_if(lora_cache.begin(), lora_cache.end(),
|
||||||
[&](const LoraEntry& e) { return e.path == path; });
|
[&](const LoraEntry& e) { return e.path == path; });
|
||||||
return (it != rt.lora_cache->end()) ? it->fullpath : "";
|
return (it != lora_cache.end()) ? it->fullpath : "";
|
||||||
}
|
};
|
||||||
|
|
||||||
void free_results(sd_image_t* result_images, int num_results) {
|
httplib::Server svr;
|
||||||
if (result_images) {
|
|
||||||
for (int i = 0; i < num_results; ++i) {
|
|
||||||
if (result_images[i].data) {
|
|
||||||
stbi_image_free(result_images[i].data);
|
|
||||||
result_images[i].data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(result_images);
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_index_endpoints(httplib::Server& svr, const SDSvrParams& svr_params, const std::string& index_html) {
|
svr.set_pre_routing_handler([](const httplib::Request& req, httplib::Response& res) {
|
||||||
const std::string serve_html_path = svr_params.serve_html_path;
|
std::string origin = req.get_header_value("Origin");
|
||||||
svr.Get("/", [serve_html_path, index_html](const httplib::Request&, httplib::Response& res) {
|
if (origin.empty()) {
|
||||||
if (!serve_html_path.empty()) {
|
origin = "*";
|
||||||
std::ifstream file(serve_html_path);
|
}
|
||||||
|
res.set_header("Access-Control-Allow-Origin", origin);
|
||||||
|
res.set_header("Access-Control-Allow-Credentials", "true");
|
||||||
|
res.set_header("Access-Control-Allow-Methods", "*");
|
||||||
|
res.set_header("Access-Control-Allow-Headers", "*");
|
||||||
|
|
||||||
|
if (req.method == "OPTIONS") {
|
||||||
|
res.status = 204;
|
||||||
|
return httplib::Server::HandlerResponse::Handled;
|
||||||
|
}
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
});
|
||||||
|
|
||||||
|
// index html
|
||||||
|
std::string index_html;
|
||||||
|
#ifdef HAVE_INDEX_HTML
|
||||||
|
index_html.assign(reinterpret_cast<const char*>(index_html_bytes), index_html_size);
|
||||||
|
#else
|
||||||
|
index_html = "Stable Diffusion Server is running";
|
||||||
|
#endif
|
||||||
|
svr.Get("/", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
|
if (!svr_params.serve_html_path.empty()) {
|
||||||
|
std::ifstream file(svr_params.serve_html_path);
|
||||||
if (file) {
|
if (file) {
|
||||||
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
res.set_content(content, "text/html");
|
res.set_content(content, "text/html");
|
||||||
@ -358,19 +405,17 @@ void register_index_endpoints(httplib::Server& svr, const SDSvrParams& svr_param
|
|||||||
res.set_content(index_html, "text/html");
|
res.set_content(index_html, "text/html");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
// models endpoint (minimal)
|
||||||
ServerRuntime* runtime = &rt;
|
svr.Get("/v1/models", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
|
|
||||||
svr.Get("/v1/models", [runtime](const httplib::Request&, httplib::Response& res) {
|
|
||||||
json r;
|
json r;
|
||||||
r["data"] = json::array();
|
r["data"] = json::array();
|
||||||
r["data"].push_back({{"id", "sd-cpp-local"}, {"object", "model"}, {"owned_by", "local"}});
|
r["data"].push_back({{"id", "sd-cpp-local"}, {"object", "model"}, {"owned_by", "local"}});
|
||||||
res.set_content(r.dump(), "application/json");
|
res.set_content(r.dump(), "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Post("/v1/images/generations", [runtime](const httplib::Request& req, httplib::Response& res) {
|
// core endpoint: /v1/images/generations
|
||||||
|
svr.Post("/v1/images/generations", [&](const httplib::Request& req, httplib::Response& res) {
|
||||||
try {
|
try {
|
||||||
if (req.body.empty()) {
|
if (req.body.empty()) {
|
||||||
res.status = 400;
|
res.status = 400;
|
||||||
@ -384,8 +429,8 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
std::string size = j.value("size", "");
|
std::string size = j.value("size", "");
|
||||||
std::string output_format = j.value("output_format", "png");
|
std::string output_format = j.value("output_format", "png");
|
||||||
int output_compression = j.value("output_compression", 100);
|
int output_compression = j.value("output_compression", 100);
|
||||||
int width = runtime->default_gen_params->width > 0 ? runtime->default_gen_params->width : 512;
|
int width = default_gen_params.width > 0 ? default_gen_params.width : 512;
|
||||||
int height = runtime->default_gen_params->width > 0 ? runtime->default_gen_params->height : 512;
|
int height = default_gen_params.width > 0 ? default_gen_params.height : 512;
|
||||||
if (!size.empty()) {
|
if (!size.empty()) {
|
||||||
auto pos = size.find('x');
|
auto pos = size.find('x');
|
||||||
if (pos != std::string::npos) {
|
if (pos != std::string::npos) {
|
||||||
@ -413,7 +458,7 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
n = 1;
|
n = 1;
|
||||||
if (n > 8)
|
if (n > 8)
|
||||||
n = 8;
|
n = 8; // safety
|
||||||
if (output_compression > 100) {
|
if (output_compression > 100) {
|
||||||
output_compression = 100;
|
output_compression = 100;
|
||||||
}
|
}
|
||||||
@ -426,7 +471,7 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
out["data"] = json::array();
|
out["data"] = json::array();
|
||||||
out["output_format"] = output_format;
|
out["output_format"] = output_format;
|
||||||
|
|
||||||
SDGenerationParams gen_params = *runtime->default_gen_params;
|
SDGenerationParams gen_params = default_gen_params;
|
||||||
gen_params.prompt = prompt;
|
gen_params.prompt = prompt;
|
||||||
gen_params.width = width;
|
gen_params.width = width;
|
||||||
gen_params.height = height;
|
gen_params.height = height;
|
||||||
@ -479,8 +524,8 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
(int)pmid_images.size(),
|
(int)pmid_images.size(),
|
||||||
gen_params.pm_id_embed_path.c_str(),
|
gen_params.pm_id_embed_path.c_str(),
|
||||||
gen_params.pm_style_strength,
|
gen_params.pm_style_strength,
|
||||||
},
|
}, // pm_params
|
||||||
gen_params.vae_tiling_params,
|
ctx_params.vae_tiling_params,
|
||||||
gen_params.cache_params,
|
gen_params.cache_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -488,8 +533,8 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
int num_results = 0;
|
int num_results = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*runtime->sd_ctx_mutex);
|
std::lock_guard<std::mutex> lock(sd_ctx_mutex);
|
||||||
results = generate_image(runtime->sd_ctx, &img_gen_params);
|
results = generate_image(sd_ctx, &img_gen_params);
|
||||||
num_results = gen_params.batch_count;
|
num_results = gen_params.batch_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,6 +553,7 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// base64 encode
|
||||||
std::string b64 = base64_encode(image_bytes);
|
std::string b64 = base64_encode(image_bytes);
|
||||||
json item;
|
json item;
|
||||||
item["b64_json"] = b64;
|
item["b64_json"] = b64;
|
||||||
@ -527,7 +573,7 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Post("/v1/images/edits", [runtime](const httplib::Request& req, httplib::Response& res) {
|
svr.Post("/v1/images/edits", [&](const httplib::Request& req, httplib::Response& res) {
|
||||||
try {
|
try {
|
||||||
if (!req.is_multipart_form_data()) {
|
if (!req.is_multipart_form_data()) {
|
||||||
res.status = 400;
|
res.status = 400;
|
||||||
@ -612,7 +658,7 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
output_compression = 0;
|
output_compression = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDGenerationParams gen_params = *runtime->default_gen_params;
|
SDGenerationParams gen_params = default_gen_params;
|
||||||
gen_params.prompt = prompt;
|
gen_params.prompt = prompt;
|
||||||
gen_params.width = width;
|
gen_params.width = width;
|
||||||
gen_params.height = height;
|
gen_params.height = height;
|
||||||
@ -639,18 +685,18 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
sd_image_t control_image = {0, 0, 3, nullptr};
|
sd_image_t control_image = {0, 0, 3, nullptr};
|
||||||
std::vector<sd_image_t> pmid_images;
|
std::vector<sd_image_t> pmid_images;
|
||||||
|
|
||||||
auto get_resolved_width = [&gen_params, runtime]() -> int {
|
auto get_resolved_width = [&gen_params, &default_gen_params]() -> int {
|
||||||
if (gen_params.width > 0)
|
if (gen_params.width > 0)
|
||||||
return gen_params.width;
|
return gen_params.width;
|
||||||
if (runtime->default_gen_params->width > 0)
|
if (default_gen_params.width > 0)
|
||||||
return runtime->default_gen_params->width;
|
return default_gen_params.width;
|
||||||
return 512;
|
return 512;
|
||||||
};
|
};
|
||||||
auto get_resolved_height = [&gen_params, runtime]() -> int {
|
auto get_resolved_height = [&gen_params, &default_gen_params]() -> int {
|
||||||
if (gen_params.height > 0)
|
if (gen_params.height > 0)
|
||||||
return gen_params.height;
|
return gen_params.height;
|
||||||
if (runtime->default_gen_params->height > 0)
|
if (default_gen_params.height > 0)
|
||||||
return runtime->default_gen_params->height;
|
return default_gen_params.height;
|
||||||
return 512;
|
return 512;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -725,8 +771,8 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
(int)pmid_images.size(),
|
(int)pmid_images.size(),
|
||||||
gen_params.pm_id_embed_path.c_str(),
|
gen_params.pm_id_embed_path.c_str(),
|
||||||
gen_params.pm_style_strength,
|
gen_params.pm_style_strength,
|
||||||
},
|
}, // pm_params
|
||||||
gen_params.vae_tiling_params,
|
ctx_params.vae_tiling_params,
|
||||||
gen_params.cache_params,
|
gen_params.cache_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -734,8 +780,8 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
int num_results = 0;
|
int num_results = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*runtime->sd_ctx_mutex);
|
std::lock_guard<std::mutex> lock(sd_ctx_mutex);
|
||||||
results = generate_image(runtime->sd_ctx, &img_gen_params);
|
results = generate_image(sd_ctx, &img_gen_params);
|
||||||
num_results = gen_params.batch_count;
|
num_results = gen_params.batch_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,12 +826,10 @@ void register_openai_api_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
res.set_content(err.dump(), "application/json");
|
res.set_content(err.dump(), "application/json");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
// sdapi endpoints (AUTOMATIC1111 / Forge)
|
||||||
ServerRuntime* runtime = &rt;
|
|
||||||
|
|
||||||
auto sdapi_any2img = [runtime](const httplib::Request& req, httplib::Response& res, bool img2img) {
|
auto sdapi_any2img = [&](const httplib::Request& req, httplib::Response& res, bool img2img) {
|
||||||
try {
|
try {
|
||||||
if (req.body.empty()) {
|
if (req.body.empty()) {
|
||||||
res.status = 400;
|
res.status = 400;
|
||||||
@ -799,8 +843,8 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
std::string negative_prompt = j.value("negative_prompt", "");
|
std::string negative_prompt = j.value("negative_prompt", "");
|
||||||
int width = j.value("width", 512);
|
int width = j.value("width", 512);
|
||||||
int height = j.value("height", 512);
|
int height = j.value("height", 512);
|
||||||
int steps = j.value("steps", runtime->default_gen_params->sample_params.sample_steps);
|
int steps = j.value("steps", default_gen_params.sample_params.sample_steps);
|
||||||
float cfg_scale = j.value("cfg_scale", runtime->default_gen_params->sample_params.guidance.txt_cfg);
|
float cfg_scale = j.value("cfg_scale", default_gen_params.sample_params.guidance.txt_cfg);
|
||||||
int64_t seed = j.value("seed", -1);
|
int64_t seed = j.value("seed", -1);
|
||||||
int batch_size = j.value("batch_size", 1);
|
int batch_size = j.value("batch_size", 1);
|
||||||
int clip_skip = j.value("clip_skip", -1);
|
int clip_skip = j.value("clip_skip", -1);
|
||||||
@ -850,7 +894,7 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
return bad("lora.path required");
|
return bad("lora.path required");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fullpath = get_lora_full_path(*runtime, path);
|
std::string fullpath = get_lora_full_path(path);
|
||||||
if (fullpath.empty()) {
|
if (fullpath.empty()) {
|
||||||
return bad("invalid lora path: " + path);
|
return bad("invalid lora path: " + path);
|
||||||
}
|
}
|
||||||
@ -868,6 +912,7 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
auto get_sample_method = [](std::string name) -> enum sample_method_t {
|
auto get_sample_method = [](std::string name) -> enum sample_method_t {
|
||||||
enum sample_method_t result = str_to_sample_method(name.c_str());
|
enum sample_method_t result = str_to_sample_method(name.c_str());
|
||||||
if (result != SAMPLE_METHOD_COUNT) return result;
|
if (result != SAMPLE_METHOD_COUNT) return result;
|
||||||
|
// some applications use a hardcoded sampler list
|
||||||
std::transform(name.begin(), name.end(), name.begin(),
|
std::transform(name.begin(), name.end(), name.begin(),
|
||||||
[](unsigned char c) { return std::tolower(c); });
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
static const std::unordered_map<std::string_view, sample_method_t> hardcoded{
|
static const std::unordered_map<std::string_view, sample_method_t> hardcoded{
|
||||||
@ -893,9 +938,10 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum sample_method_t sample_method = get_sample_method(sampler_name);
|
enum sample_method_t sample_method = get_sample_method(sampler_name);
|
||||||
|
|
||||||
enum scheduler_t scheduler = str_to_scheduler(scheduler_name.c_str());
|
enum scheduler_t scheduler = str_to_scheduler(scheduler_name.c_str());
|
||||||
|
|
||||||
SDGenerationParams gen_params = *runtime->default_gen_params;
|
SDGenerationParams gen_params = default_gen_params;
|
||||||
gen_params.prompt = prompt;
|
gen_params.prompt = prompt;
|
||||||
gen_params.negative_prompt = negative_prompt;
|
gen_params.negative_prompt = negative_prompt;
|
||||||
gen_params.seed = seed;
|
gen_params.seed = seed;
|
||||||
@ -915,6 +961,8 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
gen_params.sample_params.scheduler = scheduler;
|
gen_params.sample_params.scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// re-read to avoid applying 512 as default before the provided
|
||||||
|
// images and/or server command-line
|
||||||
gen_params.width = j.value("width", -1);
|
gen_params.width = j.value("width", -1);
|
||||||
gen_params.height = j.value("height", -1);
|
gen_params.height = j.value("height", -1);
|
||||||
|
|
||||||
@ -927,22 +975,23 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
std::vector<sd_image_t> pmid_images;
|
std::vector<sd_image_t> pmid_images;
|
||||||
std::vector<sd_image_t> ref_images;
|
std::vector<sd_image_t> ref_images;
|
||||||
|
|
||||||
auto get_resolved_width = [&gen_params, runtime]() -> int {
|
auto get_resolved_width = [&gen_params, &default_gen_params]() -> int {
|
||||||
if (gen_params.width > 0)
|
if (gen_params.width > 0)
|
||||||
return gen_params.width;
|
return gen_params.width;
|
||||||
if (runtime->default_gen_params->width > 0)
|
if (default_gen_params.width > 0)
|
||||||
return runtime->default_gen_params->width;
|
return default_gen_params.width;
|
||||||
return 512;
|
return 512;
|
||||||
};
|
};
|
||||||
auto get_resolved_height = [&gen_params, runtime]() -> int {
|
auto get_resolved_height = [&gen_params, &default_gen_params]() -> int {
|
||||||
if (gen_params.height > 0)
|
if (gen_params.height > 0)
|
||||||
return gen_params.height;
|
return gen_params.height;
|
||||||
if (runtime->default_gen_params->height > 0)
|
if (default_gen_params.height > 0)
|
||||||
return runtime->default_gen_params->height;
|
return default_gen_params.height;
|
||||||
return 512;
|
return 512;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode_image = [&gen_params](sd_image_t& image, std::string encoded) -> bool {
|
auto decode_image = [&gen_params](sd_image_t& image, std::string encoded) -> bool {
|
||||||
|
// remove data URI prefix if present ("data:image/png;base64,")
|
||||||
auto comma_pos = encoded.find(',');
|
auto comma_pos = encoded.find(',');
|
||||||
if (comma_pos != std::string::npos) {
|
if (comma_pos != std::string::npos) {
|
||||||
encoded = encoded.substr(comma_pos + 1);
|
encoded = encoded.substr(comma_pos + 1);
|
||||||
@ -1038,8 +1087,8 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
(int)pmid_images.size(),
|
(int)pmid_images.size(),
|
||||||
gen_params.pm_id_embed_path.c_str(),
|
gen_params.pm_id_embed_path.c_str(),
|
||||||
gen_params.pm_style_strength,
|
gen_params.pm_style_strength,
|
||||||
},
|
}, // pm_params
|
||||||
gen_params.vae_tiling_params,
|
ctx_params.vae_tiling_params,
|
||||||
gen_params.cache_params,
|
gen_params.cache_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1047,14 +1096,14 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
int num_results = 0;
|
int num_results = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*runtime->sd_ctx_mutex);
|
std::lock_guard<std::mutex> lock(sd_ctx_mutex);
|
||||||
results = generate_image(runtime->sd_ctx, &img_gen_params);
|
results = generate_image(sd_ctx, &img_gen_params);
|
||||||
num_results = gen_params.batch_count;
|
num_results = gen_params.batch_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
json out;
|
json out;
|
||||||
out["images"] = json::array();
|
out["images"] = json::array();
|
||||||
out["parameters"] = j;
|
out["parameters"] = j; // TODO should return changed defaults
|
||||||
out["info"] = "";
|
out["info"] = "";
|
||||||
|
|
||||||
for (int i = 0; i < num_results; i++) {
|
for (int i = 0; i < num_results; i++) {
|
||||||
@ -1100,21 +1149,21 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
svr.Post("/sdapi/v1/txt2img", [sdapi_any2img](const httplib::Request& req, httplib::Response& res) {
|
svr.Post("/sdapi/v1/txt2img", [&](const httplib::Request& req, httplib::Response& res) {
|
||||||
sdapi_any2img(req, res, false);
|
sdapi_any2img(req, res, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Post("/sdapi/v1/img2img", [sdapi_any2img](const httplib::Request& req, httplib::Response& res) {
|
svr.Post("/sdapi/v1/img2img", [&](const httplib::Request& req, httplib::Response& res) {
|
||||||
sdapi_any2img(req, res, true);
|
sdapi_any2img(req, res, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/sdapi/v1/loras", [runtime](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/sdapi/v1/loras", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
refresh_lora_cache(*runtime);
|
refresh_lora_cache();
|
||||||
|
|
||||||
json result = json::array();
|
json result = json::array();
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(*runtime->lora_mutex);
|
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||||
for (const auto& e : *runtime->lora_cache) {
|
for (const auto& e : lora_cache) {
|
||||||
json item;
|
json item;
|
||||||
item["name"] = e.name;
|
item["name"] = e.name;
|
||||||
item["path"] = e.path;
|
item["path"] = e.path;
|
||||||
@ -1125,7 +1174,7 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
res.set_content(result.dump(), "application/json");
|
res.set_content(result.dump(), "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/sdapi/v1/samplers", [runtime](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/sdapi/v1/samplers", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
std::vector<std::string> sampler_names;
|
std::vector<std::string> sampler_names;
|
||||||
sampler_names.push_back("default");
|
sampler_names.push_back("default");
|
||||||
for (int i = 0; i < SAMPLE_METHOD_COUNT; i++) {
|
for (int i = 0; i < SAMPLE_METHOD_COUNT; i++) {
|
||||||
@ -1142,7 +1191,7 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
res.set_content(r.dump(), "application/json");
|
res.set_content(r.dump(), "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/sdapi/v1/schedulers", [runtime](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/sdapi/v1/schedulers", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
std::vector<std::string> scheduler_names;
|
std::vector<std::string> scheduler_names;
|
||||||
scheduler_names.push_back("default");
|
scheduler_names.push_back("default");
|
||||||
for (int i = 0; i < SCHEDULER_COUNT; i++) {
|
for (int i = 0; i < SCHEDULER_COUNT; i++) {
|
||||||
@ -1158,8 +1207,8 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
res.set_content(r.dump(), "application/json");
|
res.set_content(r.dump(), "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/sdapi/v1/sd-models", [runtime](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/sdapi/v1/sd-models", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
fs::path model_path = runtime->ctx_params->model_path;
|
fs::path model_path = ctx_params.model_path;
|
||||||
json entry;
|
json entry;
|
||||||
entry["title"] = model_path.stem();
|
entry["title"] = model_path.stem();
|
||||||
entry["model_name"] = model_path.stem();
|
entry["model_name"] = model_path.stem();
|
||||||
@ -1172,89 +1221,18 @@ void register_sdapi_endpoints(httplib::Server& svr, ServerRuntime& rt) {
|
|||||||
res.set_content(r.dump(), "application/json");
|
res.set_content(r.dump(), "application/json");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/sdapi/v1/options", [runtime](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/sdapi/v1/options", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
fs::path model_path = runtime->ctx_params->model_path;
|
fs::path model_path = ctx_params.model_path;
|
||||||
json r;
|
json r;
|
||||||
r["samples_format"] = "png";
|
r["samples_format"] = "png";
|
||||||
r["sd_model_checkpoint"] = model_path.stem();
|
r["sd_model_checkpoint"] = model_path.stem();
|
||||||
res.set_content(r.dump(), "application/json");
|
res.set_content(r.dump(), "application/json");
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char** argv) {
|
|
||||||
if (argc > 1 && std::string(argv[1]) == "--version") {
|
|
||||||
std::cout << version_string() << "\n";
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
SDSvrParams svr_params;
|
|
||||||
SDContextParams ctx_params;
|
|
||||||
SDGenerationParams default_gen_params;
|
|
||||||
parse_args(argc, argv, svr_params, ctx_params, default_gen_params);
|
|
||||||
|
|
||||||
sd_set_log_callback(sd_log_cb, (void*)&svr_params);
|
|
||||||
log_verbose = svr_params.verbose;
|
|
||||||
log_color = svr_params.color;
|
|
||||||
|
|
||||||
LOG_DEBUG("version: %s", version_string().c_str());
|
|
||||||
LOG_DEBUG("%s", sd_get_system_info());
|
|
||||||
LOG_DEBUG("%s", svr_params.to_string().c_str());
|
|
||||||
LOG_DEBUG("%s", ctx_params.to_string().c_str());
|
|
||||||
LOG_DEBUG("%s", default_gen_params.to_string().c_str());
|
|
||||||
|
|
||||||
sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(false, false, false);
|
|
||||||
sd_ctx_t* sd_ctx = new_sd_ctx(&sd_ctx_params);
|
|
||||||
|
|
||||||
if (sd_ctx == nullptr) {
|
|
||||||
LOG_ERROR("new_sd_ctx_t failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mutex sd_ctx_mutex;
|
|
||||||
|
|
||||||
std::vector<LoraEntry> lora_cache;
|
|
||||||
std::mutex lora_mutex;
|
|
||||||
ServerRuntime runtime = {
|
|
||||||
sd_ctx,
|
|
||||||
&sd_ctx_mutex,
|
|
||||||
&svr_params,
|
|
||||||
&ctx_params,
|
|
||||||
&default_gen_params,
|
|
||||||
&lora_cache,
|
|
||||||
&lora_mutex,
|
|
||||||
};
|
|
||||||
|
|
||||||
httplib::Server svr;
|
|
||||||
|
|
||||||
svr.set_pre_routing_handler([](const httplib::Request& req, httplib::Response& res) {
|
|
||||||
std::string origin = req.get_header_value("Origin");
|
|
||||||
if (origin.empty()) {
|
|
||||||
origin = "*";
|
|
||||||
}
|
|
||||||
res.set_header("Access-Control-Allow-Origin", origin);
|
|
||||||
res.set_header("Access-Control-Allow-Credentials", "true");
|
|
||||||
res.set_header("Access-Control-Allow-Methods", "*");
|
|
||||||
res.set_header("Access-Control-Allow-Headers", "*");
|
|
||||||
|
|
||||||
if (req.method == "OPTIONS") {
|
|
||||||
res.status = 204;
|
|
||||||
return httplib::Server::HandlerResponse::Handled;
|
|
||||||
}
|
|
||||||
return httplib::Server::HandlerResponse::Unhandled;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::string index_html;
|
|
||||||
#ifdef HAVE_INDEX_HTML
|
|
||||||
index_html.assign(reinterpret_cast<const char*>(index_html_bytes), index_html_size);
|
|
||||||
#else
|
|
||||||
index_html = "Stable Diffusion Server is running";
|
|
||||||
#endif
|
|
||||||
register_index_endpoints(svr, svr_params, index_html);
|
|
||||||
register_openai_api_endpoints(svr, runtime);
|
|
||||||
register_sdapi_endpoints(svr, runtime);
|
|
||||||
|
|
||||||
LOG_INFO("listening on: %s:%d\n", svr_params.listen_ip.c_str(), svr_params.listen_port);
|
LOG_INFO("listening on: %s:%d\n", svr_params.listen_ip.c_str(), svr_params.listen_port);
|
||||||
svr.listen(svr_params.listen_ip, svr_params.listen_port);
|
svr.listen(svr_params.listen_ip, svr_params.listen_port);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
free_sd_ctx(sd_ctx);
|
free_sd_ctx(sd_ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
2
ggml
2
ggml
@ -1 +1 @@
|
|||||||
Subproject commit 404fcb9d7c96989569e68c9e7881ee3465a05c50
|
Subproject commit a8db410a252c8c8f2d120c6f2e7133ebe032f35d
|
||||||
@ -120,8 +120,7 @@ enum sd_type_t {
|
|||||||
// SD_TYPE_IQ4_NL_4_8 = 37,
|
// SD_TYPE_IQ4_NL_4_8 = 37,
|
||||||
// SD_TYPE_IQ4_NL_8_8 = 38,
|
// SD_TYPE_IQ4_NL_8_8 = 38,
|
||||||
SD_TYPE_MXFP4 = 39, // MXFP4 (1 block)
|
SD_TYPE_MXFP4 = 39, // MXFP4 (1 block)
|
||||||
SD_TYPE_NVFP4 = 40, // NVFP4 (4 blocks, E4M3 scale)
|
SD_TYPE_COUNT = 40,
|
||||||
SD_TYPE_COUNT = 41,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sd_log_level_t {
|
enum sd_log_level_t {
|
||||||
|
|||||||
@ -1313,14 +1313,14 @@ struct T5CLIPEmbedder : public Conditioner {
|
|||||||
std::shared_ptr<T5Runner> t5;
|
std::shared_ptr<T5Runner> t5;
|
||||||
size_t chunk_len = 512;
|
size_t chunk_len = 512;
|
||||||
bool use_mask = false;
|
bool use_mask = false;
|
||||||
int mask_pad = 0;
|
int mask_pad = 1;
|
||||||
bool is_umt5 = false;
|
bool is_umt5 = false;
|
||||||
|
|
||||||
T5CLIPEmbedder(ggml_backend_t backend,
|
T5CLIPEmbedder(ggml_backend_t backend,
|
||||||
bool offload_params_to_cpu,
|
bool offload_params_to_cpu,
|
||||||
const String2TensorStorage& tensor_storage_map = {},
|
const String2TensorStorage& tensor_storage_map = {},
|
||||||
bool use_mask = false,
|
bool use_mask = false,
|
||||||
int mask_pad = 0,
|
int mask_pad = 1,
|
||||||
bool is_umt5 = false)
|
bool is_umt5 = false)
|
||||||
: use_mask(use_mask), mask_pad(mask_pad), t5_tokenizer(is_umt5) {
|
: use_mask(use_mask), mask_pad(mask_pad), t5_tokenizer(is_umt5) {
|
||||||
bool use_t5 = false;
|
bool use_t5 = false;
|
||||||
|
|||||||
247
src/denoiser.hpp
247
src/denoiser.hpp
@ -2,7 +2,6 @@
|
|||||||
#define __DENOISER_HPP__
|
#define __DENOISER_HPP__
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "ggml_extend.hpp"
|
#include "ggml_extend.hpp"
|
||||||
#include "gits_noise.inl"
|
#include "gits_noise.inl"
|
||||||
@ -764,33 +763,16 @@ struct Flux2FlowDenoiser : public FluxFlowDenoiser {
|
|||||||
|
|
||||||
typedef std::function<sd::Tensor<float>(const sd::Tensor<float>&, float, int)> denoise_cb_t;
|
typedef std::function<sd::Tensor<float>(const sd::Tensor<float>&, float, int)> denoise_cb_t;
|
||||||
|
|
||||||
static std::pair<float, float> get_ancestral_step(float sigma_from,
|
// k diffusion reverse ODE: dx = (x - D(x;\sigma)) / \sigma dt; \sigma(t) = t
|
||||||
float sigma_to,
|
static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
||||||
float eta = 1.0f) {
|
denoise_cb_t model,
|
||||||
float sigma_up = 0.0f;
|
|
||||||
float sigma_down = sigma_to;
|
|
||||||
|
|
||||||
if (eta <= 0.0f) {
|
|
||||||
return {sigma_down, sigma_up};
|
|
||||||
}
|
|
||||||
|
|
||||||
float sigma_from_sq = sigma_from * sigma_from;
|
|
||||||
float sigma_to_sq = sigma_to * sigma_to;
|
|
||||||
if (sigma_from_sq > 0.0f) {
|
|
||||||
float term = sigma_to_sq * (sigma_from_sq - sigma_to_sq) / sigma_from_sq;
|
|
||||||
sigma_up = std::min(sigma_to, eta * std::sqrt(std::max(term, 0.0f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
float sigma_down_sq = sigma_to_sq - sigma_up * sigma_up;
|
|
||||||
sigma_down = sigma_down_sq > 0.0f ? std::sqrt(sigma_down_sq) : 0.0f;
|
|
||||||
return {sigma_down, sigma_up};
|
|
||||||
}
|
|
||||||
|
|
||||||
static sd::Tensor<float> sample_euler_ancestral(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
sd::Tensor<float> x,
|
||||||
const std::vector<float>& sigmas,
|
std::vector<float> sigmas,
|
||||||
std::shared_ptr<RNG> rng) {
|
std::shared_ptr<RNG> rng,
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
float eta) {
|
||||||
|
size_t steps = sigmas.size() - 1;
|
||||||
|
switch (method) {
|
||||||
|
case EULER_A_SAMPLE_METHOD: {
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
auto denoised_opt = model(x, sigma, i + 1);
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
@ -799,19 +781,18 @@ static sd::Tensor<float> sample_euler_ancestral(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
sd::Tensor<float> d = (x - denoised) / sigma;
|
sd::Tensor<float> d = (x - denoised) / sigma;
|
||||||
auto [sigma_down, sigma_up] = get_ancestral_step(sigmas[i], sigmas[i + 1]);
|
float sigma_up = std::min(sigmas[i + 1],
|
||||||
x += d * (sigma_down - sigmas[i]);
|
std::sqrt(sigmas[i + 1] * sigmas[i + 1] * (sigmas[i] * sigmas[i] - sigmas[i + 1] * sigmas[i + 1]) / (sigmas[i] * sigmas[i])));
|
||||||
|
float sigma_down = std::sqrt(sigmas[i + 1] * sigmas[i + 1] - sigma_up * sigma_up);
|
||||||
|
float dt = sigma_down - sigmas[i];
|
||||||
|
x += d * dt;
|
||||||
if (sigmas[i + 1] > 0) {
|
if (sigmas[i + 1] > 0) {
|
||||||
x += sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
x += sd::Tensor<float>::randn_like(x, rng) * sigma_up;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case EULER_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_euler(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
auto denoised_opt = model(x, sigma, i + 1);
|
auto denoised_opt = model(x, sigma, i + 1);
|
||||||
@ -820,15 +801,12 @@ static sd::Tensor<float> sample_euler(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
sd::Tensor<float> d = (x - denoised) / sigma;
|
sd::Tensor<float> d = (x - denoised) / sigma;
|
||||||
x += d * (sigmas[i + 1] - sigma);
|
float dt = sigmas[i + 1] - sigma;
|
||||||
|
x += d * dt;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case HEUN_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_heun(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
@ -852,11 +830,7 @@ static sd::Tensor<float> sample_heun(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case DPM2_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_dpm2(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
@ -865,7 +839,8 @@ static sd::Tensor<float> sample_dpm2(denoise_cb_t model,
|
|||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
sd::Tensor<float> d = (x - denoised) / sigmas[i];
|
sd::Tensor<float> d = (x - denoised) / sigmas[i];
|
||||||
if (sigmas[i + 1] == 0) {
|
if (sigmas[i + 1] == 0) {
|
||||||
x += d * (sigmas[i + 1] - sigmas[i]);
|
float dt = sigmas[i + 1] - sigmas[i];
|
||||||
|
x += d * dt;
|
||||||
} else {
|
} else {
|
||||||
float sigma_mid = exp(0.5f * (log(sigmas[i]) + log(sigmas[i + 1])));
|
float sigma_mid = exp(0.5f * (log(sigmas[i]) + log(sigmas[i + 1])));
|
||||||
float dt_1 = sigma_mid - sigmas[i];
|
float dt_1 = sigma_mid - sigmas[i];
|
||||||
@ -881,22 +856,18 @@ static sd::Tensor<float> sample_dpm2(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case DPMPP2S_A_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_dpmpp_2s_ancestral(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng) {
|
|
||||||
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
|
||||||
auto sigma_fn = [](float t) -> float { return exp(-t); };
|
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
auto denoised_opt = model(x, sigmas[i], -(i + 1));
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
auto [sigma_down, sigma_up] = get_ancestral_step(sigmas[i], sigmas[i + 1]);
|
float sigma_up = std::min(sigmas[i + 1],
|
||||||
|
std::sqrt(sigmas[i + 1] * sigmas[i + 1] * (sigmas[i] * sigmas[i] - sigmas[i + 1] * sigmas[i + 1]) / (sigmas[i] * sigmas[i])));
|
||||||
|
float sigma_down = std::sqrt(sigmas[i + 1] * sigmas[i + 1] - sigma_up * sigma_up);
|
||||||
|
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
||||||
|
auto sigma_fn = [](float t) -> float { return exp(-t); };
|
||||||
|
|
||||||
if (sigma_down == 0) {
|
if (sigma_down == 0) {
|
||||||
x = denoised;
|
x = denoised;
|
||||||
@ -911,7 +882,7 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral(denoise_cb_t model,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
sd::Tensor<float> denoised2 = std::move(denoised2_opt);
|
sd::Tensor<float> denoised2 = std::move(denoised2_opt);
|
||||||
x = (sigma_fn(t_next) / sigma_fn(t)) * x - (exp(-h) - 1) * denoised2;
|
x = (sigma_fn(t_next) / sigma_fn(t)) * (x) - (exp(-h) - 1) * denoised2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigmas[i + 1] > 0) {
|
if (sigmas[i + 1] > 0) {
|
||||||
@ -920,14 +891,9 @@ static sd::Tensor<float> sample_dpmpp_2s_ancestral(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case DPMPP2M_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_dpmpp_2m(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
sd::Tensor<float> old_denoised = x;
|
sd::Tensor<float> old_denoised = x;
|
||||||
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
@ -941,25 +907,20 @@ static sd::Tensor<float> sample_dpmpp_2m(denoise_cb_t model,
|
|||||||
float b = exp(-h) - 1.f;
|
float b = exp(-h) - 1.f;
|
||||||
|
|
||||||
if (i == 0 || sigmas[i + 1] == 0) {
|
if (i == 0 || sigmas[i + 1] == 0) {
|
||||||
x = a * x - b * denoised;
|
x = a * (x)-b * denoised;
|
||||||
} else {
|
} else {
|
||||||
float h_last = t - t_fn(sigmas[i - 1]);
|
float h_last = t - t_fn(sigmas[i - 1]);
|
||||||
float r = h_last / h;
|
float r = h_last / h;
|
||||||
sd::Tensor<float> denoised_d = (1.f + 1.f / (2.f * r)) * denoised - (1.f / (2.f * r)) * old_denoised;
|
sd::Tensor<float> denoised_d = (1.f + 1.f / (2.f * r)) * denoised - (1.f / (2.f * r)) * old_denoised;
|
||||||
x = a * x - b * denoised_d;
|
x = a * (x)-b * denoised_d;
|
||||||
}
|
}
|
||||||
old_denoised = denoised;
|
old_denoised = denoised;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case DPMPP2Mv2_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_dpmpp_2m_v2(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
sd::Tensor<float> old_denoised = x;
|
sd::Tensor<float> old_denoised = x;
|
||||||
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
auto t_fn = [](float sigma) -> float { return -log(sigma); };
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
@ -970,10 +931,9 @@ static sd::Tensor<float> sample_dpmpp_2m_v2(denoise_cb_t model,
|
|||||||
float t_next = t_fn(sigmas[i + 1]);
|
float t_next = t_fn(sigmas[i + 1]);
|
||||||
float h = t_next - t;
|
float h = t_next - t;
|
||||||
float a = sigmas[i + 1] / sigmas[i];
|
float a = sigmas[i + 1] / sigmas[i];
|
||||||
|
|
||||||
if (i == 0 || sigmas[i + 1] == 0) {
|
if (i == 0 || sigmas[i + 1] == 0) {
|
||||||
float b = exp(-h) - 1.f;
|
float b = exp(-h) - 1.f;
|
||||||
x = a * x - b * denoised;
|
x = a * (x)-b * denoised;
|
||||||
} else {
|
} else {
|
||||||
float h_last = t - t_fn(sigmas[i - 1]);
|
float h_last = t - t_fn(sigmas[i - 1]);
|
||||||
float h_min = std::min(h_last, h);
|
float h_min = std::min(h_last, h);
|
||||||
@ -982,38 +942,30 @@ static sd::Tensor<float> sample_dpmpp_2m_v2(denoise_cb_t model,
|
|||||||
float h_d = (h_max + h_min) / 2.f;
|
float h_d = (h_max + h_min) / 2.f;
|
||||||
float b = exp(-h_d) - 1.f;
|
float b = exp(-h_d) - 1.f;
|
||||||
sd::Tensor<float> denoised_d = (1.f + 1.f / (2.f * r)) * denoised - (1.f / (2.f * r)) * old_denoised;
|
sd::Tensor<float> denoised_d = (1.f + 1.f / (2.f * r)) * denoised - (1.f / (2.f * r)) * old_denoised;
|
||||||
x = a * x - b * denoised_d;
|
x = a * (x)-b * denoised_d;
|
||||||
}
|
}
|
||||||
old_denoised = denoised;
|
old_denoised = denoised;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case LCM_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_lcm(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng) {
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
x = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
|
|
||||||
|
x = denoised;
|
||||||
if (sigmas[i + 1] > 0) {
|
if (sigmas[i + 1] > 0) {
|
||||||
x += sd::Tensor<float>::randn_like(x, rng) * sigmas[i + 1];
|
x += sd::Tensor<float>::randn_like(x, rng) * sigmas[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case IPNDM_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_ipndm(denoise_cb_t model,
|
int max_order = 4;
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
const int max_order = 4;
|
|
||||||
std::vector<sd::Tensor<float>> hist = {};
|
std::vector<sd::Tensor<float>> hist = {};
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
float sigma_next = sigmas[i + 1];
|
float sigma_next = sigmas[i + 1];
|
||||||
@ -1050,14 +1002,9 @@ static sd::Tensor<float> sample_ipndm(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case IPNDM_V_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_ipndm_v(denoise_cb_t model,
|
int max_order = 4;
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas) {
|
|
||||||
const int max_order = 4;
|
|
||||||
std::vector<sd::Tensor<float>> hist = {};
|
std::vector<sd::Tensor<float>> hist = {};
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma = sigmas[i];
|
float sigma = sigmas[i];
|
||||||
float t_next = sigmas[i + 1];
|
float t_next = sigmas[i + 1];
|
||||||
@ -1095,13 +1042,9 @@ static sd::Tensor<float> sample_ipndm_v(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case RES_MULTISTEP_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
sd::Tensor<float> old_denoised = x;
|
sd::Tensor<float> old_denoised = x;
|
||||||
|
|
||||||
bool have_old_sigma = false;
|
bool have_old_sigma = false;
|
||||||
float old_sigma_down = 0.0f;
|
float old_sigma_down = 0.0f;
|
||||||
|
|
||||||
@ -1121,7 +1064,6 @@ static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|||||||
return (phi1_val - 1.0f) / t;
|
return (phi1_val - 1.0f) / t;
|
||||||
};
|
};
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
auto denoised_opt = model(x, sigmas[i], i + 1);
|
auto denoised_opt = model(x, sigmas[i], i + 1);
|
||||||
if (denoised_opt.empty()) {
|
if (denoised_opt.empty()) {
|
||||||
@ -1131,7 +1073,22 @@ static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|||||||
|
|
||||||
float sigma_from = sigmas[i];
|
float sigma_from = sigmas[i];
|
||||||
float sigma_to = sigmas[i + 1];
|
float sigma_to = sigmas[i + 1];
|
||||||
auto [sigma_down, sigma_up] = get_ancestral_step(sigma_from, sigma_to, eta);
|
float sigma_up = 0.0f;
|
||||||
|
float sigma_down = sigma_to;
|
||||||
|
|
||||||
|
if (eta > 0.0f) {
|
||||||
|
float sigma_from_sq = sigma_from * sigma_from;
|
||||||
|
float sigma_to_sq = sigma_to * sigma_to;
|
||||||
|
if (sigma_from_sq > 0.0f) {
|
||||||
|
float term = sigma_to_sq * (sigma_from_sq - sigma_to_sq) / sigma_from_sq;
|
||||||
|
if (term > 0.0f) {
|
||||||
|
sigma_up = eta * std::sqrt(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sigma_up = std::min(sigma_up, sigma_to);
|
||||||
|
float sigma_down_sq = sigma_to_sq - sigma_up * sigma_up;
|
||||||
|
sigma_down = sigma_down_sq > 0.0f ? std::sqrt(sigma_down_sq) : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
if (sigma_down == 0.0f || !have_old_sigma) {
|
if (sigma_down == 0.0f || !have_old_sigma) {
|
||||||
x += ((x - denoised) / sigma_from) * (sigma_down - sigma_from);
|
x += ((x - denoised) / sigma_from) * (sigma_down - sigma_from);
|
||||||
@ -1155,7 +1112,7 @@ static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|||||||
b2 = 0.0f;
|
b2 = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = sigma_fn(h) * x + h * (b1 * denoised + b2 * old_denoised);
|
x = sigma_fn(h) * (x) + h * (b1 * denoised + b2 * old_denoised);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigmas[i + 1] > 0 && sigma_up > 0.0f) {
|
if (sigmas[i + 1] > 0 && sigma_up > 0.0f) {
|
||||||
@ -1168,12 +1125,7 @@ static sd::Tensor<float> sample_res_multistep(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case RES_2S_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
const float c2 = 0.5f;
|
const float c2 = 0.5f;
|
||||||
auto t_fn = [](float sigma) -> float { return -logf(sigma); };
|
auto t_fn = [](float sigma) -> float { return -logf(sigma); };
|
||||||
auto phi1_fn = [](float t) -> float {
|
auto phi1_fn = [](float t) -> float {
|
||||||
@ -1190,7 +1142,6 @@ static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|||||||
return (phi1_val - 1.0f) / t;
|
return (phi1_val - 1.0f) / t;
|
||||||
};
|
};
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
float sigma_from = sigmas[i];
|
float sigma_from = sigmas[i];
|
||||||
float sigma_to = sigmas[i + 1];
|
float sigma_to = sigmas[i + 1];
|
||||||
@ -1201,7 +1152,21 @@ static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
sd::Tensor<float> denoised = std::move(denoised_opt);
|
sd::Tensor<float> denoised = std::move(denoised_opt);
|
||||||
|
|
||||||
auto [sigma_down, sigma_up] = get_ancestral_step(sigma_from, sigma_to, eta);
|
float sigma_up = 0.0f;
|
||||||
|
float sigma_down = sigma_to;
|
||||||
|
if (eta > 0.0f) {
|
||||||
|
float sigma_from_sq = sigma_from * sigma_from;
|
||||||
|
float sigma_to_sq = sigma_to * sigma_to;
|
||||||
|
if (sigma_from_sq > 0.0f) {
|
||||||
|
float term = sigma_to_sq * (sigma_from_sq - sigma_to_sq) / sigma_from_sq;
|
||||||
|
if (term > 0.0f) {
|
||||||
|
sigma_up = eta * std::sqrt(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sigma_up = std::min(sigma_up, sigma_to);
|
||||||
|
float sigma_down_sq = sigma_to_sq - sigma_up * sigma_up;
|
||||||
|
sigma_down = sigma_down_sq > 0.0f ? std::sqrt(sigma_down_sq) : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
sd::Tensor<float> x0 = x;
|
sd::Tensor<float> x0 = x;
|
||||||
if (sigma_down == 0.0f || sigma_from == 0.0f) {
|
if (sigma_down == 0.0f || sigma_from == 0.0f) {
|
||||||
@ -1236,12 +1201,7 @@ static sd::Tensor<float> sample_res_2s(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case DDIM_TRAILING_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_ddim_trailing(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
float beta_start = 0.00085f;
|
float beta_start = 0.00085f;
|
||||||
float beta_end = 0.0120f;
|
float beta_end = 0.0120f;
|
||||||
std::vector<double> alphas_cumprod(TIMESTEPS);
|
std::vector<double> alphas_cumprod(TIMESTEPS);
|
||||||
@ -1258,10 +1218,9 @@ static sd::Tensor<float> sample_ddim_trailing(denoise_cb_t model,
|
|||||||
std::sqrt((1 - alphas_cumprod[i]) / alphas_cumprod[i]);
|
std::sqrt((1 - alphas_cumprod[i]) / alphas_cumprod[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
int timestep = static_cast<int>(roundf(TIMESTEPS - i * ((float)TIMESTEPS / steps))) - 1;
|
int timestep = static_cast<int>(roundf(TIMESTEPS - i * ((float)TIMESTEPS / steps))) - 1;
|
||||||
int prev_timestep = timestep - TIMESTEPS / steps;
|
int prev_timestep = timestep - TIMESTEPS / static_cast<int>(steps);
|
||||||
float sigma = static_cast<float>(compvis_sigmas[timestep]);
|
float sigma = static_cast<float>(compvis_sigmas[timestep]);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
x *= std::sqrt(sigma * sigma + 1) / sigma;
|
x *= std::sqrt(sigma * sigma + 1) / sigma;
|
||||||
@ -1298,12 +1257,7 @@ static sd::Tensor<float> sample_ddim_trailing(denoise_cb_t model,
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
case TCD_SAMPLE_METHOD: {
|
||||||
static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
const std::vector<float>& sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
float beta_start = 0.00085f;
|
float beta_start = 0.00085f;
|
||||||
float beta_end = 0.0120f;
|
float beta_end = 0.0120f;
|
||||||
std::vector<double> alphas_cumprod(TIMESTEPS);
|
std::vector<double> alphas_cumprod(TIMESTEPS);
|
||||||
@ -1319,9 +1273,7 @@ static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|||||||
compvis_sigmas[i] =
|
compvis_sigmas[i] =
|
||||||
std::sqrt((1 - alphas_cumprod[i]) / alphas_cumprod[i]);
|
std::sqrt((1 - alphas_cumprod[i]) / alphas_cumprod[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int original_steps = 50;
|
int original_steps = 50;
|
||||||
int steps = static_cast<int>(sigmas.size()) - 1;
|
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
int timestep = TIMESTEPS - 1 - (TIMESTEPS / original_steps) * (int)floor(i * ((float)original_steps / steps));
|
int timestep = TIMESTEPS - 1 - (TIMESTEPS / original_steps) * (int)floor(i * ((float)original_steps / steps));
|
||||||
int prev_timestep = i >= steps - 1 ? 0 : TIMESTEPS - 1 - (TIMESTEPS / original_steps) * (int)floor((i + 1) * ((float)original_steps / steps));
|
int prev_timestep = i >= steps - 1 ? 0 : TIMESTEPS - 1 - (TIMESTEPS / original_steps) * (int)floor((i + 1) * ((float)original_steps / steps));
|
||||||
@ -1355,49 +1307,12 @@ static sd::Tensor<float> sample_tcd(denoise_cb_t model,
|
|||||||
std::sqrt(beta_prod_s) * model_output;
|
std::sqrt(beta_prod_s) * model_output;
|
||||||
|
|
||||||
if (eta > 0 && i != steps - 1) {
|
if (eta > 0 && i != steps - 1) {
|
||||||
x = std::sqrt(alpha_prod_t_prev / alpha_prod_s) * x +
|
x = std::sqrt(alpha_prod_t_prev / alpha_prod_s) * (x) +
|
||||||
std::sqrt(1.0f - alpha_prod_t_prev / alpha_prod_s) * sd::Tensor<float>::randn_like(x, rng);
|
std::sqrt(1.0f - alpha_prod_t_prev / alpha_prod_s) * sd::Tensor<float>::randn_like(x, rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// k diffusion reverse ODE: dx = (x - D(x;\sigma)) / \sigma dt; \sigma(t) = t
|
|
||||||
static sd::Tensor<float> sample_k_diffusion(sample_method_t method,
|
|
||||||
denoise_cb_t model,
|
|
||||||
sd::Tensor<float> x,
|
|
||||||
std::vector<float> sigmas,
|
|
||||||
std::shared_ptr<RNG> rng,
|
|
||||||
float eta) {
|
|
||||||
switch (method) {
|
|
||||||
case EULER_A_SAMPLE_METHOD:
|
|
||||||
return sample_euler_ancestral(model, std::move(x), sigmas, rng);
|
|
||||||
case EULER_SAMPLE_METHOD:
|
|
||||||
return sample_euler(model, std::move(x), sigmas);
|
|
||||||
case HEUN_SAMPLE_METHOD:
|
|
||||||
return sample_heun(model, std::move(x), sigmas);
|
|
||||||
case DPM2_SAMPLE_METHOD:
|
|
||||||
return sample_dpm2(model, std::move(x), sigmas);
|
|
||||||
case DPMPP2S_A_SAMPLE_METHOD:
|
|
||||||
return sample_dpmpp_2s_ancestral(model, std::move(x), sigmas, rng);
|
|
||||||
case DPMPP2M_SAMPLE_METHOD:
|
|
||||||
return sample_dpmpp_2m(model, std::move(x), sigmas);
|
|
||||||
case DPMPP2Mv2_SAMPLE_METHOD:
|
|
||||||
return sample_dpmpp_2m_v2(model, std::move(x), sigmas);
|
|
||||||
case LCM_SAMPLE_METHOD:
|
|
||||||
return sample_lcm(model, std::move(x), sigmas, rng);
|
|
||||||
case IPNDM_SAMPLE_METHOD:
|
|
||||||
return sample_ipndm(model, std::move(x), sigmas);
|
|
||||||
case IPNDM_V_SAMPLE_METHOD:
|
|
||||||
return sample_ipndm_v(model, std::move(x), sigmas);
|
|
||||||
case RES_MULTISTEP_SAMPLE_METHOD:
|
|
||||||
return sample_res_multistep(model, std::move(x), sigmas, rng, eta);
|
|
||||||
case RES_2S_SAMPLE_METHOD:
|
|
||||||
return sample_res_2s(model, std::move(x), sigmas, rng, eta);
|
|
||||||
case DDIM_TRAILING_SAMPLE_METHOD:
|
|
||||||
return sample_ddim_trailing(model, std::move(x), sigmas, rng, eta);
|
|
||||||
case TCD_SAMPLE_METHOD:
|
|
||||||
return sample_tcd(model, std::move(x), sigmas, rng, eta);
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -493,7 +493,7 @@ public:
|
|||||||
offload_params_to_cpu,
|
offload_params_to_cpu,
|
||||||
tensor_storage_map,
|
tensor_storage_map,
|
||||||
true,
|
true,
|
||||||
0,
|
1,
|
||||||
true);
|
true);
|
||||||
diffusion_model = std::make_shared<WanModel>(backend,
|
diffusion_model = std::make_shared<WanModel>(backend,
|
||||||
offload_params_to_cpu,
|
offload_params_to_cpu,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user