Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ggml
Submodule ggml updated from 7d9ce1 to 93c657
86 changes: 84 additions & 2 deletions src/core/ggml_extend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
#include <inttypes.h>
#include <stdarg.h>
#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <atomic>
#include <cstring>
#include <fstream>
#include <functional>
Expand All @@ -21,6 +21,7 @@
#include <set>
#include <sstream>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>
#include <vector>
Expand All @@ -43,6 +44,52 @@

#define EPS 1e-05f

// Select the compact representation before any model parameter tensor is
// created. The default is deliberately native: an unsupported backend is a
// configuration error rather than a silent CPU reroute or full F16 expansion.
// Set SD_CONVROT_MODE=compat to explicitly request the compatibility loader.
inline String2TensorStorage select_convrot_tensor_storage(ggml_backend_t backend,
const String2TensorStorage& source,
const std::string& component) {
// OrderedMap's default copy also copies its iterator index; rebuild it so
// this independent policy view owns a valid index into its own list.
String2TensorStorage selected;
bool has_convrot = false;
for (const auto& [name, storage] : source) {
selected.insert({name, storage});
has_convrot = has_convrot || storage.is_comfy_int8_convrot_weight();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major: scope ConvRot preflight to the component being initialized. source is the shared model storage map, and this scan treats a ConvRot weight anywhere in it as a requirement for the current runner's backend. For example, floating-point text-encoder weights assigned to CUDA are rejected when only the diffusion component, assigned to CPU, contains ConvRot weights. The component argument currently changes only the message. Please pass the runner's parameter prefix and restrict detection/selection to its tensors, with a mixed-component/backend regression test.

}
if (!has_convrot) {
return selected;
}

const char* mode = std::getenv("SD_CONVROT_MODE");
const bool compatibility_mode = mode != nullptr && std::strcmp(mode, "compat") == 0;
if (mode != nullptr && !compatibility_mode && std::strcmp(mode, "native") != 0) {
throw std::runtime_error("invalid SD_CONVROT_MODE; expected 'native' or 'compat'");
}
const char* backend_name = backend != nullptr ? ggml_backend_name(backend) : "unknown";
if (compatibility_mode) {
LOG_INFO("ConvRot: using explicitly selected F16 compatibility path for %s on backend %s",
component.c_str(), backend_name);
return selected;
}
if (!ggml_backend_supports_convrot(backend, GGML_TYPE_F32, 256)) {
throw std::runtime_error("ConvRot native support is required for " + component +

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major: return configuration failures through the initialization error path. This exception, and the invalid-mode exception above, can propagate from runner construction through StableDiffusionGGML::init() into new_sd_ctx(), which does not catch them. Selecting an unsupported backend or mistyping SD_CONVROT_MODE can therefore escape the C API and bypass its normal cleanup/null-result behavior. Please catch and translate these failures at initialization or use the existing error-return mechanism. This finding is based on tracing the constructor and C-entry-point paths.

" but backend '" + backend_name +
"' lacks the 256-wide I8/F32 ConvRot operation; use a capable backend or set "
"SD_CONVROT_MODE=compat to select the F16 compatibility path");
}
for (auto& [_, storage] : selected) {
if (storage.is_comfy_int8_convrot_weight()) {
storage.comfy_int8_native_enabled = true;
}
}
LOG_INFO("ConvRot: selected native compact I8/F32 path for %s on backend %s",
component.c_str(), backend_name);
return selected;
}

