mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-10-02 10:24:37 +08:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d60fb27560 | ||
|
|
c7ccafbd6f | ||
|
|
aa0b899397 | ||
|
|
5e264372ce | ||
|
|
f0f641a142 | ||
|
|
9f56833e14 | ||
|
|
65891d74cc | ||
|
|
f957fa3d2a | ||
|
|
c252e03c6b |
@@ -485,6 +485,153 @@ jobs:
|
||||
path: |
|
||||
sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-x64.zip
|
||||
|
||||
ubuntu-latest-rocm:
|
||||
runs-on: ubuntu-latest
|
||||
container: rocm/dev-ubuntu-24.04:7.2
|
||||
|
||||
env:
|
||||
ROCM_VERSION: "7.2"
|
||||
UBUNTU_VERSION: "24.04"
|
||||
GPU_TARGETS: "gfx1151;gfx1150;gfx1100;gfx1101;gfx1102;gfx1200;gfx1201"
|
||||
|
||||
steps:
|
||||
- run: apt-get update && apt-get install -y git
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Free disk space
|
||||
run: |
|
||||
# Remove preinstalled SDKs and caches not needed for this job
|
||||
sudo rm -rf /usr/share/dotnet || true
|
||||
sudo rm -rf /usr/local/lib/android || true
|
||||
sudo rm -rf /opt/ghc || true
|
||||
sudo rm -rf /usr/local/.ghcup || true
|
||||
sudo rm -rf /opt/hostedtoolcache || true
|
||||
|
||||
# Remove old package lists and caches
|
||||
sudo rm -rf /var/lib/apt/lists/* || true
|
||||
sudo apt clean
|
||||
|
||||
- name: Dependencies
|
||||
id: depends
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt install -y \
|
||||
cmake \
|
||||
hip-dev \
|
||||
hipblas-dev \
|
||||
ninja-build \
|
||||
rocm-dev \
|
||||
zip
|
||||
# Clean apt caches to recover disk space
|
||||
sudo apt clean
|
||||
sudo rm -rf /var/lib/apt/lists/* || true
|
||||
|
||||
- name: Setup ROCm Environment
|
||||
run: |
|
||||
# Add ROCm to PATH for current session
|
||||
echo "/opt/rocm/bin" >> $GITHUB_PATH
|
||||
|
||||
# Build case pattern from GPU_TARGETS
|
||||
PATTERN=$(printf '%s' "$GPU_TARGETS" | sed 's/;/\*|\*/g')
|
||||
PATTERN="*${PATTERN}*"
|
||||
|
||||
# Remove library files for architectures we're not building for to save disk space
|
||||
echo "Cleaning up unneeded architecture files..."
|
||||
cd /opt/rocm/lib/rocblas/library
|
||||
# Keep only our target architectures
|
||||
for file in *; do
|
||||
case "$file" in
|
||||
$PATTERN)
|
||||
;;
|
||||
*)
|
||||
sudo rm -f "$file" ;;
|
||||
esac;
|
||||
done
|
||||
|
||||
cd /opt/rocm/lib/hipblaslt/library
|
||||
for file in *; do
|
||||
case "$file" in
|
||||
$PATTERN)
|
||||
;;
|
||||
*)
|
||||
sudo rm -f "$file" ;;
|
||||
esac;
|
||||
done
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G Ninja \
|
||||
-DCMAKE_CXX_COMPILER=amdclang++ \
|
||||
-DCMAKE_C_COMPILER=amdclang \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DSD_HIPBLAS=ON \
|
||||
-DGPU_TARGETS="${{ env.GPU_TARGETS }}" \
|
||||
-DAMDGPU_TARGETS="${{ env.GPU_TARGETS }}" \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DSD_BUILD_SHARED_LIBS=ON
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Get commit hash
|
||||
id: commit
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: pr-mpt/actions-commit-hash@v2
|
||||
|
||||
- name: Prepare artifacts
|
||||
id: prepare_artifacts
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
run: |
|
||||
# Copy licenses
|
||||
cp ggml/LICENSE ./build/bin/ggml.txt
|
||||
cp LICENSE ./build/bin/stable-diffusion.cpp.txt
|
||||
|
||||
# Create directories for ROCm libraries
|
||||
mkdir -p ./build/bin/rocblas/library
|
||||
mkdir -p ./build/bin/hipblaslt/library
|
||||
|
||||
# Copy ROCm runtime libraries (use || true to continue if files don't exist)
|
||||
cp /opt/rocm/lib/librocsparse.so* ./build/bin/ || true
|
||||
cp /opt/rocm/lib/libhsa-runtime64.so* ./build/bin/ || true
|
||||
cp /opt/rocm/lib/libamdhip64.so* ./build/bin/ || true
|
||||
cp /opt/rocm/lib/libhipblas.so* ./build/bin/ || true
|
||||
cp /opt/rocm/lib/libhipblaslt.so* ./build/bin/ || true
|
||||
cp /opt/rocm/lib/librocblas.so* ./build/bin/ || true
|
||||
|
||||
# Copy library files (already filtered to target architectures)
|
||||
cp /opt/rocm/lib/rocblas/library/* ./build/bin/rocblas/library/ || true
|
||||
cp /opt/rocm/lib/hipblaslt/library/* ./build/bin/hipblaslt/library/ || true
|
||||
|
||||
- name: Fetch system info
|
||||
id: system-info
|
||||
run: |
|
||||
echo "CPU_ARCH=`uname -m`" >> "$GITHUB_OUTPUT"
|
||||
echo "OS_NAME=`lsb_release -s -i`" >> "$GITHUB_OUTPUT"
|
||||
echo "OS_VERSION=`lsb_release -s -r`" >> "$GITHUB_OUTPUT"
|
||||
echo "OS_TYPE=`uname -s`" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Pack artifacts
|
||||
id: pack_artifacts
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
run: |
|
||||
cp ggml/LICENSE ./build/bin/ggml.txt
|
||||
cp LICENSE ./build/bin/stable-diffusion.cpp.txt
|
||||
zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm.zip ./build/bin/*
|
||||
|
||||
- name: Upload artifacts
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm.zip
|
||||
path: |
|
||||
sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm.zip
|
||||
|
||||
release:
|
||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||
|
||||
@@ -493,6 +640,7 @@ jobs:
|
||||
needs:
|
||||
- ubuntu-latest-cmake
|
||||
- ubuntu-latest-cmake-vulkan
|
||||
- ubuntu-latest-rocm
|
||||
- build-and-push-docker-images
|
||||
- macOS-latest-cmake
|
||||
- windows-latest-cmake
|
||||
|
||||
@@ -34,6 +34,7 @@ struct Conditioner {
|
||||
virtual void free_params_buffer() = 0;
|
||||
virtual void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) = 0;
|
||||
virtual size_t get_params_buffer_size() = 0;
|
||||
virtual void set_flash_attention_enabled(bool enabled) = 0;
|
||||
virtual void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) {}
|
||||
virtual std::tuple<SDCondition, std::vector<bool>> get_learned_condition_with_trigger(ggml_context* work_ctx,
|
||||
int n_threads,
|
||||
@@ -115,6 +116,13 @@ struct FrozenCLIPEmbedderWithCustomWords : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_flash_attention_enabled(bool enabled) override {
|
||||
text_model->set_flash_attention_enabled(enabled);
|
||||
if (sd_version_is_sdxl(version)) {
|
||||
text_model2->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
text_model->set_weight_adapter(adapter);
|
||||
if (sd_version_is_sdxl(version)) {
|
||||
@@ -783,6 +791,18 @@ struct SD3CLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_flash_attention_enabled(bool enabled) override {
|
||||
if (clip_l) {
|
||||
clip_l->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
if (clip_g) {
|
||||
clip_g->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
if (t5) {
|
||||
t5->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (clip_l) {
|
||||
clip_l->set_weight_adapter(adapter);
|
||||
@@ -1191,6 +1211,15 @@ struct FluxCLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_flash_attention_enabled(bool enabled) override {
|
||||
if (clip_l) {
|
||||
clip_l->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
if (t5) {
|
||||
t5->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) {
|
||||
if (clip_l) {
|
||||
clip_l->set_weight_adapter(adapter);
|
||||
@@ -1440,6 +1469,12 @@ struct T5CLIPEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_flash_attention_enabled(bool enabled) override {
|
||||
if (t5) {
|
||||
t5->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (t5) {
|
||||
t5->set_weight_adapter(adapter);
|
||||
@@ -1650,6 +1685,10 @@ struct LLMEmbedder : public Conditioner {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void set_flash_attention_enabled(bool enabled) override {
|
||||
llm->set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter) override {
|
||||
if (llm) {
|
||||
llm->set_weight_adapter(adapter);
|
||||
|
||||
+7
-7
@@ -38,7 +38,7 @@ struct DiffusionModel {
|
||||
virtual size_t get_params_buffer_size() = 0;
|
||||
virtual void set_weight_adapter(const std::shared_ptr<WeightAdapter>& adapter){};
|
||||
virtual int64_t get_adm_in_channels() = 0;
|
||||
virtual void set_flash_attn_enabled(bool enabled) = 0;
|
||||
virtual void set_flash_attention_enabled(bool enabled) = 0;
|
||||
virtual void set_circular_axes(bool circular_x, bool circular_y) = 0;
|
||||
};
|
||||
|
||||
@@ -84,7 +84,7 @@ struct UNetModel : public DiffusionModel {
|
||||
return unet.unet.adm_in_channels;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
unet.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ struct MMDiTModel : public DiffusionModel {
|
||||
return 768 + 1280;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
mmdit.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ struct FluxModel : public DiffusionModel {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
flux.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ struct WanModel : public DiffusionModel {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
wan.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ struct QwenImageModel : public DiffusionModel {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
qwen_image.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ struct ZImageModel : public DiffusionModel {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void set_flash_attn_enabled(bool enabled) {
|
||||
void set_flash_attention_enabled(bool enabled) {
|
||||
z_image.set_flash_attention_enabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ Context Options:
|
||||
--control-net-cpu keep controlnet in cpu (for low vram)
|
||||
--clip-on-cpu keep clip in cpu (for low vram)
|
||||
--vae-on-cpu keep vae in cpu (for low vram)
|
||||
--diffusion-fa use flash attention in the diffusion model
|
||||
--fa use flash attention
|
||||
--diffusion-fa use flash attention in the diffusion model only
|
||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||
--circular enable circular padding for convolutions
|
||||
|
||||
+26
-11
@@ -394,12 +394,15 @@ bool save_results(const SDCliParams& cli_params,
|
||||
|
||||
fs::path base_path = out_path;
|
||||
fs::path ext = out_path.has_extension() ? out_path.extension() : fs::path{};
|
||||
if (!ext.empty())
|
||||
base_path.replace_extension();
|
||||
|
||||
std::string ext_lower = ext.string();
|
||||
std::transform(ext_lower.begin(), ext_lower.end(), ext_lower.begin(), ::tolower);
|
||||
bool is_jpg = (ext_lower == ".jpg" || ext_lower == ".jpeg" || ext_lower == ".jpe");
|
||||
if (!ext.empty()) {
|
||||
if (is_jpg || ext_lower == ".png") {
|
||||
base_path.replace_extension();
|
||||
}
|
||||
}
|
||||
|
||||
int output_begin_idx = cli_params.output_begin_idx;
|
||||
if (output_begin_idx < 0) {
|
||||
@@ -409,7 +412,7 @@ bool save_results(const SDCliParams& cli_params,
|
||||
auto write_image = [&](const fs::path& path, int idx) {
|
||||
const sd_image_t& img = results[idx];
|
||||
if (!img.data)
|
||||
return;
|
||||
return false;
|
||||
|
||||
std::string params = get_image_params(cli_params, ctx_params, gen_params, gen_params.seed + idx);
|
||||
int ok = 0;
|
||||
@@ -419,8 +422,11 @@ bool save_results(const SDCliParams& cli_params,
|
||||
ok = stbi_write_png(path.string().c_str(), img.width, img.height, img.channel, img.data, 0, params.c_str());
|
||||
}
|
||||
LOG_INFO("save result image %d to '%s' (%s)", idx, path.string().c_str(), ok ? "success" : "failure");
|
||||
return ok != 0;
|
||||
};
|
||||
|
||||
int sucessful_reults = 0;
|
||||
|
||||
if (std::regex_search(cli_params.output_path, format_specifier_regex)) {
|
||||
if (!is_jpg && ext_lower != ".png")
|
||||
ext = ".png";
|
||||
@@ -429,9 +435,12 @@ bool save_results(const SDCliParams& cli_params,
|
||||
|
||||
for (int i = 0; i < num_results; ++i) {
|
||||
fs::path img_path = format_frame_idx(pattern.string(), output_begin_idx + i);
|
||||
write_image(img_path, i);
|
||||
if (write_image(img_path, i)) {
|
||||
sucessful_reults++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
LOG_INFO("%d/%d images saved", sucessful_reults, num_results);
|
||||
return sucessful_reults != 0;
|
||||
}
|
||||
|
||||
if (cli_params.mode == VID_GEN && num_results > 1) {
|
||||
@@ -439,9 +448,13 @@ bool save_results(const SDCliParams& cli_params,
|
||||
ext = ".avi";
|
||||
fs::path video_path = base_path;
|
||||
video_path += ext;
|
||||
create_mjpg_avi_from_sd_images(video_path.string().c_str(), results, num_results, gen_params.fps);
|
||||
LOG_INFO("save result MJPG AVI video to '%s'", video_path.string().c_str());
|
||||
return true;
|
||||
if (create_mjpg_avi_from_sd_images(video_path.string().c_str(), results, num_results, gen_params.fps) == 0) {
|
||||
LOG_INFO("save result MJPG AVI video to '%s'", video_path.string().c_str());
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERROR("Failed to save result MPG AVI video to '%s'", video_path.string().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_jpg && ext_lower != ".png")
|
||||
@@ -453,10 +466,12 @@ bool save_results(const SDCliParams& cli_params,
|
||||
img_path += "_" + std::to_string(output_begin_idx + i);
|
||||
}
|
||||
img_path += ext;
|
||||
write_image(img_path, i);
|
||||
if (write_image(img_path, i)) {
|
||||
sucessful_reults++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
LOG_INFO("%d/%d images saved", sucessful_reults, num_results);
|
||||
return sucessful_reults != 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
||||
@@ -457,6 +457,7 @@ struct SDContextParams {
|
||||
bool control_net_cpu = false;
|
||||
bool clip_on_cpu = false;
|
||||
bool vae_on_cpu = false;
|
||||
bool flash_attn = false;
|
||||
bool diffusion_flash_attn = false;
|
||||
bool diffusion_conv_direct = false;
|
||||
bool vae_conv_direct = false;
|
||||
@@ -615,9 +616,13 @@ struct SDContextParams {
|
||||
"--vae-on-cpu",
|
||||
"keep vae in cpu (for low vram)",
|
||||
true, &vae_on_cpu},
|
||||
{"",
|
||||
"--fa",
|
||||
"use flash attention",
|
||||
true, &flash_attn},
|
||||
{"",
|
||||
"--diffusion-fa",
|
||||
"use flash attention in the diffusion model",
|
||||
"use flash attention in the diffusion model only",
|
||||
true, &diffusion_flash_attn},
|
||||
{"",
|
||||
"--diffusion-conv-direct",
|
||||
@@ -904,6 +909,7 @@ struct SDContextParams {
|
||||
<< " control_net_cpu: " << (control_net_cpu ? "true" : "false") << ",\n"
|
||||
<< " clip_on_cpu: " << (clip_on_cpu ? "true" : "false") << ",\n"
|
||||
<< " vae_on_cpu: " << (vae_on_cpu ? "true" : "false") << ",\n"
|
||||
<< " flash_attn: " << (flash_attn ? "true" : "false") << ",\n"
|
||||
<< " diffusion_flash_attn: " << (diffusion_flash_attn ? "true" : "false") << ",\n"
|
||||
<< " diffusion_conv_direct: " << (diffusion_conv_direct ? "true" : "false") << ",\n"
|
||||
<< " vae_conv_direct: " << (vae_conv_direct ? "true" : "false") << ",\n"
|
||||
@@ -968,6 +974,7 @@ struct SDContextParams {
|
||||
clip_on_cpu,
|
||||
control_net_cpu,
|
||||
vae_on_cpu,
|
||||
flash_attn,
|
||||
diffusion_flash_attn,
|
||||
taesd_preview,
|
||||
diffusion_conv_direct,
|
||||
|
||||
@@ -44,7 +44,8 @@ Context Options:
|
||||
--clip-on-cpu keep clip in cpu (for low vram)
|
||||
--vae-on-cpu keep vae in cpu (for low vram)
|
||||
--mmap whether to memory-map model
|
||||
--diffusion-fa use flash attention in the diffusion model
|
||||
--fa use flash attention
|
||||
--diffusion-fa use flash attention in the diffusion model only
|
||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||
--circular enable circular padding for convolutions
|
||||
|
||||
+115
-15
@@ -263,6 +263,11 @@ void sd_log_cb(enum sd_log_level_t level, const char* log, void* data) {
|
||||
log_print(level, log, svr_params->verbose, svr_params->color);
|
||||
}
|
||||
|
||||
struct LoraEntry {
|
||||
std::string name;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
if (argc > 1 && std::string(argv[1]) == "--version") {
|
||||
std::cout << version_string() << "\n";
|
||||
@@ -293,6 +298,54 @@ int main(int argc, const char** argv) {
|
||||
|
||||
std::mutex sd_ctx_mutex;
|
||||
|
||||
std::vector<LoraEntry> lora_cache;
|
||||
std::mutex lora_mutex;
|
||||
|
||||
auto refresh_lora_cache = [&]() {
|
||||
std::vector<LoraEntry> new_cache;
|
||||
|
||||
fs::path lora_dir = ctx_params.lora_model_dir;
|
||||
if (fs::exists(lora_dir) && fs::is_directory(lora_dir)) {
|
||||
auto is_lora_ext = [](const fs::path& p) {
|
||||
auto ext = p.extension().string();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
return ext == ".gguf" || ext == ".pt" || ext == ".pth" || ext == ".safetensors";
|
||||
};
|
||||
|
||||
for (auto& entry : fs::recursive_directory_iterator(lora_dir)) {
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
const fs::path& p = entry.path();
|
||||
if (!is_lora_ext(p))
|
||||
continue;
|
||||
|
||||
LoraEntry e;
|
||||
e.name = p.stem().u8string();
|
||||
std::string rel = fs::relative(p, lora_dir).u8string();
|
||||
std::replace(rel.begin(), rel.end(), '\\', '/');
|
||||
e.path = rel;
|
||||
|
||||
new_cache.push_back(std::move(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(new_cache.begin(), new_cache.end(),
|
||||
[](const LoraEntry& a, const LoraEntry& b) {
|
||||
return a.path < b.path;
|
||||
});
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||
lora_cache = std::move(new_cache);
|
||||
}
|
||||
};
|
||||
|
||||
auto is_valid_lora_path = [&](const std::string& path) -> bool {
|
||||
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||
return std::any_of(lora_cache.begin(), lora_cache.end(),
|
||||
[&](const LoraEntry& e) { return e.path == path; });
|
||||
};
|
||||
|
||||
httplib::Server svr;
|
||||
|
||||
svr.set_pre_routing_handler([](const httplib::Request& req, httplib::Response& res) {
|
||||
@@ -312,7 +365,7 @@ int main(int argc, const char** argv) {
|
||||
return httplib::Server::HandlerResponse::Unhandled;
|
||||
});
|
||||
|
||||
// health
|
||||
// root
|
||||
svr.Get("/", [&](const httplib::Request&, httplib::Response& res) {
|
||||
if (!svr_params.serve_html_path.empty()) {
|
||||
std::ifstream file(svr_params.serve_html_path);
|
||||
@@ -733,8 +786,8 @@ int main(int argc, const char** argv) {
|
||||
std::string negative_prompt = j.value("negative_prompt", "");
|
||||
int width = j.value("width", 512);
|
||||
int height = j.value("height", 512);
|
||||
int steps = j.value("steps", -1);
|
||||
float cfg_scale = j.value("cfg_scale", 7.f);
|
||||
int steps = j.value("steps", default_gen_params.sample_params.sample_steps);
|
||||
float cfg_scale = j.value("cfg_scale", default_gen_params.sample_params.guidance.txt_cfg);
|
||||
int64_t seed = j.value("seed", -1);
|
||||
int batch_size = j.value("batch_size", 1);
|
||||
int clip_skip = j.value("clip_skip", -1);
|
||||
@@ -767,6 +820,37 @@ int main(int argc, const char** argv) {
|
||||
return bad("prompt required");
|
||||
}
|
||||
|
||||
std::vector<sd_lora_t> sd_loras;
|
||||
std::vector<std::string> lora_path_storage;
|
||||
|
||||
if (j.contains("lora") && j["lora"].is_array()) {
|
||||
for (const auto& item : j["lora"]) {
|
||||
if (!item.is_object()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string path = item.value("path", "");
|
||||
float multiplier = item.value("multiplier", 1.0f);
|
||||
bool is_high_noise = item.value("is_high_noise", false);
|
||||
|
||||
if (path.empty()) {
|
||||
return bad("lora.path required");
|
||||
}
|
||||
|
||||
if (!is_valid_lora_path(path)) {
|
||||
return bad("invalid lora path: " + path);
|
||||
}
|
||||
|
||||
lora_path_storage.push_back(path);
|
||||
sd_lora_t l;
|
||||
l.is_high_noise = is_high_noise;
|
||||
l.multiplier = multiplier;
|
||||
l.path = lora_path_storage.back().c_str();
|
||||
|
||||
sd_loras.push_back(l);
|
||||
}
|
||||
}
|
||||
|
||||
auto get_sample_method = [](std::string name) -> enum sample_method_t {
|
||||
enum sample_method_t result = str_to_sample_method(name.c_str());
|
||||
if (result != SAMPLE_METHOD_COUNT) return result;
|
||||
@@ -799,16 +883,15 @@ int main(int argc, const char** argv) {
|
||||
|
||||
enum scheduler_t scheduler = str_to_scheduler(scheduler_name.c_str());
|
||||
|
||||
// avoid excessive resource usage
|
||||
|
||||
SDGenerationParams gen_params = default_gen_params;
|
||||
gen_params.prompt = prompt;
|
||||
gen_params.negative_prompt = negative_prompt;
|
||||
gen_params.width = width;
|
||||
gen_params.height = height;
|
||||
gen_params.seed = seed;
|
||||
gen_params.sample_params.sample_steps = steps;
|
||||
gen_params.batch_count = batch_size;
|
||||
SDGenerationParams gen_params = default_gen_params;
|
||||
gen_params.prompt = prompt;
|
||||
gen_params.negative_prompt = negative_prompt;
|
||||
gen_params.width = width;
|
||||
gen_params.height = height;
|
||||
gen_params.seed = seed;
|
||||
gen_params.sample_params.sample_steps = steps;
|
||||
gen_params.batch_count = batch_size;
|
||||
gen_params.sample_params.guidance.txt_cfg = cfg_scale;
|
||||
|
||||
if (clip_skip > 0) {
|
||||
gen_params.clip_skip = clip_skip;
|
||||
@@ -894,8 +977,8 @@ int main(int argc, const char** argv) {
|
||||
}
|
||||
|
||||
sd_img_gen_params_t img_gen_params = {
|
||||
gen_params.lora_vec.data(),
|
||||
static_cast<uint32_t>(gen_params.lora_vec.size()),
|
||||
sd_loras.data(),
|
||||
static_cast<uint32_t>(sd_loras.size()),
|
||||
gen_params.prompt.c_str(),
|
||||
gen_params.negative_prompt.c_str(),
|
||||
gen_params.clip_skip,
|
||||
@@ -987,6 +1070,23 @@ int main(int argc, const char** argv) {
|
||||
sdapi_any2img(req, res, true);
|
||||
});
|
||||
|
||||
svr.Get("/sdapi/v1/loras", [&](const httplib::Request&, httplib::Response& res) {
|
||||
refresh_lora_cache();
|
||||
|
||||
json result = json::array();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lora_mutex);
|
||||
for (const auto& e : lora_cache) {
|
||||
json item;
|
||||
item["name"] = e.name;
|
||||
item["path"] = e.path;
|
||||
result.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
res.set_content(result.dump(), "application/json");
|
||||
});
|
||||
|
||||
svr.Get("/sdapi/v1/samplers", [&](const httplib::Request&, httplib::Response& res) {
|
||||
std::vector<std::string> sampler_names;
|
||||
sampler_names.push_back("default");
|
||||
|
||||
+1
-1
Submodule ggml updated: 8891ab6fc7...a8db410a25
+180
-8
@@ -767,7 +767,7 @@ __STATIC_INLINE__ ggml_tensor* ggml_ext_silu_act(ggml_context* ctx, ggml_tensor*
|
||||
return x;
|
||||
}
|
||||
|
||||
typedef std::function<void(ggml_tensor*, ggml_tensor*, bool)> on_tile_process;
|
||||
typedef std::function<bool(ggml_tensor*, ggml_tensor*, bool)> on_tile_process;
|
||||
|
||||
__STATIC_INLINE__ void sd_tiling_calc_tiles(int& num_tiles_dim,
|
||||
float& tile_overlap_factor_dim,
|
||||
@@ -918,12 +918,15 @@ __STATIC_INLINE__ void sd_tiling_non_square(ggml_tensor* input,
|
||||
|
||||
int64_t t1 = ggml_time_ms();
|
||||
ggml_ext_tensor_split_2d(input, input_tile, x_in, y_in);
|
||||
on_processing(input_tile, output_tile, false);
|
||||
ggml_ext_tensor_merge_2d(output_tile, output, x_out, y_out, overlap_x_out, overlap_y_out, dx, dy);
|
||||
if (on_processing(input_tile, output_tile, false)) {
|
||||
ggml_ext_tensor_merge_2d(output_tile, output, x_out, y_out, overlap_x_out, overlap_y_out, dx, dy);
|
||||
|
||||
int64_t t2 = ggml_time_ms();
|
||||
last_time = (t2 - t1) / 1000.0f;
|
||||
pretty_progress(tile_count, num_tiles, last_time);
|
||||
int64_t t2 = ggml_time_ms();
|
||||
last_time = (t2 - t1) / 1000.0f;
|
||||
pretty_progress(tile_count, num_tiles, last_time);
|
||||
} else {
|
||||
LOG_ERROR("Failed to process patch %d at (%d, %d)", tile_count, x, y);
|
||||
}
|
||||
tile_count++;
|
||||
}
|
||||
last_x = false;
|
||||
@@ -1577,7 +1580,7 @@ struct WeightAdapter {
|
||||
bool force_prec_f32 = false;
|
||||
float scale = 1.f;
|
||||
} linear;
|
||||
struct {
|
||||
struct conv2d_params_t {
|
||||
int s0 = 1;
|
||||
int s1 = 1;
|
||||
int p0 = 0;
|
||||
@@ -2623,11 +2626,180 @@ public:
|
||||
v = v_proj->forward(ctx, x);
|
||||
}
|
||||
|
||||
x = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, n_head, mask); // [N, n_token, embed_dim]
|
||||
x = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, n_head, mask, false); // [N, n_token, embed_dim]
|
||||
|
||||
x = out_proj->forward(ctx, x); // [N, n_token, embed_dim]
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
__STATIC_INLINE__ struct ggml_tensor* ggml_ext_lokr_forward(
|
||||
struct ggml_context* ctx,
|
||||
struct ggml_tensor* h, // Input: [q, batch] or [W, H, q, batch]
|
||||
struct ggml_tensor* w1, // Outer C (Full rank)
|
||||
struct ggml_tensor* w1a, // Outer A (Low rank part 1)
|
||||
struct ggml_tensor* w1b, // Outer B (Low rank part 2)
|
||||
struct ggml_tensor* w2, // Inner BA (Full rank)
|
||||
struct ggml_tensor* w2a, // Inner A (Low rank part 1)
|
||||
struct ggml_tensor* w2b, // Inner B (Low rank part 2)
|
||||
bool is_conv,
|
||||
WeightAdapter::ForwardParams::conv2d_params_t conv_params,
|
||||
float scale) {
|
||||
GGML_ASSERT((w1 != NULL || (w1a != NULL && w1b != NULL)));
|
||||
GGML_ASSERT((w2 != NULL || (w2a != NULL && w2b != NULL)));
|
||||
|
||||
int uq = (w1 != NULL) ? (int)w1->ne[0] : (int)w1a->ne[0];
|
||||
int up = (w1 != NULL) ? (int)w1->ne[1] : (int)w1b->ne[1];
|
||||
|
||||
int q_actual = is_conv ? (int)h->ne[2] : (int)h->ne[0];
|
||||
int vq = q_actual / uq;
|
||||
|
||||
int vp = (w2 != NULL) ? (is_conv ? (int)w2->ne[3] : (int)w2->ne[1])
|
||||
: (int)w2a->ne[1];
|
||||
GGML_ASSERT(q_actual == (uq * vq) && "Input dimension mismatch for LoKR split");
|
||||
|
||||
struct ggml_tensor* hb;
|
||||
|
||||
if (!is_conv) {
|
||||
int batch = (int)h->ne[1];
|
||||
int merge_batch_uq = batch;
|
||||
int merge_batch_vp = batch;
|
||||
|
||||
#if SD_USE_VULKAN
|
||||
if (batch > 1) {
|
||||
// no access to backend here, worst case is slightly worse perfs for other backends when built alongside Vulkan backend
|
||||
int max_batch = 65535;
|
||||
int max_batch_uq = max_batch / uq;
|
||||
merge_batch_uq = 1;
|
||||
for (int i = max_batch_uq; i > 0; i--) {
|
||||
if (batch % i == 0) {
|
||||
merge_batch_uq = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int max_batch_vp = max_batch / vp;
|
||||
merge_batch_vp = 1;
|
||||
for (int i = max_batch_vp; i > 0; i--) {
|
||||
if (batch % i == 0) {
|
||||
merge_batch_vp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ggml_tensor* h_split = ggml_reshape_3d(ctx, h, vq, uq * merge_batch_uq, batch / merge_batch_uq);
|
||||
if (w2 != NULL) {
|
||||
hb = ggml_mul_mat(ctx, w2, h_split);
|
||||
} else {
|
||||
hb = ggml_mul_mat(ctx, w2b, ggml_mul_mat(ctx, w2a, h_split));
|
||||
}
|
||||
|
||||
if (batch > 1) {
|
||||
hb = ggml_reshape_3d(ctx, hb, vp, uq, batch);
|
||||
}
|
||||
struct ggml_tensor* hb_t = ggml_cont(ctx, ggml_transpose(ctx, hb));
|
||||
hb_t = ggml_reshape_3d(ctx, hb_t, uq, vp * merge_batch_vp, batch / merge_batch_vp);
|
||||
|
||||
struct ggml_tensor* hc_t;
|
||||
if (w1 != NULL) {
|
||||
hc_t = ggml_mul_mat(ctx, w1, hb_t);
|
||||
} else {
|
||||
hc_t = ggml_mul_mat(ctx, w1b, ggml_mul_mat(ctx, w1a, hb_t));
|
||||
}
|
||||
|
||||
if (batch > 1) {
|
||||
hc_t = ggml_reshape_3d(ctx, hc_t, up, vp, batch);
|
||||
}
|
||||
|
||||
struct ggml_tensor* hc = ggml_transpose(ctx, hc_t);
|
||||
struct ggml_tensor* out = ggml_reshape_2d(ctx, ggml_cont(ctx, hc), up * vp, batch);
|
||||
return ggml_scale(ctx, out, scale);
|
||||
} else {
|
||||
int batch = (int)h->ne[3];
|
||||
// 1. Reshape input: [W, H, vq*uq, batch] -> [W, H, vq, uq * batch]
|
||||
struct ggml_tensor* h_split = ggml_reshape_4d(ctx, h, h->ne[0], h->ne[1], vq, uq * batch);
|
||||
|
||||
if (w2 != NULL) {
|
||||
hb = ggml_ext_conv_2d(ctx, h_split, w2, nullptr,
|
||||
conv_params.s0,
|
||||
conv_params.s1,
|
||||
conv_params.p0,
|
||||
conv_params.p1,
|
||||
conv_params.d0,
|
||||
conv_params.d1,
|
||||
conv_params.direct,
|
||||
conv_params.circular_x,
|
||||
conv_params.circular_y,
|
||||
conv_params.scale);
|
||||
} else {
|
||||
// swap a and b order for conv lora
|
||||
struct ggml_tensor* a = w2b;
|
||||
struct ggml_tensor* b = w2a;
|
||||
|
||||
// unpack conv2d weights if needed
|
||||
if (ggml_n_dims(a) < 4) {
|
||||
int k = (int)sqrt(a->ne[0] / h_split->ne[2]);
|
||||
GGML_ASSERT(k * k * h_split->ne[2] == a->ne[0]);
|
||||
a = ggml_reshape_4d(ctx, a, k, k, a->ne[0] / (k * k), a->ne[1]);
|
||||
} else if (a->ne[2] != h_split->ne[2]) {
|
||||
int k = (int)sqrt(a->ne[2] / h_split->ne[2]);
|
||||
GGML_ASSERT(k * k * h_split->ne[2] == a->ne[2]);
|
||||
a = ggml_reshape_4d(ctx, a, a->ne[0] * k, a->ne[1] * k, a->ne[2] / (k * k), a->ne[3]);
|
||||
}
|
||||
struct ggml_tensor* ha = ggml_ext_conv_2d(ctx, h_split, a, nullptr,
|
||||
conv_params.s0,
|
||||
conv_params.s1,
|
||||
conv_params.p0,
|
||||
conv_params.p1,
|
||||
conv_params.d0,
|
||||
conv_params.d1,
|
||||
conv_params.direct,
|
||||
conv_params.circular_x,
|
||||
conv_params.circular_y,
|
||||
conv_params.scale);
|
||||
|
||||
// not supporting lora_mid here
|
||||
hb = ggml_ext_conv_2d(ctx,
|
||||
ha,
|
||||
b,
|
||||
nullptr,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
conv_params.direct,
|
||||
conv_params.circular_x,
|
||||
conv_params.circular_y,
|
||||
conv_params.scale);
|
||||
}
|
||||
|
||||
// Current hb shape: [W_out, H_out, vp, uq * batch]
|
||||
int w_out = (int)hb->ne[0];
|
||||
int h_out = (int)hb->ne[1];
|
||||
|
||||
// struct ggml_tensor* hb_cat = ggml_reshape_4d(ctx, hb, w_out , h_out , vp * uq, batch);
|
||||
// [W_out, H_out, vp * uq, batch]
|
||||
// Now left to compute (W1 kr Id) * hb_cat == (W1 kr W2) cv h
|
||||
|
||||
// merge the uq groups of size vp*w_out*h_out
|
||||
struct ggml_tensor* hb_merged = ggml_reshape_2d(ctx, hb, w_out * h_out * vp, uq * batch);
|
||||
struct ggml_tensor* hc_t;
|
||||
struct ggml_tensor* hb_merged_t = ggml_cont(ctx, ggml_transpose(ctx, hb_merged));
|
||||
if (w1 != NULL) {
|
||||
// Would be great to be able to transpose w1 instead to avoid transposing both hb and hc
|
||||
hc_t = ggml_mul_mat(ctx, w1, hb_merged_t);
|
||||
} else {
|
||||
hc_t = ggml_mul_mat(ctx, w1b, ggml_mul_mat(ctx, w1a, hb_merged_t));
|
||||
}
|
||||
struct ggml_tensor* hc = ggml_transpose(ctx, hc_t);
|
||||
// ungroup
|
||||
struct ggml_tensor* out = ggml_reshape_4d(ctx, ggml_cont(ctx, hc), w_out, h_out, up * vp, batch);
|
||||
return ggml_scale(ctx, out, scale);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __GGML_EXTEND__HPP__
|
||||
|
||||
@@ -468,10 +468,10 @@ struct LoraModel : public GGMLRunner {
|
||||
return updown;
|
||||
}
|
||||
|
||||
ggml_tensor* get_weight_diff(const std::string& model_tensor_name, ggml_context* ctx, ggml_tensor* model_tensor, bool with_lora = true) {
|
||||
ggml_tensor* get_weight_diff(const std::string& model_tensor_name, ggml_context* ctx, ggml_tensor* model_tensor, bool with_lora_and_lokr = true) {
|
||||
// lora
|
||||
ggml_tensor* diff = nullptr;
|
||||
if (with_lora) {
|
||||
if (with_lora_and_lokr) {
|
||||
diff = get_lora_weight_diff(model_tensor_name, ctx);
|
||||
}
|
||||
// diff
|
||||
@@ -483,7 +483,7 @@ struct LoraModel : public GGMLRunner {
|
||||
diff = get_loha_weight_diff(model_tensor_name, ctx);
|
||||
}
|
||||
// lokr
|
||||
if (diff == nullptr) {
|
||||
if (diff == nullptr && with_lora_and_lokr) {
|
||||
diff = get_lokr_weight_diff(model_tensor_name, ctx);
|
||||
}
|
||||
if (diff != nullptr) {
|
||||
@@ -514,6 +514,108 @@ struct LoraModel : public GGMLRunner {
|
||||
} else {
|
||||
key = model_tensor_name + "." + std::to_string(index);
|
||||
}
|
||||
bool is_conv2d = forward_params.op_type == WeightAdapter::ForwardParams::op_type_t::OP_CONV2D;
|
||||
|
||||
std::string lokr_w1_name = "lora." + key + ".lokr_w1";
|
||||
std::string lokr_w1_a_name = "lora." + key + ".lokr_w1_a";
|
||||
// if either of these is found, then we have a lokr lora
|
||||
auto iter = lora_tensors.find(lokr_w1_name);
|
||||
auto iter_a = lora_tensors.find(lokr_w1_a_name);
|
||||
if (iter != lora_tensors.end() || iter_a != lora_tensors.end()) {
|
||||
std::string lokr_w1_b_name = "lora." + key + ".lokr_w1_b";
|
||||
std::string lokr_w2_name = "lora." + key + ".lokr_w2";
|
||||
std::string lokr_w2_a_name = "lora." + key + ".lokr_w2_a";
|
||||
std::string lokr_w2_b_name = "lora." + key + ".lokr_w2_b";
|
||||
std::string alpha_name = "lora." + key + ".alpha";
|
||||
|
||||
ggml_tensor* lokr_w1 = nullptr;
|
||||
ggml_tensor* lokr_w1_a = nullptr;
|
||||
ggml_tensor* lokr_w1_b = nullptr;
|
||||
ggml_tensor* lokr_w2 = nullptr;
|
||||
ggml_tensor* lokr_w2_a = nullptr;
|
||||
ggml_tensor* lokr_w2_b = nullptr;
|
||||
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w1 = iter->second;
|
||||
}
|
||||
iter = iter_a;
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w1_a = iter->second;
|
||||
}
|
||||
iter = lora_tensors.find(lokr_w1_b_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w1_b = iter->second;
|
||||
}
|
||||
|
||||
iter = lora_tensors.find(lokr_w2_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w2 = iter->second;
|
||||
if (is_conv2d && lokr_w2->type != GGML_TYPE_F16) {
|
||||
lokr_w2 = ggml_cast(ctx, lokr_w2, GGML_TYPE_F16);
|
||||
}
|
||||
}
|
||||
iter = lora_tensors.find(lokr_w2_a_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w2_a = iter->second;
|
||||
if (is_conv2d && lokr_w2_a->type != GGML_TYPE_F16) {
|
||||
lokr_w2_a = ggml_cast(ctx, lokr_w2_a, GGML_TYPE_F16);
|
||||
}
|
||||
}
|
||||
iter = lora_tensors.find(lokr_w2_b_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
lokr_w2_b = iter->second;
|
||||
if (is_conv2d && lokr_w2_b->type != GGML_TYPE_F16) {
|
||||
lokr_w2_b = ggml_cast(ctx, lokr_w2_b, GGML_TYPE_F16);
|
||||
}
|
||||
}
|
||||
|
||||
int rank = 1;
|
||||
if (lokr_w1_b) {
|
||||
rank = (int)lokr_w1_b->ne[ggml_n_dims(lokr_w1_b) - 1];
|
||||
}
|
||||
if (lokr_w2_b) {
|
||||
rank = (int)lokr_w2_b->ne[ggml_n_dims(lokr_w2_b) - 1];
|
||||
}
|
||||
|
||||
float scale_value = 1.0f;
|
||||
iter = lora_tensors.find(alpha_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(iter->second);
|
||||
scale_value = alpha / rank;
|
||||
applied_lora_tensors.insert(alpha_name);
|
||||
}
|
||||
|
||||
if (rank == 1) {
|
||||
scale_value = 1.0f;
|
||||
}
|
||||
scale_value *= multiplier;
|
||||
|
||||
auto curr_out_diff = ggml_ext_lokr_forward(ctx, x, lokr_w1, lokr_w1_a, lokr_w1_b, lokr_w2, lokr_w2_a, lokr_w2_b, is_conv2d, forward_params.conv2d, scale_value);
|
||||
if (out_diff == nullptr) {
|
||||
out_diff = curr_out_diff;
|
||||
} else {
|
||||
out_diff = ggml_concat(ctx, out_diff, curr_out_diff, 0);
|
||||
}
|
||||
|
||||
if (lokr_w1)
|
||||
applied_lora_tensors.insert(lokr_w1_name);
|
||||
if (lokr_w1_a)
|
||||
applied_lora_tensors.insert(lokr_w1_a_name);
|
||||
if (lokr_w1_b)
|
||||
applied_lora_tensors.insert(lokr_w1_b_name);
|
||||
if (lokr_w2)
|
||||
applied_lora_tensors.insert(lokr_w2_name);
|
||||
if (lokr_w2_a)
|
||||
applied_lora_tensors.insert(lokr_w2_name);
|
||||
if (lokr_w2_b)
|
||||
applied_lora_tensors.insert(lokr_w2_b_name);
|
||||
applied_lora_tensors.insert(alpha_name);
|
||||
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// not a lokr, normal lora path
|
||||
|
||||
std::string lora_down_name = "lora." + key + ".lora_down";
|
||||
std::string lora_up_name = "lora." + key + ".lora_up";
|
||||
@@ -525,9 +627,7 @@ struct LoraModel : public GGMLRunner {
|
||||
ggml_tensor* lora_mid = nullptr;
|
||||
ggml_tensor* lora_down = nullptr;
|
||||
|
||||
bool is_conv2d = forward_params.op_type == WeightAdapter::ForwardParams::op_type_t::OP_CONV2D;
|
||||
|
||||
auto iter = lora_tensors.find(lora_up_name);
|
||||
iter = lora_tensors.find(lora_up_name);
|
||||
if (iter != lora_tensors.end()) {
|
||||
lora_up = iter->second;
|
||||
if (is_conv2d && lora_up->type != GGML_TYPE_F16) {
|
||||
@@ -741,9 +841,9 @@ public:
|
||||
: lora_models(lora_models) {
|
||||
}
|
||||
|
||||
ggml_tensor* patch_weight(ggml_context* ctx, ggml_tensor* weight, const std::string& weight_name, bool with_lora) {
|
||||
ggml_tensor* patch_weight(ggml_context* ctx, ggml_tensor* weight, const std::string& weight_name, bool with_lora_and_lokr) {
|
||||
for (auto& lora_model : lora_models) {
|
||||
ggml_tensor* diff = lora_model->get_weight_diff(weight_name, ctx, weight, with_lora);
|
||||
ggml_tensor* diff = lora_model->get_weight_diff(weight_name, ctx, weight, with_lora_and_lokr);
|
||||
if (diff == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ namespace Qwen {
|
||||
|
||||
blocks["txt_norm1"] = std::shared_ptr<GGMLBlock>(new LayerNorm(dim, eps, false));
|
||||
blocks["txt_norm2"] = std::shared_ptr<GGMLBlock>(new LayerNorm(dim, eps, false));
|
||||
blocks["txt_mlp"] = std::shared_ptr<GGMLBlock>(new FeedForward(dim, dim, 4, FeedForward::Activation::GELU));
|
||||
blocks["txt_mlp"] = std::shared_ptr<GGMLBlock>(new FeedForward(dim, dim, 4, FeedForward::Activation::GELU, true));
|
||||
|
||||
blocks["attn"] = std::shared_ptr<GGMLBlock>(new QwenImageAttention(dim,
|
||||
attention_head_dim,
|
||||
|
||||
+42
-17
@@ -445,7 +445,7 @@ public:
|
||||
}
|
||||
}
|
||||
if (is_chroma) {
|
||||
if (sd_ctx_params->diffusion_flash_attn && sd_ctx_params->chroma_use_dit_mask) {
|
||||
if ((sd_ctx_params->flash_attn || 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. "
|
||||
@@ -571,14 +571,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (sd_ctx_params->diffusion_flash_attn) {
|
||||
LOG_INFO("Using flash attention in the diffusion model");
|
||||
diffusion_model->set_flash_attn_enabled(true);
|
||||
if (high_noise_diffusion_model) {
|
||||
high_noise_diffusion_model->set_flash_attn_enabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
cond_stage_model->alloc_params_buffer();
|
||||
cond_stage_model->get_param_tensors(tensors);
|
||||
|
||||
@@ -725,6 +717,28 @@ public:
|
||||
pmid_model->get_param_tensors(tensors, "pmid");
|
||||
}
|
||||
|
||||
if (sd_ctx_params->flash_attn) {
|
||||
LOG_INFO("Using flash attention");
|
||||
cond_stage_model->set_flash_attention_enabled(true);
|
||||
if (clip_vision) {
|
||||
clip_vision->set_flash_attention_enabled(true);
|
||||
}
|
||||
if (first_stage_model) {
|
||||
first_stage_model->set_flash_attention_enabled(true);
|
||||
}
|
||||
if (tae_first_stage) {
|
||||
tae_first_stage->set_flash_attention_enabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (sd_ctx_params->flash_attn || sd_ctx_params->diffusion_flash_attn) {
|
||||
LOG_INFO("Using flash attention in the diffusion model");
|
||||
diffusion_model->set_flash_attention_enabled(true);
|
||||
if (high_noise_diffusion_model) {
|
||||
high_noise_diffusion_model->set_flash_attention_enabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
diffusion_model->set_circular_axes(sd_ctx_params->circular_x, sd_ctx_params->circular_y);
|
||||
if (high_noise_diffusion_model) {
|
||||
high_noise_diffusion_model->set_circular_axes(sd_ctx_params->circular_x, sd_ctx_params->circular_y);
|
||||
@@ -1544,7 +1558,7 @@ public:
|
||||
if (vae_tiling_params.enabled) {
|
||||
// split latent in 32x32 tiles and compute in several steps
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
first_stage_model->compute(n_threads, in, true, &out, nullptr);
|
||||
return first_stage_model->compute(n_threads, in, true, &out, nullptr);
|
||||
};
|
||||
silent_tiling(latents, result, get_vae_scale_factor(), 32, 0.5f, on_tiling);
|
||||
|
||||
@@ -1563,7 +1577,7 @@ public:
|
||||
if (vae_tiling_params.enabled) {
|
||||
// split latent in 64x64 tiles and compute in several steps
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
tae_first_stage->compute(n_threads, in, true, &out, nullptr);
|
||||
return tae_first_stage->compute(n_threads, in, true, &out, nullptr);
|
||||
};
|
||||
silent_tiling(latents, result, get_vae_scale_factor(), 64, 0.5f, on_tiling);
|
||||
} else {
|
||||
@@ -2532,7 +2546,7 @@ public:
|
||||
LOG_DEBUG("VAE Tile size: %dx%d", tile_size_x, tile_size_y);
|
||||
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
first_stage_model->compute(n_threads, in, false, &out, work_ctx);
|
||||
return first_stage_model->compute(n_threads, in, false, &out, work_ctx);
|
||||
};
|
||||
sd_tiling_non_square(x, result, vae_scale_factor, tile_size_x, tile_size_y, tile_overlap, on_tiling);
|
||||
} else {
|
||||
@@ -2543,7 +2557,7 @@ public:
|
||||
if (vae_tiling_params.enabled && !encode_video) {
|
||||
// split latent in 32x32 tiles and compute in several steps
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
tae_first_stage->compute(n_threads, in, false, &out, nullptr);
|
||||
return tae_first_stage->compute(n_threads, in, false, &out, nullptr);
|
||||
};
|
||||
sd_tiling(x, result, vae_scale_factor, 64, 0.5f, on_tiling);
|
||||
} else {
|
||||
@@ -2661,11 +2675,15 @@ public:
|
||||
|
||||
// split latent in 32x32 tiles and compute in several steps
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
first_stage_model->compute(n_threads, in, true, &out, nullptr);
|
||||
return first_stage_model->compute(n_threads, in, true, &out, nullptr);
|
||||
};
|
||||
sd_tiling_non_square(x, result, vae_scale_factor, tile_size_x, tile_size_y, tile_overlap, on_tiling);
|
||||
} else {
|
||||
first_stage_model->compute(n_threads, x, true, &result, work_ctx);
|
||||
if(!first_stage_model->compute(n_threads, x, true, &result, work_ctx)){
|
||||
LOG_ERROR("Failed to decode latetnts");
|
||||
first_stage_model->free_compute_buffer();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
first_stage_model->free_compute_buffer();
|
||||
process_vae_output_tensor(result);
|
||||
@@ -2673,11 +2691,15 @@ public:
|
||||
if (vae_tiling_params.enabled) {
|
||||
// split latent in 64x64 tiles and compute in several steps
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
tae_first_stage->compute(n_threads, in, true, &out);
|
||||
return tae_first_stage->compute(n_threads, in, true, &out);
|
||||
};
|
||||
sd_tiling(x, result, vae_scale_factor, 64, 0.5f, on_tiling);
|
||||
} else {
|
||||
tae_first_stage->compute(n_threads, x, true, &result);
|
||||
if(!tae_first_stage->compute(n_threads, x, true, &result)){
|
||||
LOG_ERROR("Failed to decode latetnts");
|
||||
tae_first_stage->free_compute_buffer();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
tae_first_stage->free_compute_buffer();
|
||||
}
|
||||
@@ -2942,6 +2964,7 @@ char* sd_ctx_params_to_str(const sd_ctx_params_t* sd_ctx_params) {
|
||||
"keep_clip_on_cpu: %s\n"
|
||||
"keep_control_net_on_cpu: %s\n"
|
||||
"keep_vae_on_cpu: %s\n"
|
||||
"flash_attn: %s\n"
|
||||
"diffusion_flash_attn: %s\n"
|
||||
"circular_x: %s\n"
|
||||
"circular_y: %s\n"
|
||||
@@ -2973,6 +2996,7 @@ char* sd_ctx_params_to_str(const sd_ctx_params_t* sd_ctx_params) {
|
||||
BOOL_STR(sd_ctx_params->keep_clip_on_cpu),
|
||||
BOOL_STR(sd_ctx_params->keep_control_net_on_cpu),
|
||||
BOOL_STR(sd_ctx_params->keep_vae_on_cpu),
|
||||
BOOL_STR(sd_ctx_params->flash_attn),
|
||||
BOOL_STR(sd_ctx_params->diffusion_flash_attn),
|
||||
BOOL_STR(sd_ctx_params->circular_x),
|
||||
BOOL_STR(sd_ctx_params->circular_y),
|
||||
@@ -3445,6 +3469,7 @@ sd_image_t* generate_image_internal(sd_ctx_t* sd_ctx,
|
||||
ggml_free(work_ctx);
|
||||
return nullptr;
|
||||
}
|
||||
memset(result_images, 0, batch_count * sizeof(sd_image_t));
|
||||
|
||||
for (size_t i = 0; i < decoded_images.size(); i++) {
|
||||
result_images[i].width = width;
|
||||
|
||||
@@ -189,6 +189,7 @@ typedef struct {
|
||||
bool keep_clip_on_cpu;
|
||||
bool keep_control_net_on_cpu;
|
||||
bool keep_vae_on_cpu;
|
||||
bool flash_attn;
|
||||
bool diffusion_flash_attn;
|
||||
bool tae_preview_only;
|
||||
bool diffusion_conv_direct;
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ struct UpscalerGGML {
|
||||
|
||||
ggml_tensor* upscaled = ggml_new_tensor_4d(upscale_ctx, GGML_TYPE_F32, output_width, output_height, 3, 1);
|
||||
auto on_tiling = [&](ggml_tensor* in, ggml_tensor* out, bool init) {
|
||||
esrgan_upscaler->compute(n_threads, in, &out);
|
||||
return esrgan_upscaler->compute(n_threads, in, &out);
|
||||
};
|
||||
int64_t t0 = ggml_time_ms();
|
||||
sd_tiling(input_image_tensor, upscaled, esrgan_upscaler->scale, esrgan_upscaler->tile_size, 0.25f, on_tiling);
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
v = ggml_reshape_3d(ctx->ggml_ctx, v, c, h * w, n); // [N, h * w, in_channels]
|
||||
}
|
||||
|
||||
h_ = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, 1, nullptr, true, false);
|
||||
h_ = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, 1, nullptr, true, ctx->flash_attn_enabled);
|
||||
|
||||
if (use_linear) {
|
||||
h_ = proj_out->forward(ctx, h_); // [N, h * w, in_channels]
|
||||
|
||||
@@ -572,8 +572,8 @@ namespace WAN {
|
||||
auto v = qkv_vec[2];
|
||||
v = ggml_reshape_3d(ctx->ggml_ctx, v, h * w, c, n); // [t, c, h * w]
|
||||
|
||||
v = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, v, 1, 0, 2, 3)); // [t, h * w, c]
|
||||
x = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, 1, nullptr, true, false); // [t, h * w, c]
|
||||
v = ggml_cont(ctx->ggml_ctx, ggml_ext_torch_permute(ctx->ggml_ctx, v, 1, 0, 2, 3)); // [t, h * w, c]
|
||||
x = ggml_ext_attention_ext(ctx->ggml_ctx, ctx->backend, q, k, v, 1, nullptr, true, ctx->flash_attn_enabled); // [t, h * w, c]
|
||||
|
||||
x = ggml_ext_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3)); // [t, c, h * w]
|
||||
x = ggml_reshape_4d(ctx->ggml_ctx, x, w, h, c, n); // [t, c, h, w]
|
||||
|
||||
Reference in New Issue
Block a user