mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-09-27 13:40:38 +00:00
fix: improve GGUF metadata parsing and reader selection (#2062)
Co-authored-by: leejet <leejet714@gmail.com>
This commit is contained in:
parent
2f886889e6
commit
168f7b88b9
BIN
assets/wan/Wan2.2_A14B_vace_r2v.mp4
Normal file
BIN
assets/wan/Wan2.2_A14B_vace_r2v.mp4
Normal file
Binary file not shown.
25
docs/wan.md
25
docs/wan.md
@ -40,6 +40,9 @@ Wan models require `-M vid_gen`, including single-frame generation. `--video-fra
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/tree/main/split_files/diffusion_models
|
||||
- gguf: https://huggingface.co/QuantStack/Wan2.2-S2V-14B-GGUF/tree/main
|
||||
- int8_convrot safetensors: https://huggingface.co/noctrex/Wan2.2-S2V-14B-int8_convrot
|
||||
- Wan2.2 VACE-Fun A14B
|
||||
- safetensors: https://huggingface.co/alibaba-pai/Wan2.2-VACE-Fun-A14B
|
||||
- gguf: https://huggingface.co/QuantStack/Wan2.2-VACE-Fun-A14B-GGUF/tree/main
|
||||
- Download vae
|
||||
- wan_2.1_vae (for all the wan model except Wan2.2 TI2V 5B)
|
||||
- safetensors: https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/blob/main/split_files/vae/wan_2.1_vae.safetensors
|
||||
@ -256,3 +259,25 @@ ffmpeg -i ..\..\ComfyUI\input\post+depth.mp4 -qscale:v 1 -vf fps=8 post+depth\fr
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.1_14B_vace_v2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
|
||||
### Wan2.2 VACE-Fun A14B
|
||||
|
||||
VACE-Fun runs as a MoE pair: `--diffusion-model` takes the low-noise expert and
|
||||
`--high-noise-diffusion-model` the high-noise one. Reference-to-video uses `-i`
|
||||
for the reference image, same as Wan2.1 VACE.
|
||||
|
||||
#### R2V
|
||||
|
||||
```
|
||||
.\bin\Release\sd-cli.exe -M vid_gen --diffusion-model ..\models\diffusion_models\Wan2.2-VACE-Fun-A14B-low-noise-Q8_0.gguf --high-noise-diffusion-model ..\models\diffusion_models\Wan2.2-VACE-Fun-A14B-high-noise-Q8_0.gguf --vae ..\models\vae\wan_2.1_vae.safetensors --t5xxl ..\models\text_encoders\umt5-xxl-encoder-Q8_0.gguf -p "a lovely cat" --cfg-scale 3.5 --sampling-method euler --steps 10 --high-noise-cfg-scale 3.5 --high-noise-sampling-method euler --high-noise-steps 8 -v -n "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部, 畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" -W 832 -H 480 --diffusion-fa -i ..\assets\cat_with_sd_cpp_42.png --video-frames 33 --offload-to-cpu
|
||||
```
|
||||
|
||||
<video src=../assets/wan/Wan2.2_A14B_vace_r2v.mp4 controls="controls" muted="muted" type="video/mp4"></video>
|
||||
|
||||
#### T2V
|
||||
|
||||
Same command without `-i` (VACE context is synthesized from an empty control
|
||||
video, like Wan2.1 VACE t2v).
|
||||
|
||||
> On GPUs with ~12 GB VRAM, VACE also needs `--vae-tiling` — the control-video
|
||||
> encode can exceed the budget otherwise.
|
||||
|
||||
@ -47,10 +47,14 @@ bool read_gguf_file(const std::string& file_path,
|
||||
gguf_context* ctx_gguf_ = nullptr;
|
||||
ggml_context* ctx_meta_ = nullptr;
|
||||
|
||||
ctx_gguf_ = gguf_init_from_file(file_path.c_str(), {true, &ctx_meta_});
|
||||
GGUFReader gguf_reader;
|
||||
bool probe_ok = gguf_reader.load(file_path);
|
||||
|
||||
if (!probe_ok || !gguf_reader.has_tensors_beyond_ggml_limits()) {
|
||||
ctx_gguf_ = gguf_init_from_file(file_path.c_str(), {true, &ctx_meta_});
|
||||
}
|
||||
if (!ctx_gguf_) {
|
||||
GGUFReader gguf_reader;
|
||||
if (!gguf_reader.load(file_path)) {
|
||||
if (!probe_ok && !gguf_reader.load(file_path)) {
|
||||
set_error(error, "failed to open '" + file_path + "' with GGUFReader");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -35,23 +35,72 @@ enum class GGUFMetadataType : uint32_t {
|
||||
class GGUFReader {
|
||||
private:
|
||||
std::vector<GGUFTensorInfo> tensors_;
|
||||
bool has_wide_tensors_ = false;
|
||||
uint64_t remaining_bytes_ = 0;
|
||||
size_t data_offset_;
|
||||
size_t alignment_ = 32; // default alignment is 32
|
||||
|
||||
template <typename T>
|
||||
bool safe_read(std::ifstream& fin, T& value) {
|
||||
fin.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
return fin.good();
|
||||
return safe_read(fin, reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
bool safe_read(std::ifstream& fin, char* buffer, size_t size) {
|
||||
if (size > remaining_bytes_)
|
||||
return false;
|
||||
fin.read(buffer, size);
|
||||
return fin.good();
|
||||
if (!fin.good())
|
||||
return false;
|
||||
remaining_bytes_ -= size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool safe_seek(std::ifstream& fin, std::streamoff offset, std::ios::seekdir dir) {
|
||||
fin.seekg(offset, dir);
|
||||
return fin.good();
|
||||
bool safe_skip(std::ifstream& fin, uint64_t count, uint64_t element_size = 1) {
|
||||
if (count > remaining_bytes_ / element_size)
|
||||
return false;
|
||||
uint64_t size = count * element_size;
|
||||
fin.seekg(static_cast<std::streamoff>(size), std::ios::cur);
|
||||
if (!fin.good())
|
||||
return false;
|
||||
remaining_bytes_ -= size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skip_metadata_values(std::ifstream& fin, GGUFMetadataType type, uint64_t count) {
|
||||
switch (type) {
|
||||
case GGUFMetadataType::UINT8:
|
||||
case GGUFMetadataType::INT8:
|
||||
case GGUFMetadataType::BOOL:
|
||||
return safe_skip(fin, count);
|
||||
|
||||
case GGUFMetadataType::UINT16:
|
||||
case GGUFMetadataType::INT16:
|
||||
return safe_skip(fin, count, 2);
|
||||
|
||||
case GGUFMetadataType::UINT32:
|
||||
case GGUFMetadataType::INT32:
|
||||
case GGUFMetadataType::FLOAT32:
|
||||
return safe_skip(fin, count, 4);
|
||||
|
||||
case GGUFMetadataType::UINT64:
|
||||
case GGUFMetadataType::INT64:
|
||||
case GGUFMetadataType::FLOAT64:
|
||||
return safe_skip(fin, count, 8);
|
||||
|
||||
case GGUFMetadataType::STRING:
|
||||
if (count > remaining_bytes_ / sizeof(uint64_t))
|
||||
return false;
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
uint64_t len = 0;
|
||||
if (!safe_read(fin, len) || !safe_skip(fin, len))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown metadata type=%u", static_cast<uint32_t>(type));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool read_metadata(std::ifstream& fin) {
|
||||
@ -84,52 +133,12 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (static_cast<GGUFMetadataType>(type)) {
|
||||
case GGUFMetadataType::UINT8:
|
||||
case GGUFMetadataType::INT8:
|
||||
case GGUFMetadataType::BOOL:
|
||||
return safe_seek(fin, 1, std::ios::cur);
|
||||
|
||||
case GGUFMetadataType::UINT16:
|
||||
case GGUFMetadataType::INT16:
|
||||
return safe_seek(fin, 2, std::ios::cur);
|
||||
|
||||
case GGUFMetadataType::UINT32:
|
||||
case GGUFMetadataType::INT32:
|
||||
case GGUFMetadataType::FLOAT32:
|
||||
return safe_seek(fin, 4, std::ios::cur);
|
||||
|
||||
case GGUFMetadataType::UINT64:
|
||||
case GGUFMetadataType::INT64:
|
||||
case GGUFMetadataType::FLOAT64:
|
||||
return safe_seek(fin, 8, std::ios::cur);
|
||||
|
||||
case GGUFMetadataType::STRING: {
|
||||
uint64_t len = 0;
|
||||
if (!safe_read(fin, len))
|
||||
return false;
|
||||
return safe_seek(fin, len, std::ios::cur);
|
||||
}
|
||||
|
||||
case GGUFMetadataType::ARRAY: {
|
||||
uint32_t elem_type = 0;
|
||||
uint64_t len = 0;
|
||||
if (!safe_read(fin, elem_type))
|
||||
return false;
|
||||
if (!safe_read(fin, len))
|
||||
return false;
|
||||
|
||||
for (uint64_t i = 0; i < len; i++) {
|
||||
if (!read_metadata(fin))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown metadata type=%u", type);
|
||||
uint64_t count = 1;
|
||||
if (type == static_cast<uint32_t>(GGUFMetadataType::ARRAY)) {
|
||||
if (!safe_read(fin, type) || !safe_read(fin, count))
|
||||
return false;
|
||||
}
|
||||
return skip_metadata_values(fin, static_cast<GGUFMetadataType>(type), count);
|
||||
}
|
||||
|
||||
GGUFTensorInfo read_tensor_info(std::ifstream& fin) {
|
||||
@ -154,6 +163,7 @@ private:
|
||||
}
|
||||
|
||||
if (n_dims > GGML_MAX_DIMS) {
|
||||
has_wide_tensors_ = true;
|
||||
for (uint32_t i = GGML_MAX_DIMS; i < n_dims; i++) {
|
||||
info.shape[GGML_MAX_DIMS - 1] *= info.shape[i]; // stack to last dim;
|
||||
}
|
||||
@ -174,12 +184,20 @@ private:
|
||||
|
||||
public:
|
||||
bool load(const std::string& file_path) {
|
||||
std::ifstream fin(file_path, std::ios::binary);
|
||||
std::ifstream fin(file_path, std::ios::binary | std::ios::ate);
|
||||
if (!fin) {
|
||||
LOG_ERROR("failed to open '%s'", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::streamoff file_size = fin.tellg();
|
||||
if (file_size < 0)
|
||||
return false;
|
||||
remaining_bytes_ = static_cast<uint64_t>(file_size);
|
||||
fin.seekg(0, std::ios::beg);
|
||||
if (!fin.good())
|
||||
return false;
|
||||
|
||||
// --- Header ---
|
||||
char magic[4];
|
||||
if (!safe_read(fin, magic, 4) || strncmp(magic, "GGUF", 4) != 0) {
|
||||
@ -228,6 +246,8 @@ public:
|
||||
}
|
||||
|
||||
const std::vector<GGUFTensorInfo>& tensors() const { return tensors_; }
|
||||
|
||||
bool has_tensors_beyond_ggml_limits() const { return has_wide_tensors_; }
|
||||
size_t data_offset() const { return data_offset_; }
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user