mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-10-03 10:48:48 +08:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49d6570c43 | ||
|
|
6bbaf161ad | ||
|
|
87cdbd5978 | ||
|
|
b017918106 | ||
|
|
ac5a215998 | ||
|
|
abb36d66b5 | ||
|
|
ff4fdbb88d | ||
|
|
abb115cd02 | ||
|
|
c648001030 | ||
|
|
c587a43c99 |
+3
-2
@@ -1,13 +1,14 @@
|
||||
build*/
|
||||
cmake-build-*/
|
||||
test/
|
||||
.vscode/
|
||||
.idea/
|
||||
.cache/
|
||||
*.swp
|
||||
.vscode/
|
||||
*.bat
|
||||
*.bin
|
||||
*.exe
|
||||
*.gguf
|
||||
output*.png
|
||||
models*
|
||||
*.log
|
||||
*.log
|
||||
|
||||
@@ -149,3 +149,7 @@ if (SD_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
set(SD_PUBLIC_HEADERS stable-diffusion.h)
|
||||
set_target_properties(${SD_LIB} PROPERTIES PUBLIC_HEADER "${SD_PUBLIC_HEADERS}")
|
||||
|
||||
install(TARGETS ${SD_LIB} LIBRARY PUBLIC_HEADER)
|
||||
|
||||
@@ -137,7 +137,9 @@ This provides BLAS acceleration using the ROCm cores of your AMD GPU. Make sure
|
||||
Windows User Refer to [docs/hipBLAS_on_Windows.md](docs%2FhipBLAS_on_Windows.md) for a comprehensive guide.
|
||||
|
||||
```
|
||||
cmake .. -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSD_HIPBLAS=ON -DCMAKE_BUILD_TYPE=Release -DAMDGPU_TARGETS=gfx1100 -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON
|
||||
export GFX_NAME=$(rocminfo | grep -m 1 -E "gfx[^0]{1}" | sed -e 's/ *Name: *//' | awk '{$1=$1; print}' || echo "rocminfo missing")
|
||||
echo $GFX_NAME
|
||||
cmake .. -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSD_HIPBLAS=ON -DCMAKE_BUILD_TYPE=Release -DGPU_TARGETS=$GFX_NAME -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
@@ -319,6 +321,7 @@ arguments:
|
||||
-i, --end-img [IMAGE] path to the end image, required by flf2v
|
||||
--control-image [IMAGE] path to image condition, control net
|
||||
-r, --ref-image [PATH] reference image for Flux Kontext models (can be used multiple times)
|
||||
--increase-ref-index automatically increase the indices of references images based on the order they are listed (starting with 1).
|
||||
-o, --output OUTPUT path to write result image to (default: ./output.png)
|
||||
-p, --prompt [PROMPT] the prompt to render
|
||||
-n, --negative-prompt PROMPT the negative prompt (default: "")
|
||||
|
||||
@@ -251,6 +251,35 @@ struct KarrasSchedule : SigmaSchedule {
|
||||
}
|
||||
};
|
||||
|
||||
// Close to Beta Schedule, but increadably simple in code.
|
||||
struct SmoothStepSchedule : SigmaSchedule {
|
||||
static constexpr float smoothstep(float x) {
|
||||
return x * x * (3.0f - 2.0f * x);
|
||||
}
|
||||
|
||||
std::vector<float> get_sigmas(uint32_t n, float /*sigma_min*/, float /*sigma_max*/, t_to_sigma_t t_to_sigma) override {
|
||||
std::vector<float> result;
|
||||
result.reserve(n + 1);
|
||||
|
||||
const int t_max = TIMESTEPS - 1;
|
||||
if (n == 0) {
|
||||
return result;
|
||||
} else if (n == 1) {
|
||||
result.push_back(t_to_sigma((float)t_max));
|
||||
result.push_back(0.f);
|
||||
return result;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
float u = 1.f - float(i) / float(n);
|
||||
result.push_back(t_to_sigma(std::round(smoothstep(u) * t_max)));
|
||||
}
|
||||
|
||||
result.push_back(0.f);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct Denoiser {
|
||||
std::shared_ptr<SigmaSchedule> scheduler = std::make_shared<DiscreteSchedule>();
|
||||
virtual float sigma_min() = 0;
|
||||
|
||||
+6
-1
@@ -16,6 +16,7 @@ struct DiffusionModel {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f,
|
||||
@@ -77,6 +78,7 @@ struct UNetModel : public DiffusionModel {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f,
|
||||
@@ -133,6 +135,7 @@ struct MMDiTModel : public DiffusionModel {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f,
|
||||
@@ -191,13 +194,14 @@ struct FluxModel : public DiffusionModel {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL,
|
||||
std::vector<int> skip_layers = std::vector<int>()) {
|
||||
return flux.compute(n_threads, x, timesteps, context, c_concat, y, guidance, ref_latents, output, output_ctx, skip_layers);
|
||||
return flux.compute(n_threads, x, timesteps, context, c_concat, y, guidance, ref_latents, increase_ref_index, output, output_ctx, skip_layers);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -250,6 +254,7 @@ struct WanModel : public DiffusionModel {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f,
|
||||
|
||||
+27
-1
@@ -10,4 +10,30 @@ Here's a simple example:
|
||||
./bin/sd -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat<lora:marblesh:1>" --lora-model-dir ../models
|
||||
```
|
||||
|
||||
`../models/marblesh.safetensors` or `../models/marblesh.ckpt` will be applied to the model
|
||||
`../models/marblesh.safetensors` or `../models/marblesh.ckpt` will be applied to the model
|
||||
|
||||
# Support matrix
|
||||
|
||||
> ℹ️ CUDA `get_rows` support is defined here:
|
||||
> [ggml-org/ggml/src/ggml-cuda/getrows.cu#L156](https://github.com/ggml-org/ggml/blob/7dee1d6a1e7611f238d09be96738388da97c88ed/src/ggml-cuda/getrows.cu#L156)
|
||||
> Currently only the basic types + Q4/Q5/Q8 are implemented. K-quants are **not** supported.
|
||||
|
||||
NOTE: The other backends may have different support.
|
||||
|
||||
| Quant / Type | CUDA |
|
||||
|--------------|------|
|
||||
| F32 | ✔️ |
|
||||
| F16 | ✔️ |
|
||||
| BF16 | ✔️ |
|
||||
| I32 | ✔️ |
|
||||
| Q4_0 | ✔️ |
|
||||
| Q4_1 | ✔️ |
|
||||
| Q5_0 | ✔️ |
|
||||
| Q5_1 | ✔️ |
|
||||
| Q8_0 | ✔️ |
|
||||
| Q2_K | ❌ |
|
||||
| Q3_K | ❌ |
|
||||
| Q4_K | ❌ |
|
||||
| Q5_K | ❌ |
|
||||
| Q6_K | ❌ |
|
||||
| Q8_K | ❌ |
|
||||
|
||||
+23
-2
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
@@ -74,6 +75,7 @@ struct SDParams {
|
||||
std::string mask_image_path;
|
||||
std::string control_image_path;
|
||||
std::vector<std::string> ref_image_paths;
|
||||
bool increase_ref_index = false;
|
||||
|
||||
std::string prompt;
|
||||
std::string negative_prompt;
|
||||
@@ -156,6 +158,7 @@ void print_params(SDParams params) {
|
||||
for (auto& path : params.ref_image_paths) {
|
||||
printf(" %s\n", path.c_str());
|
||||
};
|
||||
printf(" increase_ref_index: %s\n", params.increase_ref_index ? "true" : "false");
|
||||
printf(" offload_params_to_cpu: %s\n", params.offload_params_to_cpu ? "true" : "false");
|
||||
printf(" clip_on_cpu: %s\n", params.clip_on_cpu ? "true" : "false");
|
||||
printf(" control_net_cpu: %s\n", params.control_net_cpu ? "true" : "false");
|
||||
@@ -222,6 +225,7 @@ void print_usage(int argc, const char* argv[]) {
|
||||
printf(" -i, --end-img [IMAGE] path to the end image, required by flf2v\n");
|
||||
printf(" --control-image [IMAGE] path to image condition, control net\n");
|
||||
printf(" -r, --ref-image [PATH] reference image for Flux Kontext models (can be used multiple times) \n");
|
||||
printf(" --increase-ref-index automatically increase the indices of references images based on the order they are listed (starting with 1).\n");
|
||||
printf(" -o, --output OUTPUT path to write result image to (default: ./output.png)\n");
|
||||
printf(" -p, --prompt [PROMPT] the prompt to render\n");
|
||||
printf(" -n, --negative-prompt PROMPT the negative prompt (default: \"\")\n");
|
||||
@@ -234,7 +238,7 @@ void print_usage(int argc, const char* argv[]) {
|
||||
printf(" --skip-layers LAYERS Layers to skip for SLG steps: (default: [7,8,9])\n");
|
||||
printf(" --skip-layer-start START SLG enabling point: (default: 0.01)\n");
|
||||
printf(" --skip-layer-end END SLG disabling point: (default: 0.2)\n");
|
||||
printf(" --scheduler {discrete, karras, exponential, ays, gits} Denoiser sigma scheduler (default: discrete)\n");
|
||||
printf(" --scheduler {discrete, karras, exponential, ays, gits, smoothstep} Denoiser sigma scheduler (default: discrete)\n");
|
||||
printf(" --sampling-method {euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd}\n");
|
||||
printf(" sampling method (default: \"euler_a\")\n");
|
||||
printf(" --steps STEPS number of sample steps (default: 20)\n");
|
||||
@@ -247,7 +251,7 @@ void print_usage(int argc, const char* argv[]) {
|
||||
printf(" --high-noise-skip-layers LAYERS (high noise) Layers to skip for SLG steps: (default: [7,8,9])\n");
|
||||
printf(" --high-noise-skip-layer-start (high noise) SLG enabling point: (default: 0.01)\n");
|
||||
printf(" --high-noise-skip-layer-end END (high noise) SLG disabling point: (default: 0.2)\n");
|
||||
printf(" --high-noise-scheduler {discrete, karras, exponential, ays, gits} Denoiser sigma scheduler (default: discrete)\n");
|
||||
printf(" --high-noise-scheduler {discrete, karras, exponential, ays, gits, smoothstep} Denoiser sigma scheduler (default: discrete)\n");
|
||||
printf(" --high-noise-sampling-method {euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd}\n");
|
||||
printf(" (high noise) sampling method (default: \"euler_a\")\n");
|
||||
printf(" --high-noise-steps STEPS (high noise) number of sample steps (default: -1 = auto)\n");
|
||||
@@ -536,6 +540,7 @@ void parse_args(int argc, const char** argv, SDParams& params) {
|
||||
{"", "--color", "", true, ¶ms.color},
|
||||
{"", "--chroma-disable-dit-mask", "", false, ¶ms.chroma_use_dit_mask},
|
||||
{"", "--chroma-enable-t5-mask", "", true, ¶ms.chroma_use_t5_mask},
|
||||
{"", "--increase-ref-index", "", true, ¶ms.increase_ref_index},
|
||||
};
|
||||
|
||||
auto on_mode_arg = [&](int argc, const char** argv, int index) {
|
||||
@@ -1207,6 +1212,7 @@ int main(int argc, const char* argv[]) {
|
||||
init_image,
|
||||
ref_images.data(),
|
||||
(int)ref_images.size(),
|
||||
params.increase_ref_index,
|
||||
mask_image,
|
||||
params.width,
|
||||
params.height,
|
||||
@@ -1278,6 +1284,21 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// create directory if not exists
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
const fs::path out_path = params.output_path;
|
||||
if (const fs::path out_dir = out_path.parent_path(); !out_dir.empty()) {
|
||||
std::error_code ec;
|
||||
fs::create_directories(out_dir, ec); // OK if already exists
|
||||
if (ec) {
|
||||
fprintf(stderr, "failed to create directory '%s': %s\n",
|
||||
out_dir.string().c_str(), ec.message().c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string base_path;
|
||||
std::string file_ext;
|
||||
std::string file_ext_lower;
|
||||
|
||||
@@ -960,6 +960,7 @@ namespace Flux {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
std::vector<int> skip_layers = {}) {
|
||||
GGML_ASSERT(x->ne[3] == 1);
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, FLUX_GRAPH_SIZE, false);
|
||||
@@ -999,6 +1000,7 @@ namespace Flux {
|
||||
x->ne[3],
|
||||
context->ne[1],
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
flux_params.theta,
|
||||
flux_params.axes_dim);
|
||||
int pos_len = pe_vec.size() / flux_params.axes_dim_sum / 2;
|
||||
@@ -1035,6 +1037,7 @@ namespace Flux {
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor* guidance,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL,
|
||||
std::vector<int> skip_layers = std::vector<int>()) {
|
||||
@@ -1044,7 +1047,7 @@ namespace Flux {
|
||||
// y: [N, adm_in_channels] or [1, adm_in_channels]
|
||||
// guidance: [N, ]
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(x, timesteps, context, c_concat, y, guidance, ref_latents, skip_layers);
|
||||
return build_graph(x, timesteps, context, c_concat, y, guidance, ref_latents, increase_ref_index, skip_layers);
|
||||
};
|
||||
|
||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||
@@ -1084,7 +1087,7 @@ namespace Flux {
|
||||
struct ggml_tensor* out = NULL;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, timesteps, context, NULL, y, guidance, {}, &out, work_ctx);
|
||||
compute(8, x, timesteps, context, NULL, y, guidance, {}, false, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
|
||||
+19
-7
@@ -56,6 +56,25 @@
|
||||
#define __STATIC_INLINE__ static inline
|
||||
#endif
|
||||
|
||||
__STATIC_INLINE__ void ggml_log_callback_default(ggml_log_level level, const char* text, void*) {
|
||||
switch (level) {
|
||||
case GGML_LOG_LEVEL_DEBUG:
|
||||
LOG_DEBUG(text);
|
||||
break;
|
||||
case GGML_LOG_LEVEL_INFO:
|
||||
LOG_INFO(text);
|
||||
break;
|
||||
case GGML_LOG_LEVEL_WARN:
|
||||
LOG_WARN(text);
|
||||
break;
|
||||
case GGML_LOG_LEVEL_ERROR:
|
||||
LOG_ERROR(text);
|
||||
break;
|
||||
default:
|
||||
LOG_DEBUG(text);
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(GGML_MAX_NAME >= 128, "GGML_MAX_NAME must be at least 128");
|
||||
|
||||
// n-mode trensor-matrix product
|
||||
@@ -124,13 +143,6 @@ __STATIC_INLINE__ struct ggml_tensor* ggml_kronecker(ggml_context* ctx, struct g
|
||||
b);
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ void ggml_log_callback_default(ggml_log_level level, const char* text, void* user_data) {
|
||||
(void)level;
|
||||
(void)user_data;
|
||||
fputs(text, stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ void ggml_tensor_set_f32_randn(struct ggml_tensor* tensor, std::shared_ptr<RNG> rng) {
|
||||
uint32_t n = (uint32_t)ggml_nelements(tensor);
|
||||
std::vector<float> random_numbers = rng->randn(n);
|
||||
|
||||
@@ -58,6 +58,7 @@ struct LoraModel : public GGMLRunner {
|
||||
{"x_block.attn.proj", "attn.to_out.0"},
|
||||
{"x_block.attn2.proj", "attn2.to_out.0"},
|
||||
// flux
|
||||
{"img_in", "x_embedder"},
|
||||
// singlestream
|
||||
{"linear2", "proj_out"},
|
||||
{"modulation.lin", "norm.linear"},
|
||||
|
||||
@@ -1966,6 +1966,16 @@ std::vector<TensorStorage> remove_duplicates(const std::vector<TensorStorage>& v
|
||||
}
|
||||
|
||||
bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
int64_t process_time_ms = 0;
|
||||
int64_t read_time_ms = 0;
|
||||
int64_t memcpy_time_ms = 0;
|
||||
int64_t copy_to_backend_time_ms = 0;
|
||||
int64_t convert_time_ms = 0;
|
||||
|
||||
int64_t prev_time_ms = 0;
|
||||
int64_t curr_time_ms = 0;
|
||||
int64_t start_time = ggml_time_ms();
|
||||
prev_time_ms = start_time;
|
||||
std::vector<TensorStorage> processed_tensor_storages;
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
// LOG_DEBUG("%s", name.c_str());
|
||||
@@ -1978,6 +1988,9 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
}
|
||||
std::vector<TensorStorage> dedup = remove_duplicates(processed_tensor_storages);
|
||||
processed_tensor_storages = dedup;
|
||||
curr_time_ms = ggml_time_ms();
|
||||
process_time_ms = curr_time_ms - prev_time_ms;
|
||||
prev_time_ms = curr_time_ms;
|
||||
|
||||
bool success = true;
|
||||
for (size_t file_index = 0; file_index < file_paths_.size(); file_index++) {
|
||||
@@ -2019,15 +2032,27 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
size_t entry_size = zip_entry_size(zip);
|
||||
if (entry_size != n) {
|
||||
read_buffer.resize(entry_size);
|
||||
prev_time_ms = ggml_time_ms();
|
||||
zip_entry_noallocread(zip, (void*)read_buffer.data(), entry_size);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
read_time_ms += curr_time_ms - prev_time_ms;
|
||||
prev_time_ms = curr_time_ms;
|
||||
memcpy((void*)buf, (void*)(read_buffer.data() + tensor_storage.offset), n);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
memcpy_time_ms += curr_time_ms - prev_time_ms;
|
||||
} else {
|
||||
prev_time_ms = ggml_time_ms();
|
||||
zip_entry_noallocread(zip, (void*)buf, n);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
read_time_ms += curr_time_ms - prev_time_ms;
|
||||
}
|
||||
zip_entry_close(zip);
|
||||
} else {
|
||||
prev_time_ms = ggml_time_ms();
|
||||
file.seekg(tensor_storage.offset);
|
||||
file.read(buf, n);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
read_time_ms += curr_time_ms - prev_time_ms;
|
||||
if (!file) {
|
||||
LOG_ERROR("read tensor data failed: '%s'", file_path.c_str());
|
||||
return false;
|
||||
@@ -2072,6 +2097,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
read_data(tensor_storage, (char*)dst_tensor->data, nbytes_to_read);
|
||||
}
|
||||
|
||||
prev_time_ms = ggml_time_ms();
|
||||
if (tensor_storage.is_bf16) {
|
||||
// inplace op
|
||||
bf16_to_f32_vec((uint16_t*)dst_tensor->data, (float*)dst_tensor->data, tensor_storage.nelements());
|
||||
@@ -2086,10 +2112,13 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
} else if (tensor_storage.is_i64) {
|
||||
i64_to_i32_vec((int64_t*)read_buffer.data(), (int32_t*)dst_tensor->data, tensor_storage.nelements());
|
||||
}
|
||||
curr_time_ms = ggml_time_ms();
|
||||
convert_time_ms += curr_time_ms - prev_time_ms;
|
||||
} else {
|
||||
read_buffer.resize(std::max(tensor_storage.nbytes(), tensor_storage.nbytes_to_read()));
|
||||
read_data(tensor_storage, (char*)read_buffer.data(), nbytes_to_read);
|
||||
|
||||
prev_time_ms = ggml_time_ms();
|
||||
if (tensor_storage.is_bf16) {
|
||||
// inplace op
|
||||
bf16_to_f32_vec((uint16_t*)read_buffer.data(), (float*)read_buffer.data(), tensor_storage.nelements());
|
||||
@@ -2109,11 +2138,14 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
|
||||
convert_tensor((void*)read_buffer.data(), tensor_storage.type, dst_tensor->data,
|
||||
dst_tensor->type, (int)tensor_storage.nelements() / (int)tensor_storage.ne[0], (int)tensor_storage.ne[0]);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
convert_time_ms += curr_time_ms - prev_time_ms;
|
||||
}
|
||||
} else {
|
||||
read_buffer.resize(std::max(tensor_storage.nbytes(), tensor_storage.nbytes_to_read()));
|
||||
read_data(tensor_storage, (char*)read_buffer.data(), nbytes_to_read);
|
||||
|
||||
prev_time_ms = ggml_time_ms();
|
||||
if (tensor_storage.is_bf16) {
|
||||
// inplace op
|
||||
bf16_to_f32_vec((uint16_t*)read_buffer.data(), (float*)read_buffer.data(), tensor_storage.nelements());
|
||||
@@ -2133,14 +2165,24 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
|
||||
if (tensor_storage.type == dst_tensor->type) {
|
||||
// copy to device memory
|
||||
curr_time_ms = ggml_time_ms();
|
||||
convert_time_ms += curr_time_ms - prev_time_ms;
|
||||
prev_time_ms = curr_time_ms;
|
||||
ggml_backend_tensor_set(dst_tensor, read_buffer.data(), 0, ggml_nbytes(dst_tensor));
|
||||
curr_time_ms = ggml_time_ms();
|
||||
copy_to_backend_time_ms += curr_time_ms - prev_time_ms;
|
||||
} else {
|
||||
// convert first, then copy to device memory
|
||||
convert_buffer.resize(ggml_nbytes(dst_tensor));
|
||||
convert_tensor((void*)read_buffer.data(), tensor_storage.type,
|
||||
(void*)convert_buffer.data(), dst_tensor->type,
|
||||
(int)tensor_storage.nelements() / (int)tensor_storage.ne[0], (int)tensor_storage.ne[0]);
|
||||
curr_time_ms = ggml_time_ms();
|
||||
convert_time_ms += curr_time_ms - prev_time_ms;
|
||||
prev_time_ms = curr_time_ms;
|
||||
ggml_backend_tensor_set(dst_tensor, convert_buffer.data(), 0, ggml_nbytes(dst_tensor));
|
||||
curr_time_ms = ggml_time_ms();
|
||||
copy_to_backend_time_ms += curr_time_ms - prev_time_ms;
|
||||
}
|
||||
}
|
||||
++tensor_count;
|
||||
@@ -2170,6 +2212,14 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int64_t end_time = ggml_time_ms();
|
||||
LOG_INFO("loading tensors completed, taking %.2fs (process: %.2fs, read: %.2fs, memcpy: %.2fs, convert: %.2fs, copy_to_backend: %.2fs)",
|
||||
(end_time - start_time) / 1000.f,
|
||||
process_time_ms / 1000.f,
|
||||
read_time_ms / 1000.f,
|
||||
memcpy_time_ms / 1000.f,
|
||||
convert_time_ms / 1000.f,
|
||||
copy_to_backend_time_ms / 1000.f);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,25 +156,33 @@ struct Rope {
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
std::vector<ggml_tensor*> ref_latents) {
|
||||
std::vector<ggml_tensor*> ref_latents,
|
||||
bool increase_ref_index) {
|
||||
auto txt_ids = gen_txt_ids(bs, context_len);
|
||||
auto img_ids = gen_img_ids(h, w, patch_size, bs);
|
||||
|
||||
auto ids = concat_ids(txt_ids, img_ids, bs);
|
||||
uint64_t curr_h_offset = 0;
|
||||
uint64_t curr_w_offset = 0;
|
||||
int index = 1;
|
||||
for (ggml_tensor* ref : ref_latents) {
|
||||
uint64_t h_offset = 0;
|
||||
uint64_t w_offset = 0;
|
||||
if (ref->ne[1] + curr_h_offset > ref->ne[0] + curr_w_offset) {
|
||||
w_offset = curr_w_offset;
|
||||
} else {
|
||||
h_offset = curr_h_offset;
|
||||
if (!increase_ref_index) {
|
||||
if (ref->ne[1] + curr_h_offset > ref->ne[0] + curr_w_offset) {
|
||||
w_offset = curr_w_offset;
|
||||
} else {
|
||||
h_offset = curr_h_offset;
|
||||
}
|
||||
}
|
||||
|
||||
auto ref_ids = gen_img_ids(ref->ne[1], ref->ne[0], patch_size, bs, 1, h_offset, w_offset);
|
||||
auto ref_ids = gen_img_ids(ref->ne[1], ref->ne[0], patch_size, bs, index, h_offset, w_offset);
|
||||
ids = concat_ids(ids, ref_ids, bs);
|
||||
|
||||
if (increase_ref_index) {
|
||||
index++;
|
||||
}
|
||||
|
||||
curr_h_offset = std::max(curr_h_offset, ref->ne[1] + h_offset);
|
||||
curr_w_offset = std::max(curr_w_offset, ref->ne[0] + w_offset);
|
||||
}
|
||||
@@ -188,9 +196,10 @@ struct Rope {
|
||||
int bs,
|
||||
int context_len,
|
||||
std::vector<ggml_tensor*> ref_latents,
|
||||
bool increase_ref_index,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
std::vector<std::vector<float>> ids = gen_flux_ids(h, w, patch_size, bs, context_len, ref_latents);
|
||||
std::vector<std::vector<float>> ids = gen_flux_ids(h, w, patch_size, bs, context_len, ref_latents, increase_ref_index);
|
||||
return embed_nd(ids, bs, theta, axes_dim);
|
||||
}
|
||||
|
||||
|
||||
+37
-18
@@ -145,7 +145,6 @@ public:
|
||||
#endif
|
||||
#ifdef SD_USE_METAL
|
||||
LOG_DEBUG("Using Metal backend");
|
||||
ggml_log_set(ggml_log_callback_default, nullptr);
|
||||
backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
#ifdef SD_USE_VULKAN
|
||||
@@ -192,6 +191,8 @@ public:
|
||||
rng = std::make_shared<PhiloxRNG>();
|
||||
}
|
||||
|
||||
ggml_log_set(ggml_log_callback_default, nullptr);
|
||||
|
||||
init_backend();
|
||||
|
||||
ModelLoader model_loader;
|
||||
@@ -330,7 +331,7 @@ public:
|
||||
if (sd_version_is_dit(version)) {
|
||||
use_t5xxl = true;
|
||||
}
|
||||
if (!ggml_backend_is_cpu(backend) && use_t5xxl) {
|
||||
if (!clip_on_cpu && !ggml_backend_is_cpu(backend) && use_t5xxl) {
|
||||
LOG_WARN(
|
||||
"!!!It appears that you are using the T5 model. Some backends may encounter issues with it."
|
||||
"If you notice that the generated images are completely black,"
|
||||
@@ -344,9 +345,6 @@ public:
|
||||
LOG_INFO("Using flash attention in the diffusion model");
|
||||
}
|
||||
if (sd_version_is_sd3(version)) {
|
||||
if (sd_ctx_params->diffusion_flash_attn) {
|
||||
LOG_WARN("flash attention in this diffusion model is currently unsupported!");
|
||||
}
|
||||
cond_stage_model = std::make_shared<SD3CLIPEmbedder>(clip_backend,
|
||||
offload_params_to_cpu,
|
||||
model_loader.tensor_storages_types);
|
||||
@@ -362,6 +360,15 @@ public:
|
||||
}
|
||||
}
|
||||
if (is_chroma) {
|
||||
if (sd_ctx_params->diffusion_flash_attn && sd_ctx_params->chroma_use_dit_mask) {
|
||||
LOG_WARN(
|
||||
"!!!It looks like you are using Chroma with flash attention. "
|
||||
"This is currently unsupported. "
|
||||
"If you find that the generated images are broken, "
|
||||
"try either disabling flash attention or specifying "
|
||||
"--chroma-disable-dit-mask as a workaround.");
|
||||
}
|
||||
|
||||
cond_stage_model = std::make_shared<T5CLIPEmbedder>(clip_backend,
|
||||
offload_params_to_cpu,
|
||||
model_loader.tensor_storages_types,
|
||||
@@ -557,8 +564,6 @@ public:
|
||||
// load weights
|
||||
LOG_DEBUG("loading weights");
|
||||
|
||||
int64_t t0 = ggml_time_ms();
|
||||
|
||||
std::set<std::string> ignore_tensors;
|
||||
tensors["alphas_cumprod"] = alphas_cumprod_tensor;
|
||||
if (use_tiny_autoencoder) {
|
||||
@@ -656,11 +661,7 @@ public:
|
||||
ggml_backend_is_cpu(clip_backend) ? "RAM" : "VRAM");
|
||||
}
|
||||
|
||||
int64_t t1 = ggml_time_ms();
|
||||
LOG_INFO("loading model from '%s' completed, taking %.2fs", SAFE_STR(sd_ctx_params->model_path), (t1 - t0) * 1.0f / 1000);
|
||||
|
||||
// check is_using_v_parameterization_for_sd2
|
||||
|
||||
if (sd_version_is_sd2(version)) {
|
||||
if (is_using_v_parameterization_for_sd2(ctx, sd_version_is_inpaint(version))) {
|
||||
is_using_v_parameterization = true;
|
||||
@@ -750,6 +751,10 @@ public:
|
||||
denoiser->scheduler = std::make_shared<GITSSchedule>();
|
||||
denoiser->scheduler->version = version;
|
||||
break;
|
||||
case SMOOTHSTEP:
|
||||
LOG_INFO("Running with SmoothStep scheduler");
|
||||
denoiser->scheduler = std::make_shared<SmoothStepSchedule>();
|
||||
break;
|
||||
case DEFAULT:
|
||||
// Don't touch anything.
|
||||
break;
|
||||
@@ -775,7 +780,7 @@ public:
|
||||
|
||||
int64_t t0 = ggml_time_ms();
|
||||
struct ggml_tensor* out = ggml_dup_tensor(work_ctx, x_t);
|
||||
diffusion_model->compute(n_threads, x_t, timesteps, c, concat, NULL, NULL, {}, -1, {}, 0.f, &out);
|
||||
diffusion_model->compute(n_threads, x_t, timesteps, c, concat, NULL, NULL, {}, false, -1, {}, 0.f, &out);
|
||||
diffusion_model->free_compute_buffer();
|
||||
|
||||
double result = 0.f;
|
||||
@@ -1032,6 +1037,7 @@ public:
|
||||
int start_merge_step,
|
||||
SDCondition id_cond,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
ggml_tensor* denoise_mask = nullptr) {
|
||||
std::vector<int> skip_layers(guidance.slg.layers, guidance.slg.layers + guidance.slg.layer_count);
|
||||
|
||||
@@ -1126,6 +1132,7 @@ public:
|
||||
cond.c_vector,
|
||||
guidance_tensor,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
-1,
|
||||
controls,
|
||||
control_strength,
|
||||
@@ -1139,6 +1146,7 @@ public:
|
||||
id_cond.c_vector,
|
||||
guidance_tensor,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
-1,
|
||||
controls,
|
||||
control_strength,
|
||||
@@ -1160,6 +1168,7 @@ public:
|
||||
uncond.c_vector,
|
||||
guidance_tensor,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
-1,
|
||||
controls,
|
||||
control_strength,
|
||||
@@ -1177,6 +1186,7 @@ public:
|
||||
img_cond.c_vector,
|
||||
guidance_tensor,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
-1,
|
||||
controls,
|
||||
control_strength,
|
||||
@@ -1198,6 +1208,7 @@ public:
|
||||
cond.c_vector,
|
||||
guidance_tensor,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
-1,
|
||||
controls,
|
||||
control_strength,
|
||||
@@ -1527,6 +1538,7 @@ const char* schedule_to_str[] = {
|
||||
"exponential",
|
||||
"ays",
|
||||
"gits",
|
||||
"smoothstep",
|
||||
};
|
||||
|
||||
const char* sd_schedule_name(enum scheduler_t scheduler) {
|
||||
@@ -1546,7 +1558,7 @@ enum scheduler_t str_to_schedule(const char* str) {
|
||||
}
|
||||
|
||||
void sd_ctx_params_init(sd_ctx_params_t* sd_ctx_params) {
|
||||
memset((void*)sd_ctx_params, 0, sizeof(sd_ctx_params_t));
|
||||
*sd_ctx_params = {};
|
||||
sd_ctx_params->vae_decode_only = true;
|
||||
sd_ctx_params->vae_tiling = false;
|
||||
sd_ctx_params->free_params_immediately = true;
|
||||
@@ -1630,6 +1642,7 @@ char* sd_ctx_params_to_str(const sd_ctx_params_t* sd_ctx_params) {
|
||||
}
|
||||
|
||||
void sd_sample_params_init(sd_sample_params_t* sample_params) {
|
||||
*sample_params = {};
|
||||
sample_params->guidance.txt_cfg = 7.0f;
|
||||
sample_params->guidance.img_cfg = INFINITY;
|
||||
sample_params->guidance.distilled_guidance = 3.5f;
|
||||
@@ -1676,9 +1689,9 @@ char* sd_sample_params_to_str(const sd_sample_params_t* sample_params) {
|
||||
}
|
||||
|
||||
void sd_img_gen_params_init(sd_img_gen_params_t* sd_img_gen_params) {
|
||||
memset((void*)sd_img_gen_params, 0, sizeof(sd_img_gen_params_t));
|
||||
sd_img_gen_params->clip_skip = -1;
|
||||
*sd_img_gen_params = {};
|
||||
sd_sample_params_init(&sd_img_gen_params->sample_params);
|
||||
sd_img_gen_params->clip_skip = -1;
|
||||
sd_img_gen_params->ref_images_count = 0;
|
||||
sd_img_gen_params->width = 512;
|
||||
sd_img_gen_params->height = 512;
|
||||
@@ -1710,6 +1723,7 @@ char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params) {
|
||||
"\n"
|
||||
"batch_count: %d\n"
|
||||
"ref_images_count: %d\n"
|
||||
"increase_ref_index: %s\n"
|
||||
"control_strength: %.2f\n"
|
||||
"style_strength: %.2f\n"
|
||||
"normalize_input: %s\n"
|
||||
@@ -1724,6 +1738,7 @@ char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params) {
|
||||
sd_img_gen_params->seed,
|
||||
sd_img_gen_params->batch_count,
|
||||
sd_img_gen_params->ref_images_count,
|
||||
BOOL_STR(sd_img_gen_params->increase_ref_index),
|
||||
sd_img_gen_params->control_strength,
|
||||
sd_img_gen_params->style_strength,
|
||||
BOOL_STR(sd_img_gen_params->normalize_input),
|
||||
@@ -1733,7 +1748,7 @@ char* sd_img_gen_params_to_str(const sd_img_gen_params_t* sd_img_gen_params) {
|
||||
}
|
||||
|
||||
void sd_vid_gen_params_init(sd_vid_gen_params_t* sd_vid_gen_params) {
|
||||
memset((void*)sd_vid_gen_params, 0, sizeof(sd_vid_gen_params_t));
|
||||
*sd_vid_gen_params = {};
|
||||
sd_sample_params_init(&sd_vid_gen_params->sample_params);
|
||||
sd_sample_params_init(&sd_vid_gen_params->high_noise_sample_params);
|
||||
sd_vid_gen_params->high_noise_sample_params.sample_steps = -1;
|
||||
@@ -1757,6 +1772,7 @@ sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params) {
|
||||
|
||||
sd_ctx->sd = new StableDiffusionGGML();
|
||||
if (sd_ctx->sd == NULL) {
|
||||
free(sd_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1797,6 +1813,7 @@ sd_image_t* generate_image_internal(sd_ctx_t* sd_ctx,
|
||||
bool normalize_input,
|
||||
std::string input_id_images_path,
|
||||
std::vector<ggml_tensor*> ref_latents,
|
||||
bool increase_ref_index,
|
||||
ggml_tensor* concat_latent = NULL,
|
||||
ggml_tensor* denoise_mask = NULL) {
|
||||
if (seed < 0) {
|
||||
@@ -2054,6 +2071,7 @@ sd_image_t* generate_image_internal(sd_ctx_t* sd_ctx,
|
||||
start_merge_step,
|
||||
id_cond,
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
denoise_mask);
|
||||
// print_ggml_tensor(x_0);
|
||||
int64_t sampling_end = ggml_time_ms();
|
||||
@@ -2304,7 +2322,7 @@ sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* sd_img_g
|
||||
LOG_INFO("EDIT mode");
|
||||
}
|
||||
|
||||
std::vector<struct ggml_tensor*> ref_latents;
|
||||
std::vector<ggml_tensor*> ref_latents;
|
||||
for (int i = 0; i < sd_img_gen_params->ref_images_count; i++) {
|
||||
ggml_tensor* img = ggml_new_tensor_4d(work_ctx,
|
||||
GGML_TYPE_F32,
|
||||
@@ -2357,8 +2375,9 @@ sd_image_t* generate_image(sd_ctx_t* sd_ctx, const sd_img_gen_params_t* sd_img_g
|
||||
sd_img_gen_params->control_strength,
|
||||
sd_img_gen_params->style_strength,
|
||||
sd_img_gen_params->normalize_input,
|
||||
sd_img_gen_params->input_id_images_path,
|
||||
SAFE_STR(sd_img_gen_params->input_id_images_path),
|
||||
ref_latents,
|
||||
sd_img_gen_params->increase_ref_index,
|
||||
concat_latent,
|
||||
denoise_mask);
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ enum scheduler_t {
|
||||
EXPONENTIAL,
|
||||
AYS,
|
||||
GITS,
|
||||
SMOOTHSTEP,
|
||||
SCHEDULE_COUNT
|
||||
};
|
||||
|
||||
@@ -182,6 +183,7 @@ typedef struct {
|
||||
sd_image_t init_image;
|
||||
sd_image_t* ref_images;
|
||||
int ref_images_count;
|
||||
bool increase_ref_index;
|
||||
sd_image_t mask_image;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
+1
-1
@@ -19,13 +19,13 @@ struct UpscalerGGML {
|
||||
|
||||
bool load_from_file(const std::string& esrgan_path,
|
||||
bool offload_params_to_cpu) {
|
||||
ggml_log_set(ggml_log_callback_default, nullptr);
|
||||
#ifdef SD_USE_CUDA
|
||||
LOG_DEBUG("Using CUDA backend");
|
||||
backend = ggml_backend_cuda_init(0);
|
||||
#endif
|
||||
#ifdef SD_USE_METAL
|
||||
LOG_DEBUG("Using Metal backend");
|
||||
ggml_log_set(ggml_log_callback_default, nullptr);
|
||||
backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
#ifdef SD_USE_VULKAN
|
||||
|
||||
@@ -414,7 +414,10 @@ void log_printf(sd_log_level_t level, const char* file, int line, const char* fo
|
||||
if (written >= 0 && written < LOG_BUFFER_SIZE) {
|
||||
vsnprintf(log_buffer + written, LOG_BUFFER_SIZE - written, format, args);
|
||||
}
|
||||
strncat(log_buffer, "\n", LOG_BUFFER_SIZE - strlen(log_buffer));
|
||||
size_t len = strlen(log_buffer);
|
||||
if (log_buffer[len - 1] != '\n') {
|
||||
strncat(log_buffer, "\n", LOG_BUFFER_SIZE - len);
|
||||
}
|
||||
|
||||
if (sd_log_cb) {
|
||||
sd_log_cb(level, log_buffer, sd_log_cb_data);
|
||||
|
||||
Reference in New Issue
Block a user