#ifndef __STATIC_INLINE__
#define __STATIC_INLINE__ static inline
#endif
Expand Down Expand Up @@ -3875,12 +3922,31 @@ class Linear : public UnaryBlock {
bool force_prec_f32;
bool allow_weight_scale;
bool has_weight_scale = false;
// This is distinct from `weight_scale`: the latter is a regular
// post-linear model parameter, while ConvRot's F32 vector is a private
// sidecar input to GGML_OP_MUL_MAT_CONVROT.
bool has_convrot_weight = false;
bool use_convrot_f16_compat = false;
float scale;
std::string prefix;

void init_params(ggml_context* ctx, const String2TensorStorage& tensor_storage_map = {}, const std::string prefix = "") override {
this->prefix = prefix;
has_weight_scale = false;
has_convrot_weight = false;
use_convrot_f16_compat = false;
const auto storage_it = tensor_storage_map.find(prefix + "weight");
if (storage_it != tensor_storage_map.end() && storage_it->second.is_comfy_int8_convrot_weight() &&
storage_it->second.comfy_int8_native_enabled) {
params["weight"] = ggml_new_tensor_2d(ctx, GGML_TYPE_I8, in_features, out_features);
params["weight.convrot_scale"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, out_features);
has_convrot_weight = true;
use_convrot_f16_compat = storage_it->second.name.rfind("text_encoders.llm.", 0) == 0;
if (bias) {
params["bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, out_features);
}
return;
}
enum ggml_type wtype = get_type(prefix + "weight", tensor_storage_map, GGML_TYPE_F32);
if (in_features % ggml_blck_size(wtype) != 0 || force_f32) {
wtype = GGML_TYPE_F32;
Expand Down Expand Up @@ -3928,7 +3994,23 @@ class Linear : public UnaryBlock {
}
ggml_tensor* linear_bias = has_weight_scale ? nullptr : b;
ggml_tensor* out = nullptr;
if (ctx->weight_adapter) {
if (has_convrot_weight) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major: preserve or explicitly reject runtime LoRA on native ConvRot layers. This branch bypasses ctx->weight_adapter->forward_with_lora(), so enabling an adapter silently has no effect on these layers. A local probe observed zero adapter calls for a native ConvRot Linear and one for the same layer using compatibility storage. Please apply the adapter contribution with the correct ConvRot semantics, or reject this combination before inference instead of silently dropping it.

// ConvRot weights and their tensor-wise scales remain compact at
// rest. The operator owns the scale semantics; do not route it
// through the ordinary `weight_scale` post-multiply path.
out = ggml_mul_mat_convrot(ctx->ggml_ctx, x, w, params["weight.convrot_scale"], 256);
// MiniMax H3's ConvRot text encoder is calibrated for the F16
// compatibility arithmetic. CUDA reconstructs one F16 matrix at
// a time and uses its standard F16 GEMM without retaining an F16
// copy of the complete text encoder. Other backends may ignore
// this hint and keep their native compact implementation.
if (use_convrot_f16_compat) {
ggml_mul_mat_convrot_set_f16_compat(out, true);
}
if (b != nullptr) {
out = ggml_add_inplace(ctx->ggml_ctx, out, b);
}
} else if (ctx->weight_adapter) {
WeightAdapter::ForwardParams forward_params;
forward_params.op_type = WeightAdapter::ForwardParams::op_type_t::OP_LINEAR;
forward_params.linear.force_prec_f32 = force_prec_f32;
Expand Down
4 changes: 3 additions & 1 deletion src/model/diffusion/minimax_h3.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,9 @@ namespace MiniMaxH3 {
: DiffusionModelRunner(backend, prefix, weight_manager),
config(Config::detect_from_weights(tensors, prefix)),
model(config) {
model.init(params_ctx, tensors, prefix);
model.init(params_ctx,
select_convrot_tensor_storage(backend, tensors, "MiniMax-H3 diffusion model"),
prefix);
}

std::string get_desc() override {
Expand Down
4 changes: 3 additions & 1 deletion src/model/te/llm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,7 +1771,9 @@ namespace LLM {
}
}
model = LLM(config, enable_vision, config.llama_cpp_style);
model.init(params_ctx, tensor_storage_map, prefix);
model.init(params_ctx,
select_convrot_tensor_storage(backend, tensor_storage_map, "LLM"),
prefix);
}

std::string get_desc() override {
Expand Down
Loading
Loading