File size: 5,283 Bytes
96db1c1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd7c6d9..a4938ae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -417,3 +417,9 @@ configure_file(cmake/stable-diffusion.pc.in
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/stable-diffusion.pc"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+# ROCmFPX: build against the ROCmFPX fork of ggml (adds ROCmFP4/ROCmFPX quant types)
+option(SD_ROCMFPX "sd: ggml is the ROCmFPX fork; force-include API shims" OFF)
+if(SD_ROCMFPX)
+ target_compile_options(stable-diffusion PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/rfx_compat.h)
+endif()
diff --git a/include/stable-diffusion.h b/include/stable-diffusion.h
index 267e7a7..ace983e 100644
--- a/include/stable-diffusion.h
+++ b/include/stable-diffusion.h
@@ -144,7 +144,15 @@ enum sd_type_t {
SD_TYPE_Q2_0 = 42,
SD_TYPE_F8_E4M3 = 43,
SD_TYPE_F8_E5M2 = 44,
- SD_TYPE_COUNT = 45,
+ // ROCmFPX fork of ggml (github.com/charlie12345/ROCmFPX); ids match its ggml_type
+ SD_TYPE_Q4_0_ROCMFP4 = 100,
+ SD_TYPE_Q4_0_ROCMFP4_FAST = 101,
+ SD_TYPE_Q6_0_ROCMFPX = 102,
+ SD_TYPE_Q8_0_ROCMFPX = 103,
+ SD_TYPE_Q3_0_ROCMFPX = 104,
+ SD_TYPE_Q2_0_ROCMFPX = 107,
+ SD_TYPE_Q4_0_ROCMI4 = 108,
+ SD_TYPE_COUNT = 109,
};
enum sd_log_level_t {
diff --git a/src/model_io/gguf_io.cpp b/src/model_io/gguf_io.cpp
index 8120131..1337dbb 100644
--- a/src/model_io/gguf_io.cpp
+++ b/src/model_io/gguf_io.cpp
@@ -167,6 +167,17 @@ bool GGUFStreamingWriter::write_metadata(const std::string& file_path,
return false;
}
+ const bool is_moss_image = std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) {
+ return tensor.name == "video_embedder.bias";
+ }) && std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) {
+ return tensor.name == "layers.0.proj.q.weight";
+ }) && std::any_of(tensors.begin(), tensors.end(), [](const TensorWritePlan& tensor) {
+ return tensor.name == "final_linear_video.weight";
+ });
+ if (is_moss_image) {
+ gguf_set_val_str(gguf_ctx_, "general.architecture", "moss_image");
+ }
+
for (const TensorWritePlan& plan : tensors) {
ggml_tensor* tensor = ggml_new_tensor(meta_ctx_, plan.type, plan.n_dims, plan.ne);
if (tensor == nullptr) {
diff --git a/src/model_loader.cpp b/src/model_loader.cpp
index 8822b2c..a677baa 100644
--- a/src/model_loader.cpp
+++ b/src/model_loader.cpp
@@ -1605,6 +1605,10 @@ bool ModelLoader::tensor_should_be_converted(const TensorStorage& tensor_storage
if (tensor_storage.is_int8_tensorwise) {
return false;
}
+ if (type == GGML_TYPE_F32 && tensor_storage.type != GGML_TYPE_F32) {
+ // widening to F32 is lossless and keeps element-wise ops valid (e.g. BF16 adaLN tables in LTX-2.5)
+ return true;
+ }
if (type != GGML_TYPE_COUNT) {
if (ggml_is_quantized(type) && tensor_storage.ne[0] % ggml_blck_size(type) != 0) {
// Pass, do not convert
diff --git a/src/name_conversion.cpp b/src/name_conversion.cpp
index 6a519ba..e1ecdef 100644
--- a/src/name_conversion.cpp
+++ b/src/name_conversion.cpp
@@ -1696,6 +1696,13 @@ std::string convert_tensor_name(std::string name, SDVersion version) {
replace_with_prefix_map(name, prefix_map);
if (version == VERSION_MOSS_IMAGE) {
+ // The official Diffusers MOSS checkpoint stores Qwen3.5 under
+ // `language_model.*`, while the internal LLM runner uses `model.*`.
+ // GGUF Qwen3.5 checkpoints already use the latter namespace.
+ const std::string hf_language_model_prefix = "text_encoders.llm.language_model.";
+ if (starts_with(name, hf_language_model_prefix)) {
+ name = "text_encoders.llm.model." + name.substr(hf_language_model_prefix.size());
+ }
const std::string te_prefix = "text_encoders.llm.";
if (starts_with(name, te_prefix + "blk.")) {
static const std::vector<std::pair<std::string, std::string>> qwen35_name_map = {
diff --git a/src/stable-diffusion.cpp b/src/stable-diffusion.cpp
index 1cc4c09..50566f5 100644
--- a/src/stable-diffusion.cpp
+++ b/src/stable-diffusion.cpp
@@ -48,7 +48,7 @@ enum sd_type_t str_to_sd_type(const char* str) {
}
for (int i = 0; i < std::min<int>(SD_TYPE_COUNT, GGML_TYPE_COUNT); i++) {
auto trait = ggml_get_type_traits((ggml_type)i);
- if (!strcmp(str, trait->type_name)) {
+ if (trait->type_name != nullptr && !strcmp(str, trait->type_name)) {
return (enum sd_type_t)i;
}
}
diff --git a/rfx_compat.h b/rfx_compat.h
new file mode 100644
index 0000000..eb36d34
--- /dev/null
+++ b/rfx_compat.h
@@ -0,0 +1,13 @@
+// shims so stable-diffusion.cpp builds against the ROCmFPX fork of ggml (older API)
+#pragma once
+#include "ggml.h"
+#ifdef __cplusplus
+static inline bool ggml_prec_set_acc(struct ggml_tensor * a, enum ggml_prec prec) {
+ switch (a->op) {
+ case GGML_OP_MUL_MAT:
+ case GGML_OP_MUL_MAT_ID: a->op_params[0] = (int32_t) prec; return true;
+ case GGML_OP_FLASH_ATTN_EXT: a->op_params[3] = (int32_t) prec; return true;
+ default: return false;
+ }
+}
+#endif
|