mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-10-14 05:10:44 +08:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd75fc081c | ||
|
|
77eb95f8e4 | ||
|
|
8a45d0ff7f | ||
|
|
9e28be6479 | ||
|
|
062490aa7c | ||
|
|
faabc5ad3c | ||
|
|
69b9511ce9 | ||
|
|
917f7bfe99 | ||
|
|
48e0a28ddf | ||
|
|
d05e46ca5e | ||
|
|
64a7698347 | ||
|
|
0723ee51c9 | ||
|
|
90ef5f8246 | ||
|
|
db6f4791b4 | ||
|
|
b25785bc10 | ||
|
|
0585e2609d | ||
|
|
683d6d08a8 | ||
|
|
40a6a8710e | ||
|
|
e3702585cb | ||
|
|
a7d6d296c7 | ||
|
|
2e9242e37f | ||
|
|
c64994dc1d | ||
|
|
5436f6b814 |
+10
@@ -0,0 +1,10 @@
|
||||
Checks: >
|
||||
modernize-make-shared,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-override,
|
||||
modernize-pass-by-value,
|
||||
modernize-return-braced-init-list,
|
||||
modernize-deprecated-headers,
|
||||
HeaderFilterRegex: '^$'
|
||||
WarningsAsErrors: ''
|
||||
FormatStyle: none
|
||||
@@ -0,0 +1,73 @@
|
||||
name: 🐞 Bug Report
|
||||
description: Report a bug or unexpected behavior
|
||||
title: "[Bug] "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please use this template and include as many details as possible to help us reproduce and fix the issue.
|
||||
- type: textarea
|
||||
id: commit
|
||||
attributes:
|
||||
label: Git commit
|
||||
description: Which commit are you trying to compile?
|
||||
placeholder: |
|
||||
$git rev-parse HEAD
|
||||
40a6a8710ec15b1b5db6b5a098409f6bc8f654a4
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System & Version
|
||||
placeholder: e.g. “Ubuntu 22.04”, “Windows 11 23H2”, “macOS 14.3”
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: backends
|
||||
attributes:
|
||||
label: GGML backends
|
||||
description: Which GGML backends do you know to be affected?
|
||||
options: [CPU, CUDA, HIP, Metal, Musa, SYCL, Vulkan, OpenCL]
|
||||
multiple: true
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: cmd_arguments
|
||||
attributes:
|
||||
label: Command-line arguments used
|
||||
placeholder: The full command line you ran (with all flags)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps_to_reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
placeholder: A step-by-step list of what you did
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected_behavior
|
||||
attributes:
|
||||
label: What you expected to happen
|
||||
placeholder: Describe the expected behavior or result
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual_behavior
|
||||
attributes:
|
||||
label: What actually happened
|
||||
placeholder: Describe what you saw instead (errors, logs, crash, etc.)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs_and_errors
|
||||
attributes:
|
||||
label: Logs / error messages / stack trace
|
||||
placeholder: Paste complete logs or error output
|
||||
- type: textarea
|
||||
id: additional_info
|
||||
attributes:
|
||||
label: Additional context / environment details
|
||||
placeholder: e.g. CPU model, GPU, RAM, model file versions, quantization type, etc.
|
||||
@@ -0,0 +1,33 @@
|
||||
name: 💡 Feature Request
|
||||
description: Suggest a new feature or improvement
|
||||
title: "[Feature] "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for suggesting an improvement! Please fill in the fields below.
|
||||
- type: input
|
||||
id: summary
|
||||
attributes:
|
||||
label: Feature Summary
|
||||
placeholder: A one-line summary of the feature you’d like
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Detailed Description
|
||||
placeholder: What problem does this solve? How do you expect it to work?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives you considered
|
||||
placeholder: Any alternative designs or workarounds you tried
|
||||
- type: textarea
|
||||
id: additional_context
|
||||
attributes:
|
||||
label: Additional context
|
||||
placeholder: Any extra information (use cases, related functionalities, constraints)
|
||||
+7
-3
@@ -33,6 +33,7 @@ option(SD_SYCL "sd: sycl backend" OFF)
|
||||
option(SD_MUSA "sd: musa backend" OFF)
|
||||
option(SD_FAST_SOFTMAX "sd: x1.5 faster softmax, indeterministic (sometimes, same seed don't generate same image), cuda only" OFF)
|
||||
option(SD_BUILD_SHARED_LIBS "sd: build shared libs" OFF)
|
||||
option(SD_BUILD_SHARED_GGML_LIB "sd: build ggml as a separate shared lib" OFF)
|
||||
option(SD_USE_SYSTEM_GGML "sd: use system-installed GGML library" OFF)
|
||||
#option(SD_BUILD_SERVER "sd: build server example" ON)
|
||||
|
||||
@@ -86,18 +87,21 @@ file(GLOB SD_LIB_SOURCES
|
||||
"*.hpp"
|
||||
)
|
||||
|
||||
# we can get only one share lib
|
||||
if(SD_BUILD_SHARED_LIBS)
|
||||
message("-- Build shared library")
|
||||
message(${SD_LIB_SOURCES})
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
if(NOT SD_BUILD_SHARED_GGML_LIB)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
add_library(${SD_LIB} SHARED ${SD_LIB_SOURCES})
|
||||
add_definitions(-DSD_BUILD_SHARED_LIB)
|
||||
target_compile_definitions(${SD_LIB} PRIVATE -DSD_BUILD_DLL)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
message("-- Build static library")
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
if(NOT SD_BUILD_SHARED_GGML_LIB)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
add_library(${SD_LIB} STATIC ${SD_LIB_SOURCES})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -4,11 +4,29 @@
|
||||
|
||||
# stable-diffusion.cpp
|
||||
|
||||
<div align="center">
|
||||
<a href="https://trendshift.io/repositories/9714" target="_blank"><img src="https://trendshift.io/api/badge/repositories/9714" alt="leejet%2Fstable-diffusion.cpp | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</div>
|
||||
|
||||
Diffusion model(SD,Flux,Wan,...) inference in pure C/C++
|
||||
|
||||
***Note that this project is under active development. \
|
||||
API and command-line option may change frequently.***
|
||||
|
||||
## 🔥Important News
|
||||
|
||||
* **2025/10/13** 🚀 stable-diffusion.cpp now supports **Qwen-Image-Edit / Qwen-Image-Edit 2509**
|
||||
👉 Details: [PR #877](https://github.com/leejet/stable-diffusion.cpp/pull/877)
|
||||
|
||||
* **2025/10/12** 🚀 stable-diffusion.cpp now supports **Qwen-Image**
|
||||
👉 Details: [PR #851](https://github.com/leejet/stable-diffusion.cpp/pull/851)
|
||||
|
||||
* **2025/09/14** 🚀 stable-diffusion.cpp now supports **Wan2.1 Vace**
|
||||
👉 Details: [PR #819](https://github.com/leejet/stable-diffusion.cpp/pull/819)
|
||||
|
||||
* **2025/09/06** 🚀 stable-diffusion.cpp now supports **Wan2.1 / Wan2.2**
|
||||
👉 Details: [PR #778](https://github.com/leejet/stable-diffusion.cpp/pull/778)
|
||||
|
||||
## Features
|
||||
|
||||
- Plain C/C++ implementation based on [ggml](https://github.com/ggerganov/ggml), working in the same way as [llama.cpp](https://github.com/ggerganov/llama.cpp)
|
||||
@@ -17,13 +35,15 @@ API and command-line option may change frequently.***
|
||||
- Image Models
|
||||
- SD1.x, SD2.x, [SD-Turbo](https://huggingface.co/stabilityai/sd-turbo)
|
||||
- SDXL, [SDXL-Turbo](https://huggingface.co/stabilityai/sdxl-turbo)
|
||||
- !!!The VAE in SDXL encounters NaN issues under FP16, but unfortunately, the ggml_conv_2d only operates under FP16. Hence, a parameter is needed to specify the VAE that has fixed the FP16 NaN issue. You can find it here: [SDXL VAE FP16 Fix](https://huggingface.co/madebyollin/sdxl-vae-fp16-fix/blob/main/sdxl_vae.safetensors).
|
||||
- [Some SD1.x and SDXL distilled models](./docs/distilled_sd.md)
|
||||
- [SD3/SD3.5](./docs/sd3.md)
|
||||
- [Flux-dev/Flux-schnell](./docs/flux.md)
|
||||
- [Chroma](./docs/chroma.md)
|
||||
- [Chroma1-Radiance](./docs/chroma_radiance.md)
|
||||
- [Qwen Image](./docs/qwen_image.md)
|
||||
- Image Edit Models
|
||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||
- [Qwen Image Edit/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
||||
- Video Models
|
||||
- [Wan2.1/Wan2.2](./docs/wan.md)
|
||||
- [PhotoMaker](https://github.com/TencentARC/PhotoMaker) support.
|
||||
@@ -32,14 +52,22 @@ API and command-line option may change frequently.***
|
||||
- Latent Consistency Models support (LCM/LCM-LoRA)
|
||||
- Faster and memory efficient latent decoding with [TAESD](https://github.com/madebyollin/taesd)
|
||||
- Upscale images generated with [ESRGAN](https://github.com/xinntao/Real-ESRGAN)
|
||||
- 16-bit, 32-bit float support
|
||||
- 2-bit, 3-bit, 4-bit, 5-bit and 8-bit integer quantization support
|
||||
- Accelerated memory-efficient CPU inference
|
||||
- Only requires ~2.3GB when using txt2img with fp16 precision to generate a 512x512 image, enabling Flash Attention just requires ~1.8GB.
|
||||
- AVX, AVX2 and AVX512 support for x86 architectures
|
||||
- Full CUDA, Metal, Vulkan, OpenCL and SYCL backend for GPU acceleration.
|
||||
- Can load ckpt, safetensors and diffusers models/checkpoints. Standalone VAEs models
|
||||
- No need to convert to `.ggml` or `.gguf` anymore!
|
||||
- Supported backends
|
||||
- CPU (AVX, AVX2 and AVX512 support for x86 architectures)
|
||||
- CUDA
|
||||
- Vulkan
|
||||
- Metal
|
||||
- OpenCL
|
||||
- SYCL
|
||||
- Supported weight formats
|
||||
- Pytorch checkpoint (`.ckpt` or `.pth`)
|
||||
- Safetensors (`./safetensors`)
|
||||
- GGUF (`.gguf`)
|
||||
- Supported platforms
|
||||
- Linux
|
||||
- Mac OS
|
||||
- Windows
|
||||
- Android (via Termux, [Local Diffusion](https://github.com/rmatif/Local-Diffusion))
|
||||
- Flash Attention for memory usage optimization
|
||||
- Negative prompt
|
||||
- [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) style tokenizer (not all the features, only token weighting for now)
|
||||
@@ -55,373 +83,45 @@ API and command-line option may change frequently.***
|
||||
- [`LCM`](https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/13952)
|
||||
- Cross-platform reproducibility (`--rng cuda`, consistent with the `stable-diffusion-webui GPU RNG`)
|
||||
- Embedds generation parameters into png output as webui-compatible text string
|
||||
- Supported platforms
|
||||
- Linux
|
||||
- Mac OS
|
||||
- Windows
|
||||
- Android (via Termux, [Local Diffusion](https://github.com/rmatif/Local-Diffusion))
|
||||
|
||||
## Usage
|
||||
## Quick Start
|
||||
|
||||
For most users, you can download the built executable program from the latest [release](https://github.com/leejet/stable-diffusion.cpp/releases/latest).
|
||||
If the built product does not meet your requirements, you can choose to build it manually.
|
||||
### Get the sd executable
|
||||
|
||||
### Get the Code
|
||||
- Download pre-built binaries from the [releases page](https://github.com/leejet/stable-diffusion.cpp/releases)
|
||||
- Or build from source by following the [build guide](./docs/build.md)
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/leejet/stable-diffusion.cpp
|
||||
cd stable-diffusion.cpp
|
||||
```
|
||||
### Download model weights
|
||||
|
||||
- If you have already cloned the repository, you can use the following command to update the repository to the latest code.
|
||||
|
||||
```
|
||||
cd stable-diffusion.cpp
|
||||
git pull origin master
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
### Download weights
|
||||
|
||||
- download original weights(.ckpt or .safetensors). For example
|
||||
- Stable Diffusion v1.4 from https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
|
||||
- download weights(.ckpt or .safetensors or .gguf). For example
|
||||
- Stable Diffusion v1.5 from https://huggingface.co/runwayml/stable-diffusion-v1-5
|
||||
- Stable Diffuison v2.1 from https://huggingface.co/stabilityai/stable-diffusion-2-1
|
||||
- Stable Diffusion 3 2B from https://huggingface.co/stabilityai/stable-diffusion-3-medium
|
||||
|
||||
```shell
|
||||
curl -L -O https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt
|
||||
# curl -L -O https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
||||
# curl -L -O https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-nonema-pruned.safetensors
|
||||
# curl -L -O https://huggingface.co/stabilityai/stable-diffusion-3-medium/resolve/main/sd3_medium_incl_clips_t5xxlfp16.safetensors
|
||||
```sh
|
||||
curl -L -O https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
#### Build from scratch
|
||||
|
||||
```shell
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using OpenBLAS
|
||||
|
||||
```
|
||||
cmake .. -DGGML_OPENBLAS=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using CUDA
|
||||
|
||||
This provides BLAS acceleration using the CUDA cores of your Nvidia GPU. Make sure to have the CUDA toolkit installed. You can download it from your Linux distro's package manager (e.g. `apt install nvidia-cuda-toolkit`) or from here: [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads). Recommended to have at least 4 GB of VRAM.
|
||||
|
||||
```
|
||||
cmake .. -DSD_CUDA=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using HipBLAS
|
||||
This provides BLAS acceleration using the ROCm cores of your AMD GPU. Make sure to have the ROCm toolkit installed.
|
||||
To build for another GPU architecture than installed in your system, set `$GFX_NAME` manually to the desired architecture (replace first command). This is also necessary if your GPU is not officially supported by ROCm, for example you have to set `$GFX_NAME` manually to `gfx1030` for consumer RDNA2 cards.
|
||||
|
||||
Windows User Refer to [docs/hipBLAS_on_Windows.md](docs%2FhipBLAS_on_Windows.md) for a comprehensive guide.
|
||||
|
||||
```
|
||||
if command -v rocminfo; then export GFX_NAME=$(rocminfo | awk '/ *Name: +gfx[1-9]/ {print $2; exit}'); else echo "rocminfo missing!"; fi
|
||||
if [ -z "${GFX_NAME}" ]; then echo "Error: Couldn't detect GPU!"; else echo "Building for GPU: ${GFX_NAME}"; fi
|
||||
cmake .. -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSD_HIPBLAS=ON -DCMAKE_BUILD_TYPE=Release -DGPU_TARGETS=$GFX_NAME -DAMDGPU_TARGETS=$GFX_NAME -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using MUSA
|
||||
|
||||
This provides BLAS acceleration using the MUSA cores of your Moore Threads GPU. Make sure to have the MUSA toolkit installed.
|
||||
|
||||
```bash
|
||||
cmake .. -DCMAKE_C_COMPILER=/usr/local/musa/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/musa/bin/clang++ -DSD_MUSA=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using Metal
|
||||
|
||||
Using Metal makes the computation run on the GPU. Currently, there are some issues with Metal when performing operations on very large matrices, making it highly inefficient at the moment. Performance improvements are expected in the near future.
|
||||
|
||||
```
|
||||
cmake .. -DSD_METAL=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using Vulkan
|
||||
|
||||
Install Vulkan SDK from https://www.lunarg.com/vulkan-sdk/.
|
||||
|
||||
```
|
||||
cmake .. -DSD_VULKAN=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
##### Using OpenCL (for Adreno GPU)
|
||||
|
||||
Currently, it supports only Adreno GPUs and is primarily optimized for Q4_0 type
|
||||
|
||||
To build for Windows ARM please refers to [Windows 11 Arm64
|
||||
](https://github.com/ggml-org/llama.cpp/blob/master/docs/backend/OPENCL.md#windows-11-arm64)
|
||||
|
||||
Building for Android:
|
||||
|
||||
Android NDK:
|
||||
Download and install the Android NDK from the [official Android developer site](https://developer.android.com/ndk/downloads).
|
||||
|
||||
Setup OpenCL Dependencies for NDK:
|
||||
|
||||
You need to provide OpenCL headers and the ICD loader library to your NDK sysroot.
|
||||
|
||||
* OpenCL Headers:
|
||||
```bash
|
||||
# In a temporary working directory
|
||||
git clone https://github.com/KhronosGroup/OpenCL-Headers
|
||||
cd OpenCL-Headers
|
||||
# Replace <YOUR_NDK_PATH> with your actual NDK installation path
|
||||
# e.g., cp -r CL /path/to/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
|
||||
sudo cp -r CL <YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
|
||||
cd ..
|
||||
```
|
||||
|
||||
* OpenCL ICD Loader:
|
||||
```bash
|
||||
# In the same temporary working directory
|
||||
git clone https://github.com/KhronosGroup/OpenCL-ICD-Loader
|
||||
cd OpenCL-ICD-Loader
|
||||
mkdir build_ndk && cd build_ndk
|
||||
|
||||
# Replace <YOUR_NDK_PATH> in the CMAKE_TOOLCHAIN_FILE and OPENCL_ICD_LOADER_HEADERS_DIR
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_TOOLCHAIN_FILE=<YOUR_NDK_PATH>/build/cmake/android.toolchain.cmake \
|
||||
-DOPENCL_ICD_LOADER_HEADERS_DIR=<YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=24 \
|
||||
-DANDROID_STL=c++_shared
|
||||
|
||||
ninja
|
||||
# Replace <YOUR_NDK_PATH>
|
||||
# e.g., cp libOpenCL.so /path/to/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android
|
||||
sudo cp libOpenCL.so <YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android
|
||||
cd ../..
|
||||
```
|
||||
|
||||
Build `stable-diffusion.cpp` for Android with OpenCL:
|
||||
|
||||
```bash
|
||||
mkdir build-android && cd build-android
|
||||
|
||||
# Replace <YOUR_NDK_PATH> with your actual NDK installation path
|
||||
# e.g., -DCMAKE_TOOLCHAIN_FILE=/path/to/android-ndk-r26c/build/cmake/android.toolchain.cmake
|
||||
cmake .. -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=<YOUR_NDK_PATH>/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-28 \
|
||||
-DGGML_OPENMP=OFF \
|
||||
-DSD_OPENCL=ON
|
||||
|
||||
ninja
|
||||
```
|
||||
*(Note: Don't forget to include `LD_LIBRARY_PATH=/vendor/lib64` in your command line before running the binary)*
|
||||
|
||||
##### Using SYCL
|
||||
|
||||
Using SYCL makes the computation run on the Intel GPU. Please make sure you have installed the related driver and [Intel® oneAPI Base toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) before start. More details and steps can refer to [llama.cpp SYCL backend](https://github.com/ggerganov/llama.cpp/blob/master/docs/backend/SYCL.md#linux).
|
||||
|
||||
```
|
||||
# Export relevant ENV variables
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
|
||||
# Option 1: Use FP32 (recommended for better performance in most cases)
|
||||
cmake .. -DSD_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx
|
||||
|
||||
# Option 2: Use FP16
|
||||
cmake .. -DSD_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DGGML_SYCL_F16=ON
|
||||
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
Example of text2img by using SYCL backend:
|
||||
|
||||
- download `stable-diffusion` model weight, refer to [download-weight](#download-weights).
|
||||
|
||||
- run `./bin/sd -m ../models/sd3_medium_incl_clips_t5xxlfp16.safetensors --cfg-scale 5 --steps 30 --sampling-method euler -H 1024 -W 1024 --seed 42 -p "fantasy medieval village world inside a glass sphere , high detail, fantasy, realistic, light effect, hyper detail, volumetric lighting, cinematic, macro, depth of field, blur, red light and clouds from the back, highly detailed epic cinematic concept art cg render made in maya, blender and photoshop, octane render, excellent composition, dynamic dramatic cinematic lighting, aesthetic, very inspirational, world inside a glass sphere by james gurney by artgerm with james jean, joe fenton and tristan eaton by ross tran, fine details, 4k resolution"`
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/sycl_sd3_output.png" width="360x">
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
##### Using Flash Attention
|
||||
|
||||
Enabling flash attention for the diffusion model reduces memory usage by varying amounts of MB.
|
||||
eg.:
|
||||
- flux 768x768 ~600mb
|
||||
- SD2 768x768 ~1400mb
|
||||
|
||||
For most backends, it slows things down, but for cuda it generally speeds it up too.
|
||||
At the moment, it is only supported for some models and some backends (like cpu, cuda/rocm, metal).
|
||||
|
||||
Run by adding `--diffusion-fa` to the arguments and watch for:
|
||||
```
|
||||
[INFO ] stable-diffusion.cpp:312 - Using flash attention in the diffusion model
|
||||
```
|
||||
and the compute buffer shrink in the debug log:
|
||||
```
|
||||
[DEBUG] ggml_extend.hpp:1004 - flux compute buffer size: 650.00 MB(VRAM)
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```
|
||||
usage: ./bin/sd [arguments]
|
||||
|
||||
arguments:
|
||||
-h, --help show this help message and exit
|
||||
-M, --mode [MODE] run mode, one of: [img_gen, vid_gen, upscale, convert], default: img_gen
|
||||
-t, --threads N number of threads to use during computation (default: -1)
|
||||
If threads <= 0, then threads will be set to the number of CPU physical cores
|
||||
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM when needed
|
||||
-m, --model [MODEL] path to full model
|
||||
--diffusion-model path to the standalone diffusion model
|
||||
--high-noise-diffusion-model path to the standalone high noise diffusion model
|
||||
--clip_l path to the clip-l text encoder
|
||||
--clip_g path to the clip-g text encoder
|
||||
--clip_vision path to the clip-vision encoder
|
||||
--t5xxl path to the t5xxl text encoder
|
||||
--qwen2vl path to the qwen2vl text encoder
|
||||
--vae [VAE] path to vae
|
||||
--taesd [TAESD_PATH] path to taesd. Using Tiny AutoEncoder for fast decoding (low quality)
|
||||
--control-net [CONTROL_PATH] path to control net model
|
||||
--embd-dir [EMBEDDING_PATH] path to embeddings
|
||||
--upscale-model [ESRGAN_PATH] path to esrgan model. For img_gen mode, upscale images after generate, just RealESRGAN_x4plus_anime_6B supported by now
|
||||
--upscale-repeats Run the ESRGAN upscaler this many times (default 1)
|
||||
--type [TYPE] weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K, q4_K)
|
||||
If not specified, the default is the type of the weight file
|
||||
--tensor-type-rules [EXPRESSION] weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
||||
--lora-model-dir [DIR] lora model directory
|
||||
-i, --init-img [IMAGE] path to the init image, required by img2img
|
||||
--mask [MASK] path to the mask image, required by img2img with mask
|
||||
-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)
|
||||
--control-video [PATH] path to control video frames, It must be a directory path.
|
||||
The video frames inside should be stored as images in lexicographical (character) order
|
||||
For example, if the control video path is `frames`, the directory contain images such as 00.png, 01.png, 鈥?etc.
|
||||
--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: "")
|
||||
--cfg-scale SCALE unconditional guidance scale: (default: 7.0)
|
||||
--img-cfg-scale SCALE image guidance scale for inpaint or instruct-pix2pix models: (default: same as --cfg-scale)
|
||||
--guidance SCALE distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--slg-scale SCALE skip layer guidance (SLG) scale, only for DiT models: (default: 0)
|
||||
0 means disabled, a value of 2.5 is nice for sd3.5 medium
|
||||
--eta SCALE eta in DDIM, only for DDIM and TCD: (default: 0)
|
||||
--skip-layers LAYERS Layers to skip for SLG steps: (default: [7,8,9])
|
||||
--skip-layer-start START SLG enabling point: (default: 0.01)
|
||||
--skip-layer-end END SLG disabling point: (default: 0.2)
|
||||
--scheduler {discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple} Denoiser sigma scheduler (default: discrete)
|
||||
--sampling-method {euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd}
|
||||
sampling method (default: "euler" for Flux/SD3/Wan, "euler_a" otherwise)
|
||||
--timestep-shift N shift timestep for NitroFusion models, default: 0, recommended N for NitroSD-Realism around 250 and 500 for NitroSD-Vibrant
|
||||
--steps STEPS number of sample steps (default: 20)
|
||||
--high-noise-cfg-scale SCALE (high noise) unconditional guidance scale: (default: 7.0)
|
||||
--high-noise-img-cfg-scale SCALE (high noise) image guidance scale for inpaint or instruct-pix2pix models: (default: same as --cfg-scale)
|
||||
--high-noise-guidance SCALE (high noise) distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--high-noise-slg-scale SCALE (high noise) skip layer guidance (SLG) scale, only for DiT models: (default: 0)
|
||||
0 means disabled, a value of 2.5 is nice for sd3.5 medium
|
||||
--high-noise-eta SCALE (high noise) eta in DDIM, only for DDIM and TCD: (default: 0)
|
||||
--high-noise-skip-layers LAYERS (high noise) Layers to skip for SLG steps: (default: [7,8,9])
|
||||
--high-noise-skip-layer-start (high noise) SLG enabling point: (default: 0.01)
|
||||
--high-noise-skip-layer-end END (high noise) SLG disabling point: (default: 0.2)
|
||||
--high-noise-scheduler {discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple} Denoiser sigma scheduler (default: discrete)
|
||||
--high-noise-sampling-method {euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd}
|
||||
(high noise) sampling method (default: "euler_a")
|
||||
--high-noise-steps STEPS (high noise) number of sample steps (default: -1 = auto)
|
||||
SLG will be enabled at step int([STEPS]*[START]) and disabled at int([STEPS]*[END])
|
||||
--strength STRENGTH strength for noising/unnoising (default: 0.75)
|
||||
--control-strength STRENGTH strength to apply Control Net (default: 0.9)
|
||||
1.0 corresponds to full destruction of information in init image
|
||||
-H, --height H image height, in pixel space (default: 512)
|
||||
-W, --width W image width, in pixel space (default: 512)
|
||||
--rng {std_default, cuda} RNG (default: cuda)
|
||||
-s SEED, --seed SEED RNG seed (default: 42, use random seed for < 0)
|
||||
-b, --batch-count COUNT number of images to generate
|
||||
--clip-skip N ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer (default: -1)
|
||||
<= 0 represents unspecified, will be 1 for SD1.x, 2 for SD2.x
|
||||
--vae-tiling process vae in tiles to reduce memory usage
|
||||
--vae-tile-size [X]x[Y] tile size for vae tiling (default: 32x32)
|
||||
--vae-relative-tile-size [X]x[Y] relative tile size for vae tiling, in fraction of image size if < 1, in number of tiles per dim if >=1 (overrides --vae-tile-size)
|
||||
--vae-tile-overlap OVERLAP tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
||||
--vae-on-cpu keep vae in cpu (for low vram)
|
||||
--clip-on-cpu keep clip in cpu (for low vram)
|
||||
--diffusion-fa use flash attention in the diffusion model (for low vram)
|
||||
Might lower quality, since it implies converting k and v to f16.
|
||||
This might crash if it is not supported by the backend.
|
||||
--diffusion-conv-direct use Conv2d direct in the diffusion model
|
||||
This might crash if it is not supported by the backend.
|
||||
--vae-conv-direct use Conv2d direct in the vae model (should improve the performance)
|
||||
This might crash if it is not supported by the backend.
|
||||
--control-net-cpu keep controlnet in cpu (for low vram)
|
||||
--canny apply canny preprocessor (edge detection)
|
||||
--color colors the logging tags according to level
|
||||
--chroma-disable-dit-mask disable dit mask for chroma
|
||||
--chroma-enable-t5-mask enable t5 mask for chroma
|
||||
--chroma-t5-mask-pad PAD_SIZE t5 mask pad size of chroma
|
||||
--video-frames video frames (default: 1)
|
||||
--fps fps (default: 24)
|
||||
--moe-boundary BOUNDARY timestep boundary for Wan2.2 MoE model. (default: 0.875)
|
||||
only enabled if `--high-noise-steps` is set to -1
|
||||
--flow-shift SHIFT shift value for Flow models like SD3.x or WAN (default: auto)
|
||||
--vace-strength wan vace strength
|
||||
--photo-maker path to PHOTOMAKER model
|
||||
--pm-id-images-dir [DIR] path to PHOTOMAKER input id images dir
|
||||
--pm-id-embed-path [PATH] path to PHOTOMAKER v2 id embed
|
||||
--pm-style-strength strength for keeping PHOTOMAKER input identity (default: 20)
|
||||
-v, --verbose print extra info
|
||||
```
|
||||
|
||||
#### txt2img example
|
||||
### Generate an image with just one command
|
||||
|
||||
```sh
|
||||
./bin/sd -m ../models/sd-v1-4.ckpt -p "a lovely cat"
|
||||
# ./bin/sd -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat"
|
||||
# ./bin/sd -m ../models/sd_xl_base_1.0.safetensors --vae ../models/sdxl_vae-fp16-fix.safetensors -H 1024 -W 1024 -p "a lovely cat" -v
|
||||
# ./bin/sd -m ../models/sd3_medium_incl_clips_t5xxlfp16.safetensors -H 1024 -W 1024 -p 'a lovely cat holding a sign says \"Stable Diffusion CPP\"' --cfg-scale 4.5 --sampling-method euler -v --clip-on-cpu
|
||||
# ./bin/sd --diffusion-model ../models/flux1-dev-q3_k.gguf --vae ../models/ae.sft --clip_l ../models/clip_l.safetensors --t5xxl ../models/t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'flux.cpp'" --cfg-scale 1.0 --sampling-method euler -v --clip-on-cpu
|
||||
# ./bin/sd -m ..\models\sd3.5_large.safetensors --clip_l ..\models\clip_l.safetensors --clip_g ..\models\clip_g.safetensors --t5xxl ..\models\t5xxl_fp16.safetensors -H 1024 -W 1024 -p 'a lovely cat holding a sign says \"Stable diffusion 3.5 Large\"' --cfg-scale 4.5 --sampling-method euler -v --clip-on-cpu
|
||||
./bin/sd -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat"
|
||||
```
|
||||
|
||||
Using formats of different precisions will yield results of varying quality.
|
||||
***For detailed command-line arguments, check out [cli doc](./examples/cli/README.md).***
|
||||
|
||||
| f32 | f16 |q8_0 |q5_0 |q5_1 |q4_0 |q4_1 |
|
||||
| ---- |---- |---- |---- |---- |---- |---- |
|
||||
|  | | | | | | |
|
||||
## Performance
|
||||
|
||||
#### img2img example
|
||||
|
||||
- `./output.png` is the image generated from the above txt2img pipeline
|
||||
|
||||
|
||||
```
|
||||
./bin/sd -m ../models/sd-v1-4.ckpt -p "cat with blue eyes" -i ./output.png -o ./img2img_output.png --strength 0.4
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/img2img_output.png" width="256x">
|
||||
</p>
|
||||
If you want to improve performance or reduce VRAM/RAM usage, please refer to [performance guide](./docs/performance.md).
|
||||
|
||||
## More Guides
|
||||
|
||||
- [SD1.x/SD2.x/SDXL](./docs/sd.md)
|
||||
- [SD3/SD3.5](./docs/sd3.md)
|
||||
- [Flux-dev/Flux-schnell](./docs/flux.md)
|
||||
- [FLUX.1-Kontext-dev](./docs/kontext.md)
|
||||
- [Chroma](./docs/chroma.md)
|
||||
- [🔥Qwen Image](./docs/qwen_image.md)
|
||||
- [🔥Qwen Image Edit/Qwen Image Edit 2509](./docs/qwen_image_edit.md)
|
||||
- [🔥Wan2.1/Wan2.2](./docs/wan.md)
|
||||
- [LoRA](./docs/lora.md)
|
||||
- [LCM/LCM-LoRA](./docs/lcm.md)
|
||||
- [Using PhotoMaker to personalize image generation](./docs/photo_maker.md)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 477 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 457 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 415 KiB |
@@ -550,7 +550,7 @@ protected:
|
||||
int64_t num_positions;
|
||||
bool force_clip_f32;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type token_wtype = GGML_TYPE_F32;
|
||||
if (!force_clip_f32) {
|
||||
token_wtype = get_type(prefix + "token_embedding.weight", tensor_types, GGML_TYPE_F32);
|
||||
@@ -587,7 +587,7 @@ public:
|
||||
|
||||
GGML_ASSERT(input_ids->ne[0] == position_embed_weight->ne[1]);
|
||||
input_ids = ggml_reshape_3d(ctx, input_ids, input_ids->ne[0], 1, input_ids->ne[1]);
|
||||
auto token_embedding = ggml_get_rows(ctx, custom_embed_weight != NULL ? custom_embed_weight : token_embed_weight, input_ids);
|
||||
auto token_embedding = ggml_get_rows(ctx, custom_embed_weight != nullptr ? custom_embed_weight : token_embed_weight, input_ids);
|
||||
token_embedding = ggml_reshape_3d(ctx, token_embedding, token_embedding->ne[0], token_embedding->ne[1], token_embedding->ne[3]);
|
||||
|
||||
// token_embedding + position_embedding
|
||||
@@ -606,7 +606,7 @@ protected:
|
||||
int64_t image_size;
|
||||
int64_t num_patches;
|
||||
int64_t num_positions;
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type patch_wtype = GGML_TYPE_F16;
|
||||
enum ggml_type class_wtype = GGML_TYPE_F32;
|
||||
enum ggml_type position_wtype = GGML_TYPE_F32;
|
||||
@@ -641,10 +641,10 @@ public:
|
||||
// concat(patch_embedding, class_embedding) + position_embedding
|
||||
struct ggml_tensor* patch_embedding;
|
||||
int64_t N = pixel_values->ne[3];
|
||||
patch_embedding = ggml_nn_conv_2d(ctx, pixel_values, patch_embed_weight, NULL, patch_size, patch_size); // [N, embed_dim, image_size // pacht_size, image_size // pacht_size]
|
||||
patch_embedding = ggml_reshape_3d(ctx, patch_embedding, num_patches, embed_dim, N); // [N, embed_dim, num_patches]
|
||||
patch_embedding = ggml_cont(ctx, ggml_permute(ctx, patch_embedding, 1, 0, 2, 3)); // [N, num_patches, embed_dim]
|
||||
patch_embedding = ggml_reshape_4d(ctx, patch_embedding, 1, embed_dim, num_patches, N); // [N, num_patches, embed_dim, 1]
|
||||
patch_embedding = ggml_ext_conv_2d(ctx, pixel_values, patch_embed_weight, nullptr, patch_size, patch_size); // [N, embed_dim, image_size // pacht_size, image_size // pacht_size]
|
||||
patch_embedding = ggml_reshape_3d(ctx, patch_embedding, num_patches, embed_dim, N); // [N, embed_dim, num_patches]
|
||||
patch_embedding = ggml_cont(ctx, ggml_permute(ctx, patch_embedding, 1, 0, 2, 3)); // [N, num_patches, embed_dim]
|
||||
patch_embedding = ggml_reshape_4d(ctx, patch_embedding, 1, embed_dim, num_patches, N); // [N, num_patches, embed_dim, 1]
|
||||
|
||||
struct ggml_tensor* class_embedding = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, embed_dim, N);
|
||||
class_embedding = ggml_repeat(ctx, class_embed_weight, class_embedding); // [N, embed_dim]
|
||||
@@ -669,7 +669,7 @@ enum CLIPVersion {
|
||||
|
||||
class CLIPTextModel : public GGMLBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
if (version == OPEN_CLIP_VIT_BIGG_14) {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["text_projection"] = ggml_new_tensor_2d(ctx, wtype, projection_dim, hidden_size);
|
||||
@@ -735,8 +735,8 @@ public:
|
||||
if (return_pooled) {
|
||||
auto text_projection = params["text_projection"];
|
||||
ggml_tensor* pooled = ggml_view_1d(ctx, x, hidden_size, x->nb[1] * max_token_idx);
|
||||
if (text_projection != NULL) {
|
||||
pooled = ggml_nn_linear(ctx, pooled, text_projection, NULL);
|
||||
if (text_projection != nullptr) {
|
||||
pooled = ggml_ext_linear(ctx, pooled, text_projection, nullptr);
|
||||
} else {
|
||||
LOG_DEBUG("identity projection");
|
||||
}
|
||||
@@ -814,7 +814,7 @@ protected:
|
||||
int64_t out_features;
|
||||
bool transpose_weight;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
if (transpose_weight) {
|
||||
params["weight"] = ggml_new_tensor_2d(ctx, wtype, out_features, in_features);
|
||||
@@ -831,12 +831,12 @@ public:
|
||||
out_features(out_features),
|
||||
transpose_weight(transpose_weight) {}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
struct ggml_tensor* w = params["weight"];
|
||||
if (transpose_weight) {
|
||||
w = ggml_cont(ctx, ggml_transpose(ctx, w));
|
||||
}
|
||||
return ggml_nn_linear(ctx, x, w, NULL);
|
||||
return ggml_ext_linear(ctx, x, w, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -894,7 +894,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "clip";
|
||||
}
|
||||
|
||||
@@ -921,7 +921,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* input_ids,
|
||||
int num_custom_embeddings = 0,
|
||||
void* custom_embeddings_data = NULL,
|
||||
void* custom_embeddings_data = nullptr,
|
||||
size_t max_token_idx = 0,
|
||||
bool return_pooled = false,
|
||||
int clip_skip = -1) {
|
||||
@@ -929,9 +929,9 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
|
||||
input_ids = to_backend(input_ids);
|
||||
|
||||
struct ggml_tensor* embeddings = NULL;
|
||||
struct ggml_tensor* embeddings = nullptr;
|
||||
|
||||
if (num_custom_embeddings > 0 && custom_embeddings_data != NULL) {
|
||||
if (num_custom_embeddings > 0 && custom_embeddings_data != nullptr) {
|
||||
auto token_embed_weight = model.get_token_embed_weight();
|
||||
auto custom_embeddings = ggml_new_tensor_2d(compute_ctx,
|
||||
token_embed_weight->type,
|
||||
@@ -958,7 +958,7 @@ struct CLIPTextModelRunner : public GGMLRunner {
|
||||
bool return_pooled,
|
||||
int clip_skip,
|
||||
ggml_tensor** output,
|
||||
ggml_context* output_ctx = NULL) {
|
||||
ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(input_ids, num_custom_embeddings, custom_embeddings_data, max_token_idx, return_pooled, clip_skip);
|
||||
};
|
||||
|
||||
+10
-10
@@ -121,7 +121,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x, struct ggml_tensor* emb = NULL) {
|
||||
virtual struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x, struct ggml_tensor* emb = nullptr) {
|
||||
// For dims==3, we reduce dimension from 5d to 4d by merging h and w, in order not to change ggml
|
||||
// [N, c, t, h, w] => [N, c, t, h * w]
|
||||
// x: [N, channels, h, w] if dims == 2 else [N, channels, t, h, w]
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
auto out_layers_0 = std::dynamic_pointer_cast<GroupNorm32>(blocks["out_layers.0"]);
|
||||
auto out_layers_3 = std::dynamic_pointer_cast<UnaryBlock>(blocks["out_layers.3"]);
|
||||
|
||||
if (emb == NULL) {
|
||||
if (emb == nullptr) {
|
||||
GGML_ASSERT(skip_t_emb);
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ protected:
|
||||
int64_t dim_in;
|
||||
int64_t dim_out;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "proj.weight", tensor_types, GGML_TYPE_F32);
|
||||
enum ggml_type bias_wtype = GGML_TYPE_F32;
|
||||
params["proj.weight"] = ggml_new_tensor_2d(ctx, wtype, dim_in, dim_out * 2);
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
GEGLU(int64_t dim_in, int64_t dim_out)
|
||||
: dim_in(dim_in), dim_out(dim_out) {}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [ne3, ne2, ne1, dim_in]
|
||||
// return: [ne3, ne2, ne1, dim_out]
|
||||
struct ggml_tensor* w = params["proj.weight"];
|
||||
@@ -205,8 +205,8 @@ public:
|
||||
auto gate_b = ggml_view_1d(ctx, b, b->ne[0] / 2, b->nb[0] * b->ne[0] / 2); // [dim_out, ]
|
||||
|
||||
auto x_in = x;
|
||||
x = ggml_nn_linear(ctx, x_in, x_w, x_b); // [ne3, ne2, ne1, dim_out]
|
||||
auto gate = ggml_nn_linear(ctx, x_in, gate_w, gate_b); // [ne3, ne2, ne1, dim_out]
|
||||
x = ggml_ext_linear(ctx, x_in, x_w, x_b); // [ne3, ne2, ne1, dim_out]
|
||||
auto gate = ggml_ext_linear(ctx, x_in, gate_w, gate_b); // [ne3, ne2, ne1, dim_out]
|
||||
|
||||
gate = ggml_gelu_inplace(ctx, gate);
|
||||
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Linear(dim_in, dim_out, bias));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [ne3, ne2, ne1, dim_in]
|
||||
// return: [ne3, ne2, ne1, dim_out]
|
||||
auto proj = std::dynamic_pointer_cast<Linear>(blocks["proj"]);
|
||||
@@ -325,7 +325,7 @@ public:
|
||||
auto k = to_k->forward(ctx, context); // [N, n_context, inner_dim]
|
||||
auto v = to_v->forward(ctx, context); // [N, n_context, inner_dim]
|
||||
|
||||
x = ggml_nn_attention_ext(ctx, backend, q, k, v, n_head, NULL, false, false, flash_attn); // [N, n_token, inner_dim]
|
||||
x = ggml_ext_attention_ext(ctx, backend, q, k, v, n_head, nullptr, false, false, flash_attn); // [N, n_token, inner_dim]
|
||||
|
||||
x = to_out_0->forward(ctx, x); // [N, n_token, query_dim]
|
||||
return x;
|
||||
@@ -483,7 +483,7 @@ public:
|
||||
|
||||
class AlphaBlender : public GGMLBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
// Get the type of the "mix_factor" tensor from the input tensors map with the specified prefix
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["mix_factor"] = ggml_new_tensor_1d(ctx, wtype, 1);
|
||||
@@ -492,7 +492,7 @@ protected:
|
||||
float get_alpha() {
|
||||
// image_only_indicator is always tensor([0.]) and since mix_factor.shape is [1,]
|
||||
// so learned_with_images is same as learned
|
||||
float alpha = ggml_backend_tensor_get_f32(params["mix_factor"]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(params["mix_factor"]);
|
||||
return sigmoid(alpha);
|
||||
}
|
||||
|
||||
|
||||
+534
-293
File diff suppressed because it is too large
Load Diff
+23
-23
@@ -206,18 +206,18 @@ public:
|
||||
struct ggml_tensor* guided_hint,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y = NULL) {
|
||||
struct ggml_tensor* y = nullptr) {
|
||||
// x: [N, in_channels, h, w] or [N, in_channels/2, h, w]
|
||||
// timesteps: [N,]
|
||||
// context: [N, max_position, hidden_size] or [1, max_position, hidden_size]. for example, [N, 77, 768]
|
||||
// y: [N, adm_in_channels] or [1, adm_in_channels]
|
||||
if (context != NULL) {
|
||||
if (context != nullptr) {
|
||||
if (context->ne[2] != x->ne[3]) {
|
||||
context = ggml_repeat(ctx, context, ggml_new_tensor_3d(ctx, GGML_TYPE_F32, context->ne[0], context->ne[1], x->ne[3]));
|
||||
}
|
||||
}
|
||||
|
||||
if (y != NULL) {
|
||||
if (y != nullptr) {
|
||||
if (y->ne[1] != x->ne[3]) {
|
||||
y = ggml_repeat(ctx, y, ggml_new_tensor_2d(ctx, GGML_TYPE_F32, y->ne[0], x->ne[3]));
|
||||
}
|
||||
@@ -230,14 +230,14 @@ public:
|
||||
|
||||
auto middle_block_out = std::dynamic_pointer_cast<Conv2d>(blocks["middle_block_out.0"]);
|
||||
|
||||
auto t_emb = ggml_nn_timestep_embedding(ctx, timesteps, model_channels); // [N, model_channels]
|
||||
auto t_emb = ggml_ext_timestep_embedding(ctx, timesteps, model_channels); // [N, model_channels]
|
||||
|
||||
auto emb = time_embed_0->forward(ctx, t_emb);
|
||||
emb = ggml_silu_inplace(ctx, emb);
|
||||
emb = time_embed_2->forward(ctx, emb); // [N, time_embed_dim]
|
||||
|
||||
// SDXL/SVD
|
||||
if (y != NULL) {
|
||||
if (y != nullptr) {
|
||||
auto label_embed_0 = std::dynamic_pointer_cast<Linear>(blocks["label_emb.0.0"]);
|
||||
auto label_embed_2 = std::dynamic_pointer_cast<Linear>(blocks["label_emb.0.2"]);
|
||||
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
|
||||
std::vector<struct ggml_tensor*> outs;
|
||||
|
||||
if (guided_hint == NULL) {
|
||||
if (guided_hint == nullptr) {
|
||||
guided_hint = input_hint_block_forward(ctx, hint, emb, context);
|
||||
}
|
||||
outs.push_back(guided_hint);
|
||||
@@ -312,10 +312,10 @@ struct ControlNet : public GGMLRunner {
|
||||
SDVersion version = VERSION_SD1;
|
||||
ControlNetBlock control_net;
|
||||
|
||||
ggml_backend_buffer_t control_buffer = NULL; // keep control output tensors in backend memory
|
||||
ggml_context* control_ctx = NULL;
|
||||
ggml_backend_buffer_t control_buffer = nullptr; // keep control output tensors in backend memory
|
||||
ggml_context* control_ctx = nullptr;
|
||||
std::vector<struct ggml_tensor*> controls; // (12 input block outputs, 1 middle block output) SD 1.5
|
||||
struct ggml_tensor* guided_hint = NULL; // guided_hint cache, for faster inference
|
||||
struct ggml_tensor* guided_hint = nullptr; // guided_hint cache, for faster inference
|
||||
bool guided_hint_cached = false;
|
||||
|
||||
ControlNet(ggml_backend_t backend,
|
||||
@@ -337,14 +337,14 @@ struct ControlNet : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
~ControlNet() {
|
||||
~ControlNet() override {
|
||||
free_control_ctx();
|
||||
}
|
||||
|
||||
void alloc_control_ctx(std::vector<struct ggml_tensor*> outs) {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(outs.size() * ggml_tensor_overhead()) + 1024 * 1024;
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = true;
|
||||
control_ctx = ggml_init(params);
|
||||
|
||||
@@ -366,20 +366,20 @@ struct ControlNet : public GGMLRunner {
|
||||
}
|
||||
|
||||
void free_control_ctx() {
|
||||
if (control_buffer != NULL) {
|
||||
if (control_buffer != nullptr) {
|
||||
ggml_backend_buffer_free(control_buffer);
|
||||
control_buffer = NULL;
|
||||
control_buffer = nullptr;
|
||||
}
|
||||
if (control_ctx != NULL) {
|
||||
if (control_ctx != nullptr) {
|
||||
ggml_free(control_ctx);
|
||||
control_ctx = NULL;
|
||||
control_ctx = nullptr;
|
||||
}
|
||||
guided_hint = NULL;
|
||||
guided_hint = nullptr;
|
||||
guided_hint_cached = false;
|
||||
controls.clear();
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "control_net";
|
||||
}
|
||||
|
||||
@@ -391,12 +391,12 @@ struct ControlNet : public GGMLRunner {
|
||||
struct ggml_tensor* hint,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y = NULL) {
|
||||
struct ggml_tensor* y = nullptr) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, CONTROL_NET_GRAPH_SIZE, false);
|
||||
|
||||
x = to_backend(x);
|
||||
if (guided_hint_cached) {
|
||||
hint = NULL;
|
||||
hint = nullptr;
|
||||
} else {
|
||||
hint = to_backend(hint);
|
||||
}
|
||||
@@ -408,12 +408,12 @@ struct ControlNet : public GGMLRunner {
|
||||
runtime_backend,
|
||||
x,
|
||||
hint,
|
||||
guided_hint_cached ? guided_hint : NULL,
|
||||
guided_hint_cached ? guided_hint : nullptr,
|
||||
timesteps,
|
||||
context,
|
||||
y);
|
||||
|
||||
if (control_ctx == NULL) {
|
||||
if (control_ctx == nullptr) {
|
||||
alloc_control_ctx(outs);
|
||||
}
|
||||
|
||||
@@ -431,8 +431,8 @@ struct ControlNet : public GGMLRunner {
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) {
|
||||
// x: [N, in_channels, h, w]
|
||||
// timesteps: [N, ]
|
||||
// context: [N, max_position, hidden_size]([N, 77, 768]) or [1, max_position, hidden_size]
|
||||
|
||||
+46
-46
@@ -19,7 +19,7 @@ struct SigmaSchedule {
|
||||
};
|
||||
|
||||
struct DiscreteSchedule : SigmaSchedule {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) {
|
||||
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;
|
||||
|
||||
int t_max = TIMESTEPS - 1;
|
||||
@@ -43,7 +43,7 @@ struct DiscreteSchedule : SigmaSchedule {
|
||||
};
|
||||
|
||||
struct ExponentialSchedule : SigmaSchedule {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) {
|
||||
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> sigmas;
|
||||
|
||||
// Calculate step size
|
||||
@@ -150,7 +150,7 @@ std::vector<float> log_linear_interpolation(std::vector<float> sigma_in,
|
||||
https://research.nvidia.com/labs/toronto-ai/AlignYourSteps/howto.html
|
||||
*/
|
||||
struct AYSSchedule : SigmaSchedule {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||
const std::vector<float> noise_levels[] = {
|
||||
/* SD1.5 */
|
||||
{14.6146412293f, 6.4745760956f, 3.8636745985f, 2.6946151520f,
|
||||
@@ -204,7 +204,7 @@ struct AYSSchedule : SigmaSchedule {
|
||||
* GITS Scheduler: https://github.com/zju-pi/diff-sampler/tree/main/gits-main
|
||||
*/
|
||||
struct GITSSchedule : SigmaSchedule {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||
if (sigma_max <= 0.0f) {
|
||||
return std::vector<float>{};
|
||||
}
|
||||
@@ -252,7 +252,7 @@ struct SGMUniformSchedule : SigmaSchedule {
|
||||
};
|
||||
|
||||
struct KarrasSchedule : SigmaSchedule {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) {
|
||||
std::vector<float> get_sigmas(uint32_t n, float sigma_min, float sigma_max, t_to_sigma_t t_to_sigma) override {
|
||||
// These *COULD* be function arguments here,
|
||||
// but does anybody ever bother to touch them?
|
||||
float rho = 7.f;
|
||||
@@ -350,15 +350,15 @@ struct CompVisDenoiser : public Denoiser {
|
||||
|
||||
float sigma_data = 1.0f;
|
||||
|
||||
float sigma_min() {
|
||||
float sigma_min() override {
|
||||
return sigmas[0];
|
||||
}
|
||||
|
||||
float sigma_max() {
|
||||
float sigma_max() override {
|
||||
return sigmas[TIMESTEPS - 1];
|
||||
}
|
||||
|
||||
float sigma_to_t(float sigma) {
|
||||
float sigma_to_t(float sigma) override {
|
||||
float log_sigma = std::log(sigma);
|
||||
std::vector<float> dists;
|
||||
dists.reserve(TIMESTEPS);
|
||||
@@ -384,7 +384,7 @@ struct CompVisDenoiser : public Denoiser {
|
||||
return t;
|
||||
}
|
||||
|
||||
float t_to_sigma(float t) {
|
||||
float t_to_sigma(float t) override {
|
||||
int low_idx = static_cast<int>(std::floor(t));
|
||||
int high_idx = static_cast<int>(std::ceil(t));
|
||||
float w = t - static_cast<float>(low_idx);
|
||||
@@ -392,7 +392,7 @@ struct CompVisDenoiser : public Denoiser {
|
||||
return std::exp(log_sigma);
|
||||
}
|
||||
|
||||
std::vector<float> get_scalings(float sigma) {
|
||||
std::vector<float> get_scalings(float sigma) override {
|
||||
float c_skip = 1.0f;
|
||||
float c_out = -sigma;
|
||||
float c_in = 1.0f / std::sqrt(sigma * sigma + sigma_data * sigma_data);
|
||||
@@ -400,19 +400,19 @@ struct CompVisDenoiser : public Denoiser {
|
||||
}
|
||||
|
||||
// this function will modify noise/latent
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) {
|
||||
ggml_tensor_scale(noise, sigma);
|
||||
ggml_tensor_add(latent, noise);
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) override {
|
||||
ggml_ext_tensor_scale_inplace(noise, sigma);
|
||||
ggml_ext_tensor_add_inplace(latent, noise);
|
||||
return latent;
|
||||
}
|
||||
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) {
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) override {
|
||||
return latent;
|
||||
}
|
||||
};
|
||||
|
||||
struct CompVisVDenoiser : public CompVisDenoiser {
|
||||
std::vector<float> get_scalings(float sigma) {
|
||||
std::vector<float> get_scalings(float sigma) override {
|
||||
float c_skip = sigma_data * sigma_data / (sigma * sigma + sigma_data * sigma_data);
|
||||
float c_out = -sigma * sigma_data / std::sqrt(sigma * sigma + sigma_data * sigma_data);
|
||||
float c_in = 1.0f / std::sqrt(sigma * sigma + sigma_data * sigma_data);
|
||||
@@ -429,19 +429,19 @@ struct EDMVDenoiser : public CompVisVDenoiser {
|
||||
scheduler = std::make_shared<ExponentialSchedule>();
|
||||
}
|
||||
|
||||
float t_to_sigma(float t) {
|
||||
float t_to_sigma(float t) override {
|
||||
return std::exp(t * 4 / (float)TIMESTEPS);
|
||||
}
|
||||
|
||||
float sigma_to_t(float s) {
|
||||
float sigma_to_t(float s) override {
|
||||
return 0.25 * std::log(s);
|
||||
}
|
||||
|
||||
float sigma_min() {
|
||||
float sigma_min() override {
|
||||
return min_sigma;
|
||||
}
|
||||
|
||||
float sigma_max() {
|
||||
float sigma_max() override {
|
||||
return max_sigma;
|
||||
}
|
||||
};
|
||||
@@ -470,24 +470,24 @@ struct DiscreteFlowDenoiser : public Denoiser {
|
||||
}
|
||||
}
|
||||
|
||||
float sigma_min() {
|
||||
float sigma_min() override {
|
||||
return sigmas[0];
|
||||
}
|
||||
|
||||
float sigma_max() {
|
||||
float sigma_max() override {
|
||||
return sigmas[TIMESTEPS - 1];
|
||||
}
|
||||
|
||||
float sigma_to_t(float sigma) {
|
||||
float sigma_to_t(float sigma) override {
|
||||
return sigma * 1000.f;
|
||||
}
|
||||
|
||||
float t_to_sigma(float t) {
|
||||
float t_to_sigma(float t) override {
|
||||
t = t + 1;
|
||||
return time_snr_shift(shift, t / 1000.f);
|
||||
}
|
||||
|
||||
std::vector<float> get_scalings(float sigma) {
|
||||
std::vector<float> get_scalings(float sigma) override {
|
||||
float c_skip = 1.0f;
|
||||
float c_out = -sigma;
|
||||
float c_in = 1.0f;
|
||||
@@ -495,15 +495,15 @@ struct DiscreteFlowDenoiser : public Denoiser {
|
||||
}
|
||||
|
||||
// this function will modify noise/latent
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) {
|
||||
ggml_tensor_scale(noise, sigma);
|
||||
ggml_tensor_scale(latent, 1.0f - sigma);
|
||||
ggml_tensor_add(latent, noise);
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) override {
|
||||
ggml_ext_tensor_scale_inplace(noise, sigma);
|
||||
ggml_ext_tensor_scale_inplace(latent, 1.0f - sigma);
|
||||
ggml_ext_tensor_add_inplace(latent, noise);
|
||||
return latent;
|
||||
}
|
||||
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) {
|
||||
ggml_tensor_scale(latent, 1.0f / (1.0f - sigma));
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) override {
|
||||
ggml_ext_tensor_scale_inplace(latent, 1.0f / (1.0f - sigma));
|
||||
return latent;
|
||||
}
|
||||
};
|
||||
@@ -529,24 +529,24 @@ struct FluxFlowDenoiser : public Denoiser {
|
||||
}
|
||||
}
|
||||
|
||||
float sigma_min() {
|
||||
float sigma_min() override {
|
||||
return sigmas[0];
|
||||
}
|
||||
|
||||
float sigma_max() {
|
||||
float sigma_max() override {
|
||||
return sigmas[TIMESTEPS - 1];
|
||||
}
|
||||
|
||||
float sigma_to_t(float sigma) {
|
||||
float sigma_to_t(float sigma) override {
|
||||
return sigma;
|
||||
}
|
||||
|
||||
float t_to_sigma(float t) {
|
||||
float t_to_sigma(float t) override {
|
||||
t = t + 1;
|
||||
return flux_time_shift(shift, 1.0f, t / TIMESTEPS);
|
||||
}
|
||||
|
||||
std::vector<float> get_scalings(float sigma) {
|
||||
std::vector<float> get_scalings(float sigma) override {
|
||||
float c_skip = 1.0f;
|
||||
float c_out = -sigma;
|
||||
float c_in = 1.0f;
|
||||
@@ -554,15 +554,15 @@ struct FluxFlowDenoiser : public Denoiser {
|
||||
}
|
||||
|
||||
// this function will modify noise/latent
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) {
|
||||
ggml_tensor_scale(noise, sigma);
|
||||
ggml_tensor_scale(latent, 1.0f - sigma);
|
||||
ggml_tensor_add(latent, noise);
|
||||
ggml_tensor* noise_scaling(float sigma, ggml_tensor* noise, ggml_tensor* latent) override {
|
||||
ggml_ext_tensor_scale_inplace(noise, sigma);
|
||||
ggml_ext_tensor_scale_inplace(latent, 1.0f - sigma);
|
||||
ggml_ext_tensor_add_inplace(latent, noise);
|
||||
return latent;
|
||||
}
|
||||
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) {
|
||||
ggml_tensor_scale(latent, 1.0f / (1.0f - sigma));
|
||||
ggml_tensor* inverse_noise_scaling(float sigma, ggml_tensor* latent) override {
|
||||
ggml_ext_tensor_scale_inplace(latent, 1.0f / (1.0f - sigma));
|
||||
return latent;
|
||||
}
|
||||
};
|
||||
@@ -620,7 +620,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
|
||||
if (sigmas[i + 1] > 0) {
|
||||
// x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
|
||||
ggml_tensor_set_f32_randn(noise, rng);
|
||||
ggml_ext_im_set_randn_f32(noise, rng);
|
||||
// noise = load_tensor_from_file(work_ctx, "./rand" + std::to_string(i+1) + ".bin");
|
||||
{
|
||||
float* vec_x = (float*)x->data;
|
||||
@@ -820,7 +820,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
|
||||
// Noise addition
|
||||
if (sigmas[i + 1] > 0) {
|
||||
ggml_tensor_set_f32_randn(noise, rng);
|
||||
ggml_ext_im_set_randn_f32(noise, rng);
|
||||
{
|
||||
float* vec_x = (float*)x->data;
|
||||
float* vec_noise = (float*)noise->data;
|
||||
@@ -1085,7 +1085,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
|
||||
if (sigmas[i + 1] > 0) {
|
||||
// x += sigmas[i + 1] * noise_sampler(sigmas[i], sigmas[i + 1])
|
||||
ggml_tensor_set_f32_randn(noise, rng);
|
||||
ggml_ext_im_set_randn_f32(noise, rng);
|
||||
// noise = load_tensor_from_file(res_ctx, "./rand" + std::to_string(i+1) + ".bin");
|
||||
{
|
||||
float* vec_x = (float*)x->data;
|
||||
@@ -1276,7 +1276,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
}
|
||||
}
|
||||
if (eta > 0) {
|
||||
ggml_tensor_set_f32_randn(variance_noise, rng);
|
||||
ggml_ext_im_set_randn_f32(variance_noise, rng);
|
||||
float* vec_variance_noise =
|
||||
(float*)variance_noise->data;
|
||||
float* vec_x = (float*)x->data;
|
||||
@@ -1444,7 +1444,7 @@ static void sample_k_diffusion(sample_method_t method,
|
||||
if (eta > 0 && i != steps - 1) {
|
||||
// In this case, x is still pred_noised_sample,
|
||||
// continue in-place
|
||||
ggml_tensor_set_f32_randn(noise, rng);
|
||||
ggml_ext_im_set_randn_f32(noise, rng);
|
||||
float* vec_x = (float*)x->data;
|
||||
float* vec_noise = (float*)noise->data;
|
||||
for (int j = 0; j < ggml_nelements(x); j++) {
|
||||
|
||||
+57
-55
@@ -8,18 +8,18 @@
|
||||
#include "wan.hpp"
|
||||
|
||||
struct DiffusionParams {
|
||||
struct ggml_tensor* x = NULL;
|
||||
struct ggml_tensor* timesteps = NULL;
|
||||
struct ggml_tensor* context = NULL;
|
||||
struct ggml_tensor* c_concat = NULL;
|
||||
struct ggml_tensor* y = NULL;
|
||||
struct ggml_tensor* guidance = NULL;
|
||||
struct ggml_tensor* x = nullptr;
|
||||
struct ggml_tensor* timesteps = nullptr;
|
||||
struct ggml_tensor* context = nullptr;
|
||||
struct ggml_tensor* c_concat = nullptr;
|
||||
struct ggml_tensor* y = nullptr;
|
||||
struct ggml_tensor* guidance = nullptr;
|
||||
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* vace_context = NULL;
|
||||
struct ggml_tensor* vace_context = nullptr;
|
||||
float vace_strength = 1.f;
|
||||
std::vector<int> skip_layers = {};
|
||||
};
|
||||
@@ -28,8 +28,8 @@ struct DiffusionModel {
|
||||
virtual std::string get_desc() = 0;
|
||||
virtual void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) = 0;
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) = 0;
|
||||
virtual void alloc_params_buffer() = 0;
|
||||
virtual void free_params_buffer() = 0;
|
||||
virtual void free_compute_buffer() = 0;
|
||||
@@ -49,38 +49,38 @@ struct UNetModel : public DiffusionModel {
|
||||
: unet(backend, offload_params_to_cpu, tensor_types, "model.diffusion_model", version, flash_attn) {
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return unet.get_desc();
|
||||
}
|
||||
|
||||
void alloc_params_buffer() {
|
||||
void alloc_params_buffer() override {
|
||||
unet.alloc_params_buffer();
|
||||
}
|
||||
|
||||
void free_params_buffer() {
|
||||
void free_params_buffer() override {
|
||||
unet.free_params_buffer();
|
||||
}
|
||||
|
||||
void free_compute_buffer() {
|
||||
void free_compute_buffer() override {
|
||||
unet.free_compute_buffer();
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||
unet.get_param_tensors(tensors, "model.diffusion_model");
|
||||
}
|
||||
|
||||
size_t get_params_buffer_size() {
|
||||
size_t get_params_buffer_size() override {
|
||||
return unet.get_params_buffer_size();
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() {
|
||||
int64_t get_adm_in_channels() override {
|
||||
return unet.unet.adm_in_channels;
|
||||
}
|
||||
|
||||
void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
return unet.compute(n_threads,
|
||||
diffusion_params.x,
|
||||
diffusion_params.timesteps,
|
||||
@@ -103,38 +103,38 @@ struct MMDiTModel : public DiffusionModel {
|
||||
: mmdit(backend, offload_params_to_cpu, flash_attn, tensor_types, "model.diffusion_model") {
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return mmdit.get_desc();
|
||||
}
|
||||
|
||||
void alloc_params_buffer() {
|
||||
void alloc_params_buffer() override {
|
||||
mmdit.alloc_params_buffer();
|
||||
}
|
||||
|
||||
void free_params_buffer() {
|
||||
void free_params_buffer() override {
|
||||
mmdit.free_params_buffer();
|
||||
}
|
||||
|
||||
void free_compute_buffer() {
|
||||
void free_compute_buffer() override {
|
||||
mmdit.free_compute_buffer();
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||
mmdit.get_param_tensors(tensors, "model.diffusion_model");
|
||||
}
|
||||
|
||||
size_t get_params_buffer_size() {
|
||||
size_t get_params_buffer_size() override {
|
||||
return mmdit.get_params_buffer_size();
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() {
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768 + 1280;
|
||||
}
|
||||
|
||||
void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
return mmdit.compute(n_threads,
|
||||
diffusion_params.x,
|
||||
diffusion_params.timesteps,
|
||||
@@ -158,38 +158,38 @@ struct FluxModel : public DiffusionModel {
|
||||
: flux(backend, offload_params_to_cpu, tensor_types, "model.diffusion_model", version, flash_attn, use_mask) {
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return flux.get_desc();
|
||||
}
|
||||
|
||||
void alloc_params_buffer() {
|
||||
void alloc_params_buffer() override {
|
||||
flux.alloc_params_buffer();
|
||||
}
|
||||
|
||||
void free_params_buffer() {
|
||||
void free_params_buffer() override {
|
||||
flux.free_params_buffer();
|
||||
}
|
||||
|
||||
void free_compute_buffer() {
|
||||
void free_compute_buffer() override {
|
||||
flux.free_compute_buffer();
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||
flux.get_param_tensors(tensors, "model.diffusion_model");
|
||||
}
|
||||
|
||||
size_t get_params_buffer_size() {
|
||||
size_t get_params_buffer_size() override {
|
||||
return flux.get_params_buffer_size();
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() {
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
return flux.compute(n_threads,
|
||||
diffusion_params.x,
|
||||
diffusion_params.timesteps,
|
||||
@@ -218,45 +218,45 @@ struct WanModel : public DiffusionModel {
|
||||
: prefix(prefix), wan(backend, offload_params_to_cpu, tensor_types, prefix, version, flash_attn) {
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return wan.get_desc();
|
||||
}
|
||||
|
||||
void alloc_params_buffer() {
|
||||
void alloc_params_buffer() override {
|
||||
wan.alloc_params_buffer();
|
||||
}
|
||||
|
||||
void free_params_buffer() {
|
||||
void free_params_buffer() override {
|
||||
wan.free_params_buffer();
|
||||
}
|
||||
|
||||
void free_compute_buffer() {
|
||||
void free_compute_buffer() override {
|
||||
wan.free_compute_buffer();
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||
wan.get_param_tensors(tensors, prefix);
|
||||
}
|
||||
|
||||
size_t get_params_buffer_size() {
|
||||
size_t get_params_buffer_size() override {
|
||||
return wan.get_params_buffer_size();
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() {
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
return wan.compute(n_threads,
|
||||
diffusion_params.x,
|
||||
diffusion_params.timesteps,
|
||||
diffusion_params.context,
|
||||
diffusion_params.y,
|
||||
diffusion_params.c_concat,
|
||||
NULL,
|
||||
nullptr,
|
||||
diffusion_params.vace_context,
|
||||
diffusion_params.vace_strength,
|
||||
output,
|
||||
@@ -277,42 +277,44 @@ struct QwenImageModel : public DiffusionModel {
|
||||
: prefix(prefix), qwen_image(backend, offload_params_to_cpu, tensor_types, prefix, version, flash_attn) {
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return qwen_image.get_desc();
|
||||
}
|
||||
|
||||
void alloc_params_buffer() {
|
||||
void alloc_params_buffer() override {
|
||||
qwen_image.alloc_params_buffer();
|
||||
}
|
||||
|
||||
void free_params_buffer() {
|
||||
void free_params_buffer() override {
|
||||
qwen_image.free_params_buffer();
|
||||
}
|
||||
|
||||
void free_compute_buffer() {
|
||||
void free_compute_buffer() override {
|
||||
qwen_image.free_compute_buffer();
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors) override {
|
||||
qwen_image.get_param_tensors(tensors, prefix);
|
||||
}
|
||||
|
||||
size_t get_params_buffer_size() {
|
||||
size_t get_params_buffer_size() override {
|
||||
return qwen_image.get_params_buffer_size();
|
||||
}
|
||||
|
||||
int64_t get_adm_in_channels() {
|
||||
int64_t get_adm_in_channels() override {
|
||||
return 768;
|
||||
}
|
||||
|
||||
void compute(int n_threads,
|
||||
DiffusionParams diffusion_params,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
return qwen_image.compute(n_threads,
|
||||
diffusion_params.x,
|
||||
diffusion_params.timesteps,
|
||||
diffusion_params.context,
|
||||
diffusion_params.ref_latents,
|
||||
true, // increase_ref_index
|
||||
output,
|
||||
output_ctx);
|
||||
}
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# Build from scratch
|
||||
|
||||
## Get the Code
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/leejet/stable-diffusion.cpp
|
||||
cd stable-diffusion.cpp
|
||||
```
|
||||
|
||||
- If you have already cloned the repository, you can use the following command to update the repository to the latest code.
|
||||
|
||||
```
|
||||
cd stable-diffusion.cpp
|
||||
git pull origin master
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
## Build (CPU only)
|
||||
|
||||
If you don't have a GPU or CUDA installed, you can build a CPU-only version.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with OpenBLAS
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -DGGML_OPENBLAS=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with CUDA
|
||||
|
||||
This provides GPU acceleration using NVIDIA GPU. Make sure to have the CUDA toolkit installed. You can download it from your Linux distro's package manager (e.g. `apt install nvidia-cuda-toolkit`) or from here: [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads). Recommended to have at least 4 GB of VRAM.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -DSD_CUDA=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with HipBLAS
|
||||
|
||||
This provides GPU acceleration using AMD GPU. Make sure to have the ROCm toolkit installed.
|
||||
To build for another GPU architecture than installed in your system, set `$GFX_NAME` manually to the desired architecture (replace first command). This is also necessary if your GPU is not officially supported by ROCm, for example you have to set `$GFX_NAME` manually to `gfx1030` for consumer RDNA2 cards.
|
||||
|
||||
Windows User Refer to [docs/hipBLAS_on_Windows.md](docs%2FhipBLAS_on_Windows.md) for a comprehensive guide.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
if command -v rocminfo; then export GFX_NAME=$(rocminfo | awk '/ *Name: +gfx[1-9]/ {print $2; exit}'); else echo "rocminfo missing!"; fi
|
||||
if [ -z "${GFX_NAME}" ]; then echo "Error: Couldn't detect GPU!"; else echo "Building for GPU: ${GFX_NAME}"; fi
|
||||
cmake .. -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSD_HIPBLAS=ON -DCMAKE_BUILD_TYPE=Release -DGPU_TARGETS=$GFX_NAME -DAMDGPU_TARGETS=$GFX_NAME -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with MUSA
|
||||
|
||||
This provides GPU acceleration using Moore Threads GPU. Make sure to have the MUSA toolkit installed.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=/usr/local/musa/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/musa/bin/clang++ -DSD_MUSA=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with Metal
|
||||
|
||||
Using Metal makes the computation run on the GPU. Currently, there are some issues with Metal when performing operations on very large matrices, making it highly inefficient at the moment. Performance improvements are expected in the near future.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -DSD_METAL=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with Vulkan
|
||||
|
||||
Install Vulkan SDK from https://www.lunarg.com/vulkan-sdk/.
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -DSD_VULKAN=ON
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
## Build with OpenCL (for Adreno GPU)
|
||||
|
||||
Currently, it supports only Adreno GPUs and is primarily optimized for Q4_0 type
|
||||
|
||||
To build for Windows ARM please refers to [Windows 11 Arm64](https://github.com/ggml-org/llama.cpp/blob/master/docs/backend/OPENCL.md#windows-11-arm64)
|
||||
|
||||
Building for Android:
|
||||
|
||||
Android NDK:
|
||||
Download and install the Android NDK from the [official Android developer site](https://developer.android.com/ndk/downloads).
|
||||
|
||||
Setup OpenCL Dependencies for NDK:
|
||||
|
||||
You need to provide OpenCL headers and the ICD loader library to your NDK sysroot.
|
||||
|
||||
* OpenCL Headers:
|
||||
```bash
|
||||
# In a temporary working directory
|
||||
git clone https://github.com/KhronosGroup/OpenCL-Headers
|
||||
cd OpenCL-Headers
|
||||
# Replace <YOUR_NDK_PATH> with your actual NDK installation path
|
||||
# e.g., cp -r CL /path/to/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
|
||||
sudo cp -r CL <YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
|
||||
cd ..
|
||||
```
|
||||
|
||||
* OpenCL ICD Loader:
|
||||
```shell
|
||||
# In the same temporary working directory
|
||||
git clone https://github.com/KhronosGroup/OpenCL-ICD-Loader
|
||||
cd OpenCL-ICD-Loader
|
||||
mkdir build_ndk && cd build_ndk
|
||||
|
||||
# Replace <YOUR_NDK_PATH> in the CMAKE_TOOLCHAIN_FILE and OPENCL_ICD_LOADER_HEADERS_DIR
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_TOOLCHAIN_FILE=<YOUR_NDK_PATH>/build/cmake/android.toolchain.cmake \
|
||||
-DOPENCL_ICD_LOADER_HEADERS_DIR=<YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=24 \
|
||||
-DANDROID_STL=c++_shared
|
||||
|
||||
ninja
|
||||
# Replace <YOUR_NDK_PATH>
|
||||
# e.g., cp libOpenCL.so /path/to/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android
|
||||
sudo cp libOpenCL.so <YOUR_NDK_PATH>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android
|
||||
cd ../..
|
||||
```
|
||||
|
||||
Build `stable-diffusion.cpp` for Android with OpenCL:
|
||||
|
||||
```shell
|
||||
mkdir build-android && cd build-android
|
||||
|
||||
# Replace <YOUR_NDK_PATH> with your actual NDK installation path
|
||||
# e.g., -DCMAKE_TOOLCHAIN_FILE=/path/to/android-ndk-r26c/build/cmake/android.toolchain.cmake
|
||||
cmake .. -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=<YOUR_NDK_PATH>/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-28 \
|
||||
-DGGML_OPENMP=OFF \
|
||||
-DSD_OPENCL=ON
|
||||
|
||||
ninja
|
||||
```
|
||||
*(Note: Don't forget to include `LD_LIBRARY_PATH=/vendor/lib64` in your command line before running the binary)*
|
||||
|
||||
## Build with SYCL
|
||||
|
||||
Using SYCL makes the computation run on the Intel GPU. Please make sure you have installed the related driver and [Intel® oneAPI Base toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) before start. More details and steps can refer to [llama.cpp SYCL backend](https://github.com/ggerganov/llama.cpp/blob/master/docs/backend/SYCL.md#linux).
|
||||
|
||||
```shell
|
||||
# Export relevant ENV variables
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
|
||||
# Option 1: Use FP32 (recommended for better performance in most cases)
|
||||
cmake .. -DSD_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx
|
||||
|
||||
# Option 2: Use FP16
|
||||
cmake .. -DSD_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DGGML_SYCL_F16=ON
|
||||
|
||||
cmake --build . --config Release
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
# How to Use
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Chroma1-Radiance
|
||||
- safetensors: https://huggingface.co/lodestones/Chroma1-Radiance/tree/main
|
||||
- gguf: https://huggingface.co/silveroxides/Chroma1-Radiance-GGUF/tree/main
|
||||
|
||||
- Download t5xxl
|
||||
- safetensors: https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp16.safetensors
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Chroma1-Radiance-v0.4-Q8_0.gguf --t5xxl ..\..\ComfyUI\models\clip\t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'chroma radiance cpp'" --cfg-scale 4.0 --sampling-method euler -v
|
||||
```
|
||||
|
||||
<img alt="Chroma1-Radiance" src="../assets/flux/chroma1-radiance.png" />
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# Running distilled models: SSD1B and SD1.x with tiny U-Nets
|
||||
|
||||
## Preface
|
||||
|
||||
This kind of models have a reduced U-Net part.
|
||||
Unlike other SDXL models the U-Net of SSD1B has only one middle block and lesser attention layers in up and down blocks, resulting in relatively smaller files. Running these models saves more than 33% of the time. For more details, refer to Segmind's paper on https://arxiv.org/abs/2401.02677v1 .
|
||||
Unlike other SD 1.x models Tiny-UNet models consist of only 6 U-Net blocks, resulting in relatively smaller files (approximately 1 GB). Running these models saves almost 50% of the time. For more details, refer to the paper: https://arxiv.org/pdf/2305.15798.pdf .
|
||||
|
||||
## SSD1B
|
||||
|
||||
Unfortunately not all of this models follow the standard model parameter naming mapping.
|
||||
Anyway there are some very useful SSD1B models available online, such as:
|
||||
|
||||
* https://huggingface.co/segmind/SSD-1B/resolve/main/SSD-1B-A1111.safetensors
|
||||
* https://huggingface.co/hassenhamdi/SSD-1B-fp8_e4m3fn/resolve/main/SSD-1B_fp8_e4m3fn.safetensors
|
||||
|
||||
Also there are useful LORAs available:
|
||||
|
||||
* https://huggingface.co/seungminh/lora-swarovski-SSD-1B/resolve/main/pytorch_lora_weights.safetensors
|
||||
* https://huggingface.co/kylielee505/mylcmlorassd/resolve/main/pytorch_lora_weights.safetensors
|
||||
|
||||
You can use this files **out-of-the-box** - unlike models in next section.
|
||||
|
||||
|
||||
## SD1.x with tiny U-Nets
|
||||
|
||||
There are some Tiny SD 1.x models available online, such as:
|
||||
|
||||
* https://huggingface.co/segmind/tiny-sd
|
||||
* https://huggingface.co/segmind/portrait-finetuned
|
||||
* https://huggingface.co/nota-ai/bk-sdm-tiny
|
||||
|
||||
These models need some conversion, for example because partially tensors are **non contiguous** stored. To create a usable checkpoint file, follow these **easy** steps:
|
||||
|
||||
### Download model from Hugging Face
|
||||
|
||||
Download the model using Python on your computer, for example this way:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from diffusers import StableDiffusionPipeline
|
||||
pipe = StableDiffusionPipeline.from_pretrained("segmind/tiny-sd")
|
||||
unet=pipe.unet
|
||||
for param in unet.parameters():
|
||||
param.data = param.data.contiguous() # <- important here
|
||||
pipe.save_pretrained("segmindtiny-sd", safe_serialization=True)
|
||||
```
|
||||
|
||||
### Convert that to a ckpt file
|
||||
|
||||
To convert the downloaded model to a checkpoint file, you need another Python script. Download the conversion script from here:
|
||||
|
||||
* https://raw.githubusercontent.com/huggingface/diffusers/refs/heads/main/scripts/convert_diffusers_to_original_stable_diffusion.py
|
||||
|
||||
|
||||
### Run convert script
|
||||
|
||||
Now, run that conversion script:
|
||||
|
||||
```bash
|
||||
python convert_diffusers_to_original_stable_diffusion.py \
|
||||
--model_path ./segmindtiny-sd \
|
||||
--checkpoint_path ./segmind_tiny-sd.ckpt --half
|
||||
```
|
||||
|
||||
The file **segmind_tiny-sd.ckpt** will be generated and is now ready to use with sd.cpp
|
||||
|
||||
You can follow a similar process for other models mentioned above from Hugging Face.
|
||||
|
||||
|
||||
### Another ckpt file on the net
|
||||
|
||||
There is another model file available online:
|
||||
|
||||
* https://huggingface.co/ClashSAN/small-sd/resolve/main/tinySDdistilled.ckpt
|
||||
|
||||
If you want to use that, you have to adjust some **non-contiguous tensors** first:
|
||||
|
||||
```python
|
||||
import torch
|
||||
ckpt = torch.load("tinySDdistilled.ckpt", map_location=torch.device('cpu'))
|
||||
for key, value in ckpt['state_dict'].items():
|
||||
if isinstance(value, torch.Tensor):
|
||||
ckpt['state_dict'][key] = value.contiguous()
|
||||
torch.save(ckpt, "tinySDdistilled_fixed.ckpt")
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
## Use Flash Attention to save memory and improve speed.
|
||||
|
||||
Enabling flash attention for the diffusion model reduces memory usage by varying amounts of MB.
|
||||
eg.:
|
||||
- flux 768x768 ~600mb
|
||||
- SD2 768x768 ~1400mb
|
||||
|
||||
For most backends, it slows things down, but for cuda it generally speeds it up too.
|
||||
At the moment, it is only supported for some models and some backends (like cpu, cuda/rocm, metal).
|
||||
|
||||
Run by adding `--diffusion-fa` to the arguments and watch for:
|
||||
```
|
||||
[INFO ] stable-diffusion.cpp:312 - Using flash attention in the diffusion model
|
||||
```
|
||||
and the compute buffer shrink in the debug log:
|
||||
```
|
||||
[DEBUG] ggml_extend.hpp:1004 - flux compute buffer size: 650.00 MB(VRAM)
|
||||
```
|
||||
|
||||
## Offload weights to the CPU to save VRAM without reducing generation speed.
|
||||
|
||||
Using `--offload-to-cpu` allows you to offload weights to the CPU, saving VRAM without reducing generation speed.
|
||||
|
||||
## Use quantization to reduce memory usage.
|
||||
|
||||
[quantization](./quantization_and_gguf.md)
|
||||
@@ -0,0 +1,35 @@
|
||||
# How to Use
|
||||
|
||||
## Download weights
|
||||
|
||||
- Download Qwen Image
|
||||
- Qwen Image Edit
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/tree/main/split_files/diffusion_models
|
||||
- gguf: https://huggingface.co/QuantStack/Qwen-Image-Edit-GGUF/tree/main
|
||||
- Qwen Image Edit 2509
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/tree/main/split_files/diffusion_models
|
||||
- gguf: https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF/tree/main
|
||||
- Download vae
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/tree/main/split_files/vae
|
||||
- Download qwen_2.5_vl 7b
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/tree/main/split_files/text_encoders
|
||||
- gguf: https://huggingface.co/mradermacher/Qwen2.5-VL-7B-Instruct-GGUF/tree/main
|
||||
|
||||
## Examples
|
||||
|
||||
### Qwen Image Edit
|
||||
|
||||
```
|
||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen_Image_Edit-Q8_0.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --qwen2vl ..\..\ComfyUI\models\text_encoders\qwen_2.5_vl_7b.safetensors --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'edit.cpp'" --seed 1118877715456453
|
||||
```
|
||||
|
||||
<img alt="qwen_image_edit" src="../assets/qwen/qwen_image_edit.png" />
|
||||
|
||||
|
||||
### Qwen Image Edit 2509
|
||||
|
||||
```
|
||||
.\bin\Release\sd.exe --diffusion-model ..\..\ComfyUI\models\diffusion_models\Qwen-Image-Edit-2509-Q4_K_S.gguf --vae ..\..\ComfyUI\models\vae\qwen_image_vae.safetensors --qwen2vl ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct-Q8_0.gguf --qwen2vl_vision ..\..\ComfyUI\models\text_encoders\Qwen2.5-VL-7B-Instruct.mmproj-Q8_0.gguf --cfg-scale 2.5 --sampling-method euler -v --offload-to-cpu --diffusion-fa --flow-shift 3 -r ..\assets\flux\flux1-dev-q8_0.png -p "change 'flux.cpp' to 'Qwen Image Edit 2509'"
|
||||
```
|
||||
|
||||
<img alt="qwen_image_edit_2509" src="../assets/qwen/qwen_image_edit_2509.png" />
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
## Download weights
|
||||
|
||||
- download original weights(.ckpt or .safetensors). For example
|
||||
- Stable Diffusion v1.4 from https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
|
||||
- Stable Diffusion v1.5 from https://huggingface.co/runwayml/stable-diffusion-v1-5
|
||||
- Stable Diffuison v2.1 from https://huggingface.co/stabilityai/stable-diffusion-2-1
|
||||
- Stable Diffusion 3 2B from https://huggingface.co/stabilityai/stable-diffusion-3-medium
|
||||
|
||||
### txt2img example
|
||||
|
||||
```sh
|
||||
./bin/sd -m ../models/sd-v1-4.ckpt -p "a lovely cat"
|
||||
# ./bin/sd -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat"
|
||||
# ./bin/sd -m ../models/sd_xl_base_1.0.safetensors --vae ../models/sdxl_vae-fp16-fix.safetensors -H 1024 -W 1024 -p "a lovely cat" -v
|
||||
# ./bin/sd -m ../models/sd3_medium_incl_clips_t5xxlfp16.safetensors -H 1024 -W 1024 -p 'a lovely cat holding a sign says \"Stable Diffusion CPP\"' --cfg-scale 4.5 --sampling-method euler -v --clip-on-cpu
|
||||
# ./bin/sd --diffusion-model ../models/flux1-dev-q3_k.gguf --vae ../models/ae.sft --clip_l ../models/clip_l.safetensors --t5xxl ../models/t5xxl_fp16.safetensors -p "a lovely cat holding a sign says 'flux.cpp'" --cfg-scale 1.0 --sampling-method euler -v --clip-on-cpu
|
||||
# ./bin/sd -m ..\models\sd3.5_large.safetensors --clip_l ..\models\clip_l.safetensors --clip_g ..\models\clip_g.safetensors --t5xxl ..\models\t5xxl_fp16.safetensors -H 1024 -W 1024 -p 'a lovely cat holding a sign says \"Stable diffusion 3.5 Large\"' --cfg-scale 4.5 --sampling-method euler -v --clip-on-cpu
|
||||
```
|
||||
|
||||
Using formats of different precisions will yield results of varying quality.
|
||||
|
||||
| f32 | f16 |q8_0 |q5_0 |q5_1 |q4_0 |q4_1 |
|
||||
| ---- |---- |---- |---- |---- |---- |---- |
|
||||
|  | | | | | | |
|
||||
|
||||
### img2img example
|
||||
|
||||
- `./output.png` is the image generated from the above txt2img pipeline
|
||||
|
||||
|
||||
```
|
||||
./bin/sd -m ../models/sd-v1-4.ckpt -p "cat with blue eyes" -i ./output.png -o ./img2img_output.png --strength 0.4
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<img src="../assets/img2img_output.png" width="256x">
|
||||
</p>
|
||||
+1
-1
@@ -7,7 +7,7 @@ You can use TAESD to accelerate the decoding of latent images by following these
|
||||
Or curl
|
||||
|
||||
```bash
|
||||
curl -L -O https://huggingface.co/madebyollin/taesd/blob/main/diffusion_pytorch_model.safetensors
|
||||
curl -L -O https://huggingface.co/madebyollin/taesd/resolve/main/diffusion_pytorch_model.safetensors
|
||||
```
|
||||
|
||||
- Specify the model path using the `--taesd PATH` parameter. example:
|
||||
|
||||
+2
-2
@@ -174,7 +174,7 @@ struct ESRGAN : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "esrgan";
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ struct ESRGAN : public GGMLRunner {
|
||||
void compute(const int n_threads,
|
||||
struct ggml_tensor* x,
|
||||
ggml_tensor** output,
|
||||
ggml_context* output_ctx = NULL) {
|
||||
ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(x);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# Run
|
||||
|
||||
```
|
||||
usage: ./bin/sd [options]
|
||||
|
||||
Options:
|
||||
-m, --model <string> path to full model
|
||||
--clip_l <string> path to the clip-l text encoder
|
||||
--clip_g <string> path to the clip-g text encoder
|
||||
--clip_vision <string> path to the clip-vision encoder
|
||||
--t5xxl <string> path to the t5xxl text encoder
|
||||
--qwen2vl <string> path to the qwen2vl text encoder
|
||||
--qwen2vl_vision <string> path to the qwen2vl vit
|
||||
--diffusion-model <string> path to the standalone diffusion model
|
||||
--high-noise-diffusion-model <string> path to the standalone high noise diffusion model
|
||||
--vae <string> path to standalone vae model
|
||||
--taesd <string> path to taesd. Using Tiny AutoEncoder for fast decoding (low quality)
|
||||
--control-net <string> path to control net model
|
||||
--embd-dir <string> embeddings directory
|
||||
--lora-model-dir <string> lora model directory
|
||||
-i, --init-img <string> path to the init image
|
||||
--end-img <string> path to the end image, required by flf2v
|
||||
--tensor-type-rules <string> weight type per tensor pattern (example: "^vae\.=f16,model\.=q8_0")
|
||||
--photo-maker <string> path to PHOTOMAKER model
|
||||
--pm-id-images-dir <string> path to PHOTOMAKER input id images dir
|
||||
--pm-id-embed-path <string> path to PHOTOMAKER v2 id embed
|
||||
--mask <string> path to the mask image
|
||||
--control-image <string> path to control image, control net
|
||||
--control-video <string> path to control video frames, It must be a directory path. The video frames inside should be stored as images in
|
||||
lexicographical (character) order. For example, if the control video path is
|
||||
`frames`, the directory contain images such as 00.png, 01.png, ... etc.
|
||||
-o, --output <string> path to write result image to (default: ./output.png)
|
||||
-p, --prompt <string> the prompt to render
|
||||
-n, --negative-prompt <string> the negative prompt (default: "")
|
||||
--upscale-model <string> path to esrgan model.
|
||||
-t, --threads <int> number of threads to use during computation (default: -1). If threads <= 0, then threads will be set to the number of
|
||||
CPU physical cores
|
||||
--upscale-repeats <int> Run the ESRGAN upscaler this many times (default: 1)
|
||||
-H, --height <int> image height, in pixel space (default: 512)
|
||||
-W, --width <int> image width, in pixel space (default: 512)
|
||||
--steps <int> number of sample steps (default: 20)
|
||||
--high-noise-steps <int> (high noise) number of sample steps (default: -1 = auto)
|
||||
--clip-skip <int> ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer (default: -1). <= 0 represents unspecified,
|
||||
will be 1 for SD1.x, 2 for SD2.x
|
||||
-b, --batch-count <int> batch count
|
||||
--chroma-t5-mask-pad <int> t5 mask pad size of chroma
|
||||
--video-frames <int> video frames (default: 1)
|
||||
--fps <int> fps (default: 24)
|
||||
--timestep-shift <int> shift timestep for NitroFusion models (default: 0). recommended N for NitroSD-Realism around 250 and 500 for
|
||||
NitroSD-Vibrant
|
||||
--cfg-scale <float> unconditional guidance scale: (default: 7.0)
|
||||
--img-cfg-scale <float> image guidance scale for inpaint or instruct-pix2pix models: (default: same as --cfg-scale)
|
||||
--guidance <float> distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--slg-scale <float> skip layer guidance (SLG) scale, only for DiT models: (default: 0). 0 means disabled, a value of 2.5 is nice for sd3.5
|
||||
medium
|
||||
--skip-layer-start <float> SLG enabling point (default: 0.01)
|
||||
--skip-layer-end <float> SLG disabling point (default: 0.2)
|
||||
--eta <float> eta in DDIM, only for DDIM and TCD (default: 0)
|
||||
--high-noise-cfg-scale <float> (high noise) unconditional guidance scale: (default: 7.0)
|
||||
--high-noise-img-cfg-scale <float> (high noise) image guidance scale for inpaint or instruct-pix2pix models (default: same as --cfg-scale)
|
||||
--high-noise-guidance <float> (high noise) distilled guidance scale for models with guidance input (default: 3.5)
|
||||
--high-noise-slg-scale <float> (high noise) skip layer guidance (SLG) scale, only for DiT models: (default: 0)
|
||||
--high-noise-skip-layer-start <float> (high noise) SLG enabling point (default: 0.01)
|
||||
--high-noise-skip-layer-end <float> (high noise) SLG disabling point (default: 0.2)
|
||||
--high-noise-eta <float> (high noise) eta in DDIM, only for DDIM and TCD (default: 0)
|
||||
--strength <float> strength for noising/unnoising (default: 0.75)
|
||||
--pm-style-strength <float>
|
||||
--control-strength <float> strength to apply Control Net (default: 0.9). 1.0 corresponds to full destruction of information in init image
|
||||
--moe-boundary <float> timestep boundary for Wan2.2 MoE model. (default: 0.875). Only enabled if `--high-noise-steps` is set to -1
|
||||
--flow-shift <float> shift value for Flow models like SD3.x or WAN (default: auto)
|
||||
--vace-strength <float> wan vace strength
|
||||
--vae-tile-overlap <float> tile overlap for vae tiling, in fraction of tile size (default: 0.5)
|
||||
--vae-tiling process vae in tiles to reduce memory usage
|
||||
--force-sdxl-vae-conv-scale force use of conv scale on sdxl vae
|
||||
--offload-to-cpu place the weights in RAM to save VRAM, and automatically load them into VRAM when needed
|
||||
--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
|
||||
--diffusion-conv-direct use ggml_conv2d_direct in the diffusion model
|
||||
--vae-conv-direct use ggml_conv2d_direct in the vae model
|
||||
--canny apply canny preprocessor (edge detection)
|
||||
-v, --verbose print extra info
|
||||
--color colors the logging tags according to level
|
||||
--chroma-disable-dit-mask disable dit mask for chroma
|
||||
--chroma-enable-t5-mask enable t5 mask for chroma
|
||||
--increase-ref-index automatically increase the indices of references images based on the order they are listed (starting with 1).
|
||||
--disable-auto-resize-ref-image disable auto resize of ref images
|
||||
-M, --mode run mode, one of [img_gen, vid_gen, upscale, convert], default: img_gen
|
||||
--type weight type (examples: f32, f16, q4_0, q4_1, q5_0, q5_1, q8_0, q2_K, q3_K, q4_K). If not specified, the default is the
|
||||
type of the weight file
|
||||
--rng RNG, one of [std_default, cuda], default: cuda
|
||||
-s, --seed RNG seed (default: 42, use random seed for < 0)
|
||||
--sampling-method sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm, ddim_trailing,
|
||||
tcd] (default: euler for Flux/SD3/Wan, euler_a otherwise)
|
||||
--prediction prediction type override, one of [eps, v, edm_v, sd3_flow, flux_flow]
|
||||
--scheduler denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform, simple], default:
|
||||
discrete
|
||||
--skip-layers layers to skip for SLG steps (default: [7,8,9])
|
||||
--high-noise-sampling-method (high noise) sampling method, one of [euler, euler_a, heun, dpm2, dpm++2s_a, dpm++2m, dpm++2mv2, ipndm, ipndm_v, lcm,
|
||||
ddim_trailing, tcd] default: euler for Flux/SD3/Wan, euler_a otherwise
|
||||
--high-noise-scheduler (high noise) denoiser sigma scheduler, one of [discrete, karras, exponential, ays, gits, smoothstep, sgm_uniform,
|
||||
simple], default: discrete
|
||||
--high-noise-skip-layers (high noise) layers to skip for SLG steps (default: [7,8,9])
|
||||
-r, --ref-image reference image for Flux Kontext models (can be used multiple times)
|
||||
-h, --help show this help message and exit
|
||||
--vae-tile-size tile size for vae tiling, format [X]x[Y] (default: 32x32)
|
||||
--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)
|
||||
```
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef __AVI_WRITER_H__
|
||||
#define __AVI_WRITER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "stable-diffusion.h"
|
||||
|
||||
@@ -130,7 +130,7 @@ int create_mjpg_avi_from_sd_images(const char* filename, sd_image_t* images, int
|
||||
write_u32_le(f, 0); // Colors important
|
||||
|
||||
// 'movi' LIST (video frames)
|
||||
long movi_list_pos = ftell(f);
|
||||
// long movi_list_pos = ftell(f);
|
||||
fwrite("LIST", 4, 1, f);
|
||||
long movi_size_pos = ftell(f);
|
||||
write_u32_le(f, 0); // Placeholder for movi size
|
||||
@@ -149,7 +149,7 @@ int create_mjpg_avi_from_sd_images(const char* filename, sd_image_t* images, int
|
||||
} jpeg_data;
|
||||
|
||||
for (int i = 0; i < num_images; i++) {
|
||||
jpeg_data.buf = NULL;
|
||||
jpeg_data.buf = nullptr;
|
||||
jpeg_data.size = 0;
|
||||
|
||||
// Callback function to collect JPEG data into memory
|
||||
|
||||
+539
-237
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,8 @@
|
||||
for f in *.cpp *.h *.hpp examples/cli/*.cpp examples/cli/*.h; do
|
||||
[[ "$f" == vocab* ]] && continue
|
||||
echo "formatting '$f'"
|
||||
# if [ "$f" != "stable-diffusion.h" ]; then
|
||||
# clang-tidy -fix -p build_linux/ "$f"
|
||||
# fi
|
||||
clang-format -style=file -i "$f"
|
||||
done
|
||||
+1
-1
Submodule ggml updated: 7bffd79a4b...2d3876d554
+360
-351
File diff suppressed because it is too large
Load Diff
@@ -100,7 +100,7 @@ struct LoraModel : public GGMLRunner {
|
||||
bool load_failed = false;
|
||||
bool applied = false;
|
||||
std::vector<int> zero_index_vec = {0};
|
||||
ggml_tensor* zero_index = NULL;
|
||||
ggml_tensor* zero_index = nullptr;
|
||||
enum lora_t type = REGULAR;
|
||||
|
||||
LoraModel(ggml_backend_t backend,
|
||||
@@ -112,7 +112,7 @@ struct LoraModel : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "lora";
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ struct LoraModel : public GGMLRunner {
|
||||
if (is_qkvm_split) {
|
||||
key = key.substr(sizeof("SPLIT_L|") - 1);
|
||||
}
|
||||
struct ggml_tensor* updown = NULL;
|
||||
struct ggml_tensor* updown = nullptr;
|
||||
float scale_value = 1.0f;
|
||||
std::string full_key = lora_pre[type] + key;
|
||||
if (is_bias) {
|
||||
@@ -314,13 +314,13 @@ struct LoraModel : public GGMLRunner {
|
||||
}
|
||||
std::string alpha_name = "";
|
||||
|
||||
ggml_tensor* hada_1_mid = NULL; // tau for tucker decomposition
|
||||
ggml_tensor* hada_1_up = NULL;
|
||||
ggml_tensor* hada_1_down = NULL;
|
||||
ggml_tensor* hada_1_mid = nullptr; // tau for tucker decomposition
|
||||
ggml_tensor* hada_1_up = nullptr;
|
||||
ggml_tensor* hada_1_down = nullptr;
|
||||
|
||||
ggml_tensor* hada_2_mid = NULL; // tau for tucker decomposition
|
||||
ggml_tensor* hada_2_up = NULL;
|
||||
ggml_tensor* hada_2_down = NULL;
|
||||
ggml_tensor* hada_2_mid = nullptr; // tau for tucker decomposition
|
||||
ggml_tensor* hada_2_up = nullptr;
|
||||
ggml_tensor* hada_2_down = nullptr;
|
||||
|
||||
std::string hada_1_mid_name = "";
|
||||
std::string hada_1_down_name = "";
|
||||
@@ -368,19 +368,19 @@ struct LoraModel : public GGMLRunner {
|
||||
applied_lora_tensors.insert(hada_2_up_name);
|
||||
|
||||
applied_lora_tensors.insert(alpha_name);
|
||||
if (hada_1_up == NULL || hada_1_down == NULL || hada_2_up == NULL || hada_2_down == NULL) {
|
||||
if (hada_1_up == nullptr || hada_1_down == nullptr || hada_2_up == nullptr || hada_2_down == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ggml_tensor* updown_1 = ggml_merge_lora(compute_ctx, hada_1_down, hada_1_up, hada_1_mid);
|
||||
struct ggml_tensor* updown_2 = ggml_merge_lora(compute_ctx, hada_2_down, hada_2_up, hada_2_mid);
|
||||
struct ggml_tensor* updown_1 = ggml_ext_merge_lora(compute_ctx, hada_1_down, hada_1_up, hada_1_mid);
|
||||
struct ggml_tensor* updown_2 = ggml_ext_merge_lora(compute_ctx, hada_2_down, hada_2_up, hada_2_mid);
|
||||
updown = ggml_mul_inplace(compute_ctx, updown_1, updown_2);
|
||||
|
||||
// calc_scale
|
||||
// TODO: .dora_scale?
|
||||
int64_t rank = hada_1_down->ne[ggml_n_dims(hada_1_down) - 1];
|
||||
if (lora_tensors.find(alpha_name) != lora_tensors.end()) {
|
||||
float alpha = ggml_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
scale_value = alpha / rank;
|
||||
}
|
||||
} else if (lora_tensors.find(full_key + ".lokr_w1") != lora_tensors.end() || lora_tensors.find(full_key + ".lokr_w1_a") != lora_tensors.end()) {
|
||||
@@ -394,8 +394,8 @@ struct LoraModel : public GGMLRunner {
|
||||
|
||||
std::string alpha_name = full_key + ".alpha";
|
||||
|
||||
ggml_tensor* lokr_w1 = NULL;
|
||||
ggml_tensor* lokr_w2 = NULL;
|
||||
ggml_tensor* lokr_w1 = nullptr;
|
||||
ggml_tensor* lokr_w2 = nullptr;
|
||||
|
||||
std::string lokr_w1_name = "";
|
||||
std::string lokr_w2_name = "";
|
||||
@@ -407,8 +407,8 @@ struct LoraModel : public GGMLRunner {
|
||||
lokr_w1 = to_f32(compute_ctx, lora_tensors[lokr_w1_name]);
|
||||
applied_lora_tensors.insert(lokr_w1_name);
|
||||
} else {
|
||||
ggml_tensor* down = NULL;
|
||||
ggml_tensor* up = NULL;
|
||||
ggml_tensor* down = nullptr;
|
||||
ggml_tensor* up = nullptr;
|
||||
std::string down_name = lokr_w1_name + "_b";
|
||||
std::string up_name = lokr_w1_name + "_a";
|
||||
if (lora_tensors.find(down_name) != lora_tensors.end()) {
|
||||
@@ -418,7 +418,7 @@ struct LoraModel : public GGMLRunner {
|
||||
|
||||
int64_t rank = down->ne[ggml_n_dims(down) - 1];
|
||||
if (lora_tensors.find(alpha_name) != lora_tensors.end()) {
|
||||
float alpha = ggml_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
scale_value = alpha / rank;
|
||||
}
|
||||
}
|
||||
@@ -426,14 +426,14 @@ struct LoraModel : public GGMLRunner {
|
||||
up = to_f32(compute_ctx, lora_tensors[up_name]);
|
||||
applied_lora_tensors.insert(up_name);
|
||||
}
|
||||
lokr_w1 = ggml_merge_lora(compute_ctx, down, up);
|
||||
lokr_w1 = ggml_ext_merge_lora(compute_ctx, down, up);
|
||||
}
|
||||
if (lora_tensors.find(lokr_w2_name) != lora_tensors.end()) {
|
||||
lokr_w2 = to_f32(compute_ctx, lora_tensors[lokr_w2_name]);
|
||||
applied_lora_tensors.insert(lokr_w2_name);
|
||||
} else {
|
||||
ggml_tensor* down = NULL;
|
||||
ggml_tensor* up = NULL;
|
||||
ggml_tensor* down = nullptr;
|
||||
ggml_tensor* up = nullptr;
|
||||
std::string down_name = lokr_w2_name + "_b";
|
||||
std::string up_name = lokr_w2_name + "_a";
|
||||
if (lora_tensors.find(down_name) != lora_tensors.end()) {
|
||||
@@ -442,7 +442,7 @@ struct LoraModel : public GGMLRunner {
|
||||
|
||||
int64_t rank = down->ne[ggml_n_dims(down) - 1];
|
||||
if (lora_tensors.find(alpha_name) != lora_tensors.end()) {
|
||||
float alpha = ggml_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
scale_value = alpha / rank;
|
||||
}
|
||||
}
|
||||
@@ -450,19 +450,19 @@ struct LoraModel : public GGMLRunner {
|
||||
up = to_f32(compute_ctx, lora_tensors[up_name]);
|
||||
applied_lora_tensors.insert(up_name);
|
||||
}
|
||||
lokr_w2 = ggml_merge_lora(compute_ctx, down, up);
|
||||
lokr_w2 = ggml_ext_merge_lora(compute_ctx, down, up);
|
||||
}
|
||||
|
||||
// Technically it might be unused, but I believe it's the expected behavior
|
||||
applied_lora_tensors.insert(alpha_name);
|
||||
|
||||
updown = ggml_kronecker(compute_ctx, lokr_w1, lokr_w2);
|
||||
updown = ggml_ext_kronecker(compute_ctx, lokr_w1, lokr_w2);
|
||||
|
||||
} else {
|
||||
// LoRA mode
|
||||
ggml_tensor* lora_mid = NULL; // tau for tucker decomposition
|
||||
ggml_tensor* lora_up = NULL;
|
||||
ggml_tensor* lora_down = NULL;
|
||||
ggml_tensor* lora_mid = nullptr; // tau for tucker decomposition
|
||||
ggml_tensor* lora_up = nullptr;
|
||||
ggml_tensor* lora_down = nullptr;
|
||||
|
||||
std::string alpha_name = "";
|
||||
std::string scale_name = "";
|
||||
@@ -497,12 +497,12 @@ struct LoraModel : public GGMLRunner {
|
||||
auto split_k_alpha_name = full_key + "k" + suffix + ".alpha";
|
||||
auto split_v_alpha_name = full_key + "v" + suffix + ".alpha";
|
||||
|
||||
ggml_tensor* lora_q_down = NULL;
|
||||
ggml_tensor* lora_q_up = NULL;
|
||||
ggml_tensor* lora_k_down = NULL;
|
||||
ggml_tensor* lora_k_up = NULL;
|
||||
ggml_tensor* lora_v_down = NULL;
|
||||
ggml_tensor* lora_v_up = NULL;
|
||||
ggml_tensor* lora_q_down = nullptr;
|
||||
ggml_tensor* lora_q_up = nullptr;
|
||||
ggml_tensor* lora_k_down = nullptr;
|
||||
ggml_tensor* lora_k_up = nullptr;
|
||||
ggml_tensor* lora_v_down = nullptr;
|
||||
ggml_tensor* lora_v_up = nullptr;
|
||||
|
||||
lora_q_down = to_f32(compute_ctx, lora_tensors[split_q_d_name]);
|
||||
|
||||
@@ -535,30 +535,30 @@ struct LoraModel : public GGMLRunner {
|
||||
float lora_v_scale = 1;
|
||||
|
||||
if (lora_tensors.find(split_q_scale_name) != lora_tensors.end()) {
|
||||
lora_q_scale = ggml_backend_tensor_get_f32(lora_tensors[split_q_scale_name]);
|
||||
lora_q_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_q_scale_name]);
|
||||
applied_lora_tensors.insert(split_q_scale_name);
|
||||
}
|
||||
if (lora_tensors.find(split_k_scale_name) != lora_tensors.end()) {
|
||||
lora_k_scale = ggml_backend_tensor_get_f32(lora_tensors[split_k_scale_name]);
|
||||
lora_k_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_k_scale_name]);
|
||||
applied_lora_tensors.insert(split_k_scale_name);
|
||||
}
|
||||
if (lora_tensors.find(split_v_scale_name) != lora_tensors.end()) {
|
||||
lora_v_scale = ggml_backend_tensor_get_f32(lora_tensors[split_v_scale_name]);
|
||||
lora_v_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_v_scale_name]);
|
||||
applied_lora_tensors.insert(split_v_scale_name);
|
||||
}
|
||||
|
||||
if (lora_tensors.find(split_q_alpha_name) != lora_tensors.end()) {
|
||||
float lora_q_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_q_alpha_name]);
|
||||
float lora_q_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_q_alpha_name]);
|
||||
applied_lora_tensors.insert(split_q_alpha_name);
|
||||
lora_q_scale = lora_q_alpha / q_rank;
|
||||
}
|
||||
if (lora_tensors.find(split_k_alpha_name) != lora_tensors.end()) {
|
||||
float lora_k_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_k_alpha_name]);
|
||||
float lora_k_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_k_alpha_name]);
|
||||
applied_lora_tensors.insert(split_k_alpha_name);
|
||||
lora_k_scale = lora_k_alpha / k_rank;
|
||||
}
|
||||
if (lora_tensors.find(split_v_alpha_name) != lora_tensors.end()) {
|
||||
float lora_v_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_v_alpha_name]);
|
||||
float lora_v_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_v_alpha_name]);
|
||||
applied_lora_tensors.insert(split_v_alpha_name);
|
||||
lora_v_scale = lora_v_alpha / v_rank;
|
||||
}
|
||||
@@ -633,15 +633,15 @@ struct LoraModel : public GGMLRunner {
|
||||
auto split_v_alpha_name = full_key + "attn.to_v" + ".alpha";
|
||||
auto split_m_alpha_name = full_key + "proj_mlp" + ".alpha";
|
||||
|
||||
ggml_tensor* lora_q_down = NULL;
|
||||
ggml_tensor* lora_q_up = NULL;
|
||||
ggml_tensor* lora_k_down = NULL;
|
||||
ggml_tensor* lora_k_up = NULL;
|
||||
ggml_tensor* lora_v_down = NULL;
|
||||
ggml_tensor* lora_v_up = NULL;
|
||||
ggml_tensor* lora_q_down = nullptr;
|
||||
ggml_tensor* lora_q_up = nullptr;
|
||||
ggml_tensor* lora_k_down = nullptr;
|
||||
ggml_tensor* lora_k_up = nullptr;
|
||||
ggml_tensor* lora_v_down = nullptr;
|
||||
ggml_tensor* lora_v_up = nullptr;
|
||||
|
||||
ggml_tensor* lora_m_down = NULL;
|
||||
ggml_tensor* lora_m_up = NULL;
|
||||
ggml_tensor* lora_m_down = nullptr;
|
||||
ggml_tensor* lora_m_up = nullptr;
|
||||
|
||||
lora_q_up = to_f32(compute_ctx, lora_tensors[split_q_u_name]);
|
||||
|
||||
@@ -688,39 +688,39 @@ struct LoraModel : public GGMLRunner {
|
||||
float lora_m_scale = 1;
|
||||
|
||||
if (lora_tensors.find(split_q_scale_name) != lora_tensors.end()) {
|
||||
lora_q_scale = ggml_backend_tensor_get_f32(lora_tensors[split_q_scale_name]);
|
||||
lora_q_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_q_scale_name]);
|
||||
applied_lora_tensors.insert(split_q_scale_name);
|
||||
}
|
||||
if (lora_tensors.find(split_k_scale_name) != lora_tensors.end()) {
|
||||
lora_k_scale = ggml_backend_tensor_get_f32(lora_tensors[split_k_scale_name]);
|
||||
lora_k_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_k_scale_name]);
|
||||
applied_lora_tensors.insert(split_k_scale_name);
|
||||
}
|
||||
if (lora_tensors.find(split_v_scale_name) != lora_tensors.end()) {
|
||||
lora_v_scale = ggml_backend_tensor_get_f32(lora_tensors[split_v_scale_name]);
|
||||
lora_v_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_v_scale_name]);
|
||||
applied_lora_tensors.insert(split_v_scale_name);
|
||||
}
|
||||
if (lora_tensors.find(split_m_scale_name) != lora_tensors.end()) {
|
||||
lora_m_scale = ggml_backend_tensor_get_f32(lora_tensors[split_m_scale_name]);
|
||||
lora_m_scale = ggml_ext_backend_tensor_get_f32(lora_tensors[split_m_scale_name]);
|
||||
applied_lora_tensors.insert(split_m_scale_name);
|
||||
}
|
||||
|
||||
if (lora_tensors.find(split_q_alpha_name) != lora_tensors.end()) {
|
||||
float lora_q_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_q_alpha_name]);
|
||||
float lora_q_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_q_alpha_name]);
|
||||
applied_lora_tensors.insert(split_q_alpha_name);
|
||||
lora_q_scale = lora_q_alpha / q_rank;
|
||||
}
|
||||
if (lora_tensors.find(split_k_alpha_name) != lora_tensors.end()) {
|
||||
float lora_k_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_k_alpha_name]);
|
||||
float lora_k_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_k_alpha_name]);
|
||||
applied_lora_tensors.insert(split_k_alpha_name);
|
||||
lora_k_scale = lora_k_alpha / k_rank;
|
||||
}
|
||||
if (lora_tensors.find(split_v_alpha_name) != lora_tensors.end()) {
|
||||
float lora_v_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_v_alpha_name]);
|
||||
float lora_v_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_v_alpha_name]);
|
||||
applied_lora_tensors.insert(split_v_alpha_name);
|
||||
lora_v_scale = lora_v_alpha / v_rank;
|
||||
}
|
||||
if (lora_tensors.find(split_m_alpha_name) != lora_tensors.end()) {
|
||||
float lora_m_alpha = ggml_backend_tensor_get_f32(lora_tensors[split_m_alpha_name]);
|
||||
float lora_m_alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[split_m_alpha_name]);
|
||||
applied_lora_tensors.insert(split_m_alpha_name);
|
||||
lora_m_scale = lora_m_alpha / m_rank;
|
||||
}
|
||||
@@ -809,23 +809,23 @@ struct LoraModel : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
if (lora_up == NULL || lora_down == NULL) {
|
||||
if (lora_up == nullptr || lora_down == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// calc_scale
|
||||
// TODO: .dora_scale?
|
||||
int64_t rank = lora_down->ne[ggml_n_dims(lora_down) - 1];
|
||||
if (lora_tensors.find(scale_name) != lora_tensors.end()) {
|
||||
scale_value = ggml_backend_tensor_get_f32(lora_tensors[scale_name]);
|
||||
scale_value = ggml_ext_backend_tensor_get_f32(lora_tensors[scale_name]);
|
||||
applied_lora_tensors.insert(scale_name);
|
||||
} else if (lora_tensors.find(alpha_name) != lora_tensors.end()) {
|
||||
float alpha = ggml_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(lora_tensors[alpha_name]);
|
||||
scale_value = alpha / rank;
|
||||
// LOG_DEBUG("rank %s %ld %.2f %.2f", alpha_name.c_str(), rank, alpha, scale_value);
|
||||
applied_lora_tensors.insert(alpha_name);
|
||||
}
|
||||
|
||||
updown = ggml_merge_lora(compute_ctx, lora_down, lora_up, lora_mid);
|
||||
updown = ggml_ext_merge_lora(compute_ctx, lora_down, lora_up, lora_mid);
|
||||
}
|
||||
scale_value *= multiplier;
|
||||
ggml_tensor* original_tensor = model_tensor;
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace LTXV {
|
||||
public:
|
||||
CausalConv3d(int64_t in_channels,
|
||||
int64_t out_channels,
|
||||
int kernel_size = 3,
|
||||
std::tuple<int> stride = {1, 1, 1},
|
||||
int dilation = 1,
|
||||
bool bias = true) {
|
||||
int kernel_size = 3,
|
||||
std::tuple<int, int, int> stride = {1, 1, 1},
|
||||
int dilation = 1,
|
||||
bool bias = true) {
|
||||
time_kernel_size = kernel_size / 2;
|
||||
blocks["conv"] = std::shared_ptr<GGMLBlock>(new Conv3d(in_channels,
|
||||
out_channels,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef __MMDIT_HPP__
|
||||
#define __MMDIT_HPP__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ggml_extend.hpp"
|
||||
#include "model.h"
|
||||
|
||||
@@ -111,7 +113,7 @@ public:
|
||||
auto mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["mlp.0"]);
|
||||
auto mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["mlp.2"]);
|
||||
|
||||
auto t_freq = ggml_nn_timestep_embedding(ctx, t, frequency_embedding_size); // [N, frequency_embedding_size]
|
||||
auto t_freq = ggml_ext_timestep_embedding(ctx, t, frequency_embedding_size); // [N, frequency_embedding_size]
|
||||
|
||||
auto t_emb = mlp_0->forward(ctx, t_freq);
|
||||
t_emb = ggml_silu_inplace(ctx, t_emb);
|
||||
@@ -208,8 +210,8 @@ public:
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x) {
|
||||
auto qkv = pre_attention(ctx, x);
|
||||
x = ggml_nn_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, NULL, false, false, true); // [N, n_token, dim]
|
||||
x = post_attention(ctx, x); // [N, n_token, dim]
|
||||
x = ggml_ext_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, nullptr, false, false, true); // [N, n_token, dim]
|
||||
x = post_attention(ctx, x); // [N, n_token, dim]
|
||||
return x;
|
||||
}
|
||||
};
|
||||
@@ -347,7 +349,7 @@ public:
|
||||
auto attn_in = modulate(ctx, norm1->forward(ctx, x), shift_msa, scale_msa);
|
||||
auto qkv = attn->pre_attention(ctx, attn_in);
|
||||
|
||||
return {qkv, {NULL, NULL, NULL, NULL, NULL}};
|
||||
return {qkv, {nullptr, nullptr, nullptr, nullptr, nullptr}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,8 +441,8 @@ public:
|
||||
auto qkv2 = std::get<1>(qkv_intermediates);
|
||||
auto intermediates = std::get<2>(qkv_intermediates);
|
||||
|
||||
auto attn_out = ggml_nn_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
auto attn2_out = ggml_nn_attention_ext(ctx, backend, qkv2[0], qkv2[1], qkv2[2], num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
auto attn_out = ggml_ext_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
auto attn2_out = ggml_ext_attention_ext(ctx, backend, qkv2[0], qkv2[1], qkv2[2], num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
x = post_attention_x(ctx,
|
||||
attn_out,
|
||||
attn2_out,
|
||||
@@ -456,7 +458,7 @@ public:
|
||||
auto qkv = qkv_intermediates.first;
|
||||
auto intermediates = qkv_intermediates.second;
|
||||
|
||||
auto attn_out = ggml_nn_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
auto attn_out = ggml_ext_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
x = post_attention(ctx,
|
||||
attn_out,
|
||||
intermediates[0],
|
||||
@@ -502,8 +504,8 @@ block_mixing(struct ggml_context* ctx,
|
||||
qkv.push_back(ggml_concat(ctx, context_qkv[i], x_qkv[i], 1));
|
||||
}
|
||||
|
||||
auto attn = ggml_nn_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], x_block->num_heads, NULL, false, false, flash_attn); // [N, n_context + n_token, hidden_size]
|
||||
attn = ggml_cont(ctx, ggml_permute(ctx, attn, 0, 2, 1, 3)); // [n_context + n_token, N, hidden_size]
|
||||
auto attn = ggml_ext_attention_ext(ctx, backend, qkv[0], qkv[1], qkv[2], x_block->num_heads, nullptr, false, false, flash_attn); // [N, n_context + n_token, hidden_size]
|
||||
attn = ggml_cont(ctx, ggml_permute(ctx, attn, 0, 2, 1, 3)); // [n_context + n_token, N, hidden_size]
|
||||
auto context_attn = ggml_view_3d(ctx,
|
||||
attn,
|
||||
attn->ne[0],
|
||||
@@ -532,11 +534,11 @@ block_mixing(struct ggml_context* ctx,
|
||||
context_intermediates[3],
|
||||
context_intermediates[4]);
|
||||
} else {
|
||||
context = NULL;
|
||||
context = nullptr;
|
||||
}
|
||||
|
||||
if (x_block->self_attn) {
|
||||
auto attn2 = ggml_nn_attention_ext(ctx, backend, x_qkv2[0], x_qkv2[1], x_qkv2[2], x_block->num_heads); // [N, n_token, hidden_size]
|
||||
auto attn2 = ggml_ext_attention_ext(ctx, backend, x_qkv2[0], x_qkv2[1], x_qkv2[2], x_block->num_heads); // [N, n_token, hidden_size]
|
||||
|
||||
x = x_block->post_attention_x(ctx,
|
||||
x_attn,
|
||||
@@ -645,7 +647,7 @@ protected:
|
||||
std::string qk_norm;
|
||||
bool flash_attn = false;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, std::string prefix = "") override {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["pos_embed"] = ggml_new_tensor_3d(ctx, wtype, hidden_size, num_patchs, 1);
|
||||
}
|
||||
@@ -823,8 +825,8 @@ public:
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* t,
|
||||
struct ggml_tensor* y = NULL,
|
||||
struct ggml_tensor* context = NULL,
|
||||
struct ggml_tensor* y = nullptr,
|
||||
struct ggml_tensor* context = nullptr,
|
||||
std::vector<int> skip_layers = std::vector<int>()) {
|
||||
// Forward pass of DiT.
|
||||
// x: (N, C, H, W) tensor of spatial inputs (images or latent representations of images)
|
||||
@@ -843,14 +845,14 @@ public:
|
||||
x = ggml_add(ctx, patch_embed, pos_embed); // [N, H*W, hidden_size]
|
||||
|
||||
auto c = t_embedder->forward(ctx, t); // [N, hidden_size]
|
||||
if (y != NULL && adm_in_channels != -1) {
|
||||
if (y != nullptr && adm_in_channels != -1) {
|
||||
auto y_embedder = std::dynamic_pointer_cast<VectorEmbedder>(blocks["y_embedder"]);
|
||||
|
||||
y = y_embedder->forward(ctx, y); // [N, hidden_size]
|
||||
c = ggml_add(ctx, c, y);
|
||||
}
|
||||
|
||||
if (context != NULL) {
|
||||
if (context != nullptr) {
|
||||
auto context_embedder = std::dynamic_pointer_cast<Linear>(blocks["context_embedder"]);
|
||||
|
||||
context = context_embedder->forward(ctx, context); // [N, L, D] aka [N, L, 1536]
|
||||
@@ -875,7 +877,7 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
mmdit.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "mmdit";
|
||||
}
|
||||
|
||||
@@ -913,8 +915,8 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* y,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL,
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr,
|
||||
std::vector<int> skip_layers = std::vector<int>()) {
|
||||
// x: [N, in_channels, h, w]
|
||||
// timesteps: [N, ]
|
||||
@@ -930,11 +932,11 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(10 * 1024 * 1024); // 10 MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
// cpu f16: pass
|
||||
@@ -955,7 +957,7 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
ggml_set_f32(y, 0.01f);
|
||||
// print_ggml_tensor(y);
|
||||
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, timesteps, context, y, &out, work_ctx);
|
||||
@@ -970,7 +972,7 @@ struct MMDiTRunner : public GGMLRunner {
|
||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
std::shared_ptr<MMDiTRunner> mmdit = std::shared_ptr<MMDiTRunner>(new MMDiTRunner(backend, false, false));
|
||||
std::shared_ptr<MMDiTRunner> mmdit = std::make_shared<MMDiTRunner>(backend, false, false);
|
||||
{
|
||||
LOG_INFO("loading from '%s'", file_path.c_str());
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
@@ -113,7 +113,6 @@ const char* unused_tensors[] = {
|
||||
"text_encoders.t5xxl.transformer.encoder.embed_tokens.weight", // only used during training
|
||||
"text_encoders.qwen2vl.output.weight",
|
||||
"text_encoders.qwen2vl.lm_head.",
|
||||
"text_encoders.qwen2vl.visual.",
|
||||
};
|
||||
|
||||
bool is_unused_tensor(std::string name) {
|
||||
@@ -212,6 +211,24 @@ std::unordered_map<std::string, std::string> qwenvl_name_map{
|
||||
{"output_norm.", "model.norm."},
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::string> qwenvl_vision_name_map{
|
||||
{"mm.", "merger.mlp."},
|
||||
{"v.post_ln.", "merger.ln_q."},
|
||||
{"v.patch_embd.weight", "patch_embed.proj.0.weight"},
|
||||
{"patch_embed.proj.0.weight.1", "patch_embed.proj.1.weight"},
|
||||
{"v.patch_embd.weight.1", "patch_embed.proj.1.weight"},
|
||||
{"v.blk.", "blocks."},
|
||||
{"attn_q.", "attn.q_proj."},
|
||||
{"attn_k.", "attn.k_proj."},
|
||||
{"attn_v.", "attn.v_proj."},
|
||||
{"attn_out.", "attn.proj."},
|
||||
{"ffn_down.", "mlp.down_proj."},
|
||||
{"ffn_gate.", "mlp.gate_proj."},
|
||||
{"ffn_up.", "mlp.up_proj."},
|
||||
{"ln1.", "norm1."},
|
||||
{"ln2.", "norm2."},
|
||||
};
|
||||
|
||||
std::string convert_cond_model_name(const std::string& name) {
|
||||
std::string new_name = name;
|
||||
std::string prefix;
|
||||
@@ -270,10 +287,19 @@ std::string convert_cond_model_name(const std::string& name) {
|
||||
new_name.replace(pos, 11, "layer.0.SelfAttention.relative_attention_bias.");
|
||||
}
|
||||
} else if (contains(name, "qwen2vl")) {
|
||||
for (auto kv : qwenvl_name_map) {
|
||||
size_t pos = new_name.find(kv.first);
|
||||
if (pos != std::string::npos) {
|
||||
new_name.replace(pos, kv.first.size(), kv.second);
|
||||
if (contains(name, "qwen2vl.visual")) {
|
||||
for (auto kv : qwenvl_vision_name_map) {
|
||||
size_t pos = new_name.find(kv.first);
|
||||
if (pos != std::string::npos) {
|
||||
new_name.replace(pos, kv.first.size(), kv.second);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto kv : qwenvl_name_map) {
|
||||
size_t pos = new_name.find(kv.first);
|
||||
if (pos != std::string::npos) {
|
||||
new_name.replace(pos, kv.first.size(), kv.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name == "text_encoders.t5xxl.transformer.token_embd.weight") {
|
||||
@@ -304,6 +330,10 @@ std::string convert_cond_model_name(const std::string& name) {
|
||||
return new_name;
|
||||
}
|
||||
|
||||
if (new_name == "model.text_projection.weight") {
|
||||
new_name = "transformer.text_model.text_projection";
|
||||
}
|
||||
|
||||
if (open_clip_to_hf_clip_model.find(new_name) != open_clip_to_hf_clip_model.end()) {
|
||||
new_name = open_clip_to_hf_clip_model[new_name];
|
||||
}
|
||||
@@ -597,6 +627,14 @@ std::string convert_tensor_name(std::string name) {
|
||||
if (starts_with(name, "diffusion_model")) {
|
||||
name = "model." + name;
|
||||
}
|
||||
if (starts_with(name, "model.diffusion_model.up_blocks.0.attentions.0.")) {
|
||||
name.replace(0, sizeof("model.diffusion_model.up_blocks.0.attentions.0.") - 1,
|
||||
"model.diffusion_model.output_blocks.0.1.");
|
||||
}
|
||||
if (starts_with(name, "model.diffusion_model.up_blocks.0.attentions.1.")) {
|
||||
name.replace(0, sizeof("model.diffusion_model.up_blocks.0.attentions.1.") - 1,
|
||||
"model.diffusion_model.output_blocks.1.1.");
|
||||
}
|
||||
// size_t pos = name.find("lora_A");
|
||||
// if (pos != std::string::npos) {
|
||||
// name.replace(pos, strlen("lora_A"), "lora_up");
|
||||
@@ -843,7 +881,6 @@ uint16_t f8_e5m2_to_f16(uint8_t fp8) {
|
||||
}
|
||||
|
||||
if (exponent == 0) { // subnormal numbers
|
||||
fp16_exponent = 0;
|
||||
fp16_mantissa = (mantissa << 8);
|
||||
return fp16_sign | fp16_mantissa;
|
||||
}
|
||||
@@ -922,7 +959,7 @@ void convert_tensor(void* src,
|
||||
ggml_fp16_to_fp32_row((ggml_fp16_t*)src, (float*)dst, n);
|
||||
} else {
|
||||
auto qtype = ggml_get_type_traits(src_type);
|
||||
if (qtype->to_float == NULL) {
|
||||
if (qtype->to_float == nullptr) {
|
||||
throw std::runtime_error(format("type %s unsupported for integer quantization: no dequantization available",
|
||||
ggml_type_name(src_type)));
|
||||
}
|
||||
@@ -932,7 +969,7 @@ void convert_tensor(void* src,
|
||||
// src_type == GGML_TYPE_F16 => dst_type is quantized
|
||||
// src_type is quantized => dst_type == GGML_TYPE_F16 or dst_type is quantized
|
||||
auto qtype = ggml_get_type_traits(src_type);
|
||||
if (qtype->to_float == NULL) {
|
||||
if (qtype->to_float == nullptr) {
|
||||
throw std::runtime_error(format("type %s unsupported for integer quantization: no dequantization available",
|
||||
ggml_type_name(src_type)));
|
||||
}
|
||||
@@ -994,7 +1031,7 @@ std::map<char, int> unicode_to_byte() {
|
||||
|
||||
bool is_zip_file(const std::string& file_path) {
|
||||
struct zip_t* zip = zip_open(file_path.c_str(), 0, 'r');
|
||||
if (zip == NULL) {
|
||||
if (zip == nullptr) {
|
||||
return false;
|
||||
}
|
||||
zip_close(zip);
|
||||
@@ -1090,8 +1127,8 @@ bool ModelLoader::init_from_gguf_file(const std::string& file_path, const std::s
|
||||
file_paths_.push_back(file_path);
|
||||
size_t file_index = file_paths_.size() - 1;
|
||||
|
||||
gguf_context* ctx_gguf_ = NULL;
|
||||
ggml_context* ctx_meta_ = NULL;
|
||||
gguf_context* ctx_gguf_ = nullptr;
|
||||
ggml_context* ctx_meta_ = nullptr;
|
||||
|
||||
ctx_gguf_ = gguf_init_from_file(file_path.c_str(), {true, &ctx_meta_});
|
||||
if (!ctx_gguf_) {
|
||||
@@ -1700,7 +1737,7 @@ bool ModelLoader::init_from_ckpt_file(const std::string& file_path, const std::s
|
||||
size_t file_index = file_paths_.size() - 1;
|
||||
|
||||
struct zip_t* zip = zip_open(file_path.c_str(), 0, 'r');
|
||||
if (zip == NULL) {
|
||||
if (zip == nullptr) {
|
||||
LOG_ERROR("failed to open '%s'", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -1713,7 +1750,7 @@ bool ModelLoader::init_from_ckpt_file(const std::string& file_path, const std::s
|
||||
if (pos != std::string::npos) {
|
||||
std::string dir = name.substr(0, pos);
|
||||
printf("ZIP %d, name = %s, dir = %s \n", i, name.c_str(), dir.c_str());
|
||||
void* pkl_data = NULL;
|
||||
void* pkl_data = nullptr;
|
||||
size_t pkl_size;
|
||||
zip_entry_read(zip, &pkl_data, &pkl_size);
|
||||
|
||||
@@ -1741,7 +1778,6 @@ bool ModelLoader::model_is_unet() {
|
||||
|
||||
SDVersion ModelLoader::get_sd_version() {
|
||||
TensorStorage token_embedding_weight, input_block_weight;
|
||||
bool input_block_checked = false;
|
||||
|
||||
bool has_multiple_encoders = false;
|
||||
bool is_unet = false;
|
||||
@@ -1751,14 +1787,15 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
bool is_wan = false;
|
||||
int64_t patch_embedding_channels = 0;
|
||||
bool has_img_emb = false;
|
||||
bool has_middle_block_1 = false;
|
||||
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
if (!(is_xl || is_flux)) {
|
||||
if (!(is_xl)) {
|
||||
if (tensor_storage.name.find("model.diffusion_model.double_blocks.") != std::string::npos) {
|
||||
is_flux = true;
|
||||
if (input_block_checked) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tensor_storage.name.find("model.diffusion_model.nerf_final_layer_conv.") != std::string::npos) {
|
||||
return VERSION_CHROMA_RADIANCE;
|
||||
}
|
||||
if (tensor_storage.name.find("model.diffusion_model.joint_blocks.") != std::string::npos) {
|
||||
return VERSION_SD3;
|
||||
@@ -1775,28 +1812,29 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
if (tensor_storage.name.find("model.diffusion_model.img_emb") != std::string::npos) {
|
||||
has_img_emb = true;
|
||||
}
|
||||
if (tensor_storage.name.find("model.diffusion_model.input_blocks.") != std::string::npos || tensor_storage.name.find("unet.down_blocks.") != std::string::npos) {
|
||||
if (tensor_storage.name.find("model.diffusion_model.input_blocks.") != std::string::npos ||
|
||||
tensor_storage.name.find("unet.down_blocks.") != std::string::npos) {
|
||||
is_unet = true;
|
||||
if (has_multiple_encoders) {
|
||||
is_xl = true;
|
||||
if (input_block_checked) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tensor_storage.name.find("conditioner.embedders.1") != std::string::npos || tensor_storage.name.find("cond_stage_model.1") != std::string::npos || tensor_storage.name.find("te.1") != std::string::npos) {
|
||||
if (tensor_storage.name.find("conditioner.embedders.1") != std::string::npos ||
|
||||
tensor_storage.name.find("cond_stage_model.1") != std::string::npos ||
|
||||
tensor_storage.name.find("te.1") != std::string::npos) {
|
||||
has_multiple_encoders = true;
|
||||
if (is_unet) {
|
||||
is_xl = true;
|
||||
if (input_block_checked) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tensor_storage.name.find("model.diffusion_model.input_blocks.8.0.time_mixer.mix_factor") != std::string::npos) {
|
||||
return VERSION_SVD;
|
||||
}
|
||||
}
|
||||
if (tensor_storage.name.find("model.diffusion_model.middle_block.1.") != std::string::npos ||
|
||||
tensor_storage.name.find("unet.mid_block.resnets.1.") != std::string::npos) {
|
||||
has_middle_block_1 = true;
|
||||
}
|
||||
if (tensor_storage.name == "cond_stage_model.transformer.text_model.embeddings.token_embedding.weight" ||
|
||||
tensor_storage.name == "cond_stage_model.model.token_embedding.weight" ||
|
||||
tensor_storage.name == "text_model.embeddings.token_embedding.weight" ||
|
||||
@@ -1806,12 +1844,10 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
token_embedding_weight = tensor_storage;
|
||||
// break;
|
||||
}
|
||||
if (tensor_storage.name == "model.diffusion_model.input_blocks.0.0.weight" || tensor_storage.name == "model.diffusion_model.img_in.weight" || tensor_storage.name == "unet.conv_in.weight") {
|
||||
input_block_weight = tensor_storage;
|
||||
input_block_checked = true;
|
||||
if (is_xl || is_flux) {
|
||||
break;
|
||||
}
|
||||
if (tensor_storage.name == "model.diffusion_model.input_blocks.0.0.weight" ||
|
||||
tensor_storage.name == "model.diffusion_model.img_in.weight" ||
|
||||
tensor_storage.name == "unet.conv_in.weight") {
|
||||
input_block_weight = tensor_storage;
|
||||
}
|
||||
}
|
||||
if (is_wan) {
|
||||
@@ -1833,6 +1869,9 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
if (is_ip2p) {
|
||||
return VERSION_SDXL_PIX2PIX;
|
||||
}
|
||||
if (!has_middle_block_1) {
|
||||
return VERSION_SDXL_SSD1B;
|
||||
}
|
||||
return VERSION_SDXL;
|
||||
}
|
||||
|
||||
@@ -1856,6 +1895,9 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
if (is_ip2p) {
|
||||
return VERSION_SD1_PIX2PIX;
|
||||
}
|
||||
if (!has_middle_block_1) {
|
||||
return VERSION_SD1_TINY_UNET;
|
||||
}
|
||||
return VERSION_SD1;
|
||||
} else if (token_embedding_weight.ne[0] == 1024) {
|
||||
if (is_inpaint) {
|
||||
@@ -1866,24 +1908,25 @@ SDVersion ModelLoader::get_sd_version() {
|
||||
return VERSION_COUNT;
|
||||
}
|
||||
|
||||
ggml_type ModelLoader::get_sd_wtype() {
|
||||
std::map<ggml_type, uint32_t> ModelLoader::get_wtype_stat() {
|
||||
std::map<ggml_type, uint32_t> wtype_stat;
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
if (is_unused_tensor(tensor_storage.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ggml_is_quantized(tensor_storage.type)) {
|
||||
return tensor_storage.type;
|
||||
}
|
||||
|
||||
if (tensor_should_be_converted(tensor_storage, GGML_TYPE_Q4_K)) {
|
||||
return tensor_storage.type;
|
||||
auto iter = wtype_stat.find(tensor_storage.type);
|
||||
if (iter != wtype_stat.end()) {
|
||||
iter->second++;
|
||||
} else {
|
||||
wtype_stat[tensor_storage.type] = 1;
|
||||
}
|
||||
}
|
||||
return GGML_TYPE_COUNT;
|
||||
return wtype_stat;
|
||||
}
|
||||
|
||||
ggml_type ModelLoader::get_conditioner_wtype() {
|
||||
std::map<ggml_type, uint32_t> ModelLoader::get_conditioner_wtype_stat() {
|
||||
std::map<ggml_type, uint32_t> wtype_stat;
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
if (is_unused_tensor(tensor_storage.name)) {
|
||||
continue;
|
||||
@@ -1896,18 +1939,18 @@ ggml_type ModelLoader::get_conditioner_wtype() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ggml_is_quantized(tensor_storage.type)) {
|
||||
return tensor_storage.type;
|
||||
}
|
||||
|
||||
if (tensor_should_be_converted(tensor_storage, GGML_TYPE_Q4_K)) {
|
||||
return tensor_storage.type;
|
||||
auto iter = wtype_stat.find(tensor_storage.type);
|
||||
if (iter != wtype_stat.end()) {
|
||||
iter->second++;
|
||||
} else {
|
||||
wtype_stat[tensor_storage.type] = 1;
|
||||
}
|
||||
}
|
||||
return GGML_TYPE_COUNT;
|
||||
return wtype_stat;
|
||||
}
|
||||
|
||||
ggml_type ModelLoader::get_diffusion_model_wtype() {
|
||||
std::map<ggml_type, uint32_t> ModelLoader::get_diffusion_model_wtype_stat() {
|
||||
std::map<ggml_type, uint32_t> wtype_stat;
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
if (is_unused_tensor(tensor_storage.name)) {
|
||||
continue;
|
||||
@@ -1917,18 +1960,18 @@ ggml_type ModelLoader::get_diffusion_model_wtype() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ggml_is_quantized(tensor_storage.type)) {
|
||||
return tensor_storage.type;
|
||||
}
|
||||
|
||||
if (tensor_should_be_converted(tensor_storage, GGML_TYPE_Q4_K)) {
|
||||
return tensor_storage.type;
|
||||
auto iter = wtype_stat.find(tensor_storage.type);
|
||||
if (iter != wtype_stat.end()) {
|
||||
iter->second++;
|
||||
} else {
|
||||
wtype_stat[tensor_storage.type] = 1;
|
||||
}
|
||||
}
|
||||
return GGML_TYPE_COUNT;
|
||||
return wtype_stat;
|
||||
}
|
||||
|
||||
ggml_type ModelLoader::get_vae_wtype() {
|
||||
std::map<ggml_type, uint32_t> ModelLoader::get_vae_wtype_stat() {
|
||||
std::map<ggml_type, uint32_t> wtype_stat;
|
||||
for (auto& tensor_storage : tensor_storages) {
|
||||
if (is_unused_tensor(tensor_storage.name)) {
|
||||
continue;
|
||||
@@ -1939,15 +1982,14 @@ ggml_type ModelLoader::get_vae_wtype() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ggml_is_quantized(tensor_storage.type)) {
|
||||
return tensor_storage.type;
|
||||
}
|
||||
|
||||
if (tensor_should_be_converted(tensor_storage, GGML_TYPE_Q4_K)) {
|
||||
return tensor_storage.type;
|
||||
auto iter = wtype_stat.find(tensor_storage.type);
|
||||
if (iter != wtype_stat.end()) {
|
||||
iter->second++;
|
||||
} else {
|
||||
wtype_stat[tensor_storage.type] = 1;
|
||||
}
|
||||
}
|
||||
return GGML_TYPE_COUNT;
|
||||
return wtype_stat;
|
||||
}
|
||||
|
||||
void ModelLoader::set_wtype_override(ggml_type wtype, std::string prefix) {
|
||||
@@ -2118,10 +2160,10 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
for (int i = 0; i < n_threads; ++i) {
|
||||
workers.emplace_back([&, file_path, is_zip]() {
|
||||
std::ifstream file;
|
||||
struct zip_t* zip = NULL;
|
||||
struct zip_t* zip = nullptr;
|
||||
if (is_zip) {
|
||||
zip = zip_open(file_path.c_str(), 0, 'r');
|
||||
if (zip == NULL) {
|
||||
if (zip == nullptr) {
|
||||
LOG_ERROR("failed to open zip '%s'", file_path.c_str());
|
||||
failed = true;
|
||||
return;
|
||||
@@ -2146,7 +2188,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
}
|
||||
|
||||
const TensorStorage& tensor_storage = *file_tensors[idx];
|
||||
ggml_tensor* dst_tensor = NULL;
|
||||
ggml_tensor* dst_tensor = nullptr;
|
||||
|
||||
t0 = ggml_time_ms();
|
||||
|
||||
@@ -2156,7 +2198,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst_tensor == NULL) {
|
||||
if (dst_tensor == nullptr) {
|
||||
t1 = ggml_time_ms();
|
||||
read_time_ms.fetch_add(t1 - t0);
|
||||
continue;
|
||||
@@ -2165,7 +2207,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
size_t nbytes_to_read = tensor_storage.nbytes_to_read();
|
||||
|
||||
auto read_data = [&](char* buf, size_t n) {
|
||||
if (zip != NULL) {
|
||||
if (zip != nullptr) {
|
||||
zip_entry_openbyindex(zip, tensor_storage.index_in_zip);
|
||||
size_t entry_size = zip_entry_size(zip);
|
||||
if (entry_size != n) {
|
||||
@@ -2189,7 +2231,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
}
|
||||
};
|
||||
|
||||
if (dst_tensor->buffer == NULL || ggml_backend_buffer_is_host(dst_tensor->buffer)) {
|
||||
if (dst_tensor->buffer == nullptr || ggml_backend_buffer_is_host(dst_tensor->buffer)) {
|
||||
if (tensor_storage.type == dst_tensor->type) {
|
||||
GGML_ASSERT(ggml_nbytes(dst_tensor) == tensor_storage.nbytes());
|
||||
if (tensor_storage.is_f64 || tensor_storage.is_i64) {
|
||||
@@ -2291,7 +2333,7 @@ bool ModelLoader::load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_thread
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zip != NULL) {
|
||||
if (zip != nullptr) {
|
||||
zip_close(zip);
|
||||
}
|
||||
});
|
||||
@@ -2481,7 +2523,7 @@ bool ModelLoader::save_to_gguf_file(const std::string& file_path, ggml_type type
|
||||
mem_size += tensor_storages.size() * ggml_tensor_overhead();
|
||||
mem_size += get_params_mem_size(backend, type);
|
||||
LOG_INFO("model tensors mem size: %.2fMB", mem_size / 1024.f / 1024.f);
|
||||
ggml_context* ggml_ctx = ggml_init({mem_size, NULL, false});
|
||||
ggml_context* ggml_ctx = ggml_init({mem_size, nullptr, false});
|
||||
|
||||
gguf_context* gguf_ctx = gguf_init_empty();
|
||||
|
||||
@@ -2507,7 +2549,7 @@ bool ModelLoader::save_to_gguf_file(const std::string& file_path, ggml_type type
|
||||
|
||||
std::lock_guard<std::mutex> lock(tensor_mutex);
|
||||
ggml_tensor* tensor = ggml_new_tensor(ggml_ctx, tensor_type, tensor_storage.n_dims, tensor_storage.ne);
|
||||
if (tensor == NULL) {
|
||||
if (tensor == nullptr) {
|
||||
LOG_ERROR("ggml_new_tensor failed");
|
||||
return false;
|
||||
}
|
||||
@@ -2540,7 +2582,7 @@ bool ModelLoader::save_to_gguf_file(const std::string& file_path, ggml_type type
|
||||
|
||||
int64_t ModelLoader::get_params_mem_size(ggml_backend_t backend, ggml_type type) {
|
||||
size_t alignment = 128;
|
||||
if (backend != NULL) {
|
||||
if (backend != nullptr) {
|
||||
alignment = ggml_backend_get_alignment(backend);
|
||||
}
|
||||
int64_t mem_size = 0;
|
||||
@@ -2570,7 +2612,7 @@ bool convert(const char* input_path, const char* vae_path, const char* output_pa
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vae_path != NULL && strlen(vae_path) > 0) {
|
||||
if (vae_path != nullptr && strlen(vae_path) > 0) {
|
||||
if (!model_loader.init_from_file(vae_path, "vae.")) {
|
||||
LOG_ERROR("init model loader from file failed: '%s'", vae_path);
|
||||
return false;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ggml-backend.h"
|
||||
@@ -22,17 +23,20 @@ enum SDVersion {
|
||||
VERSION_SD1,
|
||||
VERSION_SD1_INPAINT,
|
||||
VERSION_SD1_PIX2PIX,
|
||||
VERSION_SD1_TINY_UNET,
|
||||
VERSION_SD2,
|
||||
VERSION_SD2_INPAINT,
|
||||
VERSION_SDXL,
|
||||
VERSION_SDXL_INPAINT,
|
||||
VERSION_SDXL_PIX2PIX,
|
||||
VERSION_SDXL_SSD1B,
|
||||
VERSION_SVD,
|
||||
VERSION_SD3,
|
||||
VERSION_FLUX,
|
||||
VERSION_FLUX_FILL,
|
||||
VERSION_FLUX_CONTROLS,
|
||||
VERSION_FLEX_2,
|
||||
VERSION_CHROMA_RADIANCE,
|
||||
VERSION_WAN2,
|
||||
VERSION_WAN2_2_I2V,
|
||||
VERSION_WAN2_2_TI2V,
|
||||
@@ -41,7 +45,7 @@ enum SDVersion {
|
||||
};
|
||||
|
||||
static inline bool sd_version_is_sd1(SDVersion version) {
|
||||
if (version == VERSION_SD1 || version == VERSION_SD1_INPAINT || version == VERSION_SD1_PIX2PIX) {
|
||||
if (version == VERSION_SD1 || version == VERSION_SD1_INPAINT || version == VERSION_SD1_PIX2PIX || version == VERSION_SD1_TINY_UNET) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -55,7 +59,7 @@ static inline bool sd_version_is_sd2(SDVersion version) {
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_sdxl(SDVersion version) {
|
||||
if (version == VERSION_SDXL || version == VERSION_SDXL_INPAINT || version == VERSION_SDXL_PIX2PIX) {
|
||||
if (version == VERSION_SDXL || version == VERSION_SDXL_INPAINT || version == VERSION_SDXL_PIX2PIX || version == VERSION_SDXL_SSD1B) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -69,7 +73,11 @@ static inline bool sd_version_is_sd3(SDVersion version) {
|
||||
}
|
||||
|
||||
static inline bool sd_version_is_flux(SDVersion version) {
|
||||
if (version == VERSION_FLUX || version == VERSION_FLUX_FILL || version == VERSION_FLUX_CONTROLS || version == VERSION_FLEX_2) {
|
||||
if (version == VERSION_FLUX ||
|
||||
version == VERSION_FLUX_FILL ||
|
||||
version == VERSION_FLUX_CONTROLS ||
|
||||
version == VERSION_FLEX_2 ||
|
||||
version == VERSION_CHROMA_RADIANCE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -140,8 +148,8 @@ struct TensorStorage {
|
||||
|
||||
TensorStorage() = default;
|
||||
|
||||
TensorStorage(const std::string& name, ggml_type type, const int64_t* ne, int n_dims, size_t file_index, size_t offset = 0)
|
||||
: name(name), type(type), n_dims(n_dims), file_index(file_index), offset(offset) {
|
||||
TensorStorage(std::string name, ggml_type type, const int64_t* ne, int n_dims, size_t file_index, size_t offset = 0)
|
||||
: name(std::move(name)), type(type), n_dims(n_dims), file_index(file_index), offset(offset) {
|
||||
for (int i = 0; i < n_dims; i++) {
|
||||
this->ne[i] = ne[i];
|
||||
}
|
||||
@@ -259,10 +267,10 @@ public:
|
||||
bool init_from_file(const std::string& file_path, const std::string& prefix = "");
|
||||
bool model_is_unet();
|
||||
SDVersion get_sd_version();
|
||||
ggml_type get_sd_wtype();
|
||||
ggml_type get_conditioner_wtype();
|
||||
ggml_type get_diffusion_model_wtype();
|
||||
ggml_type get_vae_wtype();
|
||||
std::map<ggml_type, uint32_t> get_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_conditioner_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_diffusion_model_wtype_stat();
|
||||
std::map<ggml_type, uint32_t> get_vae_wtype_stat();
|
||||
void set_wtype_override(ggml_type wtype, std::string prefix = "");
|
||||
bool load_tensors(on_new_tensor_cb_t on_new_tensor_cb, int n_threads = 0);
|
||||
bool load_tensors(std::map<std::string, struct ggml_tensor*>& tensors,
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
auto layer_norm = std::dynamic_pointer_cast<LayerNorm>(blocks["layernorm"]);
|
||||
|
||||
struct ggml_tensor* r = x;
|
||||
// x = ggml_nn_layer_norm(ctx, x, ln_w, ln_b);
|
||||
// x = ggml_ext_layer_norm(ctx, x, ln_w, ln_b);
|
||||
x = layer_norm->forward(ctx, x);
|
||||
// x = ggml_add(ctx, ggml_mul_mat(ctx, fc1_w, x), fc1_b);
|
||||
x = fc1->forward(ctx, x);
|
||||
@@ -472,8 +472,8 @@ public:
|
||||
struct ggml_tensor* prompt_embeds_d = to_backend(prompt_embeds);
|
||||
struct ggml_tensor* id_embeds_d = to_backend(id_embeds);
|
||||
|
||||
struct ggml_tensor* left = NULL;
|
||||
struct ggml_tensor* right = NULL;
|
||||
struct ggml_tensor* left = nullptr;
|
||||
struct ggml_tensor* right = nullptr;
|
||||
for (int i = 0; i < class_tokens_mask.size(); i++) {
|
||||
if (class_tokens_mask[i]) {
|
||||
// printf(" 1,");
|
||||
@@ -528,7 +528,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
struct ggml_tensor* updated_prompt_embeds = NULL;
|
||||
struct ggml_tensor* updated_prompt_embeds = nullptr;
|
||||
if (pm_version == PM_VERSION_1)
|
||||
updated_prompt_embeds = id_encoder.forward(ctx0,
|
||||
runtime_backend,
|
||||
@@ -638,7 +638,7 @@ struct PhotoMakerIDEmbed : public GGMLRunner {
|
||||
pos = tensors.find("pmid.id_embeds");
|
||||
if (pos != tensors.end())
|
||||
return pos->second;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+35
-37
@@ -6,8 +6,8 @@
|
||||
|
||||
void convolve(struct ggml_tensor* input, struct ggml_tensor* output, struct ggml_tensor* kernel, int padding) {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = 20 * 1024 * 1024; // 10
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_size = 80 * input->ne[0] * input->ne[1]; // 20M for 512x512
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
struct ggml_context* ctx0 = ggml_init(params);
|
||||
struct ggml_tensor* kernel_fp16 = ggml_new_tensor_4d(ctx0, GGML_TYPE_F16, kernel->ne[0], kernel->ne[1], 1, 1);
|
||||
@@ -28,7 +28,7 @@ void gaussian_kernel(struct ggml_tensor* kernel) {
|
||||
for (int x = 0; x < kernel->ne[1]; x++) {
|
||||
float gy = -ks_mid + x;
|
||||
float k_ = expf(-((gx * gx + gy * gy) / (2.0f * powf(sigma, 2.0f)))) * normal;
|
||||
ggml_tensor_set_f32(kernel, k_, x, y);
|
||||
ggml_ext_tensor_set_f32(kernel, k_, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,11 @@ void gaussian_kernel(struct ggml_tensor* kernel) {
|
||||
void grayscale(struct ggml_tensor* rgb_img, struct ggml_tensor* grayscale) {
|
||||
for (int iy = 0; iy < rgb_img->ne[1]; iy++) {
|
||||
for (int ix = 0; ix < rgb_img->ne[0]; ix++) {
|
||||
float r = ggml_tensor_get_f32(rgb_img, ix, iy);
|
||||
float g = ggml_tensor_get_f32(rgb_img, ix, iy, 1);
|
||||
float b = ggml_tensor_get_f32(rgb_img, ix, iy, 2);
|
||||
float r = ggml_ext_tensor_get_f32(rgb_img, ix, iy);
|
||||
float g = ggml_ext_tensor_get_f32(rgb_img, ix, iy, 1);
|
||||
float b = ggml_ext_tensor_get_f32(rgb_img, ix, iy, 2);
|
||||
float gray = 0.2989f * r + 0.5870f * g + 0.1140f * b;
|
||||
ggml_tensor_set_f32(grayscale, gray, ix, iy);
|
||||
ggml_ext_tensor_set_f32(grayscale, gray, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,37 +81,37 @@ void normalize_tensor(struct ggml_tensor* g) {
|
||||
void non_max_supression(struct ggml_tensor* result, struct ggml_tensor* G, struct ggml_tensor* D) {
|
||||
for (int iy = 1; iy < result->ne[1] - 1; iy++) {
|
||||
for (int ix = 1; ix < result->ne[0] - 1; ix++) {
|
||||
float angle = ggml_tensor_get_f32(D, ix, iy) * 180.0f / M_PI_;
|
||||
float angle = ggml_ext_tensor_get_f32(D, ix, iy) * 180.0f / M_PI_;
|
||||
angle = angle < 0.0f ? angle += 180.0f : angle;
|
||||
float q = 1.0f;
|
||||
float r = 1.0f;
|
||||
|
||||
// angle 0
|
||||
if ((0 >= angle && angle < 22.5f) || (157.5f >= angle && angle <= 180)) {
|
||||
q = ggml_tensor_get_f32(G, ix, iy + 1);
|
||||
r = ggml_tensor_get_f32(G, ix, iy - 1);
|
||||
q = ggml_ext_tensor_get_f32(G, ix, iy + 1);
|
||||
r = ggml_ext_tensor_get_f32(G, ix, iy - 1);
|
||||
}
|
||||
// angle 45
|
||||
else if (22.5f >= angle && angle < 67.5f) {
|
||||
q = ggml_tensor_get_f32(G, ix + 1, iy - 1);
|
||||
r = ggml_tensor_get_f32(G, ix - 1, iy + 1);
|
||||
q = ggml_ext_tensor_get_f32(G, ix + 1, iy - 1);
|
||||
r = ggml_ext_tensor_get_f32(G, ix - 1, iy + 1);
|
||||
}
|
||||
// angle 90
|
||||
else if (67.5f >= angle && angle < 112.5) {
|
||||
q = ggml_tensor_get_f32(G, ix + 1, iy);
|
||||
r = ggml_tensor_get_f32(G, ix - 1, iy);
|
||||
q = ggml_ext_tensor_get_f32(G, ix + 1, iy);
|
||||
r = ggml_ext_tensor_get_f32(G, ix - 1, iy);
|
||||
}
|
||||
// angle 135
|
||||
else if (112.5 >= angle && angle < 157.5f) {
|
||||
q = ggml_tensor_get_f32(G, ix - 1, iy - 1);
|
||||
r = ggml_tensor_get_f32(G, ix + 1, iy + 1);
|
||||
q = ggml_ext_tensor_get_f32(G, ix - 1, iy - 1);
|
||||
r = ggml_ext_tensor_get_f32(G, ix + 1, iy + 1);
|
||||
}
|
||||
|
||||
float cur = ggml_tensor_get_f32(G, ix, iy);
|
||||
float cur = ggml_ext_tensor_get_f32(G, ix, iy);
|
||||
if ((cur >= q) && (cur >= r)) {
|
||||
ggml_tensor_set_f32(result, cur, ix, iy);
|
||||
ggml_ext_tensor_set_f32(result, cur, ix, iy);
|
||||
} else {
|
||||
ggml_tensor_set_f32(result, 0.0f, ix, iy);
|
||||
ggml_ext_tensor_set_f32(result, 0.0f, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,9 +138,9 @@ void threshold_hystersis(struct ggml_tensor* img, float high_threshold, float lo
|
||||
for (int iy = 0; iy < img->ne[1]; iy++) {
|
||||
for (int ix = 0; ix < img->ne[0]; ix++) {
|
||||
if (ix >= 3 && ix <= img->ne[0] - 3 && iy >= 3 && iy <= img->ne[1] - 3) {
|
||||
ggml_tensor_set_f32(img, ggml_tensor_get_f32(img, ix, iy), ix, iy);
|
||||
ggml_ext_tensor_set_f32(img, ggml_ext_tensor_get_f32(img, ix, iy), ix, iy);
|
||||
} else {
|
||||
ggml_tensor_set_f32(img, 0.0f, ix, iy);
|
||||
ggml_ext_tensor_set_f32(img, 0.0f, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,14 +148,14 @@ void threshold_hystersis(struct ggml_tensor* img, float high_threshold, float lo
|
||||
// hysteresis
|
||||
for (int iy = 1; iy < img->ne[1] - 1; iy++) {
|
||||
for (int ix = 1; ix < img->ne[0] - 1; ix++) {
|
||||
float imd_v = ggml_tensor_get_f32(img, ix, iy);
|
||||
float imd_v = ggml_ext_tensor_get_f32(img, ix, iy);
|
||||
if (imd_v == weak) {
|
||||
if (ggml_tensor_get_f32(img, ix + 1, iy - 1) == strong || ggml_tensor_get_f32(img, ix + 1, iy) == strong ||
|
||||
ggml_tensor_get_f32(img, ix, iy - 1) == strong || ggml_tensor_get_f32(img, ix, iy + 1) == strong ||
|
||||
ggml_tensor_get_f32(img, ix - 1, iy - 1) == strong || ggml_tensor_get_f32(img, ix - 1, iy) == strong) {
|
||||
ggml_tensor_set_f32(img, strong, ix, iy);
|
||||
if (ggml_ext_tensor_get_f32(img, ix + 1, iy - 1) == strong || ggml_ext_tensor_get_f32(img, ix + 1, iy) == strong ||
|
||||
ggml_ext_tensor_get_f32(img, ix, iy - 1) == strong || ggml_ext_tensor_get_f32(img, ix, iy + 1) == strong ||
|
||||
ggml_ext_tensor_get_f32(img, ix - 1, iy - 1) == strong || ggml_ext_tensor_get_f32(img, ix - 1, iy) == strong) {
|
||||
ggml_ext_tensor_set_f32(img, strong, ix, iy);
|
||||
} else {
|
||||
ggml_tensor_set_f32(img, 0.0f, ix, iy);
|
||||
ggml_ext_tensor_set_f32(img, 0.0f, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,8 +164,8 @@ void threshold_hystersis(struct ggml_tensor* img, float high_threshold, float lo
|
||||
|
||||
bool preprocess_canny(sd_image_t img, float high_threshold, float low_threshold, float weak, float strong, bool inverse) {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(10 * 1024 * 1024); // 10MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_size = static_cast<size_t>(40 * img.width * img.height); // 10MB for 512x512
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
|
||||
@@ -198,7 +198,7 @@ bool preprocess_canny(sd_image_t img, float high_threshold, float low_threshold,
|
||||
struct ggml_tensor* iY = ggml_dup_tensor(work_ctx, image_gray);
|
||||
struct ggml_tensor* G = ggml_dup_tensor(work_ctx, image_gray);
|
||||
struct ggml_tensor* tetha = ggml_dup_tensor(work_ctx, image_gray);
|
||||
sd_image_to_tensor(img, image);
|
||||
sd_image_to_ggml_tensor(img, image);
|
||||
grayscale(image, image_gray);
|
||||
convolve(image_gray, image_gray, gkernel, 2);
|
||||
convolve(image_gray, iX, sf_kx, 1);
|
||||
@@ -211,16 +211,14 @@ bool preprocess_canny(sd_image_t img, float high_threshold, float low_threshold,
|
||||
// to RGB channels
|
||||
for (int iy = 0; iy < img.height; iy++) {
|
||||
for (int ix = 0; ix < img.width; ix++) {
|
||||
float gray = ggml_tensor_get_f32(image_gray, ix, iy);
|
||||
float gray = ggml_ext_tensor_get_f32(image_gray, ix, iy);
|
||||
gray = inverse ? 1.0f - gray : gray;
|
||||
ggml_tensor_set_f32(image, gray, ix, iy);
|
||||
ggml_tensor_set_f32(image, gray, ix, iy, 1);
|
||||
ggml_tensor_set_f32(image, gray, ix, iy, 2);
|
||||
ggml_ext_tensor_set_f32(image, gray, ix, iy);
|
||||
ggml_ext_tensor_set_f32(image, gray, ix, iy, 1);
|
||||
ggml_ext_tensor_set_f32(image, gray, ix, iy, 2);
|
||||
}
|
||||
}
|
||||
uint8_t* output = sd_tensor_to_image(image);
|
||||
free(img.data);
|
||||
img.data = output;
|
||||
ggml_tensor_to_sd_image(image, img.data);
|
||||
ggml_free(work_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
+87
-34
@@ -1,6 +1,8 @@
|
||||
#ifndef __QWEN_IMAGE_HPP__
|
||||
#define __QWEN_IMAGE_HPP__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "flux.hpp"
|
||||
#include "ggml_extend.hpp"
|
||||
@@ -54,7 +56,7 @@ namespace Qwen {
|
||||
// return: [N, embedding_dim]
|
||||
auto timestep_embedder = std::dynamic_pointer_cast<TimestepEmbedding>(blocks["timestep_embedder"]);
|
||||
|
||||
auto timesteps_proj = ggml_nn_timestep_embedding(ctx, timesteps, 256, 10000, 1.f);
|
||||
auto timesteps_proj = ggml_ext_timestep_embedding(ctx, timesteps, 256, 10000, 1.f);
|
||||
auto timesteps_emb = timestep_embedder->forward(ctx, timesteps_proj);
|
||||
return timesteps_emb;
|
||||
}
|
||||
@@ -94,12 +96,12 @@ namespace Qwen {
|
||||
blocks["norm_added_q"] = std::shared_ptr<GGMLBlock>(new RMSNorm(dim_head, eps));
|
||||
blocks["norm_added_k"] = std::shared_ptr<GGMLBlock>(new RMSNorm(dim_head, eps));
|
||||
|
||||
blocks["to_out.0"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_dim, out_bias));
|
||||
// to_out.1 is nn.Dropout
|
||||
|
||||
float scale = 1.f / 32.f;
|
||||
// The purpose of the scale here is to prevent NaN issues in certain situations.
|
||||
// For example when using CUDA but the weights are k-quants (not all prompts).
|
||||
blocks["to_out.0"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_dim, out_bias, false, false, scale));
|
||||
// to_out.1 is nn.Dropout
|
||||
|
||||
blocks["to_add_out"] = std::shared_ptr<GGMLBlock>(new Linear(inner_dim, out_context_dim, out_bias, false, false, scale));
|
||||
}
|
||||
|
||||
@@ -159,7 +161,7 @@ namespace Qwen {
|
||||
auto k = ggml_concat(ctx, txt_k, img_k, 2); // [N, n_txt_token + n_img_token, n_head, d_head]
|
||||
auto v = ggml_concat(ctx, txt_v, img_v, 2); // [N, n_txt_token + n_img_token, n_head, d_head]
|
||||
|
||||
auto attn = Flux::attention(ctx, backend, q, k, v, pe, mask, flash_attn, (1.0f / 128.f)); // [N, n_txt_token + n_img_token, n_head*d_head]
|
||||
auto attn = Rope::attention(ctx, backend, q, k, v, pe, mask, flash_attn, (1.0f / 128.f)); // [N, n_txt_token + n_img_token, n_head*d_head]
|
||||
attn = ggml_cont(ctx, ggml_permute(ctx, attn, 0, 2, 1, 3)); // [n_txt_token + n_img_token, N, hidden_size]
|
||||
auto txt_attn_out = ggml_view_3d(ctx,
|
||||
attn,
|
||||
@@ -244,11 +246,11 @@ namespace Qwen {
|
||||
|
||||
auto img_mod_params = ggml_silu(ctx, t_emb);
|
||||
img_mod_params = img_mod_1->forward(ctx, img_mod_params);
|
||||
auto img_mod_param_vec = ggml_chunk(ctx, img_mod_params, 6, 0);
|
||||
auto img_mod_param_vec = ggml_ext_chunk(ctx, img_mod_params, 6, 0);
|
||||
|
||||
auto txt_mod_params = ggml_silu(ctx, t_emb);
|
||||
txt_mod_params = txt_mod_1->forward(ctx, txt_mod_params);
|
||||
auto txt_mod_param_vec = ggml_chunk(ctx, txt_mod_params, 6, 0);
|
||||
auto txt_mod_param_vec = ggml_ext_chunk(ctx, txt_mod_params, 6, 0);
|
||||
|
||||
auto img_normed = img_norm1->forward(ctx, img);
|
||||
auto img_modulated = Flux::modulate(ctx, img_normed, img_mod_param_vec[0], img_mod_param_vec[1]);
|
||||
@@ -303,7 +305,7 @@ namespace Qwen {
|
||||
auto linear = std::dynamic_pointer_cast<Linear>(blocks["linear"]);
|
||||
|
||||
auto emb = linear->forward(ctx, ggml_silu(ctx, c));
|
||||
auto mods = ggml_chunk(ctx, emb, 2, 0);
|
||||
auto mods = ggml_ext_chunk(ctx, emb, 2, 0);
|
||||
auto scale = mods[0];
|
||||
auto shift = mods[1];
|
||||
|
||||
@@ -389,6 +391,13 @@ namespace Qwen {
|
||||
return x;
|
||||
}
|
||||
|
||||
struct ggml_tensor* process_img(struct ggml_context* ctx,
|
||||
struct ggml_tensor* x) {
|
||||
x = pad_to_patch_size(ctx, x);
|
||||
x = patchify(ctx, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct ggml_tensor* unpatchify(struct ggml_context* ctx,
|
||||
struct ggml_tensor* x,
|
||||
int64_t h,
|
||||
@@ -449,7 +458,8 @@ namespace Qwen {
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* timestep,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* pe) {
|
||||
struct ggml_tensor* pe,
|
||||
std::vector<ggml_tensor*> ref_latents = {}) {
|
||||
// Forward pass of DiT.
|
||||
// x: [N, C, H, W]
|
||||
// timestep: [N,]
|
||||
@@ -462,19 +472,32 @@ namespace Qwen {
|
||||
int64_t C = x->ne[2];
|
||||
int64_t N = x->ne[3];
|
||||
|
||||
x = pad_to_patch_size(ctx, x);
|
||||
x = patchify(ctx, x);
|
||||
auto img = process_img(ctx, x);
|
||||
uint64_t img_tokens = img->ne[1];
|
||||
|
||||
if (ref_latents.size() > 0) {
|
||||
for (ggml_tensor* ref : ref_latents) {
|
||||
ref = process_img(ctx, ref);
|
||||
img = ggml_concat(ctx, img, ref, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t h_len = ((H + (params.patch_size / 2)) / params.patch_size);
|
||||
int64_t w_len = ((W + (params.patch_size / 2)) / params.patch_size);
|
||||
|
||||
auto out = forward_orig(ctx, backend, x, timestep, context, pe); // [N, h_len*w_len, ph*pw*C]
|
||||
auto out = forward_orig(ctx, backend, img, timestep, context, pe); // [N, h_len*w_len, ph*pw*C]
|
||||
|
||||
if (out->ne[1] > img_tokens) {
|
||||
out = ggml_cont(ctx, ggml_permute(ctx, out, 0, 2, 1, 3)); // [num_tokens, N, C * patch_size * patch_size]
|
||||
out = ggml_view_3d(ctx, out, out->ne[0], out->ne[1], img_tokens, out->nb[1], out->nb[2], 0);
|
||||
out = ggml_cont(ctx, ggml_permute(ctx, out, 0, 2, 1, 3)); // [N, h*w, C * patch_size * patch_size]
|
||||
}
|
||||
|
||||
out = unpatchify(ctx, out, h_len, w_len); // [N, C, H + pad_h, W + pad_w]
|
||||
|
||||
// slice
|
||||
out = ggml_slice(ctx, out, 1, 0, H); // [N, C, H, W + pad_w]
|
||||
out = ggml_slice(ctx, out, 0, 0, W); // [N, C, H, W]
|
||||
out = ggml_ext_slice(ctx, out, 1, 0, H); // [N, C, H, W + pad_w]
|
||||
out = ggml_ext_slice(ctx, out, 0, 0, W); // [N, C, H, W]
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -495,11 +518,30 @@ namespace Qwen {
|
||||
bool flash_attn = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
qwen_image_params.flash_attn = flash_attn;
|
||||
qwen_image = QwenImageModel(qwen_image_params);
|
||||
qwen_image_params.num_layers = 0;
|
||||
for (auto pair : tensor_types) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find(prefix) == std::string::npos)
|
||||
continue;
|
||||
size_t pos = tensor_name.find("transformer_blocks.");
|
||||
if (pos != std::string::npos) {
|
||||
tensor_name = tensor_name.substr(pos); // remove prefix
|
||||
auto items = split_string(tensor_name, '.');
|
||||
if (items.size() > 1) {
|
||||
int block_index = atoi(items[1].c_str());
|
||||
if (block_index + 1 > qwen_image_params.num_layers) {
|
||||
qwen_image_params.num_layers = block_index + 1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOG_INFO("qwen_image_params.num_layers: %ld", qwen_image_params.num_layers);
|
||||
qwen_image = QwenImageModel(qwen_image_params);
|
||||
qwen_image.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "qwen_image";
|
||||
}
|
||||
|
||||
@@ -509,7 +551,9 @@ namespace Qwen {
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context) {
|
||||
struct ggml_tensor* context,
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false) {
|
||||
GGML_ASSERT(x->ne[3] == 1);
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, QWEN_IMAGE_GRAPH_SIZE, false);
|
||||
|
||||
@@ -517,19 +561,25 @@ namespace Qwen {
|
||||
context = to_backend(context);
|
||||
timesteps = to_backend(timesteps);
|
||||
|
||||
for (int i = 0; i < ref_latents.size(); i++) {
|
||||
ref_latents[i] = to_backend(ref_latents[i]);
|
||||
}
|
||||
|
||||
pe_vec = Rope::gen_qwen_image_pe(x->ne[1],
|
||||
x->ne[0],
|
||||
qwen_image_params.patch_size,
|
||||
x->ne[3],
|
||||
context->ne[1],
|
||||
ref_latents,
|
||||
increase_ref_index,
|
||||
qwen_image_params.theta,
|
||||
qwen_image_params.axes_dim);
|
||||
int pos_len = pe_vec.size() / qwen_image_params.axes_dim_sum / 2;
|
||||
// LOG_DEBUG("pos_len %d", pos_len);
|
||||
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, qwen_image_params.axes_dim_sum / 2, pos_len);
|
||||
// pe->data = pe_vec.data();
|
||||
// print_ggml_tensor(pe);
|
||||
// pe->data = NULL;
|
||||
// print_ggml_tensor(pe, true, "pe");
|
||||
// pe->data = nullptr;
|
||||
set_backend_tensor_data(pe, pe_vec.data());
|
||||
|
||||
struct ggml_tensor* out = qwen_image.forward(compute_ctx,
|
||||
@@ -537,7 +587,8 @@ namespace Qwen {
|
||||
x,
|
||||
timesteps,
|
||||
context,
|
||||
pe);
|
||||
pe,
|
||||
ref_latents);
|
||||
|
||||
ggml_build_forward_expand(gf, out);
|
||||
|
||||
@@ -548,13 +599,15 @@ namespace Qwen {
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
std::vector<ggml_tensor*> ref_latents = {},
|
||||
bool increase_ref_index = false,
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) {
|
||||
// x: [N, in_channels, h, w]
|
||||
// timesteps: [N, ]
|
||||
// context: [N, max_position, hidden_size]
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(x, timesteps, context);
|
||||
return build_graph(x, timesteps, context, ref_latents, increase_ref_index);
|
||||
};
|
||||
|
||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||
@@ -563,11 +616,11 @@ namespace Qwen {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(1024 * 1024) * 1024; // 1GB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
// auto x = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 16, 16, 16, 1);
|
||||
@@ -583,10 +636,10 @@ namespace Qwen {
|
||||
auto context = load_tensor_from_file(work_ctx, "./qwen_image_context.bin");
|
||||
print_ggml_tensor(context);
|
||||
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, timesteps, context, &out, work_ctx);
|
||||
compute(8, x, timesteps, context, {}, false, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
@@ -596,7 +649,7 @@ namespace Qwen {
|
||||
|
||||
static void load_from_file_and_test(const std::string& file_path) {
|
||||
// cuda q8: pass
|
||||
// cuda q8 fa: nan
|
||||
// cuda q8 fa: pass
|
||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
||||
@@ -615,12 +668,12 @@ namespace Qwen {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<QwenImageRunner> qwen_image = std::shared_ptr<QwenImageRunner>(new QwenImageRunner(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
"model.diffusion_model",
|
||||
VERSION_QWEN_IMAGE,
|
||||
true));
|
||||
std::shared_ptr<QwenImageRunner> qwen_image = std::make_shared<QwenImageRunner>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
"model.diffusion_model",
|
||||
VERSION_QWEN_IMAGE,
|
||||
true);
|
||||
|
||||
qwen_image->alloc_params_buffer();
|
||||
std::map<std::string, ggml_tensor*> tensors;
|
||||
|
||||
+689
-30
@@ -5,19 +5,23 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "clip.hpp"
|
||||
#include "ggml_extend.hpp"
|
||||
#include "json.hpp"
|
||||
#include "rope.hpp"
|
||||
#include "tokenize_util.h"
|
||||
|
||||
namespace Qwen {
|
||||
constexpr int QWENVL_GRAPH_SIZE = 10240;
|
||||
|
||||
class Qwen2Tokenizer {
|
||||
private:
|
||||
@@ -340,9 +344,9 @@ namespace Qwen {
|
||||
struct Qwen2_5_VLMLP : public GGMLBlock {
|
||||
public:
|
||||
Qwen2_5_VLMLP(int64_t hidden_size, int64_t intermediate_size, bool bias = false) {
|
||||
blocks["gate_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, intermediate_size, false));
|
||||
blocks["up_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, intermediate_size, false));
|
||||
blocks["down_proj"] = std::shared_ptr<GGMLBlock>(new Linear(intermediate_size, hidden_size, false));
|
||||
blocks["gate_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, intermediate_size, bias));
|
||||
blocks["up_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, intermediate_size, bias));
|
||||
blocks["down_proj"] = std::shared_ptr<GGMLBlock>(new Linear(intermediate_size, hidden_size, bias));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
@@ -359,6 +363,288 @@ namespace Qwen {
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VisionPatchEmbed : public GGMLBlock {
|
||||
protected:
|
||||
bool llama_cpp_style;
|
||||
int patch_size;
|
||||
int temporal_patch_size;
|
||||
int64_t in_channels;
|
||||
int64_t embed_dim;
|
||||
|
||||
public:
|
||||
Qwen2_5_VisionPatchEmbed(bool llama_cpp_style,
|
||||
int patch_size = 14,
|
||||
int temporal_patch_size = 2,
|
||||
int64_t in_channels = 3,
|
||||
int64_t embed_dim = 1152)
|
||||
: llama_cpp_style(llama_cpp_style),
|
||||
patch_size(patch_size),
|
||||
temporal_patch_size(temporal_patch_size),
|
||||
in_channels(in_channels),
|
||||
embed_dim(embed_dim) {
|
||||
if (llama_cpp_style) {
|
||||
blocks["proj.0"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels,
|
||||
embed_dim,
|
||||
{patch_size, patch_size},
|
||||
{patch_size, patch_size}, // stride
|
||||
{0, 0}, // padding
|
||||
{1, 1}, // dilation
|
||||
false));
|
||||
blocks["proj.1"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels,
|
||||
embed_dim,
|
||||
{patch_size, patch_size},
|
||||
{patch_size, patch_size}, // stride
|
||||
{0, 0}, // padding
|
||||
{1, 1}, // dilation
|
||||
false));
|
||||
} else {
|
||||
std::tuple<int, int, int> kernel_size = {(int)temporal_patch_size, (int)patch_size, (int)patch_size};
|
||||
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Conv3d(in_channels,
|
||||
embed_dim,
|
||||
kernel_size,
|
||||
kernel_size, // stride
|
||||
{0, 0, 0}, // padding
|
||||
{1, 1, 1}, // dilation
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
// x: [N*grid_t*grid_h*grid_w, in_channels, temporal_patch_size*patch_size*patch_size]
|
||||
// return: [N*grid_t*grid_h*grid_w, embed_dim]
|
||||
x = ggml_reshape_4d(ctx,
|
||||
x,
|
||||
patch_size,
|
||||
patch_size,
|
||||
temporal_patch_size,
|
||||
ggml_nelements(x) / (temporal_patch_size * patch_size * patch_size));
|
||||
|
||||
if (llama_cpp_style) {
|
||||
auto proj_0 = std::dynamic_pointer_cast<Conv2d>(blocks["proj.0"]);
|
||||
auto proj_1 = std::dynamic_pointer_cast<Conv2d>(blocks["proj.1"]);
|
||||
|
||||
auto x0 = ggml_ext_slice(ctx, x, 2, 0, 1);
|
||||
x0 = ggml_reshape_4d(ctx, x0, x0->ne[0], x0->ne[1], in_channels, x0->ne[3] / in_channels);
|
||||
x0 = proj_0->forward(ctx, x0);
|
||||
|
||||
auto x1 = ggml_ext_slice(ctx, x, 2, 1, 2);
|
||||
x1 = ggml_reshape_4d(ctx, x1, x1->ne[0], x1->ne[1], in_channels, x1->ne[3] / in_channels);
|
||||
x1 = proj_1->forward(ctx, x1);
|
||||
|
||||
x = ggml_add(ctx, x0, x1);
|
||||
} else {
|
||||
auto proj = std::dynamic_pointer_cast<Conv3d>(blocks["proj"]);
|
||||
|
||||
x = proj->forward(ctx, x);
|
||||
}
|
||||
|
||||
x = ggml_reshape_2d(ctx, x, embed_dim, ggml_nelements(x) / embed_dim);
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLPatchMerger : public GGMLBlock {
|
||||
protected:
|
||||
int64_t hidden_size;
|
||||
|
||||
public:
|
||||
Qwen2_5_VLPatchMerger(int64_t dim,
|
||||
int64_t context_dim,
|
||||
int64_t spatial_merge_size) {
|
||||
hidden_size = context_dim * spatial_merge_size * spatial_merge_size;
|
||||
blocks["ln_q"] = std::shared_ptr<GGMLBlock>(new RMSNorm(context_dim, 1e-6f));
|
||||
blocks["mlp.0"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size));
|
||||
// mlp.1 is nn.GELU()
|
||||
blocks["mlp.2"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, dim));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
auto ln_q = std::dynamic_pointer_cast<RMSNorm>(blocks["ln_q"]);
|
||||
auto mlp_0 = std::dynamic_pointer_cast<Linear>(blocks["mlp.0"]);
|
||||
auto mlp_2 = std::dynamic_pointer_cast<Linear>(blocks["mlp.2"]);
|
||||
|
||||
x = ln_q->forward(ctx, x);
|
||||
x = ggml_reshape_2d(ctx, x, hidden_size, ggml_nelements(x) / hidden_size);
|
||||
x = mlp_0->forward(ctx, x);
|
||||
x = ggml_gelu(ctx, x);
|
||||
x = mlp_2->forward(ctx, x);
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLVisionAttention : public GGMLBlock {
|
||||
protected:
|
||||
bool llama_cpp_style;
|
||||
int64_t head_dim;
|
||||
int64_t num_heads;
|
||||
|
||||
public:
|
||||
Qwen2_5_VLVisionAttention(bool llama_cpp_style,
|
||||
int64_t hidden_size,
|
||||
int64_t num_heads)
|
||||
: llama_cpp_style(llama_cpp_style), num_heads(num_heads) {
|
||||
head_dim = hidden_size / num_heads;
|
||||
GGML_ASSERT(num_heads * head_dim == hidden_size);
|
||||
if (llama_cpp_style) {
|
||||
blocks["q_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size));
|
||||
blocks["k_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size));
|
||||
blocks["v_proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size));
|
||||
} else {
|
||||
blocks["qkv"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size * 3));
|
||||
}
|
||||
blocks["proj"] = std::shared_ptr<GGMLBlock>(new Linear(hidden_size, hidden_size));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* mask = nullptr) {
|
||||
// x: [N, n_token, hidden_size]
|
||||
int64_t n_token = x->ne[1];
|
||||
int64_t N = x->ne[2];
|
||||
auto proj = std::dynamic_pointer_cast<Linear>(blocks["proj"]);
|
||||
|
||||
std::vector<ggml_tensor*> qkv_vec;
|
||||
if (llama_cpp_style) {
|
||||
auto q_proj = std::dynamic_pointer_cast<Linear>(blocks["q_proj"]);
|
||||
auto k_proj = std::dynamic_pointer_cast<Linear>(blocks["k_proj"]);
|
||||
auto v_proj = std::dynamic_pointer_cast<Linear>(blocks["v_proj"]);
|
||||
|
||||
auto q = q_proj->forward(ctx, x);
|
||||
auto k = k_proj->forward(ctx, x);
|
||||
auto v = v_proj->forward(ctx, x);
|
||||
|
||||
qkv_vec = {q, k, v};
|
||||
} else {
|
||||
auto qkv_proj = std::dynamic_pointer_cast<Linear>(blocks["qkv"]);
|
||||
auto qkv = qkv_proj->forward(ctx, x);
|
||||
qkv_vec = split_qkv(ctx, qkv);
|
||||
}
|
||||
|
||||
auto q = ggml_reshape_4d(ctx, qkv_vec[0], head_dim, num_heads, qkv_vec[0]->ne[1], qkv_vec[0]->ne[2]); // [N, n_token, n_head, d_head]
|
||||
auto k = ggml_reshape_4d(ctx, qkv_vec[1], head_dim, num_heads, qkv_vec[1]->ne[1], qkv_vec[1]->ne[2]); // [N, n_token, n_head, d_head]
|
||||
auto v = ggml_reshape_4d(ctx, qkv_vec[2], head_dim, num_heads, qkv_vec[2]->ne[1], qkv_vec[2]->ne[2]); // [N, n_token, n_head, d_head]
|
||||
|
||||
x = Rope::attention(ctx, backend, q, k, v, pe, mask, false, 1.f, false); // [N, n_token, hidden_size]
|
||||
|
||||
x = proj->forward(ctx, x); // [N, n_token, hidden_size]
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLVisionBlock : public GGMLBlock {
|
||||
public:
|
||||
Qwen2_5_VLVisionBlock(bool llama_cpp_style,
|
||||
int64_t hidden_size,
|
||||
int64_t intermediate_size,
|
||||
int64_t num_heads,
|
||||
float eps = 1e-6f) {
|
||||
blocks["attn"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLVisionAttention(llama_cpp_style, hidden_size, num_heads));
|
||||
blocks["mlp"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLMLP(hidden_size, intermediate_size, true));
|
||||
blocks["norm1"] = std::shared_ptr<GGMLBlock>(new RMSNorm(hidden_size, eps));
|
||||
blocks["norm2"] = std::shared_ptr<GGMLBlock>(new RMSNorm(hidden_size, eps));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* mask = nullptr) {
|
||||
// x: [N, n_token, hidden_size]
|
||||
auto attn = std::dynamic_pointer_cast<Qwen2_5_VLVisionAttention>(blocks["attn"]);
|
||||
auto mlp = std::dynamic_pointer_cast<Qwen2_5_VLMLP>(blocks["mlp"]);
|
||||
auto norm1 = std::dynamic_pointer_cast<RMSNorm>(blocks["norm1"]);
|
||||
auto norm2 = std::dynamic_pointer_cast<RMSNorm>(blocks["norm2"]);
|
||||
|
||||
auto residual = x;
|
||||
x = norm1->forward(ctx, x);
|
||||
x = attn->forward(ctx, backend, x, pe, mask);
|
||||
x = ggml_add_inplace(ctx, x, residual);
|
||||
|
||||
residual = x;
|
||||
x = norm2->forward(ctx, x);
|
||||
x = mlp->forward(ctx, x);
|
||||
x = ggml_add_inplace(ctx, x, residual);
|
||||
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLVisionModel : public GGMLBlock {
|
||||
protected:
|
||||
int64_t num_layers;
|
||||
int64_t spatial_merge_size;
|
||||
std::set<int> fullatt_block_indexes;
|
||||
|
||||
public:
|
||||
Qwen2_5_VLVisionModel(bool llama_cpp_style,
|
||||
int64_t num_layers,
|
||||
int64_t in_channels,
|
||||
int64_t hidden_size,
|
||||
int64_t out_hidden_size,
|
||||
int64_t intermediate_size,
|
||||
int64_t num_heads,
|
||||
int64_t spatial_merge_size,
|
||||
int64_t patch_size,
|
||||
int64_t temporal_patch_size,
|
||||
int64_t window_size,
|
||||
std::set<int> fullatt_block_indexes = {7, 15, 23, 31},
|
||||
float eps = 1e-6f)
|
||||
: num_layers(num_layers), fullatt_block_indexes(std::move(fullatt_block_indexes)), spatial_merge_size(spatial_merge_size) {
|
||||
blocks["patch_embed"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VisionPatchEmbed(llama_cpp_style,
|
||||
patch_size,
|
||||
temporal_patch_size,
|
||||
in_channels,
|
||||
hidden_size));
|
||||
for (int i = 0; i < num_layers; i++) {
|
||||
blocks["blocks." + std::to_string(i)] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLVisionBlock(llama_cpp_style,
|
||||
hidden_size,
|
||||
intermediate_size,
|
||||
num_heads,
|
||||
eps));
|
||||
}
|
||||
blocks["merger"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLPatchMerger(out_hidden_size, hidden_size, spatial_merge_size));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* pixel_values,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* window_index,
|
||||
struct ggml_tensor* window_inverse_index,
|
||||
struct ggml_tensor* window_mask) {
|
||||
// pixel_values: [grid_t*(H/mh/ph)*(W/mw/pw)*mh*mw, C*pt*ph*pw]
|
||||
// window_index: [grid_t*(H/mh/ph)*(W/mw/pw)]
|
||||
// window_inverse_index: [grid_t*(H/mh/ph)*(W/mw/pw)]
|
||||
// window_mask: [grid_h*grid_w, grid_h*grid_w]
|
||||
auto patch_embed = std::dynamic_pointer_cast<Qwen2_5_VisionPatchEmbed>(blocks["patch_embed"]);
|
||||
auto merger = std::dynamic_pointer_cast<Qwen2_5_VLPatchMerger>(blocks["merger"]);
|
||||
|
||||
auto x = patch_embed->forward(ctx, pixel_values);
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, x->ne[0] * spatial_merge_size * spatial_merge_size, x->ne[1] / spatial_merge_size / spatial_merge_size, x->ne[2], x->ne[3]);
|
||||
x = ggml_get_rows(ctx, x, window_index);
|
||||
x = ggml_reshape_4d(ctx, x, x->ne[0] / spatial_merge_size / spatial_merge_size, x->ne[1] * spatial_merge_size * spatial_merge_size, x->ne[2], x->ne[3]);
|
||||
|
||||
for (int i = 0; i < num_layers; i++) {
|
||||
auto block = std::dynamic_pointer_cast<Qwen2_5_VLVisionBlock>(blocks["blocks." + std::to_string(i)]);
|
||||
|
||||
auto mask = window_mask;
|
||||
if (fullatt_block_indexes.find(i) != fullatt_block_indexes.end()) {
|
||||
mask = nullptr;
|
||||
}
|
||||
x = block->forward(ctx, backend, x, pe, mask);
|
||||
}
|
||||
|
||||
x = merger->forward(ctx, x);
|
||||
|
||||
x = ggml_get_rows(ctx, x, window_inverse_index);
|
||||
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLAttention : public GGMLBlock {
|
||||
protected:
|
||||
int64_t head_dim;
|
||||
@@ -402,13 +688,13 @@ namespace Qwen {
|
||||
q = ggml_rope_multi(ctx, q, input_pos, nullptr, head_dim, sections, GGML_ROPE_TYPE_MROPE, 128000, 1000000.f, 1.f, 0.f, 1.f, 32.f, 1.f);
|
||||
k = ggml_rope_multi(ctx, k, input_pos, nullptr, head_dim, sections, GGML_ROPE_TYPE_MROPE, 128000, 1000000.f, 1.f, 0.f, 1.f, 32.f, 1.f);
|
||||
|
||||
q = ggml_cont(ctx, ggml_torch_permute(ctx, q, 0, 2, 1, 3)); // [N, num_heads, n_token, head_dim]
|
||||
q = ggml_cont(ctx, ggml_ext_torch_permute(ctx, q, 0, 2, 1, 3)); // [N, num_heads, n_token, head_dim]
|
||||
q = ggml_reshape_3d(ctx, q, q->ne[0], q->ne[1], q->ne[2] * q->ne[3]); // [N*num_heads, n_token, head_dim]
|
||||
|
||||
k = ggml_cont(ctx, ggml_torch_permute(ctx, k, 0, 2, 1, 3)); // [N, num_kv_heads, n_token, head_dim]
|
||||
k = ggml_cont(ctx, ggml_ext_torch_permute(ctx, k, 0, 2, 1, 3)); // [N, num_kv_heads, n_token, head_dim]
|
||||
k = ggml_reshape_3d(ctx, k, k->ne[0], k->ne[1], k->ne[2] * k->ne[3]); // [N*num_kv_heads, n_token, head_dim]
|
||||
|
||||
x = ggml_nn_attention_ext(ctx, backend, q, k, v, num_heads, nullptr, true, true, false); // [N, n_token, hidden_size]
|
||||
x = ggml_ext_attention_ext(ctx, backend, q, k, v, num_heads, nullptr, true, true, false); // [N, n_token, hidden_size]
|
||||
|
||||
x = out_proj->forward(ctx, x); // [N, n_token, hidden_size]
|
||||
return x;
|
||||
@@ -478,7 +764,8 @@ namespace Qwen {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* input_pos) {
|
||||
struct ggml_tensor* input_pos,
|
||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds) {
|
||||
// input_ids: [N, n_token]
|
||||
// return: [N, n_token, hidden_size]
|
||||
|
||||
@@ -487,6 +774,45 @@ namespace Qwen {
|
||||
|
||||
auto x = embed_tokens->forward(ctx, input_ids);
|
||||
|
||||
if (image_embeds.size() > 0) {
|
||||
GGML_ASSERT(x->ne[2] == 1); // N == 1
|
||||
|
||||
auto raw_x = ggml_cast(ctx, x, image_embeds[0].second->type);
|
||||
int64_t txt_token_start = 0;
|
||||
int64_t txt_token_end = 0;
|
||||
|
||||
ggml_tensor* input_embed = nullptr;
|
||||
|
||||
for (int i = 0; i < image_embeds.size(); i++) {
|
||||
if (i == 0) {
|
||||
txt_token_start = 0;
|
||||
} else {
|
||||
txt_token_start = image_embeds[i - 1].first + image_embeds[i - 1].second->ne[1];
|
||||
}
|
||||
txt_token_end = image_embeds[i].first;
|
||||
|
||||
auto txt_embed = ggml_ext_slice(ctx, raw_x, 1, txt_token_start, txt_token_end);
|
||||
if (input_embed == nullptr) {
|
||||
input_embed = txt_embed;
|
||||
} else {
|
||||
input_embed = ggml_concat(ctx, input_embed, txt_embed, 1);
|
||||
}
|
||||
|
||||
auto image_embed = image_embeds[i].second;
|
||||
input_embed = ggml_concat(ctx, input_embed, image_embed, 1);
|
||||
}
|
||||
|
||||
txt_token_start = image_embeds[image_embeds.size() - 1].first + image_embeds[image_embeds.size() - 1].second->ne[1];
|
||||
txt_token_end = raw_x->ne[1];
|
||||
|
||||
auto final_txt_embed = ggml_ext_slice(ctx, raw_x, 1, txt_token_start, txt_token_end);
|
||||
|
||||
input_embed = ggml_concat(ctx, input_embed, final_txt_embed, 1);
|
||||
GGML_ASSERT(raw_x->ne[1] == input_embed->ne[1]);
|
||||
|
||||
x = input_embed;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_layers; i++) {
|
||||
auto block = std::dynamic_pointer_cast<Qwen2_5_VLBlock>(blocks["layers." + std::to_string(i)]);
|
||||
|
||||
@@ -498,6 +824,20 @@ namespace Qwen {
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLVisionParams {
|
||||
int64_t num_layers = 32;
|
||||
int64_t hidden_size = 1280;
|
||||
int64_t intermediate_size = 3420;
|
||||
int64_t num_heads = 16;
|
||||
int64_t in_channels = 3;
|
||||
int64_t out_hidden_size = 3584;
|
||||
int64_t temporal_patch_size = 2;
|
||||
int64_t patch_size = 14;
|
||||
int64_t spatial_merge_size = 2;
|
||||
int64_t window_size = 112;
|
||||
std::set<int> fullatt_block_indexes = {7, 15, 23, 31};
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLParams {
|
||||
int64_t num_layers = 28;
|
||||
int64_t hidden_size = 3584;
|
||||
@@ -506,15 +846,17 @@ namespace Qwen {
|
||||
int64_t num_kv_heads = 4;
|
||||
int64_t vocab_size = 152064;
|
||||
float rms_norm_eps = 1e-06f;
|
||||
Qwen2_5_VLVisionParams vision;
|
||||
};
|
||||
|
||||
struct Qwen2_5_VL : public GGMLBlock {
|
||||
bool enable_vision;
|
||||
Qwen2_5_VLParams params;
|
||||
|
||||
public:
|
||||
Qwen2_5_VL() {}
|
||||
Qwen2_5_VL(Qwen2_5_VLParams params)
|
||||
: params(params) {
|
||||
Qwen2_5_VL(Qwen2_5_VLParams params, bool enable_vision = false, bool llama_cpp_style = false)
|
||||
: enable_vision(enable_vision), params(params) {
|
||||
blocks["model"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLTextModel(params.num_layers,
|
||||
params.vocab_size,
|
||||
params.hidden_size,
|
||||
@@ -522,36 +864,94 @@ namespace Qwen {
|
||||
params.num_heads,
|
||||
params.num_kv_heads,
|
||||
params.rms_norm_eps));
|
||||
if (enable_vision) {
|
||||
blocks["visual"] = std::shared_ptr<GGMLBlock>(new Qwen2_5_VLVisionModel(llama_cpp_style,
|
||||
params.vision.num_layers,
|
||||
params.vision.in_channels,
|
||||
params.vision.hidden_size,
|
||||
params.vision.out_hidden_size,
|
||||
params.vision.intermediate_size,
|
||||
params.vision.num_heads,
|
||||
params.vision.spatial_merge_size,
|
||||
params.vision.patch_size,
|
||||
params.vision.temporal_patch_size,
|
||||
params.vision.window_size,
|
||||
params.vision.fullatt_block_indexes));
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* input_pos) {
|
||||
struct ggml_tensor* input_pos,
|
||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds) {
|
||||
// input_ids: [N, n_token]
|
||||
auto model = std::dynamic_pointer_cast<Qwen2_5_VLTextModel>(blocks["model"]);
|
||||
|
||||
auto x = model->forward(ctx, backend, input_ids, input_pos);
|
||||
auto x = model->forward(ctx, backend, input_ids, input_pos, image_embeds);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct ggml_tensor* vision_forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* pixel_values,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* window_index,
|
||||
struct ggml_tensor* window_inverse_index,
|
||||
struct ggml_tensor* window_mask) {
|
||||
GGML_ASSERT(enable_vision);
|
||||
auto vision_model = std::dynamic_pointer_cast<Qwen2_5_VLVisionModel>(blocks["visual"]);
|
||||
return vision_model->forward(ctx, backend, pixel_values, pe, window_index, window_inverse_index, window_mask);
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLRunner : public GGMLRunner {
|
||||
Qwen2_5_VLParams params;
|
||||
bool enable_vision;
|
||||
Qwen2_5_VL model;
|
||||
|
||||
std::vector<int> input_pos_vec;
|
||||
std::vector<float> window_mask_vec;
|
||||
std::vector<int> window_index_vec;
|
||||
std::vector<int> window_inverse_index_vec;
|
||||
std::vector<float> pe_vec;
|
||||
|
||||
Qwen2_5_VLRunner(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types,
|
||||
const std::string prefix)
|
||||
: GGMLRunner(backend, offload_params_to_cpu) {
|
||||
model = Qwen2_5_VL(params);
|
||||
const std::string prefix,
|
||||
bool enable_vision_ = false)
|
||||
: GGMLRunner(backend, offload_params_to_cpu), enable_vision(enable_vision_) {
|
||||
bool have_vision_weight = false;
|
||||
bool llama_cpp_style = false;
|
||||
for (auto pair : tensor_types) {
|
||||
std::string tensor_name = pair.first;
|
||||
if (tensor_name.find(prefix) == std::string::npos)
|
||||
continue;
|
||||
size_t pos = tensor_name.find("visual.");
|
||||
if (pos != std::string::npos) {
|
||||
have_vision_weight = true;
|
||||
if (contains(tensor_name, "attn.q_proj")) {
|
||||
llama_cpp_style = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enable_vision && !have_vision_weight) {
|
||||
LOG_WARN("no vision weights detected, vision disabled");
|
||||
enable_vision = false;
|
||||
}
|
||||
if (enable_vision) {
|
||||
LOG_DEBUG("enable qwen2vl vision");
|
||||
if (llama_cpp_style) {
|
||||
LOG_DEBUG("llama.cpp style vision weight");
|
||||
}
|
||||
}
|
||||
model = Qwen2_5_VL(params, enable_vision, llama_cpp_style);
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "qwenvl2.5";
|
||||
}
|
||||
|
||||
@@ -562,16 +962,32 @@ namespace Qwen {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* input_pos) {
|
||||
auto hidden_states = model.forward(ctx, backend, input_ids, input_pos); // [N, n_token, hidden_size]
|
||||
struct ggml_tensor* input_pos,
|
||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds) {
|
||||
auto hidden_states = model.forward(ctx, backend, input_ids, input_pos, image_embeds); // [N, n_token, hidden_size]
|
||||
return hidden_states;
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* input_ids) {
|
||||
struct ggml_tensor* vision_forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* pixel_values,
|
||||
struct ggml_tensor* input_pos,
|
||||
struct ggml_tensor* window_index,
|
||||
struct ggml_tensor* window_inverse_index,
|
||||
struct ggml_tensor* window_mask) {
|
||||
auto hidden_states = model.vision_forward(ctx, backend, pixel_values, input_pos, window_index, window_inverse_index, window_mask);
|
||||
return hidden_states;
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* input_ids, std::vector<std::pair<int, ggml_tensor*>> image_embeds) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph(compute_ctx);
|
||||
|
||||
input_ids = to_backend(input_ids);
|
||||
|
||||
for (auto& image_embed : image_embeds) {
|
||||
image_embed.second = to_backend(image_embed.second);
|
||||
}
|
||||
|
||||
int64_t n_tokens = input_ids->ne[0];
|
||||
input_pos_vec.resize(n_tokens * 4);
|
||||
for (int i = 0; i < n_tokens; ++i) {
|
||||
@@ -586,7 +1002,7 @@ namespace Qwen {
|
||||
n_tokens * 4);
|
||||
set_backend_tensor_data(input_pos, input_pos_vec.data());
|
||||
|
||||
struct ggml_tensor* hidden_states = forward(compute_ctx, runtime_backend, input_ids, input_pos);
|
||||
struct ggml_tensor* hidden_states = forward(compute_ctx, runtime_backend, input_ids, input_pos, image_embeds);
|
||||
|
||||
ggml_build_forward_expand(gf, hidden_states);
|
||||
|
||||
@@ -595,13 +1011,183 @@ namespace Qwen {
|
||||
|
||||
void compute(const int n_threads,
|
||||
struct ggml_tensor* input_ids,
|
||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds,
|
||||
ggml_tensor** output,
|
||||
ggml_context* output_ctx = NULL) {
|
||||
ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(input_ids);
|
||||
return build_graph(input_ids, image_embeds);
|
||||
};
|
||||
GGMLRunner::compute(get_graph, n_threads, true, output, output_ctx);
|
||||
}
|
||||
|
||||
int64_t get_num_image_tokens(int64_t t, int64_t h, int64_t w) {
|
||||
int grid_t = 1;
|
||||
int grid_h = h / params.vision.patch_size;
|
||||
int grid_w = w / params.vision.patch_size;
|
||||
int llm_grid_h = grid_h / params.vision.spatial_merge_size;
|
||||
int llm_grid_w = grid_w / params.vision.spatial_merge_size;
|
||||
return grid_t * grid_h * grid_w;
|
||||
}
|
||||
|
||||
struct ggml_tensor* process_image(struct ggml_context* ctx, struct ggml_tensor* image) {
|
||||
// image: [C, H, W]
|
||||
// return: [grid_t*(H/mh/ph)*(W/mw/pw)*mh*mw, C*pt*ph*pw], grid_t == 1
|
||||
int64_t C = image->ne[2];
|
||||
int64_t H = image->ne[1];
|
||||
int64_t W = image->ne[0];
|
||||
int64_t mh = params.vision.spatial_merge_size;
|
||||
int64_t mw = params.vision.spatial_merge_size;
|
||||
int64_t pt = params.vision.temporal_patch_size;
|
||||
int64_t ph = params.vision.patch_size;
|
||||
int64_t pw = params.vision.patch_size;
|
||||
|
||||
image = ggml_reshape_4d(ctx, image, pw, mw, (W / mw / pw), H * C); // [C*H, (W/mw/pw), mw, pw]
|
||||
image = ggml_cont(ctx, ggml_ext_torch_permute(ctx, image, 0, 2, 3, 1)); // [mw, C*H, (W/mw/pw), pw]
|
||||
image = ggml_reshape_4d(ctx, image, pw * (W / mw / pw), H, C, mw); // [mw, C, H, (W/mw/pw)*pw]
|
||||
image = ggml_cont(ctx, ggml_ext_torch_permute(ctx, image, 0, 2, 3, 1)); // [H, mw, C, (W/mw/pw)*pw]
|
||||
image = ggml_reshape_4d(ctx, image, pw, (W / mw / pw) * C * mw, ph, mh * (H / mh / ph)); // [(H/mh/ph)*mh, ph, mw*C*(W/mw/pw), pw]
|
||||
image = ggml_cont(ctx, ggml_ext_torch_permute(ctx, image, 0, 2, 1, 3)); // [(H/mh/ph)*mh, mw*C*(W/mw/pw), ph, pw]
|
||||
image = ggml_reshape_4d(ctx, image, pw * ph, (W / mw / pw), C, mw * mh * (H / mh / ph)); // [(H/mh/ph)*mh*mw, C, (W/mw/pw), ph*pw]
|
||||
image = ggml_concat(ctx, image, image, 0); // [(H/mh/ph)*mh*mw, C, (W/mw/pw), pt*ph*pw]
|
||||
image = ggml_cont(ctx, ggml_ext_torch_permute(ctx, image, 0, 2, 1, 3)); // [(H/mh/ph)*mh*mw, (W/mw/pw), C, pt*ph*pw]
|
||||
image = ggml_reshape_4d(ctx, image, pw * ph * pt * C, (W / mw / pw), mw * mh, (H / mh / ph)); // [(H/mh/ph), mh*mw, (W/mw/pw), C*pt*ph*pw]
|
||||
image = ggml_cont(ctx, ggml_ext_torch_permute(ctx, image, 0, 2, 1, 3)); // [(H/mh/ph), (W/mw/pw), mh*mw, C*pt*ph*pw]
|
||||
image = ggml_reshape_2d(ctx, image, pw * ph * pt * C, mw * mh * (W / mw / pw) * (H / mh / ph)); // [(H/mh/ph)*(W/mw/pw)*mh*mw, C*pt*ph*pw]
|
||||
return image;
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_encode_image_graph(struct ggml_tensor* image) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, QWENVL_GRAPH_SIZE, false);
|
||||
|
||||
GGML_ASSERT(image->ne[1] % (params.vision.patch_size * params.vision.spatial_merge_size) == 0);
|
||||
GGML_ASSERT(image->ne[0] % (params.vision.patch_size * params.vision.spatial_merge_size) == 0);
|
||||
|
||||
int grid_t = 1;
|
||||
int grid_h = image->ne[1] / params.vision.patch_size;
|
||||
int grid_w = image->ne[0] / params.vision.patch_size;
|
||||
int llm_grid_h = grid_h / params.vision.spatial_merge_size;
|
||||
int llm_grid_w = grid_w / params.vision.spatial_merge_size;
|
||||
int vit_merger_window_size = params.vision.window_size / params.vision.patch_size / params.vision.spatial_merge_size;
|
||||
|
||||
image = to_backend(image);
|
||||
|
||||
auto pixel_values = process_image(compute_ctx, image);
|
||||
|
||||
// window index
|
||||
int inverse_index = 0;
|
||||
window_index_vec.resize(llm_grid_h * llm_grid_w);
|
||||
window_inverse_index_vec.resize(llm_grid_h * llm_grid_w);
|
||||
std::vector<int> seqlens;
|
||||
for (int ih = 0; ih < llm_grid_h; ih += vit_merger_window_size) {
|
||||
for (int iw = 0; iw < llm_grid_w; iw += vit_merger_window_size) {
|
||||
int win_h = std::min(vit_merger_window_size, llm_grid_h - ih);
|
||||
int win_w = std::min(vit_merger_window_size, llm_grid_w - iw);
|
||||
for (int iy = 0; iy < win_h; iy++) {
|
||||
for (int ix = 0; ix < win_w; ix++) {
|
||||
int index = (ih + iy) * llm_grid_w + iw + ix;
|
||||
window_index_vec[inverse_index] = index;
|
||||
window_inverse_index_vec[index] = inverse_index;
|
||||
inverse_index++;
|
||||
}
|
||||
}
|
||||
seqlens.push_back(win_h * win_w * params.vision.spatial_merge_size * params.vision.spatial_merge_size);
|
||||
}
|
||||
}
|
||||
// printf("window_index: ");
|
||||
// for (int i : window_index_vec) {
|
||||
// printf("%d ", i);
|
||||
// }
|
||||
// printf("\n");
|
||||
// printf("window_inverse_index: ");
|
||||
// for (int i : window_inverse_index_vec) {
|
||||
// printf("%d ", i);
|
||||
// }
|
||||
// printf("\n");
|
||||
// printf("seqlens: ");
|
||||
// for (int i : seqlens) {
|
||||
// printf("%d ", i);
|
||||
// }
|
||||
// printf("\n");
|
||||
auto window_index = ggml_new_tensor_1d(compute_ctx,
|
||||
GGML_TYPE_I32,
|
||||
llm_grid_h * llm_grid_w);
|
||||
auto window_inverse_index = ggml_new_tensor_1d(compute_ctx,
|
||||
GGML_TYPE_I32,
|
||||
llm_grid_h * llm_grid_w);
|
||||
set_backend_tensor_data(window_index, window_index_vec.data());
|
||||
set_backend_tensor_data(window_inverse_index, window_inverse_index_vec.data());
|
||||
|
||||
// window mask
|
||||
int seq_window_size = (vit_merger_window_size * params.vision.spatial_merge_size) * (vit_merger_window_size * params.vision.spatial_merge_size);
|
||||
window_mask_vec.resize((grid_h * grid_w) * (grid_h * grid_w));
|
||||
int window_start_index = 0;
|
||||
for (int seq_index = 0; seq_index < seqlens.size(); seq_index++) {
|
||||
int window_end_index = window_start_index + seqlens[seq_index];
|
||||
// LOG_DEBUG("%d %d", window_start_index, window_end_index);
|
||||
GGML_ASSERT(window_end_index <= grid_h * grid_w);
|
||||
for (int i = window_start_index; i < window_end_index; i++) {
|
||||
for (int j = 0; j < grid_h * grid_w; j++) {
|
||||
float mask_value = -INFINITY;
|
||||
if (j >= window_start_index && j < window_end_index) {
|
||||
mask_value = 0;
|
||||
}
|
||||
GGML_ASSERT((i * (grid_h * grid_w) + j) < window_mask_vec.size());
|
||||
window_mask_vec[i * (grid_h * grid_w) + j] = mask_value;
|
||||
}
|
||||
}
|
||||
window_start_index = window_end_index;
|
||||
// printf("\n");
|
||||
}
|
||||
// printf("window_mask: \n");
|
||||
// for (int i = 0; i < grid_h*grid_w; i++) {
|
||||
// for (int j = 0; j < grid_h*grid_w; j++) {
|
||||
// printf("%f ", window_mask_vec[i * (grid_h * grid_w) + j]);
|
||||
// }
|
||||
// printf("\n");
|
||||
// }
|
||||
auto window_mask = ggml_new_tensor_2d(compute_ctx,
|
||||
GGML_TYPE_F32,
|
||||
grid_h * grid_w,
|
||||
grid_h * grid_w);
|
||||
set_backend_tensor_data(window_mask, window_mask_vec.data());
|
||||
|
||||
// pe
|
||||
int head_dim = params.vision.hidden_size / params.vision.num_heads;
|
||||
pe_vec = Rope::gen_qwen2vl_pe(grid_h,
|
||||
grid_w,
|
||||
params.vision.spatial_merge_size,
|
||||
window_inverse_index_vec,
|
||||
10000.f,
|
||||
{head_dim / 2, head_dim / 2});
|
||||
int pos_len = pe_vec.size() / head_dim / 2;
|
||||
// LOG_DEBUG("pos_len %d", pos_len);
|
||||
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, head_dim / 2, pos_len);
|
||||
// pe->data = pe_vec.data();
|
||||
// print_ggml_tensor(pe);
|
||||
// pe->data = nullptr;
|
||||
set_backend_tensor_data(pe, pe_vec.data());
|
||||
|
||||
struct ggml_tensor* hidden_states = vision_forward(compute_ctx,
|
||||
runtime_backend,
|
||||
pixel_values,
|
||||
pe,
|
||||
window_index,
|
||||
window_inverse_index,
|
||||
window_mask);
|
||||
ggml_build_forward_expand(gf, hidden_states);
|
||||
|
||||
return gf;
|
||||
}
|
||||
|
||||
void encode_image(const int n_threads,
|
||||
struct ggml_tensor* image,
|
||||
ggml_tensor** output,
|
||||
ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_encode_image_graph(image);
|
||||
};
|
||||
GGMLRunner::compute(get_graph, n_threads, false, output, output_ctx);
|
||||
}
|
||||
};
|
||||
|
||||
struct Qwen2_5_VLEmbedder {
|
||||
@@ -611,8 +1197,9 @@ namespace Qwen {
|
||||
Qwen2_5_VLEmbedder(ggml_backend_t backend,
|
||||
bool offload_params_to_cpu,
|
||||
const String2GGMLType& tensor_types = {},
|
||||
const std::string prefix = "")
|
||||
: model(backend, offload_params_to_cpu, tensor_types, prefix) {
|
||||
const std::string prefix = "",
|
||||
bool enable_vision = false)
|
||||
: model(backend, offload_params_to_cpu, tensor_types, prefix, enable_vision) {
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||
@@ -661,13 +1248,81 @@ namespace Qwen {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(1024 * 1024) * 1024; // 1GB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
bool test_vit = true;
|
||||
bool test_decoder_with_vit = true;
|
||||
|
||||
{
|
||||
if (test_decoder_with_vit) {
|
||||
ggml_tensor* image_embed = nullptr;
|
||||
{
|
||||
auto image = load_tensor_from_file(work_ctx, "qwen2vl_normalized.bin");
|
||||
print_ggml_tensor(image, false, "image");
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
model.encode_image(8, image, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out, false, "image_embed");
|
||||
image_embed = out;
|
||||
LOG_DEBUG("qwen2vl encode_image test done in %dms", t1 - t0);
|
||||
}
|
||||
|
||||
std::string placeholder = "<|image_pad|>";
|
||||
std::string img_prompt = "Picture 1: <|vision_start|>"; // [24669, 220, 16, 25, 220, 151652]
|
||||
int64_t num_image_tokens = image_embed->ne[1];
|
||||
img_prompt.reserve(num_image_tokens * placeholder.size());
|
||||
for (int i = 0; i < num_image_tokens; i++) {
|
||||
img_prompt += placeholder;
|
||||
}
|
||||
img_prompt += "<|vision_end|>";
|
||||
|
||||
std::vector<std::pair<int, ggml_tensor*>> image_embeds;
|
||||
image_embeds.emplace_back(64, image_embed);
|
||||
|
||||
std::string text = "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n";
|
||||
text += img_prompt;
|
||||
text += "change 'flux.cpp' to 'edit.cpp'";
|
||||
text += "<|im_end|>\n<|im_start|>assistant\n";
|
||||
|
||||
auto tokens_and_weights = tokenize(text, 0, false);
|
||||
std::vector<int>& tokens = std::get<0>(tokens_and_weights);
|
||||
std::vector<float>& weights = std::get<1>(tokens_and_weights);
|
||||
for (auto token : tokens) {
|
||||
printf("%d ", token);
|
||||
}
|
||||
printf("\n");
|
||||
auto input_ids = vector_to_ggml_tensor_i32(work_ctx, tokens);
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
model.compute(8, input_ids, image_embeds, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
LOG_DEBUG("qwen2vl test done in %dms", t1 - t0);
|
||||
} else if (test_vit) {
|
||||
// auto image = ggml_new_tensor_3d(work_ctx, GGML_TYPE_F32, 280, 280, 3);
|
||||
// ggml_set_f32(image, 0.f);
|
||||
auto image = load_tensor_from_file(work_ctx, "qwen2vl_normalized.bin");
|
||||
print_ggml_tensor(image, false, "image");
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
model.encode_image(8, image, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out, false, "out");
|
||||
|
||||
// auto ref_out = load_tensor_from_file(work_ctx, "qwen2vl.bin");
|
||||
// ggml_ext_tensor_diff(ref_out, out, 0.01f);
|
||||
|
||||
LOG_DEBUG("qwen2vl test done in %dms", t1 - t0);
|
||||
} else {
|
||||
std::string text("<|im_start|>system\nDescribe the image by detailing the color, shape, size, texture, quantity, text, spatial relationships of the objects and background:<|im_end|>\n<|im_start|>user\na lovely cat<|im_end|>\n<|im_start|>assistant\n");
|
||||
auto tokens_and_weights = tokenize(text, 0, false);
|
||||
std::vector<int>& tokens = std::get<0>(tokens_and_weights);
|
||||
@@ -677,10 +1332,10 @@ namespace Qwen {
|
||||
}
|
||||
printf("\n");
|
||||
auto input_ids = vector_to_ggml_tensor_i32(work_ctx, tokens);
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
model.compute(8, input_ids, &out, work_ctx);
|
||||
model.compute(8, input_ids, {}, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
@@ -692,7 +1347,7 @@ namespace Qwen {
|
||||
// cpu f16: pass
|
||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||
ggml_type model_data_type = GGML_TYPE_Q8_0;
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
|
||||
ModelLoader model_loader;
|
||||
if (!model_loader.init_from_file(file_path, "qwen2vl.")) {
|
||||
@@ -708,7 +1363,11 @@ namespace Qwen {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Qwen2_5_VLEmbedder> qwenvl = std::shared_ptr<Qwen2_5_VLEmbedder>(new Qwen2_5_VLEmbedder(backend, false, tensor_types, "qwen2vl"));
|
||||
std::shared_ptr<Qwen2_5_VLEmbedder> qwenvl = std::make_shared<Qwen2_5_VLEmbedder>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
"qwen2vl",
|
||||
true);
|
||||
|
||||
qwenvl->alloc_params_buffer();
|
||||
std::map<std::string, ggml_tensor*> tensors;
|
||||
|
||||
@@ -15,11 +15,11 @@ private:
|
||||
std::default_random_engine generator;
|
||||
|
||||
public:
|
||||
void manual_seed(uint64_t seed) {
|
||||
void manual_seed(uint64_t seed) override {
|
||||
generator.seed((unsigned int)seed);
|
||||
}
|
||||
|
||||
std::vector<float> randn(uint32_t n) {
|
||||
std::vector<float> randn(uint32_t n) override {
|
||||
std::vector<float> result;
|
||||
float mean = 0.0;
|
||||
float stddev = 1.0;
|
||||
|
||||
+2
-2
@@ -93,12 +93,12 @@ public:
|
||||
this->offset = 0;
|
||||
}
|
||||
|
||||
void manual_seed(uint64_t seed) {
|
||||
void manual_seed(uint64_t seed) override {
|
||||
this->seed = seed;
|
||||
this->offset = 0;
|
||||
}
|
||||
|
||||
std::vector<float> randn(uint32_t n) {
|
||||
std::vector<float> randn(uint32_t n) override {
|
||||
std::vector<std::vector<uint32_t>> counter(4, std::vector<uint32_t>(n, 0));
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
counter[0][i] = this->offset;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <vector>
|
||||
#include "ggml_extend.hpp"
|
||||
|
||||
struct Rope {
|
||||
namespace Rope {
|
||||
template <class T>
|
||||
static std::vector<T> linspace(T start, T end, int num) {
|
||||
__STATIC_INLINE__ std::vector<T> linspace(T start, T end, int num) {
|
||||
std::vector<T> result(num);
|
||||
if (num == 1) {
|
||||
result[0] = start;
|
||||
@@ -19,7 +19,7 @@ struct Rope {
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> transpose(const std::vector<std::vector<float>>& mat) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> transpose(const std::vector<std::vector<float>>& mat) {
|
||||
int rows = mat.size();
|
||||
int cols = mat[0].size();
|
||||
std::vector<std::vector<float>> transposed(cols, std::vector<float>(rows));
|
||||
@@ -31,7 +31,7 @@ struct Rope {
|
||||
return transposed;
|
||||
}
|
||||
|
||||
static std::vector<float> flatten(const std::vector<std::vector<float>>& vec) {
|
||||
__STATIC_INLINE__ std::vector<float> flatten(const std::vector<std::vector<float>>& vec) {
|
||||
std::vector<float> flat_vec;
|
||||
for (const auto& sub_vec : vec) {
|
||||
flat_vec.insert(flat_vec.end(), sub_vec.begin(), sub_vec.end());
|
||||
@@ -39,7 +39,7 @@ struct Rope {
|
||||
return flat_vec;
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> rope(const std::vector<float>& pos, int dim, int theta) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> rope(const std::vector<float>& pos, int dim, int theta) {
|
||||
assert(dim % 2 == 0);
|
||||
int half_dim = dim / 2;
|
||||
|
||||
@@ -72,11 +72,11 @@ struct Rope {
|
||||
}
|
||||
|
||||
// Generate IDs for image patches and text
|
||||
static std::vector<std::vector<float>> gen_txt_ids(int bs, int context_len) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_txt_ids(int bs, int context_len) {
|
||||
return std::vector<std::vector<float>>(bs * context_len, std::vector<float>(3, 0.0));
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> gen_img_ids(int h, int w, int patch_size, int bs, int index = 0, int h_offset = 0, int w_offset = 0) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_img_ids(int h, int w, int patch_size, int bs, int index = 0, int h_offset = 0, int w_offset = 0) {
|
||||
int h_len = (h + (patch_size / 2)) / patch_size;
|
||||
int w_len = (w + (patch_size / 2)) / patch_size;
|
||||
|
||||
@@ -102,9 +102,9 @@ struct Rope {
|
||||
return img_ids_repeated;
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> concat_ids(const std::vector<std::vector<float>>& a,
|
||||
const std::vector<std::vector<float>>& b,
|
||||
int bs) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> concat_ids(const std::vector<std::vector<float>>& a,
|
||||
const std::vector<std::vector<float>>& b,
|
||||
int bs) {
|
||||
size_t a_len = a.size() / bs;
|
||||
size_t b_len = b.size() / bs;
|
||||
std::vector<std::vector<float>> ids(a.size() + b.size(), std::vector<float>(3));
|
||||
@@ -119,10 +119,10 @@ struct Rope {
|
||||
return ids;
|
||||
}
|
||||
|
||||
static std::vector<float> embed_nd(const std::vector<std::vector<float>>& ids,
|
||||
int bs,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
__STATIC_INLINE__ std::vector<float> embed_nd(const std::vector<std::vector<float>>& ids,
|
||||
int bs,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
std::vector<std::vector<float>> trans_ids = transpose(ids);
|
||||
size_t pos_len = ids.size() / bs;
|
||||
int num_axes = axes_dim.size();
|
||||
@@ -151,17 +151,11 @@ struct Rope {
|
||||
return flatten(emb);
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> gen_flux_ids(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
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);
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_refs_ids(int patch_size,
|
||||
int bs,
|
||||
const std::vector<ggml_tensor*>& ref_latents,
|
||||
bool increase_ref_index) {
|
||||
std::vector<std::vector<float>> ids;
|
||||
uint64_t curr_h_offset = 0;
|
||||
uint64_t curr_w_offset = 0;
|
||||
int index = 1;
|
||||
@@ -189,25 +183,45 @@ struct Rope {
|
||||
return ids;
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_flux_ids(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
const 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);
|
||||
if (ref_latents.size() > 0) {
|
||||
auto refs_ids = gen_refs_ids(patch_size, bs, ref_latents, increase_ref_index);
|
||||
ids = concat_ids(ids, refs_ids, bs);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Generate flux positional embeddings
|
||||
static std::vector<float> gen_flux_pe(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
std::vector<ggml_tensor*> ref_latents,
|
||||
bool increase_ref_index,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
__STATIC_INLINE__ std::vector<float> gen_flux_pe(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
const 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, increase_ref_index);
|
||||
return embed_nd(ids, bs, theta, axes_dim);
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> gen_qwen_image_ids(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_qwen_image_ids(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
const std::vector<ggml_tensor*>& ref_latents,
|
||||
bool increase_ref_index) {
|
||||
int h_len = (h + (patch_size / 2)) / patch_size;
|
||||
int w_len = (w + (patch_size / 2)) / patch_size;
|
||||
int txt_id_start = std::max(h_len, w_len);
|
||||
@@ -220,31 +234,37 @@ struct Rope {
|
||||
}
|
||||
auto img_ids = gen_img_ids(h, w, patch_size, bs);
|
||||
auto ids = concat_ids(txt_ids_repeated, img_ids, bs);
|
||||
if (ref_latents.size() > 0) {
|
||||
auto refs_ids = gen_refs_ids(patch_size, bs, ref_latents, increase_ref_index);
|
||||
ids = concat_ids(ids, refs_ids, bs);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Generate qwen_image positional embeddings
|
||||
static std::vector<float> gen_qwen_image_pe(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
std::vector<std::vector<float>> ids = gen_qwen_image_ids(h, w, patch_size, bs, context_len);
|
||||
__STATIC_INLINE__ std::vector<float> gen_qwen_image_pe(int h,
|
||||
int w,
|
||||
int patch_size,
|
||||
int bs,
|
||||
int context_len,
|
||||
const 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_qwen_image_ids(h, w, patch_size, bs, context_len, ref_latents, increase_ref_index);
|
||||
return embed_nd(ids, bs, theta, axes_dim);
|
||||
}
|
||||
|
||||
static std::vector<std::vector<float>> gen_vid_ids(int t,
|
||||
int h,
|
||||
int w,
|
||||
int pt,
|
||||
int ph,
|
||||
int pw,
|
||||
int bs,
|
||||
int t_offset = 0,
|
||||
int h_offset = 0,
|
||||
int w_offset = 0) {
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_vid_ids(int t,
|
||||
int h,
|
||||
int w,
|
||||
int pt,
|
||||
int ph,
|
||||
int pw,
|
||||
int bs,
|
||||
int t_offset = 0,
|
||||
int h_offset = 0,
|
||||
int w_offset = 0) {
|
||||
int t_len = (t + (pt / 2)) / pt;
|
||||
int h_len = (h + (ph / 2)) / ph;
|
||||
int w_len = (w + (pw / 2)) / pw;
|
||||
@@ -276,18 +296,115 @@ struct Rope {
|
||||
}
|
||||
|
||||
// Generate wan positional embeddings
|
||||
static std::vector<float> gen_wan_pe(int t,
|
||||
int h,
|
||||
int w,
|
||||
int pt,
|
||||
int ph,
|
||||
int pw,
|
||||
int bs,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
__STATIC_INLINE__ std::vector<float> gen_wan_pe(int t,
|
||||
int h,
|
||||
int w,
|
||||
int pt,
|
||||
int ph,
|
||||
int pw,
|
||||
int bs,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
std::vector<std::vector<float>> ids = gen_vid_ids(t, h, w, pt, ph, pw, bs);
|
||||
return embed_nd(ids, bs, theta, axes_dim);
|
||||
}
|
||||
}; // struct Rope
|
||||
|
||||
__STATIC_INLINE__ std::vector<std::vector<float>> gen_qwen2vl_ids(int grid_h,
|
||||
int grid_w,
|
||||
int merge_size,
|
||||
const std::vector<int>& window_index) {
|
||||
std::vector<std::vector<float>> ids(grid_h * grid_w, std::vector<float>(2, 0.0));
|
||||
int index = 0;
|
||||
for (int ih = 0; ih < grid_h; ih += merge_size) {
|
||||
for (int iw = 0; iw < grid_w; iw += merge_size) {
|
||||
for (int iy = 0; iy < merge_size; iy++) {
|
||||
for (int ix = 0; ix < merge_size; ix++) {
|
||||
int inverse_index = window_index[index / (merge_size * merge_size)];
|
||||
int i = inverse_index * (merge_size * merge_size) + index % (merge_size * merge_size);
|
||||
|
||||
GGML_ASSERT(i < grid_h * grid_w);
|
||||
|
||||
ids[i][0] = ih + iy;
|
||||
ids[i][1] = iw + ix;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Generate qwen2vl positional embeddings
|
||||
__STATIC_INLINE__ std::vector<float> gen_qwen2vl_pe(int grid_h,
|
||||
int grid_w,
|
||||
int merge_size,
|
||||
const std::vector<int>& window_index,
|
||||
int theta,
|
||||
const std::vector<int>& axes_dim) {
|
||||
std::vector<std::vector<float>> ids = gen_qwen2vl_ids(grid_h, grid_w, merge_size, window_index);
|
||||
return embed_nd(ids, 1, theta, axes_dim);
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ struct ggml_tensor* apply_rope(struct ggml_context* ctx,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* pe,
|
||||
bool rope_interleaved = true) {
|
||||
// x: [N, L, n_head, d_head]
|
||||
// pe: [L, d_head/2, 2, 2], [[cos, -sin], [sin, cos]]
|
||||
int64_t d_head = x->ne[0];
|
||||
int64_t n_head = x->ne[1];
|
||||
int64_t L = x->ne[2];
|
||||
int64_t N = x->ne[3];
|
||||
x = ggml_cont(ctx, ggml_permute(ctx, x, 0, 2, 1, 3)); // [N, n_head, L, d_head]
|
||||
if (rope_interleaved) {
|
||||
x = ggml_reshape_4d(ctx, x, 2, d_head / 2, L, n_head * N); // [N * n_head, L, d_head/2, 2]
|
||||
x = ggml_cont(ctx, ggml_permute(ctx, x, 3, 0, 1, 2)); // [2, N * n_head, L, d_head/2]
|
||||
} else {
|
||||
x = ggml_reshape_4d(ctx, x, d_head / 2, 2, L, n_head * N); // [N * n_head, L, 2, d_head/2]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 3, 1)); // [2, N * n_head, L, d_head/2]
|
||||
}
|
||||
|
||||
int64_t offset = x->nb[2] * x->ne[2];
|
||||
auto x_0 = ggml_view_3d(ctx, x, x->ne[0], x->ne[1], x->ne[2], x->nb[1], x->nb[2], offset * 0); // [N * n_head, L, d_head/2]
|
||||
auto x_1 = ggml_view_3d(ctx, x, x->ne[0], x->ne[1], x->ne[2], x->nb[1], x->nb[2], offset * 1); // [N * n_head, L, d_head/2]
|
||||
x_0 = ggml_reshape_4d(ctx, x_0, 1, x_0->ne[0], x_0->ne[1], x_0->ne[2]); // [N * n_head, L, d_head/2, 1]
|
||||
x_1 = ggml_reshape_4d(ctx, x_1, 1, x_1->ne[0], x_1->ne[1], x_1->ne[2]); // [N * n_head, L, d_head/2, 1]
|
||||
auto temp_x = ggml_new_tensor_4d(ctx, x_0->type, 2, x_0->ne[1], x_0->ne[2], x_0->ne[3]);
|
||||
x_0 = ggml_repeat(ctx, x_0, temp_x); // [N * n_head, L, d_head/2, 2]
|
||||
x_1 = ggml_repeat(ctx, x_1, temp_x); // [N * n_head, L, d_head/2, 2]
|
||||
|
||||
pe = ggml_cont(ctx, ggml_permute(ctx, pe, 3, 0, 1, 2)); // [2, L, d_head/2, 2]
|
||||
offset = pe->nb[2] * pe->ne[2];
|
||||
auto pe_0 = ggml_view_3d(ctx, pe, pe->ne[0], pe->ne[1], pe->ne[2], pe->nb[1], pe->nb[2], offset * 0); // [L, d_head/2, 2]
|
||||
auto pe_1 = ggml_view_3d(ctx, pe, pe->ne[0], pe->ne[1], pe->ne[2], pe->nb[1], pe->nb[2], offset * 1); // [L, d_head/2, 2]
|
||||
|
||||
auto x_out = ggml_add_inplace(ctx, ggml_mul(ctx, x_0, pe_0), ggml_mul(ctx, x_1, pe_1)); // [N * n_head, L, d_head/2, 2]
|
||||
if (!rope_interleaved) {
|
||||
x_out = ggml_cont(ctx, ggml_permute(ctx, x_out, 1, 0, 2, 3)); // [N * n_head, L, x, d_head/2]
|
||||
}
|
||||
x_out = ggml_reshape_3d(ctx, x_out, d_head, L, n_head * N); // [N*n_head, L, d_head]
|
||||
return x_out;
|
||||
}
|
||||
|
||||
__STATIC_INLINE__ struct ggml_tensor* attention(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* q,
|
||||
struct ggml_tensor* k,
|
||||
struct ggml_tensor* v,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* mask,
|
||||
bool flash_attn,
|
||||
float kv_scale = 1.0f,
|
||||
bool rope_interleaved = true) {
|
||||
// q,k,v: [N, L, n_head, d_head]
|
||||
// pe: [L, d_head/2, 2, 2]
|
||||
// return: [N, L, n_head*d_head]
|
||||
q = apply_rope(ctx, q, pe, rope_interleaved); // [N*n_head, L, d_head]
|
||||
k = apply_rope(ctx, k, pe, rope_interleaved); // [N*n_head, L, d_head]
|
||||
|
||||
auto x = ggml_ext_attention_ext(ctx, backend, q, k, v, v->ne[1], mask, false, true, flash_attn, kv_scale); // [N, L, n_head*d_head]
|
||||
return x;
|
||||
}
|
||||
}; // namespace Rope
|
||||
|
||||
#endif // __ROPE_HPP__
|
||||
|
||||
+573
-446
File diff suppressed because it is too large
Load Diff
@@ -64,6 +64,16 @@ enum scheduler_t {
|
||||
SCHEDULE_COUNT
|
||||
};
|
||||
|
||||
enum prediction_t {
|
||||
DEFAULT_PRED,
|
||||
EPS_PRED,
|
||||
V_PRED,
|
||||
EDM_V_PRED,
|
||||
SD3_FLOW_PRED,
|
||||
FLUX_FLOW_PRED,
|
||||
PREDICTION_COUNT
|
||||
};
|
||||
|
||||
// same as enum ggml_type
|
||||
enum sd_type_t {
|
||||
SD_TYPE_F32 = 0,
|
||||
@@ -132,6 +142,7 @@ typedef struct {
|
||||
const char* clip_vision_path;
|
||||
const char* t5xxl_path;
|
||||
const char* qwen2vl_path;
|
||||
const char* qwen2vl_vision_path;
|
||||
const char* diffusion_model_path;
|
||||
const char* high_noise_diffusion_model_path;
|
||||
const char* vae_path;
|
||||
@@ -145,6 +156,7 @@ typedef struct {
|
||||
int n_threads;
|
||||
enum sd_type_t wtype;
|
||||
enum rng_type_t rng_type;
|
||||
enum prediction_t prediction;
|
||||
bool offload_params_to_cpu;
|
||||
bool keep_clip_on_cpu;
|
||||
bool keep_control_net_on_cpu;
|
||||
@@ -152,6 +164,7 @@ typedef struct {
|
||||
bool diffusion_flash_attn;
|
||||
bool diffusion_conv_direct;
|
||||
bool vae_conv_direct;
|
||||
bool force_sdxl_vae_conv_scale;
|
||||
bool chroma_use_dit_mask;
|
||||
bool chroma_use_t5_mask;
|
||||
int chroma_t5_mask_pad;
|
||||
@@ -203,6 +216,7 @@ typedef struct {
|
||||
sd_image_t init_image;
|
||||
sd_image_t* ref_images;
|
||||
int ref_images_count;
|
||||
bool auto_resize_ref_image;
|
||||
bool increase_ref_index;
|
||||
sd_image_t mask_image;
|
||||
int width;
|
||||
@@ -254,6 +268,8 @@ SD_API const char* sd_sample_method_name(enum sample_method_t sample_method);
|
||||
SD_API enum sample_method_t str_to_sample_method(const char* str);
|
||||
SD_API const char* sd_schedule_name(enum scheduler_t scheduler);
|
||||
SD_API enum scheduler_t str_to_schedule(const char* str);
|
||||
SD_API const char* sd_prediction_name(enum prediction_t prediction);
|
||||
SD_API enum prediction_t str_to_prediction(const char* str);
|
||||
|
||||
SD_API void sd_ctx_params_init(sd_ctx_params_t* sd_ctx_params);
|
||||
SD_API char* sd_ctx_params_to_str(const sd_ctx_params_t* sd_ctx_params);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __T5_HPP__
|
||||
#define __T5_HPP__
|
||||
|
||||
#include <float.h>
|
||||
#include <cfloat>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -461,7 +461,7 @@ protected:
|
||||
int64_t hidden_size;
|
||||
float eps;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = GGML_TYPE_F32;
|
||||
params["weight"] = ggml_new_tensor_1d(ctx, wtype, hidden_size);
|
||||
}
|
||||
@@ -472,7 +472,7 @@ public:
|
||||
: hidden_size(hidden_size),
|
||||
eps(eps) {}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
struct ggml_tensor* w = params["weight"];
|
||||
x = ggml_rms_norm(ctx, x, eps);
|
||||
x = ggml_mul(ctx, x, w);
|
||||
@@ -487,7 +487,7 @@ public:
|
||||
blocks["wo"] = std::shared_ptr<GGMLBlock>(new Linear(ff_dim, model_dim, false));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, n_token, model_dim]
|
||||
auto wi = std::dynamic_pointer_cast<Linear>(blocks["wi"]);
|
||||
auto wo = std::dynamic_pointer_cast<Linear>(blocks["wo"]);
|
||||
@@ -509,7 +509,7 @@ public:
|
||||
blocks["wo"] = std::shared_ptr<GGMLBlock>(new Linear(ff_dim, model_dim, false, false, false, scale));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, n_token, model_dim]
|
||||
auto wi_0 = std::dynamic_pointer_cast<Linear>(blocks["wi_0"]);
|
||||
auto wi_1 = std::dynamic_pointer_cast<Linear>(blocks["wi_1"]);
|
||||
@@ -530,7 +530,7 @@ public:
|
||||
blocks["layer_norm"] = std::shared_ptr<GGMLBlock>(new T5LayerNorm(model_dim));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, n_token, model_dim]
|
||||
auto DenseReluDense = std::dynamic_pointer_cast<T5DenseGatedActDense>(blocks["DenseReluDense"]);
|
||||
auto layer_norm = std::dynamic_pointer_cast<T5LayerNorm>(blocks["layer_norm"]);
|
||||
@@ -582,9 +582,9 @@ public:
|
||||
std::pair<struct ggml_tensor*, struct ggml_tensor*> forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* past_bias = NULL,
|
||||
struct ggml_tensor* mask = NULL,
|
||||
struct ggml_tensor* relative_position_bucket = NULL) {
|
||||
struct ggml_tensor* past_bias = nullptr,
|
||||
struct ggml_tensor* mask = nullptr,
|
||||
struct ggml_tensor* relative_position_bucket = nullptr) {
|
||||
auto q_proj = std::dynamic_pointer_cast<Linear>(blocks["q"]);
|
||||
auto k_proj = std::dynamic_pointer_cast<Linear>(blocks["k"]);
|
||||
auto v_proj = std::dynamic_pointer_cast<Linear>(blocks["v"]);
|
||||
@@ -597,11 +597,11 @@ public:
|
||||
auto k = k_proj->forward(ctx, x);
|
||||
auto v = v_proj->forward(ctx, x);
|
||||
|
||||
if (using_relative_attention_bias && relative_position_bucket != NULL) {
|
||||
if (using_relative_attention_bias && relative_position_bucket != nullptr) {
|
||||
past_bias = compute_bias(ctx, relative_position_bucket);
|
||||
}
|
||||
if (past_bias != NULL) {
|
||||
if (mask != NULL) {
|
||||
if (past_bias != nullptr) {
|
||||
if (mask != nullptr) {
|
||||
mask = ggml_repeat(ctx, mask, past_bias);
|
||||
mask = ggml_add(ctx, mask, past_bias);
|
||||
} else {
|
||||
@@ -611,7 +611,7 @@ public:
|
||||
|
||||
k = ggml_scale_inplace(ctx, k, sqrt(d_head));
|
||||
|
||||
x = ggml_nn_attention_ext(ctx, backend, q, k, v, num_heads, mask); // [N, n_token, d_head * n_head]
|
||||
x = ggml_ext_attention_ext(ctx, backend, q, k, v, num_heads, mask); // [N, n_token, d_head * n_head]
|
||||
|
||||
x = out_proj->forward(ctx, x); // [N, n_token, model_dim]
|
||||
return {x, past_bias};
|
||||
@@ -632,9 +632,9 @@ public:
|
||||
std::pair<struct ggml_tensor*, struct ggml_tensor*> forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* past_bias = NULL,
|
||||
struct ggml_tensor* mask = NULL,
|
||||
struct ggml_tensor* relative_position_bucket = NULL) {
|
||||
struct ggml_tensor* past_bias = nullptr,
|
||||
struct ggml_tensor* mask = nullptr,
|
||||
struct ggml_tensor* relative_position_bucket = nullptr) {
|
||||
// x: [N, n_token, model_dim]
|
||||
auto SelfAttention = std::dynamic_pointer_cast<T5Attention>(blocks["SelfAttention"]);
|
||||
auto layer_norm = std::dynamic_pointer_cast<T5LayerNorm>(blocks["layer_norm"]);
|
||||
@@ -659,9 +659,9 @@ public:
|
||||
std::pair<struct ggml_tensor*, struct ggml_tensor*> forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* past_bias = NULL,
|
||||
struct ggml_tensor* mask = NULL,
|
||||
struct ggml_tensor* relative_position_bucket = NULL) {
|
||||
struct ggml_tensor* past_bias = nullptr,
|
||||
struct ggml_tensor* mask = nullptr,
|
||||
struct ggml_tensor* relative_position_bucket = nullptr) {
|
||||
// x: [N, n_token, model_dim]
|
||||
auto layer_0 = std::dynamic_pointer_cast<T5LayerSelfAttention>(blocks["layer.0"]);
|
||||
auto layer_1 = std::dynamic_pointer_cast<T5LayerFF>(blocks["layer.1"]);
|
||||
@@ -695,9 +695,9 @@ public:
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* past_bias = NULL,
|
||||
struct ggml_tensor* attention_mask = NULL,
|
||||
struct ggml_tensor* relative_position_bucket = NULL) {
|
||||
struct ggml_tensor* past_bias = nullptr,
|
||||
struct ggml_tensor* attention_mask = nullptr,
|
||||
struct ggml_tensor* relative_position_bucket = nullptr) {
|
||||
// x: [N, n_token, model_dim]
|
||||
for (int i = 0; i < num_layers; i++) {
|
||||
auto block = std::dynamic_pointer_cast<T5Block>(blocks["block." + std::to_string(i)]);
|
||||
@@ -743,9 +743,9 @@ public:
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* past_bias = NULL,
|
||||
struct ggml_tensor* attention_mask = NULL,
|
||||
struct ggml_tensor* relative_position_bucket = NULL) {
|
||||
struct ggml_tensor* past_bias = nullptr,
|
||||
struct ggml_tensor* attention_mask = nullptr,
|
||||
struct ggml_tensor* relative_position_bucket = nullptr) {
|
||||
// input_ids: [N, n_token]
|
||||
|
||||
auto shared = std::dynamic_pointer_cast<Embedding>(blocks["shared"]);
|
||||
@@ -776,7 +776,7 @@ struct T5Runner : public GGMLRunner {
|
||||
model.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "t5";
|
||||
}
|
||||
|
||||
@@ -788,16 +788,16 @@ struct T5Runner : public GGMLRunner {
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* relative_position_bucket,
|
||||
struct ggml_tensor* attention_mask = NULL) {
|
||||
struct ggml_tensor* attention_mask = nullptr) {
|
||||
size_t N = input_ids->ne[1];
|
||||
size_t n_token = input_ids->ne[0];
|
||||
|
||||
auto hidden_states = model.forward(ctx, backend, input_ids, NULL, attention_mask, relative_position_bucket); // [N, n_token, model_dim]
|
||||
auto hidden_states = model.forward(ctx, backend, input_ids, nullptr, attention_mask, relative_position_bucket); // [N, n_token, model_dim]
|
||||
return hidden_states;
|
||||
}
|
||||
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* attention_mask = NULL) {
|
||||
struct ggml_tensor* attention_mask = nullptr) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph(compute_ctx);
|
||||
|
||||
input_ids = to_backend(input_ids);
|
||||
@@ -829,7 +829,7 @@ struct T5Runner : public GGMLRunner {
|
||||
struct ggml_tensor* input_ids,
|
||||
struct ggml_tensor* attention_mask,
|
||||
ggml_tensor** output,
|
||||
ggml_context* output_ctx = NULL) {
|
||||
ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(input_ids, attention_mask);
|
||||
};
|
||||
@@ -968,11 +968,11 @@ struct T5Embedder {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(10 * 1024 * 1024); // 10 MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
std::string text("a lovely cat");
|
||||
@@ -987,7 +987,7 @@ struct T5Embedder {
|
||||
printf("\n");
|
||||
auto input_ids = vector_to_ggml_tensor_i32(work_ctx, tokens);
|
||||
auto attention_mask = vector_to_ggml_tensor(work_ctx, masks);
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
model.compute(8, input_ids, attention_mask, &out, work_ctx);
|
||||
@@ -1022,7 +1022,7 @@ struct T5Embedder {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<T5Embedder> t5 = std::shared_ptr<T5Embedder>(new T5Embedder(backend, false, tensor_types, "", true));
|
||||
std::shared_ptr<T5Embedder> t5 = std::make_shared<T5Embedder>(backend, false, tensor_types, "", true);
|
||||
|
||||
t5->alloc_params_buffer();
|
||||
std::map<std::string, ggml_tensor*> tensors;
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [n, n_in, h, w]
|
||||
// return: [n, n_out, h, w]
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
blocks[std::to_string(index++)] = std::shared_ptr<GGMLBlock>(new Conv2d(channels, z_channels, {3, 3}, {1, 1}, {1, 1}));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [n, in_channels, h, w]
|
||||
// return: [n, z_channels, h/8, w/8]
|
||||
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
blocks[std::to_string(index++)] = std::shared_ptr<GGMLBlock>(new Conv2d(channels, out_channels, {3, 3}, {1, 1}, {1, 1}));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* z) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* z) override {
|
||||
// z: [n, z_channels, h, w]
|
||||
// return: [n, out_channels, h*8, w*8]
|
||||
|
||||
@@ -218,7 +218,7 @@ struct TinyAutoEncoder : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "taesd";
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ struct TinyAutoEncoder : public GGMLRunner {
|
||||
struct ggml_tensor* z,
|
||||
bool decode_graph,
|
||||
struct ggml_tensor** output,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(z, decode_graph);
|
||||
};
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
|
||||
auto num_frames = ggml_arange(ctx, 0, timesteps, 1);
|
||||
// since b is 1, no need to do repeat
|
||||
auto t_emb = ggml_nn_timestep_embedding(ctx, num_frames, in_channels, max_time_embed_period); // [N, in_channels]
|
||||
auto t_emb = ggml_ext_timestep_embedding(ctx, num_frames, in_channels, max_time_embed_period); // [N, in_channels]
|
||||
|
||||
auto emb = time_pos_embed_0->forward(ctx, t_emb);
|
||||
emb = ggml_silu_inplace(ctx, emb);
|
||||
@@ -204,6 +204,9 @@ public:
|
||||
adm_in_channels = 768;
|
||||
num_head_channels = 64;
|
||||
num_heads = -1;
|
||||
} else if (version == VERSION_SD1_TINY_UNET) {
|
||||
num_res_blocks = 1;
|
||||
channel_mult = {1, 2, 4};
|
||||
}
|
||||
if (sd_version_is_inpaint(version)) {
|
||||
in_channels = 9;
|
||||
@@ -270,13 +273,22 @@ public:
|
||||
n_head = ch / d_head;
|
||||
}
|
||||
std::string name = "input_blocks." + std::to_string(input_block_idx) + ".1";
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch,
|
||||
n_head,
|
||||
d_head,
|
||||
transformer_depth[i],
|
||||
context_dim));
|
||||
int td = transformer_depth[i];
|
||||
if (version == VERSION_SDXL_SSD1B) {
|
||||
if (i == 2) {
|
||||
td = 4;
|
||||
}
|
||||
}
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch,
|
||||
n_head,
|
||||
d_head,
|
||||
td,
|
||||
context_dim));
|
||||
}
|
||||
input_block_chans.push_back(ch);
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
input_block_idx++;
|
||||
}
|
||||
}
|
||||
if (i != len_mults - 1) {
|
||||
input_block_idx += 1;
|
||||
@@ -295,14 +307,17 @@ public:
|
||||
d_head = num_head_channels;
|
||||
n_head = ch / d_head;
|
||||
}
|
||||
blocks["middle_block.0"] = std::shared_ptr<GGMLBlock>(get_resblock(ch, time_embed_dim, ch));
|
||||
blocks["middle_block.1"] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch,
|
||||
n_head,
|
||||
d_head,
|
||||
transformer_depth[transformer_depth.size() - 1],
|
||||
context_dim));
|
||||
blocks["middle_block.2"] = std::shared_ptr<GGMLBlock>(get_resblock(ch, time_embed_dim, ch));
|
||||
|
||||
if (version != VERSION_SD1_TINY_UNET) {
|
||||
blocks["middle_block.0"] = std::shared_ptr<GGMLBlock>(get_resblock(ch, time_embed_dim, ch));
|
||||
if (version != VERSION_SDXL_SSD1B) {
|
||||
blocks["middle_block.1"] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch,
|
||||
n_head,
|
||||
d_head,
|
||||
transformer_depth[transformer_depth.size() - 1],
|
||||
context_dim));
|
||||
blocks["middle_block.2"] = std::shared_ptr<GGMLBlock>(get_resblock(ch, time_embed_dim, ch));
|
||||
}
|
||||
}
|
||||
// output_blocks
|
||||
int output_block_idx = 0;
|
||||
for (int i = (int)len_mults - 1; i >= 0; i--) {
|
||||
@@ -324,12 +339,27 @@ public:
|
||||
n_head = ch / d_head;
|
||||
}
|
||||
std::string name = "output_blocks." + std::to_string(output_block_idx) + ".1";
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch, n_head, d_head, transformer_depth[i], context_dim));
|
||||
int td = transformer_depth[i];
|
||||
if (version == VERSION_SDXL_SSD1B) {
|
||||
if (i == 2 && (j == 0 || j == 1)) {
|
||||
td = 4;
|
||||
}
|
||||
if (i == 1 && (j == 1 || j == 2)) {
|
||||
td = 1;
|
||||
}
|
||||
}
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(get_attention_layer(ch, n_head, d_head, td, context_dim));
|
||||
|
||||
up_sample_idx++;
|
||||
}
|
||||
|
||||
if (i > 0 && j == num_res_blocks) {
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
output_block_idx++;
|
||||
if (output_block_idx == 2) {
|
||||
up_sample_idx = 1;
|
||||
}
|
||||
}
|
||||
std::string name = "output_blocks." + std::to_string(output_block_idx) + "." + std::to_string(up_sample_idx);
|
||||
blocks[name] = std::shared_ptr<GGMLBlock>(new UpSampleBlock(ch, ch));
|
||||
|
||||
@@ -384,8 +414,8 @@ public:
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* c_concat = NULL,
|
||||
struct ggml_tensor* y = NULL,
|
||||
struct ggml_tensor* c_concat = nullptr,
|
||||
struct ggml_tensor* y = nullptr,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f) {
|
||||
@@ -395,20 +425,20 @@ public:
|
||||
// c_concat: [N, in_channels, h, w] or [1, in_channels, h, w]
|
||||
// y: [N, adm_in_channels] or [1, adm_in_channels]
|
||||
// return: [N, out_channels, h, w]
|
||||
if (context != NULL) {
|
||||
if (context != nullptr) {
|
||||
if (context->ne[2] != x->ne[3]) {
|
||||
context = ggml_repeat(ctx, context, ggml_new_tensor_3d(ctx, GGML_TYPE_F32, context->ne[0], context->ne[1], x->ne[3]));
|
||||
}
|
||||
}
|
||||
|
||||
if (c_concat != NULL) {
|
||||
if (c_concat != nullptr) {
|
||||
if (c_concat->ne[3] != x->ne[3]) {
|
||||
c_concat = ggml_repeat(ctx, c_concat, x);
|
||||
}
|
||||
x = ggml_concat(ctx, x, c_concat, 2);
|
||||
}
|
||||
|
||||
if (y != NULL) {
|
||||
if (y != nullptr) {
|
||||
if (y->ne[1] != x->ne[3]) {
|
||||
y = ggml_repeat(ctx, y, ggml_new_tensor_2d(ctx, GGML_TYPE_F32, y->ne[0], x->ne[3]));
|
||||
}
|
||||
@@ -421,14 +451,14 @@ public:
|
||||
auto out_0 = std::dynamic_pointer_cast<GroupNorm32>(blocks["out.0"]);
|
||||
auto out_2 = std::dynamic_pointer_cast<Conv2d>(blocks["out.2"]);
|
||||
|
||||
auto t_emb = ggml_nn_timestep_embedding(ctx, timesteps, model_channels); // [N, model_channels]
|
||||
auto t_emb = ggml_ext_timestep_embedding(ctx, timesteps, model_channels); // [N, model_channels]
|
||||
|
||||
auto emb = time_embed_0->forward(ctx, t_emb);
|
||||
emb = ggml_silu_inplace(ctx, emb);
|
||||
emb = time_embed_2->forward(ctx, emb); // [N, time_embed_dim]
|
||||
|
||||
// SDXL/SVD
|
||||
if (y != NULL) {
|
||||
if (y != nullptr) {
|
||||
auto label_embed_0 = std::dynamic_pointer_cast<Linear>(blocks["label_emb.0.0"]);
|
||||
auto label_embed_2 = std::dynamic_pointer_cast<Linear>(blocks["label_emb.0.2"]);
|
||||
|
||||
@@ -463,6 +493,9 @@ public:
|
||||
}
|
||||
hs.push_back(h);
|
||||
}
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
input_block_idx++;
|
||||
}
|
||||
if (i != len_mults - 1) {
|
||||
ds *= 2;
|
||||
input_block_idx += 1;
|
||||
@@ -477,10 +510,13 @@ public:
|
||||
// [N, 4*model_channels, h/8, w/8]
|
||||
|
||||
// middle_block
|
||||
h = resblock_forward("middle_block.0", ctx, h, emb, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
h = attention_layer_forward("middle_block.1", ctx, backend, h, context, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
h = resblock_forward("middle_block.2", ctx, h, emb, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
|
||||
if (version != VERSION_SD1_TINY_UNET) {
|
||||
h = resblock_forward("middle_block.0", ctx, h, emb, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
if (version != VERSION_SDXL_SSD1B) {
|
||||
h = attention_layer_forward("middle_block.1", ctx, backend, h, context, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
h = resblock_forward("middle_block.2", ctx, h, emb, num_video_frames); // [N, 4*model_channels, h/8, w/8]
|
||||
}
|
||||
}
|
||||
if (controls.size() > 0) {
|
||||
auto cs = ggml_scale_inplace(ctx, controls[controls.size() - 1], control_strength);
|
||||
h = ggml_add(ctx, h, cs); // middle control
|
||||
@@ -516,6 +552,12 @@ public:
|
||||
}
|
||||
|
||||
if (i > 0 && j == num_res_blocks) {
|
||||
if (version == VERSION_SD1_TINY_UNET) {
|
||||
output_block_idx++;
|
||||
if (output_block_idx == 2) {
|
||||
up_sample_idx = 1;
|
||||
}
|
||||
}
|
||||
std::string name = "output_blocks." + std::to_string(output_block_idx) + "." + std::to_string(up_sample_idx);
|
||||
auto block = std::dynamic_pointer_cast<UpSampleBlock>(blocks[name]);
|
||||
|
||||
@@ -562,7 +604,7 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "unet";
|
||||
}
|
||||
|
||||
@@ -573,8 +615,8 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* c_concat = NULL,
|
||||
struct ggml_tensor* y = NULL,
|
||||
struct ggml_tensor* c_concat = nullptr,
|
||||
struct ggml_tensor* y = nullptr,
|
||||
int num_video_frames = -1,
|
||||
std::vector<struct ggml_tensor*> controls = {},
|
||||
float control_strength = 0.f) {
|
||||
@@ -619,8 +661,8 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
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) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) {
|
||||
// x: [N, in_channels, h, w]
|
||||
// timesteps: [N, ]
|
||||
// context: [N, max_position, hidden_size]([N, 77, 768]) or [1, max_position, hidden_size]
|
||||
@@ -636,11 +678,11 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(10 * 1024 * 1024); // 10 MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
// CPU, num_video_frames = 1, x{num_video_frames, 8, 8, 8}: Pass
|
||||
@@ -663,10 +705,10 @@ struct UNetModelRunner : public GGMLRunner {
|
||||
ggml_set_f32(y, 0.5f);
|
||||
// print_ggml_tensor(y);
|
||||
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, timesteps, context, NULL, y, num_video_frames, {}, 0.f, &out, work_ctx);
|
||||
compute(8, x, timesteps, context, nullptr, y, num_video_frames, {}, 0.f, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
|
||||
+16
-16
@@ -4,7 +4,7 @@
|
||||
#include "stable-diffusion.h"
|
||||
|
||||
struct UpscalerGGML {
|
||||
ggml_backend_t backend = NULL; // general backend
|
||||
ggml_backend_t backend = nullptr; // general backend
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
std::shared_ptr<ESRGAN> esrgan_upscaler;
|
||||
std::string esrgan_path;
|
||||
@@ -63,7 +63,7 @@ struct UpscalerGGML {
|
||||
|
||||
sd_image_t upscale(sd_image_t input_image, uint32_t upscale_factor) {
|
||||
// upscale_factor, unused for RealESRGAN_x4plus_anime_6B.pth
|
||||
sd_image_t upscaled_image = {0, 0, 0, NULL};
|
||||
sd_image_t upscaled_image = {0, 0, 0, nullptr};
|
||||
int output_width = (int)input_image.width * esrgan_upscaler->scale;
|
||||
int output_height = (int)input_image.height * esrgan_upscaler->scale;
|
||||
LOG_INFO("upscaling from (%i x %i) to (%i x %i)",
|
||||
@@ -71,7 +71,7 @@ struct UpscalerGGML {
|
||||
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(1024 * 1024) * 1024; // 1G
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
// draft context
|
||||
@@ -82,7 +82,7 @@ struct UpscalerGGML {
|
||||
}
|
||||
// LOG_DEBUG("upscale work buffer size: %.2f MB", params.mem_size / 1024.f / 1024.f);
|
||||
ggml_tensor* input_image_tensor = ggml_new_tensor_4d(upscale_ctx, GGML_TYPE_F32, input_image.width, input_image.height, 3, 1);
|
||||
sd_image_to_tensor(input_image, input_image_tensor);
|
||||
sd_image_to_ggml_tensor(input_image, input_image_tensor);
|
||||
|
||||
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) {
|
||||
@@ -91,8 +91,8 @@ struct UpscalerGGML {
|
||||
int64_t t0 = ggml_time_ms();
|
||||
sd_tiling(input_image_tensor, upscaled, esrgan_upscaler->scale, esrgan_upscaler->tile_size, 0.25f, on_tiling);
|
||||
esrgan_upscaler->free_compute_buffer();
|
||||
ggml_tensor_clamp(upscaled, 0.f, 1.f);
|
||||
uint8_t* upscaled_data = sd_tensor_to_image(upscaled);
|
||||
ggml_ext_tensor_clamp_inplace(upscaled, 0.f, 1.f);
|
||||
uint8_t* upscaled_data = ggml_tensor_to_sd_image(upscaled);
|
||||
ggml_free(upscale_ctx);
|
||||
int64_t t3 = ggml_time_ms();
|
||||
LOG_INFO("input_image_tensor upscaled, taking %.2fs", (t3 - t0) / 1000.0f);
|
||||
@@ -107,7 +107,7 @@ struct UpscalerGGML {
|
||||
};
|
||||
|
||||
struct upscaler_ctx_t {
|
||||
UpscalerGGML* upscaler = NULL;
|
||||
UpscalerGGML* upscaler = nullptr;
|
||||
};
|
||||
|
||||
upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path_c_str,
|
||||
@@ -115,21 +115,21 @@ upscaler_ctx_t* new_upscaler_ctx(const char* esrgan_path_c_str,
|
||||
bool direct,
|
||||
int n_threads) {
|
||||
upscaler_ctx_t* upscaler_ctx = (upscaler_ctx_t*)malloc(sizeof(upscaler_ctx_t));
|
||||
if (upscaler_ctx == NULL) {
|
||||
return NULL;
|
||||
if (upscaler_ctx == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string esrgan_path(esrgan_path_c_str);
|
||||
|
||||
upscaler_ctx->upscaler = new UpscalerGGML(n_threads, direct);
|
||||
if (upscaler_ctx->upscaler == NULL) {
|
||||
return NULL;
|
||||
if (upscaler_ctx->upscaler == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!upscaler_ctx->upscaler->load_from_file(esrgan_path, offload_params_to_cpu, n_threads)) {
|
||||
delete upscaler_ctx->upscaler;
|
||||
upscaler_ctx->upscaler = NULL;
|
||||
upscaler_ctx->upscaler = nullptr;
|
||||
free(upscaler_ctx);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return upscaler_ctx;
|
||||
}
|
||||
@@ -139,16 +139,16 @@ sd_image_t upscale(upscaler_ctx_t* upscaler_ctx, sd_image_t input_image, uint32_
|
||||
}
|
||||
|
||||
int get_upscale_factor(upscaler_ctx_t* upscaler_ctx) {
|
||||
if (upscaler_ctx == NULL || upscaler_ctx->upscaler == NULL || upscaler_ctx->upscaler->esrgan_upscaler == NULL) {
|
||||
if (upscaler_ctx == nullptr || upscaler_ctx->upscaler == nullptr || upscaler_ctx->upscaler->esrgan_upscaler == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
return upscaler_ctx->upscaler->esrgan_upscaler->scale;
|
||||
}
|
||||
|
||||
void free_upscaler_ctx(upscaler_ctx_t* upscaler_ctx) {
|
||||
if (upscaler_ctx->upscaler != NULL) {
|
||||
if (upscaler_ctx->upscaler != nullptr) {
|
||||
delete upscaler_ctx->upscaler;
|
||||
upscaler_ctx->upscaler = NULL;
|
||||
upscaler_ctx->upscaler = nullptr;
|
||||
}
|
||||
free(upscaler_ctx);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "util.h"
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <codecvt>
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
@@ -26,9 +26,6 @@
|
||||
#include "ggml.h"
|
||||
#include "stable-diffusion.h"
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
bool ends_with(const std::string& str, const std::string& ending) {
|
||||
if (str.length() >= ending.length()) {
|
||||
return (str.compare(str.length() - ending.length(), ending.length(), ending) == 0);
|
||||
@@ -64,7 +61,7 @@ std::string format(const char* fmt, ...) {
|
||||
va_list ap2;
|
||||
va_start(ap, fmt);
|
||||
va_copy(ap2, ap);
|
||||
int size = vsnprintf(NULL, 0, fmt, ap);
|
||||
int size = vsnprintf(nullptr, 0, fmt, ap);
|
||||
std::vector<char> buf(size + 1);
|
||||
int size2 = vsnprintf(buf.data(), size + 1, fmt, ap2);
|
||||
va_end(ap2);
|
||||
@@ -84,6 +81,7 @@ int round_up_to(int value, int base) {
|
||||
}
|
||||
|
||||
#ifdef _WIN32 // code for windows
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
|
||||
bool file_exists(const std::string& filename) {
|
||||
@@ -169,11 +167,11 @@ int32_t get_num_physical_cores() {
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
int32_t num_physical_cores;
|
||||
size_t len = sizeof(num_physical_cores);
|
||||
int result = sysctlbyname("hw.perflevel0.physicalcpu", &num_physical_cores, &len, NULL, 0);
|
||||
int result = sysctlbyname("hw.perflevel0.physicalcpu", &num_physical_cores, &len, nullptr, 0);
|
||||
if (result == 0) {
|
||||
return num_physical_cores;
|
||||
}
|
||||
result = sysctlbyname("hw.physicalcpu", &num_physical_cores, &len, NULL, 0);
|
||||
result = sysctlbyname("hw.physicalcpu", &num_physical_cores, &len, nullptr, 0);
|
||||
if (result == 0) {
|
||||
return num_physical_cores;
|
||||
}
|
||||
@@ -184,8 +182,8 @@ int32_t get_num_physical_cores() {
|
||||
return n_threads > 0 ? (n_threads <= 4 ? n_threads : n_threads / 2) : 4;
|
||||
}
|
||||
|
||||
static sd_progress_cb_t sd_progress_cb = NULL;
|
||||
void* sd_progress_cb_data = NULL;
|
||||
static sd_progress_cb_t sd_progress_cb = nullptr;
|
||||
void* sd_progress_cb_data = nullptr;
|
||||
|
||||
std::u32string utf8_to_utf32(const std::string& utf8_str) {
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||||
@@ -295,10 +293,10 @@ std::string trim(const std::string& s) {
|
||||
return rtrim(ltrim(s));
|
||||
}
|
||||
|
||||
static sd_log_cb_t sd_log_cb = NULL;
|
||||
void* sd_log_cb_data = NULL;
|
||||
static sd_log_cb_t sd_log_cb = nullptr;
|
||||
void* sd_log_cb_data = nullptr;
|
||||
|
||||
#define LOG_BUFFER_SIZE 1024
|
||||
#define LOG_BUFFER_SIZE 4096
|
||||
|
||||
void log_printf(sd_log_level_t level, const char* file, int line, const char* format, ...) {
|
||||
va_list args;
|
||||
@@ -387,10 +385,10 @@ sd_image_f32_t resize_sd_image_f32_t(sd_image_f32_t image, int target_width, int
|
||||
float original_x = (float)x * image.width / target_width;
|
||||
float original_y = (float)y * image.height / target_height;
|
||||
|
||||
int x1 = (int)original_x;
|
||||
int y1 = (int)original_y;
|
||||
int x2 = x1 + 1;
|
||||
int y2 = y1 + 1;
|
||||
uint32_t x1 = (uint32_t)original_x;
|
||||
uint32_t y1 = (uint32_t)original_y;
|
||||
uint32_t x2 = std::min(x1 + 1, image.width - 1);
|
||||
uint32_t y2 = std::min(y1 + 1, image.height - 1);
|
||||
|
||||
for (int k = 0; k < image.channel; k++) {
|
||||
float v1 = *(image.data + y1 * image.width * image.channel + x1 * image.channel + k);
|
||||
@@ -427,23 +425,26 @@ float means[3] = {0.48145466, 0.4578275, 0.40821073};
|
||||
float stds[3] = {0.26862954, 0.26130258, 0.27577711};
|
||||
|
||||
// Function to clip and preprocess sd_image_f32_t
|
||||
sd_image_f32_t clip_preprocess(sd_image_f32_t image, int size) {
|
||||
float scale = (float)size / fmin(image.width, image.height);
|
||||
sd_image_f32_t clip_preprocess(sd_image_f32_t image, int target_width, int target_height) {
|
||||
float width_scale = (float)target_width / image.width;
|
||||
float height_scale = (float)target_height / image.height;
|
||||
|
||||
float scale = std::fmax(width_scale, height_scale);
|
||||
|
||||
// Interpolation
|
||||
int new_width = (int)(scale * image.width);
|
||||
int new_height = (int)(scale * image.height);
|
||||
float* resized_data = (float*)malloc(new_width * new_height * image.channel * sizeof(float));
|
||||
int resized_width = (int)(scale * image.width);
|
||||
int resized_height = (int)(scale * image.height);
|
||||
float* resized_data = (float*)malloc(resized_width * resized_height * image.channel * sizeof(float));
|
||||
|
||||
for (int y = 0; y < new_height; y++) {
|
||||
for (int x = 0; x < new_width; x++) {
|
||||
float original_x = (float)x * image.width / new_width;
|
||||
float original_y = (float)y * image.height / new_height;
|
||||
for (int y = 0; y < resized_height; y++) {
|
||||
for (int x = 0; x < resized_width; x++) {
|
||||
float original_x = (float)x * image.width / resized_width;
|
||||
float original_y = (float)y * image.height / resized_height;
|
||||
|
||||
int x1 = (int)original_x;
|
||||
int y1 = (int)original_y;
|
||||
int x2 = x1 + 1;
|
||||
int y2 = y1 + 1;
|
||||
uint32_t x1 = (uint32_t)original_x;
|
||||
uint32_t y1 = (uint32_t)original_y;
|
||||
uint32_t x2 = std::min(x1 + 1, image.width - 1);
|
||||
uint32_t y2 = std::min(y1 + 1, image.height - 1);
|
||||
|
||||
for (int k = 0; k < image.channel; k++) {
|
||||
float v1 = *(image.data + y1 * image.width * image.channel + x1 * image.channel + k);
|
||||
@@ -456,26 +457,28 @@ sd_image_f32_t clip_preprocess(sd_image_f32_t image, int size) {
|
||||
|
||||
float value = interpolate(v1, v2, v3, v4, x_ratio, y_ratio);
|
||||
|
||||
*(resized_data + y * new_width * image.channel + x * image.channel + k) = value;
|
||||
*(resized_data + y * resized_width * image.channel + x * image.channel + k) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clip and preprocess
|
||||
int h = (new_height - size) / 2;
|
||||
int w = (new_width - size) / 2;
|
||||
int h_offset = std::max((int)(resized_height - target_height) / 2, 0);
|
||||
int w_offset = std::max((int)(resized_width - target_width) / 2, 0);
|
||||
|
||||
sd_image_f32_t result;
|
||||
result.width = size;
|
||||
result.height = size;
|
||||
result.width = target_width;
|
||||
result.height = target_height;
|
||||
result.channel = image.channel;
|
||||
result.data = (float*)malloc(size * size * image.channel * sizeof(float));
|
||||
result.data = (float*)malloc(target_height * target_width * image.channel * sizeof(float));
|
||||
|
||||
for (int k = 0; k < image.channel; k++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
*(result.data + i * size * image.channel + j * image.channel + k) =
|
||||
fmin(fmax(*(resized_data + (i + h) * new_width * image.channel + (j + w) * image.channel + k), 0.0f), 255.0f) / 255.0f;
|
||||
for (int i = 0; i < result.height; i++) {
|
||||
for (int j = 0; j < result.width; j++) {
|
||||
int src_y = std::min(i + h_offset, resized_height - 1);
|
||||
int src_x = std::min(j + w_offset, resized_width - 1);
|
||||
*(result.data + i * result.width * image.channel + j * image.channel + k) =
|
||||
fmin(fmax(*(resized_data + src_y * resized_width * image.channel + src_x * image.channel + k), 0.0f), 255.0f) / 255.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -485,10 +488,10 @@ sd_image_f32_t clip_preprocess(sd_image_f32_t image, int size) {
|
||||
|
||||
// Normalize
|
||||
for (int k = 0; k < image.channel; k++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
for (int i = 0; i < result.height; i++) {
|
||||
for (int j = 0; j < result.width; j++) {
|
||||
// *(result.data + i * size * image.channel + j * image.channel + k) = 0.5f;
|
||||
int offset = i * size * image.channel + j * image.channel + k;
|
||||
int offset = i * result.width * image.channel + j * image.channel + k;
|
||||
float value = *(result.data + offset);
|
||||
value = (value - means[k]) / stds[k];
|
||||
// value = 0.5f;
|
||||
|
||||
@@ -42,7 +42,7 @@ sd_image_f32_t sd_image_t_to_sd_image_f32_t(sd_image_t image);
|
||||
|
||||
sd_image_f32_t resize_sd_image_f32_t(sd_image_f32_t image, int target_width, int target_height);
|
||||
|
||||
sd_image_f32_t clip_preprocess(sd_image_f32_t image, int size);
|
||||
sd_image_f32_t clip_preprocess(sd_image_f32_t image, int target_width, int target_height);
|
||||
|
||||
std::string path_join(const std::string& p1, const std::string& p2);
|
||||
std::vector<std::string> split_string(const std::string& str, char delimiter);
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, in_channels, h, w]
|
||||
// t_emb is always None
|
||||
auto norm1 = std::dynamic_pointer_cast<GroupNorm32>(blocks["norm1"]);
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
blocks["proj_out"] = std::shared_ptr<GGMLBlock>(new Conv2d(in_channels, in_channels, {1, 1}));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, in_channels, h, w]
|
||||
auto norm = std::dynamic_pointer_cast<GroupNorm32>(blocks["norm"]);
|
||||
auto q_proj = std::dynamic_pointer_cast<Conv2d>(blocks["q"]);
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
auto v = v_proj->forward(ctx, h_); // [N, in_channels, h, w]
|
||||
v = ggml_reshape_3d(ctx, v, h * w, c, n); // [N, in_channels, h * w]
|
||||
|
||||
h_ = ggml_nn_attention(ctx, q, k, v, false); // [N, h * w, in_channels]
|
||||
h_ = ggml_ext_attention(ctx, q, k, v, false); // [N, h * w, in_channels]
|
||||
|
||||
h_ = ggml_cont(ctx, ggml_permute(ctx, h_, 1, 0, 2, 3)); // [N, in_channels, h * w]
|
||||
h_ = ggml_reshape_4d(ctx, h_, w, h, c, n); // [N, in_channels, h, w]
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx,
|
||||
struct ggml_tensor* x) {
|
||||
struct ggml_tensor* x) override {
|
||||
// timesteps always None
|
||||
// skip_video always False
|
||||
// x: [N, IC, IH, IW]
|
||||
@@ -163,13 +163,13 @@ public:
|
||||
|
||||
class VideoResnetBlock : public ResnetBlock {
|
||||
protected:
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "mix_factor", tensor_types, GGML_TYPE_F32);
|
||||
params["mix_factor"] = ggml_new_tensor_1d(ctx, wtype, 1);
|
||||
}
|
||||
|
||||
float get_alpha() {
|
||||
float alpha = ggml_backend_tensor_get_f32(params["mix_factor"]);
|
||||
float alpha = ggml_ext_backend_tensor_get_f32(params["mix_factor"]);
|
||||
return sigmoid(alpha);
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
blocks["time_stack"] = std::shared_ptr<GGMLBlock>(new ResBlock(out_channels, 0, out_channels, {video_kernel_size, 1}, 3, false, true));
|
||||
}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N, in_channels, h, w] aka [b*t, in_channels, h, w]
|
||||
// return: [N, out_channels, h, w] aka [b*t, out_channels, h, w]
|
||||
// t_emb is always None
|
||||
@@ -530,6 +530,31 @@ struct VAE : public GGMLRunner {
|
||||
struct ggml_context* output_ctx) = 0;
|
||||
virtual void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) = 0;
|
||||
virtual void enable_conv2d_direct(){};
|
||||
virtual void set_conv2d_scale(float scale) { SD_UNUSED(scale); };
|
||||
};
|
||||
|
||||
struct FakeVAE : public VAE {
|
||||
FakeVAE(ggml_backend_t backend, bool offload_params_to_cpu)
|
||||
: VAE(backend, offload_params_to_cpu) {}
|
||||
void compute(const int n_threads,
|
||||
struct ggml_tensor* z,
|
||||
bool decode_graph,
|
||||
struct ggml_tensor** output,
|
||||
struct ggml_context* output_ctx) override {
|
||||
if (*output == nullptr && output_ctx != nullptr) {
|
||||
*output = ggml_dup_tensor(output_ctx, z);
|
||||
}
|
||||
ggml_ext_tensor_iter(z, [&](ggml_tensor* z, int64_t i0, int64_t i1, int64_t i2, int64_t i3) {
|
||||
float value = ggml_ext_tensor_get_f32(z, i0, i1, i2, i3);
|
||||
ggml_ext_tensor_set_f32(*output, value, i0, i1, i2, i3);
|
||||
});
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) override {}
|
||||
|
||||
std::string get_desc() override {
|
||||
return "fake_vae";
|
||||
}
|
||||
};
|
||||
|
||||
struct AutoEncoderKL : public VAE {
|
||||
@@ -547,7 +572,7 @@ struct AutoEncoderKL : public VAE {
|
||||
ae.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
void enable_conv2d_direct() {
|
||||
void enable_conv2d_direct() override {
|
||||
std::vector<GGMLBlock*> blocks;
|
||||
ae.get_all_blocks(blocks);
|
||||
for (auto block : blocks) {
|
||||
@@ -558,11 +583,22 @@ struct AutoEncoderKL : public VAE {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
void set_conv2d_scale(float scale) override {
|
||||
std::vector<GGMLBlock*> blocks;
|
||||
ae.get_all_blocks(blocks);
|
||||
for (auto block : blocks) {
|
||||
if (block->get_desc() == "Conv2d") {
|
||||
auto conv_block = (Conv2d*)block;
|
||||
conv_block->set_scale(scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_desc() override {
|
||||
return "vae";
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) override {
|
||||
ae.get_param_tensors(tensors, prefix);
|
||||
}
|
||||
|
||||
@@ -582,7 +618,7 @@ struct AutoEncoderKL : public VAE {
|
||||
struct ggml_tensor* z,
|
||||
bool decode_graph,
|
||||
struct ggml_tensor** output,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
GGML_ASSERT(!decode_only || decode_graph);
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(z, decode_graph);
|
||||
@@ -595,11 +631,11 @@ struct AutoEncoderKL : public VAE {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(10 * 1024 * 1024); // 10 MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
// CPU, x{1, 3, 64, 64}: Pass
|
||||
@@ -609,7 +645,7 @@ struct AutoEncoderKL : public VAE {
|
||||
auto x = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 64, 64, 3, 2);
|
||||
ggml_set_f32(x, 0.5f);
|
||||
print_ggml_tensor(x);
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, false, &out, work_ctx);
|
||||
@@ -627,7 +663,7 @@ struct AutoEncoderKL : public VAE {
|
||||
auto z = ggml_new_tensor_4d(work_ctx, GGML_TYPE_F32, 8, 8, 4, 1);
|
||||
ggml_set_f32(z, 0.5f);
|
||||
print_ggml_tensor(z);
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, z, true, &out, work_ctx);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define __WAN_HPP__
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "flux.hpp"
|
||||
@@ -24,7 +26,7 @@ namespace WAN {
|
||||
std::tuple<int, int, int> dilation;
|
||||
bool bias;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
params["weight"] = ggml_new_tensor_4d(ctx,
|
||||
GGML_TYPE_F16,
|
||||
std::get<2>(kernel_size),
|
||||
@@ -46,17 +48,17 @@ namespace WAN {
|
||||
bool bias = true)
|
||||
: in_channels(in_channels),
|
||||
out_channels(out_channels),
|
||||
kernel_size(kernel_size),
|
||||
stride(stride),
|
||||
padding(padding),
|
||||
dilation(dilation),
|
||||
kernel_size(std::move(kernel_size)),
|
||||
stride(std::move(stride)),
|
||||
padding(std::move(padding)),
|
||||
dilation(std::move(dilation)),
|
||||
bias(bias) {}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x, struct ggml_tensor* cache_x = NULL) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x, struct ggml_tensor* cache_x = nullptr) {
|
||||
// x: [N*IC, ID, IH, IW]
|
||||
// result: x: [N*OC, ID, IH, IW]
|
||||
struct ggml_tensor* w = params["weight"];
|
||||
struct ggml_tensor* b = NULL;
|
||||
struct ggml_tensor* b = nullptr;
|
||||
if (bias) {
|
||||
b = params["bias"];
|
||||
}
|
||||
@@ -68,16 +70,16 @@ namespace WAN {
|
||||
int lp2 = 2 * std::get<0>(padding);
|
||||
int rp2 = 0;
|
||||
|
||||
if (cache_x != NULL && lp2 > 0) {
|
||||
if (cache_x != nullptr && lp2 > 0) {
|
||||
x = ggml_concat(ctx, cache_x, x, 2);
|
||||
lp2 -= (int)cache_x->ne[2];
|
||||
}
|
||||
|
||||
x = ggml_pad_ext(ctx, x, lp0, rp0, lp1, rp1, lp2, rp2, 0, 0);
|
||||
return ggml_nn_conv_3d(ctx, x, w, b, in_channels,
|
||||
std::get<2>(stride), std::get<1>(stride), std::get<0>(stride),
|
||||
0, 0, 0,
|
||||
std::get<2>(dilation), std::get<1>(dilation), std::get<0>(dilation));
|
||||
return ggml_ext_conv_3d(ctx, x, w, b, in_channels,
|
||||
std::get<2>(stride), std::get<1>(stride), std::get<0>(stride),
|
||||
0, 0, 0,
|
||||
std::get<2>(dilation), std::get<1>(dilation), std::get<0>(dilation));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,7 +87,7 @@ namespace WAN {
|
||||
protected:
|
||||
int64_t dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
ggml_type wtype = GGML_TYPE_F32;
|
||||
params["gamma"] = ggml_new_tensor_1d(ctx, wtype, dim);
|
||||
}
|
||||
@@ -94,15 +96,15 @@ namespace WAN {
|
||||
RMS_norm(int64_t dim)
|
||||
: dim(dim) {}
|
||||
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) {
|
||||
struct ggml_tensor* forward(struct ggml_context* ctx, struct ggml_tensor* x) override {
|
||||
// x: [N*IC, ID, IH, IW], IC == dim
|
||||
// assert N == 1
|
||||
|
||||
struct ggml_tensor* w = params["gamma"];
|
||||
auto h = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 3, 0, 1, 2)); // [ID, IH, IW, N*IC]
|
||||
auto h = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 3, 0, 1, 2)); // [ID, IH, IW, N*IC]
|
||||
h = ggml_rms_norm(ctx, h, 1e-12);
|
||||
h = ggml_mul(ctx, h, w);
|
||||
h = ggml_nn_cont(ctx, ggml_torch_permute(ctx, h, 1, 2, 3, 0));
|
||||
h = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, h, 1, 2, 3, 0));
|
||||
|
||||
return h;
|
||||
}
|
||||
@@ -159,15 +161,15 @@ namespace WAN {
|
||||
int idx = feat_idx;
|
||||
feat_idx += 1;
|
||||
if (chunk_idx == 0) {
|
||||
// feat_cache[idx] == NULL, pass
|
||||
// feat_cache[idx] == nullptr, pass
|
||||
} else {
|
||||
auto time_conv = std::dynamic_pointer_cast<CausalConv3d>(blocks["time_conv"]);
|
||||
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) { // chunk_idx >= 2
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) { // chunk_idx >= 2
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -181,9 +183,9 @@ namespace WAN {
|
||||
x = time_conv->forward(ctx, x, feat_cache[idx]);
|
||||
}
|
||||
feat_cache[idx] = cache_x;
|
||||
x = ggml_reshape_4d(ctx, x, w * h, t, c, 2); // (2, c, t, h*w)
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 3, 1, 2)); // (c, t, 2, h*w)
|
||||
x = ggml_reshape_4d(ctx, x, w, h, 2 * t, c); // (c, t*2, h, w)
|
||||
x = ggml_reshape_4d(ctx, x, w * h, t, c, 2); // (2, c, t, h*w)
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 3, 1, 2)); // (c, t, 2, h*w)
|
||||
x = ggml_reshape_4d(ctx, x, w, h, 2 * t, c); // (c, t*2, h, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,7 +194,7 @@ namespace WAN {
|
||||
if (mode != "none") {
|
||||
auto resample_1 = std::dynamic_pointer_cast<Conv2d>(blocks["resample.1"]);
|
||||
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 1, 3, 2)); // (t, c, h, w)
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 1, 3, 2)); // (t, c, h, w)
|
||||
if (mode == "upsample2d") {
|
||||
x = ggml_upscale(ctx, x, 2, GGML_SCALE_MODE_NEAREST);
|
||||
} else if (mode == "upsample3d") {
|
||||
@@ -203,21 +205,21 @@ namespace WAN {
|
||||
x = ggml_pad(ctx, x, 1, 1, 0, 0);
|
||||
}
|
||||
x = resample_1->forward(ctx, x);
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 1, 3, 2)); // (c, t, h, w)
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 1, 3, 2)); // (c, t, h, w)
|
||||
}
|
||||
|
||||
if (mode == "downsample3d") {
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
if (feat_cache[idx] == NULL) {
|
||||
if (feat_cache[idx] == nullptr) {
|
||||
feat_cache[idx] = x;
|
||||
feat_idx += 1;
|
||||
} else {
|
||||
auto time_conv = std::dynamic_pointer_cast<CausalConv3d>(blocks["time_conv"]);
|
||||
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -1, x->ne[2]);
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -1, x->ne[2]);
|
||||
x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
x,
|
||||
2);
|
||||
x = time_conv->forward(ctx, x);
|
||||
@@ -264,15 +266,15 @@ namespace WAN {
|
||||
T = x->ne[2];
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, W * H, factor_t, T / factor_t, C); // [C, T/factor_t, factor_t, H*W]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [C, factor_t, T/factor_t, H*W]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [C, factor_t, T/factor_t, H*W]
|
||||
x = ggml_reshape_4d(ctx, x, W, factor_s, (H / factor_s) * (T / factor_t), factor_t * C); // [C*factor_t, T/factor_t*H/factor_s, factor_s, W]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [C*factor_t, factor_s, T/factor_t*H/factor_s, W]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [C*factor_t, factor_s, T/factor_t*H/factor_s, W]
|
||||
x = ggml_reshape_4d(ctx, x, factor_s, W / factor_s, (H / factor_s) * (T / factor_t), factor_s * factor_t * C); // [C*factor_t*factor_s, T/factor_t*H/factor_s, W/factor_s, factor_s]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 1, 2, 0, 3)); // [C*factor_t*factor_s, factor_s, T/factor_t*H/factor_s, W/factor_s]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 2, 0, 3)); // [C*factor_t*factor_s, factor_s, T/factor_t*H/factor_s, W/factor_s]
|
||||
x = ggml_reshape_3d(ctx, x, (W / factor_s) * (H / factor_s) * (T / factor_t), group_size, out_channels); // [out_channels, group_size, T/factor_t*H/factor_s*W/factor_s]
|
||||
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 1, 0, 2, 3)); // [out_channels, T/factor_t*H/factor_s*W/factor_s, group_size]
|
||||
x = ggml_mean(ctx, x); // [out_channels, T/factor_t*H/factor_s*W/factor_s, 1]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 0, 2, 3)); // [out_channels, T/factor_t*H/factor_s*W/factor_s, group_size]
|
||||
x = ggml_mean(ctx, x); // [out_channels, T/factor_t*H/factor_s*W/factor_s, 1]
|
||||
x = ggml_reshape_4d(ctx, x, W / factor_s, H / factor_s, T / factor_t, out_channels);
|
||||
return x;
|
||||
}
|
||||
@@ -314,15 +316,15 @@ namespace WAN {
|
||||
C = out_channels;
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, W, H * T, factor_s, factor_s * factor_t * C); // [C*factor_t*factor_s, factor_s, T*H, W]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 2, 0, 1, 3)); // [C*factor_t*factor_s, T*H, W, factor_s]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 2, 0, 1, 3)); // [C*factor_t*factor_s, T*H, W, factor_s]
|
||||
x = ggml_reshape_4d(ctx, x, factor_s * W, H * T, factor_s, factor_t * C); // [C*factor_t, factor_s, T*H, W*factor_s]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [C*factor_t, T*H, factor_s, W*factor_s]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [C*factor_t, T*H, factor_s, W*factor_s]
|
||||
x = ggml_reshape_4d(ctx, x, factor_s * W * factor_s * H, T, factor_t, C); // [C, factor_t, T, H*factor_s*W*factor_s]
|
||||
x = ggml_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [C, T, factor_t, H*factor_s*W*factor_s]
|
||||
x = ggml_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [C, T, factor_t, H*factor_s*W*factor_s]
|
||||
x = ggml_reshape_4d(ctx, x, factor_s * W, factor_s * H, factor_t * T, C); // [C, T*factor_t, H*factor_s, W*factor_s]
|
||||
|
||||
if (first_chunk) {
|
||||
x = ggml_slice(ctx, x, 2, factor_t - 1, x->ne[2]);
|
||||
x = ggml_ext_slice(ctx, x, 2, factor_t - 1, x->ne[2]);
|
||||
}
|
||||
|
||||
return x;
|
||||
@@ -372,11 +374,11 @@ namespace WAN {
|
||||
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) {
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) {
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -543,7 +545,7 @@ namespace WAN {
|
||||
|
||||
x = norm->forward(ctx, x);
|
||||
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 1, 3, 2)); // (t, c, h, w)
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 1, 3, 2)); // (t, c, h, w)
|
||||
|
||||
const int64_t n = x->ne[3];
|
||||
const int64_t c = x->ne[2];
|
||||
@@ -554,26 +556,26 @@ namespace WAN {
|
||||
auto qkv_vec = split_image_qkv(ctx, qkv);
|
||||
|
||||
auto q = qkv_vec[0];
|
||||
q = ggml_nn_cont(ctx, ggml_torch_permute(ctx, q, 2, 0, 1, 3)); // [t, h, w, c]
|
||||
q = ggml_reshape_3d(ctx, q, c, h * w, n); // [t, h * w, c]
|
||||
q = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, q, 2, 0, 1, 3)); // [t, h, w, c]
|
||||
q = ggml_reshape_3d(ctx, q, c, h * w, n); // [t, h * w, c]
|
||||
|
||||
auto k = qkv_vec[1];
|
||||
k = ggml_nn_cont(ctx, ggml_torch_permute(ctx, k, 2, 0, 1, 3)); // [t, h, w, c]
|
||||
k = ggml_reshape_3d(ctx, k, c, h * w, n); // [t, h * w, c]
|
||||
k = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, k, 2, 0, 1, 3)); // [t, h, w, c]
|
||||
k = ggml_reshape_3d(ctx, k, c, h * w, n); // [t, h * w, c]
|
||||
|
||||
auto v = qkv_vec[2];
|
||||
v = ggml_reshape_3d(ctx, v, h * w, c, n); // [t, c, h * w]
|
||||
|
||||
x = ggml_nn_attention(ctx, q, k, v, false); // [t, h * w, c]
|
||||
// v = ggml_cont(ctx, ggml_torch_permute(ctx, v, 1, 0, 2, 3)); // [t, h * w, c]
|
||||
// x = ggml_nn_attention_ext(ctx, q, k, v, q->ne[2], NULL, false, false, true);
|
||||
x = ggml_ext_attention(ctx, q, k, v, false); // [t, h * w, c]
|
||||
// v = ggml_cont(ctx, ggml_ext_torch_permute(ctx, v, 1, 0, 2, 3)); // [t, h * w, c]
|
||||
// x = ggml_ext_attention_ext(ctx, q, k, v, q->ne[2], nullptr, false, false, true);
|
||||
|
||||
x = ggml_nn_cont(ctx, ggml_permute(ctx, x, 1, 0, 2, 3)); // [t, c, h * w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h, c, n); // [t, c, h, w]
|
||||
x = ggml_ext_cont(ctx, ggml_permute(ctx, x, 1, 0, 2, 3)); // [t, c, h * w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h, c, n); // [t, c, h, w]
|
||||
|
||||
x = proj->forward(ctx, x);
|
||||
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 1, 3, 2)); // (c, t, h, w)
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 1, 3, 2)); // (c, t, h, w)
|
||||
|
||||
x = ggml_add(ctx, x, identity);
|
||||
return x;
|
||||
@@ -671,11 +673,11 @@ namespace WAN {
|
||||
// conv1
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) {
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) {
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -723,11 +725,11 @@ namespace WAN {
|
||||
x = ggml_silu(ctx, x);
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) {
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) {
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -842,11 +844,11 @@ namespace WAN {
|
||||
// conv1
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) {
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) {
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -894,11 +896,11 @@ namespace WAN {
|
||||
x = ggml_silu(ctx, x);
|
||||
if (feat_cache.size() > 0) {
|
||||
int idx = feat_idx;
|
||||
auto cache_x = ggml_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != NULL) {
|
||||
auto cache_x = ggml_ext_slice(ctx, x, 2, -CACHE_T, x->ne[2]);
|
||||
if (cache_x->ne[2] < 2 && feat_cache[idx] != nullptr) {
|
||||
// cache last frame of last two chunk
|
||||
cache_x = ggml_concat(ctx,
|
||||
ggml_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
ggml_ext_slice(ctx, feat_cache[idx], 2, -1, feat_cache[idx]->ne[2]),
|
||||
cache_x,
|
||||
2);
|
||||
}
|
||||
@@ -935,9 +937,9 @@ namespace WAN {
|
||||
|
||||
void clear_cache() {
|
||||
_conv_idx = 0;
|
||||
_feat_map = std::vector<struct ggml_tensor*>(_conv_num, NULL);
|
||||
_feat_map = std::vector<struct ggml_tensor*>(_conv_num, nullptr);
|
||||
_enc_conv_idx = 0;
|
||||
_enc_feat_map = std::vector<struct ggml_tensor*>(_enc_conv_num, NULL);
|
||||
_enc_feat_map = std::vector<struct ggml_tensor*>(_enc_conv_num, nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -976,13 +978,13 @@ namespace WAN {
|
||||
int64_t h = x->ne[1] / q;
|
||||
int64_t w = x->ne[0] / r;
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, r * w, q, h, f * c * b); // [b*c*f, h, q, w*r]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c*f, q, h, w*r]
|
||||
x = ggml_reshape_4d(ctx, x, r, w, h * q, f * c * b); // [b*c*f, q*h, w, r]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 1, 2, 0, 3)); // [b*c*f, r, q*h, w]
|
||||
x = ggml_reshape_4d(ctx, x, w * h, q * r, f, c * b); // [b*c, f, r*q, h*w]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c, r*q, f, h*w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h, f, q * r * c * b); // [b*c*r*q, f, h, w]
|
||||
x = ggml_reshape_4d(ctx, x, r * w, q, h, f * c * b); // [b*c*f, h, q, w*r]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c*f, q, h, w*r]
|
||||
x = ggml_reshape_4d(ctx, x, r, w, h * q, f * c * b); // [b*c*f, q*h, w, r]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 2, 0, 3)); // [b*c*f, r, q*h, w]
|
||||
x = ggml_reshape_4d(ctx, x, w * h, q * r, f, c * b); // [b*c, f, r*q, h*w]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c, r*q, f, h*w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h, f, q * r * c * b); // [b*c*r*q, f, h, w]
|
||||
|
||||
return x;
|
||||
}
|
||||
@@ -1003,13 +1005,13 @@ namespace WAN {
|
||||
int64_t h = x->ne[1];
|
||||
int64_t w = x->ne[0];
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, w * h, f, q * r, c * b); // [b*c, r*q, f, h*w]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c, f, r*q, h*w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h * q, r, f * c * b); // [b*c*f, r, q*h, w]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 2, 0, 1, 3)); // [b*c*f, q*h, w, r]
|
||||
x = ggml_reshape_4d(ctx, x, r * w, h, q, f * c * b); // [b*c*f, q, h, w*r]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c*f, h, q, w*r]
|
||||
x = ggml_reshape_4d(ctx, x, r * w, q * h, f, c * b); // [b*c, f, h*q, w*r]
|
||||
x = ggml_reshape_4d(ctx, x, w * h, f, q * r, c * b); // [b*c, r*q, f, h*w]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c, f, r*q, h*w]
|
||||
x = ggml_reshape_4d(ctx, x, w, h * q, r, f * c * b); // [b*c*f, r, q*h, w]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 2, 0, 1, 3)); // [b*c*f, q*h, w, r]
|
||||
x = ggml_reshape_4d(ctx, x, r * w, h, q, f * c * b); // [b*c*f, q, h, w*r]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [b*c*f, h, q, w*r]
|
||||
x = ggml_reshape_4d(ctx, x, r * w, q * h, f, c * b); // [b*c, f, h*q, w*r]
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -1035,16 +1037,16 @@ namespace WAN {
|
||||
for (int i = 0; i < iter_; i++) {
|
||||
_enc_conv_idx = 0;
|
||||
if (i == 0) {
|
||||
auto in = ggml_slice(ctx, x, 2, 0, 1); // [b*c, 1, h, w]
|
||||
auto in = ggml_ext_slice(ctx, x, 2, 0, 1); // [b*c, 1, h, w]
|
||||
out = encoder->forward(ctx, in, b, _enc_feat_map, _enc_conv_idx, i);
|
||||
} else {
|
||||
auto in = ggml_slice(ctx, x, 2, 1 + 4 * (i - 1), 1 + 4 * i); // [b*c, 4, h, w]
|
||||
auto in = ggml_ext_slice(ctx, x, 2, 1 + 4 * (i - 1), 1 + 4 * i); // [b*c, 4, h, w]
|
||||
auto out_ = encoder->forward(ctx, in, b, _enc_feat_map, _enc_conv_idx, i);
|
||||
out = ggml_concat(ctx, out, out_, 2);
|
||||
}
|
||||
}
|
||||
out = conv1->forward(ctx, out);
|
||||
auto mu = ggml_chunk(ctx, out, 2, 3)[0];
|
||||
auto mu = ggml_ext_chunk(ctx, out, 2, 3)[0];
|
||||
clear_cache();
|
||||
return mu;
|
||||
}
|
||||
@@ -1066,10 +1068,10 @@ namespace WAN {
|
||||
for (int64_t i = 0; i < iter_; i++) {
|
||||
_conv_idx = 0;
|
||||
if (i == 0) {
|
||||
auto in = ggml_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
auto in = ggml_ext_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
out = decoder->forward(ctx, in, b, _feat_map, _conv_idx, i);
|
||||
} else {
|
||||
auto in = ggml_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
auto in = ggml_ext_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
auto out_ = decoder->forward(ctx, in, b, _feat_map, _conv_idx, i);
|
||||
out = ggml_concat(ctx, out, out_, 2);
|
||||
}
|
||||
@@ -1092,7 +1094,7 @@ namespace WAN {
|
||||
auto conv2 = std::dynamic_pointer_cast<CausalConv3d>(blocks["conv2"]);
|
||||
|
||||
auto x = conv2->forward(ctx, z);
|
||||
auto in = ggml_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
auto in = ggml_ext_slice(ctx, x, 2, i, i + 1); // [b*c, 1, h, w]
|
||||
_conv_idx = 0;
|
||||
auto out = decoder->forward(ctx, in, b, _feat_map, _conv_idx, i);
|
||||
if (wan2_2) {
|
||||
@@ -1116,11 +1118,11 @@ namespace WAN {
|
||||
ae.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return "wan_vae";
|
||||
}
|
||||
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) {
|
||||
void get_param_tensors(std::map<std::string, struct ggml_tensor*>& tensors, const std::string prefix) override {
|
||||
ae.get_param_tensors(tensors, prefix);
|
||||
}
|
||||
|
||||
@@ -1152,7 +1154,7 @@ namespace WAN {
|
||||
|
||||
for (int64_t feat_idx = 0; feat_idx < ae._feat_map.size(); feat_idx++) {
|
||||
ggml_tensor* feat_cache = ae._feat_map[feat_idx];
|
||||
if (feat_cache != NULL) {
|
||||
if (feat_cache != nullptr) {
|
||||
cache("feat_idx:" + std::to_string(feat_idx), feat_cache);
|
||||
ggml_build_forward_expand(gf, feat_cache);
|
||||
}
|
||||
@@ -1167,7 +1169,7 @@ namespace WAN {
|
||||
struct ggml_tensor* z,
|
||||
bool decode_graph,
|
||||
struct ggml_tensor** output,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_context* output_ctx = nullptr) override {
|
||||
if (true) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(z, decode_graph);
|
||||
@@ -1180,7 +1182,7 @@ namespace WAN {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph_partial(z, decode_graph, i);
|
||||
};
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
GGMLRunner::compute(get_graph, n_threads, true, &out, output_ctx);
|
||||
ae.clear_cache();
|
||||
if (t == 1) {
|
||||
@@ -1195,9 +1197,9 @@ namespace WAN {
|
||||
for (int64_t i2 = 0; i2 < out->ne[2]; i2++) {
|
||||
for (int64_t i1 = 0; i1 < out->ne[1]; i1++) {
|
||||
for (int64_t i0 = 0; i0 < out->ne[0]; i0++) {
|
||||
float value = ggml_tensor_get_f32(out, i0, i1, i2, i3);
|
||||
float value = ggml_ext_tensor_get_f32(out, i0, i1, i2, i3);
|
||||
int64_t offset = (i == 0) ? 0 : (1 + (i - 1) * 4);
|
||||
ggml_tensor_set_f32(*output, value, i0, i1, offset + i2, i3);
|
||||
ggml_ext_tensor_set_f32(*output, value, i0, i1, offset + i2, i3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1220,11 +1222,11 @@ namespace WAN {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(1024 * 1024) * 1024; // 1G
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
if (true) {
|
||||
// cpu f32, pass
|
||||
@@ -1235,7 +1237,7 @@ namespace WAN {
|
||||
ggml_set_f32(z, 0.5f);
|
||||
z = load_tensor_from_file(work_ctx, "wan_vae_z.bin");
|
||||
print_ggml_tensor(z);
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int64_t t0 = ggml_time_ms();
|
||||
compute(8, z, true, &out, work_ctx);
|
||||
@@ -1250,7 +1252,7 @@ namespace WAN {
|
||||
// ggml_backend_t backend = ggml_backend_cuda_init(0);
|
||||
ggml_backend_t backend = ggml_backend_cpu_init();
|
||||
ggml_type model_data_type = GGML_TYPE_F16;
|
||||
std::shared_ptr<WanVAERunner> vae = std::shared_ptr<WanVAERunner>(new WanVAERunner(backend, false, {}, "", false, VERSION_WAN2_2_TI2V));
|
||||
std::shared_ptr<WanVAERunner> vae = std::make_shared<WanVAERunner>(backend, false, String2GGMLType{}, "", false, VERSION_WAN2_2_TI2V);
|
||||
{
|
||||
LOG_INFO("loading from '%s'", file_path.c_str());
|
||||
|
||||
@@ -1309,7 +1311,7 @@ namespace WAN {
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* mask = NULL) {
|
||||
struct ggml_tensor* mask = nullptr) {
|
||||
// x: [N, n_token, dim]
|
||||
// pe: [n_token, d_head/2, 2, 2]
|
||||
// return [N, n_token, dim]
|
||||
@@ -1333,7 +1335,7 @@ namespace WAN {
|
||||
k = ggml_reshape_4d(ctx, k, head_dim, num_heads, n_token, N); // [N, n_token, n_head, d_head]
|
||||
v = ggml_reshape_4d(ctx, v, head_dim, num_heads, n_token, N); // [N, n_token, n_head, d_head]
|
||||
|
||||
x = Flux::attention(ctx, backend, q, k, v, pe, mask, flash_attn); // [N, n_token, dim]
|
||||
x = Rope::attention(ctx, backend, q, k, v, pe, mask, flash_attn); // [N, n_token, dim]
|
||||
|
||||
x = o_proj->forward(ctx, x); // [N, n_token, dim]
|
||||
return x;
|
||||
@@ -1367,7 +1369,7 @@ namespace WAN {
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* context,
|
||||
int64_t context_img_len) {
|
||||
int64_t context_img_len) override {
|
||||
// x: [N, n_token, dim]
|
||||
// context: [N, n_context, dim]
|
||||
// context_img_len: unused
|
||||
@@ -1388,7 +1390,7 @@ namespace WAN {
|
||||
k = norm_k->forward(ctx, k);
|
||||
auto v = v_proj->forward(ctx, context); // [N, n_context, dim]
|
||||
|
||||
x = ggml_nn_attention_ext(ctx, backend, q, k, v, num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
x = ggml_ext_attention_ext(ctx, backend, q, k, v, num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
|
||||
x = o_proj->forward(ctx, x); // [N, n_token, dim]
|
||||
return x;
|
||||
@@ -1417,7 +1419,7 @@ namespace WAN {
|
||||
ggml_backend_t backend,
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* context,
|
||||
int64_t context_img_len) {
|
||||
int64_t context_img_len) override {
|
||||
// x: [N, n_token, dim]
|
||||
// context: [N, context_img_len + context_txt_len, dim]
|
||||
// return [N, n_token, dim]
|
||||
@@ -1439,11 +1441,11 @@ namespace WAN {
|
||||
int64_t dim = x->ne[0];
|
||||
int64_t context_txt_len = context->ne[1] - context_img_len;
|
||||
|
||||
context = ggml_nn_cont(ctx, ggml_torch_permute(ctx, context, 0, 2, 1, 3)); // [context_img_len + context_txt_len, N, dim]
|
||||
context = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, context, 0, 2, 1, 3)); // [context_img_len + context_txt_len, N, dim]
|
||||
auto context_img = ggml_view_3d(ctx, context, dim, N, context_img_len, context->nb[1], context->nb[2], 0);
|
||||
auto context_txt = ggml_view_3d(ctx, context, dim, N, context_txt_len, context->nb[1], context->nb[2], context_img_len * context->nb[2]);
|
||||
context_img = ggml_nn_cont(ctx, ggml_torch_permute(ctx, context_img, 0, 2, 1, 3)); // [N, context_img_len, dim]
|
||||
context_txt = ggml_nn_cont(ctx, ggml_torch_permute(ctx, context_txt, 0, 2, 1, 3)); // [N, context_txt_len, dim]
|
||||
context_img = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, context_img, 0, 2, 1, 3)); // [N, context_img_len, dim]
|
||||
context_txt = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, context_txt, 0, 2, 1, 3)); // [N, context_txt_len, dim]
|
||||
|
||||
auto q = q_proj->forward(ctx, x);
|
||||
q = norm_q->forward(ctx, q);
|
||||
@@ -1455,8 +1457,8 @@ namespace WAN {
|
||||
k_img = norm_k_img->forward(ctx, k_img);
|
||||
auto v_img = v_img_proj->forward(ctx, context_img); // [N, context_img_len, dim]
|
||||
|
||||
auto img_x = ggml_nn_attention_ext(ctx, backend, q, k_img, v_img, num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
x = ggml_nn_attention_ext(ctx, backend, q, k, v, num_heads, NULL, false, false, flash_attn); // [N, n_token, dim]
|
||||
auto img_x = ggml_ext_attention_ext(ctx, backend, q, k_img, v_img, num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
x = ggml_ext_attention_ext(ctx, backend, q, k, v, num_heads, nullptr, false, false, flash_attn); // [N, n_token, dim]
|
||||
|
||||
x = ggml_add(ctx, x, img_x);
|
||||
|
||||
@@ -1497,7 +1499,7 @@ namespace WAN {
|
||||
protected:
|
||||
int dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 6, 1);
|
||||
}
|
||||
@@ -1546,7 +1548,7 @@ namespace WAN {
|
||||
|
||||
auto modulation = params["modulation"];
|
||||
e = ggml_add(ctx, e, modulation); // [N, 6, dim] or [N, T, 6, dim]
|
||||
auto es = ggml_chunk(ctx, e, 6, 1); // ([N, 1, dim], ...) or [N, T, 1, dim]
|
||||
auto es = ggml_ext_chunk(ctx, e, 6, 1); // ([N, 1, dim], ...) or [N, T, 1, dim]
|
||||
|
||||
auto norm1 = std::dynamic_pointer_cast<LayerNorm>(blocks["norm1"]);
|
||||
auto self_attn = std::dynamic_pointer_cast<WanSelfAttention>(blocks["self_attn"]);
|
||||
@@ -1587,7 +1589,7 @@ namespace WAN {
|
||||
class VaceWanAttentionBlock : public WanAttentionBlock {
|
||||
protected:
|
||||
int block_id;
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 6, 1);
|
||||
}
|
||||
@@ -1641,7 +1643,7 @@ namespace WAN {
|
||||
protected:
|
||||
int dim;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
enum ggml_type wtype = get_type(prefix + "weight", tensor_types, GGML_TYPE_F32);
|
||||
params["modulation"] = ggml_new_tensor_3d(ctx, wtype, dim, 2, 1);
|
||||
}
|
||||
@@ -1670,7 +1672,7 @@ namespace WAN {
|
||||
e = ggml_repeat_4d(ctx, e, e->ne[0], 2, e->ne[2], e->ne[3]); // [N, 2, dim] or [N, T, 2, dim]
|
||||
|
||||
e = ggml_add(ctx, e, modulation); // [N, 2, dim] or [N, T, 2, dim]
|
||||
auto es = ggml_chunk(ctx, e, 2, 1); // ([N, 1, dim], ...) or ([N, T, 1, dim], ...)
|
||||
auto es = ggml_ext_chunk(ctx, e, 2, 1); // ([N, 1, dim], ...) or ([N, T, 1, dim], ...)
|
||||
|
||||
auto norm = std::dynamic_pointer_cast<LayerNorm>(blocks["norm"]);
|
||||
auto head = std::dynamic_pointer_cast<Linear>(blocks["head"]);
|
||||
@@ -1688,7 +1690,7 @@ namespace WAN {
|
||||
int in_dim;
|
||||
int flf_pos_embed_token_number;
|
||||
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") {
|
||||
void init_params(struct ggml_context* ctx, const String2GGMLType& tensor_types = {}, const std::string prefix = "") override {
|
||||
if (flf_pos_embed_token_number > 0) {
|
||||
params["emb_pos"] = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, in_dim, flf_pos_embed_token_number, 1);
|
||||
}
|
||||
@@ -1711,8 +1713,8 @@ namespace WAN {
|
||||
if (flf_pos_embed_token_number > 0) {
|
||||
auto emb_pos = params["emb_pos"];
|
||||
|
||||
auto a = ggml_slice(ctx, image_embeds, 1, 0, emb_pos->ne[1]);
|
||||
auto b = ggml_slice(ctx, emb_pos, 1, 0, image_embeds->ne[1]);
|
||||
auto a = ggml_ext_slice(ctx, image_embeds, 1, 0, emb_pos->ne[1]);
|
||||
auto b = ggml_ext_slice(ctx, emb_pos, 1, 0, image_embeds->ne[1]);
|
||||
|
||||
image_embeds = ggml_add(ctx, a, b);
|
||||
}
|
||||
@@ -1859,13 +1861,13 @@ namespace WAN {
|
||||
GGML_ASSERT(C * pt * ph * pw == x->ne[0]);
|
||||
|
||||
x = ggml_reshape_4d(ctx, x, C, pw * ph * pt, w_len * h_len * t_len, N); // [N, t_len*h_len*w_len, pt*ph*pw, C]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 1, 2, 0, 3)); // [N, C, t_len*h_len*w_len, pt*ph*pw]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 2, 0, 3)); // [N, C, t_len*h_len*w_len, pt*ph*pw]
|
||||
x = ggml_reshape_4d(ctx, x, pw, ph * pt, w_len, h_len * t_len * C * N); // [N*C*t_len*h_len, w_len, pt*ph, pw]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len*h_len, pt*ph, w_len, pw]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len*h_len, pt*ph, w_len, pw]
|
||||
x = ggml_reshape_4d(ctx, x, pw * w_len, ph, pt, h_len * t_len * C * N); // [N*C*t_len*h_len, pt, ph, w_len*pw]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len*h_len, ph, pt, w_len*pw]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len*h_len, ph, pt, w_len*pw]
|
||||
x = ggml_reshape_4d(ctx, x, pw * w_len, pt, ph * h_len, t_len * C * N); // [N*C*t_len, h_len*ph, pt, w_len*pw]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len, pt, h_len*ph, w_len*pw]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 0, 2, 1, 3)); // [N*C*t_len, pt, h_len*ph, w_len*pw]
|
||||
x = ggml_reshape_4d(ctx, x, pw * w_len, ph * h_len, pt * t_len, C * N); // [N*C, t_len*pt, h_len*ph, w_len*pw]
|
||||
return x;
|
||||
}
|
||||
@@ -1876,8 +1878,8 @@ namespace WAN {
|
||||
struct ggml_tensor* timestep,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* clip_fea = NULL,
|
||||
struct ggml_tensor* vace_context = NULL,
|
||||
struct ggml_tensor* clip_fea = nullptr,
|
||||
struct ggml_tensor* vace_context = nullptr,
|
||||
float vace_strength = 1.f,
|
||||
int64_t N = 1) {
|
||||
// x: [N*C, T, H, W], C => in_dim
|
||||
@@ -1902,10 +1904,10 @@ namespace WAN {
|
||||
// patch_embedding
|
||||
x = patch_embedding->forward(ctx, x); // [N*dim, t_len, h_len, w_len]
|
||||
x = ggml_reshape_3d(ctx, x, x->ne[0] * x->ne[1] * x->ne[2], x->ne[3] / N, N); // [N, dim, t_len*h_len*w_len]
|
||||
x = ggml_nn_cont(ctx, ggml_torch_permute(ctx, x, 1, 0, 2, 3)); // [N, t_len*h_len*w_len, dim]
|
||||
x = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, x, 1, 0, 2, 3)); // [N, t_len*h_len*w_len, dim]
|
||||
|
||||
// time_embedding
|
||||
auto e = ggml_nn_timestep_embedding(ctx, timestep, params.freq_dim);
|
||||
auto e = ggml_ext_timestep_embedding(ctx, timestep, params.freq_dim);
|
||||
e = time_embedding_0->forward(ctx, e);
|
||||
e = ggml_silu_inplace(ctx, e);
|
||||
e = time_embedding_2->forward(ctx, e); // [N, dim] or [N, T, dim]
|
||||
@@ -1920,7 +1922,7 @@ namespace WAN {
|
||||
context = text_embedding_2->forward(ctx, context); // [N, context_txt_len, dim]
|
||||
|
||||
int64_t context_img_len = 0;
|
||||
if (clip_fea != NULL) {
|
||||
if (clip_fea != nullptr) {
|
||||
if (params.model_type == "i2v") {
|
||||
auto img_emb = std::dynamic_pointer_cast<MLPProj>(blocks["img_emb"]);
|
||||
auto context_img = img_emb->forward(ctx, clip_fea); // [N, context_img_len, dim]
|
||||
@@ -1930,13 +1932,13 @@ namespace WAN {
|
||||
}
|
||||
|
||||
// vace_patch_embedding
|
||||
ggml_tensor* c = NULL;
|
||||
ggml_tensor* c = nullptr;
|
||||
if (params.vace_layers > 0) {
|
||||
auto vace_patch_embedding = std::dynamic_pointer_cast<Conv3d>(blocks["vace_patch_embedding"]);
|
||||
|
||||
c = vace_patch_embedding->forward(ctx, vace_context); // [N*dim, t_len, h_len, w_len]
|
||||
c = ggml_reshape_3d(ctx, c, c->ne[0] * c->ne[1] * c->ne[2], c->ne[3] / N, N); // [N, dim, t_len*h_len*w_len]
|
||||
c = ggml_nn_cont(ctx, ggml_torch_permute(ctx, c, 1, 0, 2, 3)); // [N, t_len*h_len*w_len, dim]
|
||||
c = ggml_ext_cont(ctx, ggml_ext_torch_permute(ctx, c, 1, 0, 2, 3)); // [N, t_len*h_len*w_len, dim]
|
||||
}
|
||||
|
||||
auto x_orig = x;
|
||||
@@ -1971,9 +1973,9 @@ namespace WAN {
|
||||
struct ggml_tensor* timestep,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* pe,
|
||||
struct ggml_tensor* clip_fea = NULL,
|
||||
struct ggml_tensor* time_dim_concat = NULL,
|
||||
struct ggml_tensor* vace_context = NULL,
|
||||
struct ggml_tensor* clip_fea = nullptr,
|
||||
struct ggml_tensor* time_dim_concat = nullptr,
|
||||
struct ggml_tensor* vace_context = nullptr,
|
||||
float vace_strength = 1.f,
|
||||
int64_t N = 1) {
|
||||
// Forward pass of DiT.
|
||||
@@ -1997,7 +1999,7 @@ namespace WAN {
|
||||
int64_t h_len = ((H + (std::get<1>(params.patch_size) / 2)) / std::get<1>(params.patch_size));
|
||||
int64_t w_len = ((W + (std::get<2>(params.patch_size) / 2)) / std::get<2>(params.patch_size));
|
||||
|
||||
if (time_dim_concat != NULL) {
|
||||
if (time_dim_concat != nullptr) {
|
||||
time_dim_concat = pad_to_patch_size(ctx, time_dim_concat);
|
||||
x = ggml_concat(ctx, x, time_dim_concat, 2); // [N*C, (T+pad_t) + (T2+pad_t2), H + pad_h, W + pad_w]
|
||||
t_len = ((x->ne[2] + (std::get<0>(params.patch_size) / 2)) / std::get<0>(params.patch_size));
|
||||
@@ -2009,9 +2011,9 @@ namespace WAN {
|
||||
|
||||
// slice
|
||||
|
||||
out = ggml_slice(ctx, out, 2, 0, T); // [N*C, T, H + pad_h, W + pad_w]
|
||||
out = ggml_slice(ctx, out, 1, 0, H); // [N*C, T, H, W + pad_w]
|
||||
out = ggml_slice(ctx, out, 0, 0, W); // [N*C, T, H, W]
|
||||
out = ggml_ext_slice(ctx, out, 2, 0, T); // [N*C, T, H + pad_h, W + pad_w]
|
||||
out = ggml_ext_slice(ctx, out, 1, 0, H); // [N*C, T, H, W + pad_w]
|
||||
out = ggml_ext_slice(ctx, out, 0, 0, W); // [N*C, T, H, W]
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -2134,7 +2136,7 @@ namespace WAN {
|
||||
wan.init(params_ctx, tensor_types, prefix);
|
||||
}
|
||||
|
||||
std::string get_desc() {
|
||||
std::string get_desc() override {
|
||||
return desc;
|
||||
}
|
||||
|
||||
@@ -2145,10 +2147,10 @@ namespace WAN {
|
||||
struct ggml_cgraph* build_graph(struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* clip_fea = NULL,
|
||||
struct ggml_tensor* c_concat = NULL,
|
||||
struct ggml_tensor* time_dim_concat = NULL,
|
||||
struct ggml_tensor* vace_context = NULL,
|
||||
struct ggml_tensor* clip_fea = nullptr,
|
||||
struct ggml_tensor* c_concat = nullptr,
|
||||
struct ggml_tensor* time_dim_concat = nullptr,
|
||||
struct ggml_tensor* vace_context = nullptr,
|
||||
float vace_strength = 1.f) {
|
||||
struct ggml_cgraph* gf = ggml_new_graph_custom(compute_ctx, WAN_GRAPH_SIZE, false);
|
||||
|
||||
@@ -2174,10 +2176,10 @@ namespace WAN {
|
||||
auto pe = ggml_new_tensor_4d(compute_ctx, GGML_TYPE_F32, 2, 2, wan_params.axes_dim_sum / 2, pos_len);
|
||||
// pe->data = pe_vec.data();
|
||||
// print_ggml_tensor(pe);
|
||||
// pe->data = NULL;
|
||||
// pe->data = nullptr;
|
||||
set_backend_tensor_data(pe, pe_vec.data());
|
||||
|
||||
if (c_concat != NULL) {
|
||||
if (c_concat != nullptr) {
|
||||
x = ggml_concat(compute_ctx, x, c_concat, 3);
|
||||
}
|
||||
|
||||
@@ -2201,13 +2203,13 @@ namespace WAN {
|
||||
struct ggml_tensor* x,
|
||||
struct ggml_tensor* timesteps,
|
||||
struct ggml_tensor* context,
|
||||
struct ggml_tensor* clip_fea = NULL,
|
||||
struct ggml_tensor* c_concat = NULL,
|
||||
struct ggml_tensor* time_dim_concat = NULL,
|
||||
struct ggml_tensor* vace_context = NULL,
|
||||
struct ggml_tensor* clip_fea = nullptr,
|
||||
struct ggml_tensor* c_concat = nullptr,
|
||||
struct ggml_tensor* time_dim_concat = nullptr,
|
||||
struct ggml_tensor* vace_context = nullptr,
|
||||
float vace_strength = 1.f,
|
||||
struct ggml_tensor** output = NULL,
|
||||
struct ggml_context* output_ctx = NULL) {
|
||||
struct ggml_tensor** output = nullptr,
|
||||
struct ggml_context* output_ctx = nullptr) {
|
||||
auto get_graph = [&]() -> struct ggml_cgraph* {
|
||||
return build_graph(x, timesteps, context, clip_fea, c_concat, time_dim_concat, vace_context, vace_strength);
|
||||
};
|
||||
@@ -2218,11 +2220,11 @@ namespace WAN {
|
||||
void test() {
|
||||
struct ggml_init_params params;
|
||||
params.mem_size = static_cast<size_t>(200 * 1024 * 1024); // 200 MB
|
||||
params.mem_buffer = NULL;
|
||||
params.mem_buffer = nullptr;
|
||||
params.no_alloc = false;
|
||||
|
||||
struct ggml_context* work_ctx = ggml_init(params);
|
||||
GGML_ASSERT(work_ctx != NULL);
|
||||
GGML_ASSERT(work_ctx != nullptr);
|
||||
|
||||
{
|
||||
// cpu f16: pass
|
||||
@@ -2244,10 +2246,10 @@ namespace WAN {
|
||||
// auto clip_fea = load_tensor_from_file(work_ctx, "wan_dit_clip_fea.bin");
|
||||
// print_ggml_tensor(clip_fea);
|
||||
|
||||
struct ggml_tensor* out = NULL;
|
||||
struct ggml_tensor* out = nullptr;
|
||||
|
||||
int t0 = ggml_time_ms();
|
||||
compute(8, x, timesteps, context, NULL, NULL, NULL, NULL, 1.f, &out, work_ctx);
|
||||
compute(8, x, timesteps, context, nullptr, nullptr, nullptr, nullptr, 1.f, &out, work_ctx);
|
||||
int t1 = ggml_time_ms();
|
||||
|
||||
print_ggml_tensor(out);
|
||||
@@ -2275,12 +2277,12 @@ namespace WAN {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<WanRunner> wan = std::shared_ptr<WanRunner>(new WanRunner(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
"model.diffusion_model",
|
||||
VERSION_WAN2_2_TI2V,
|
||||
true));
|
||||
std::shared_ptr<WanRunner> wan = std::make_shared<WanRunner>(backend,
|
||||
false,
|
||||
tensor_types,
|
||||
"model.diffusion_model",
|
||||
VERSION_WAN2_2_TI2V,
|
||||
true);
|
||||
|
||||
wan->alloc_params_buffer();
|
||||
std::map<std::string, ggml_tensor*> tensors;
|
||||
|
||||
Reference in New Issue
Block a user