Files
wehub-resource-sync cddb07a176
build container image / cpu (push) Waiting to run
build container image / cuda (push) Waiting to run
build container image / rocm (push) Waiting to run
frontend tests / frontend-tests (push) Waiting to run
openapi checks / openapi-checks (push) Waiting to run
python tests / py3.12: macos-default (push) Waiting to run
python tests / py3.11: windows-cpu (push) Waiting to run
python tests / py3.12: windows-cpu (push) Waiting to run
python tests / py3.11: linux-cpu (push) Waiting to run
python tests / py3.12: linux-cpu (push) Waiting to run
typegen checks / typegen-checks (push) Waiting to run
uv lock checks / uv-lock-checks (push) Waiting to run
frontend checks / frontend-checks (push) Waiting to run
lfs checks / lfs-check (push) Waiting to run
python checks / python-checks (push) Waiting to run
python tests / py3.11: macos-default (push) Waiting to run
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:22:06 +08:00

84 lines
3.3 KiB
Python

import json
from pathlib import Path
from typing import Any, Optional
import gguf
import torch
from invokeai.backend.model_manager.model_on_disk import ModelOnDisk, StateDict
from invokeai.backend.quantization.gguf.ggml_tensor import GGMLTensor
class StrippedModelOnDisk(ModelOnDisk):
METADATA_KEY = "metadata_key_for_stripped_models"
STR_TO_DTYPE = {str(dtype): dtype for dtype in torch.__dict__.values() if isinstance(dtype, torch.dtype)}
def load_state_dict(self, path: Optional[Path] = None) -> StateDict:
path = self.resolve_weight_file(path)
return self.load_stripped_model(path)
def metadata(self, path: Optional[Path] = None) -> dict[str, str]:
path = self.resolve_weight_file(path)
with open(path, "r") as f:
contents = json.load(f)
return contents.get(self.METADATA_KEY, {})
@classmethod
def strip(cls, v: Any):
match v:
case GGMLTensor():
# GGMLTensor needs special handling to preserve quantization metadata. It is a subclass of torch.Tensor,
# so we need to check for it before checking for torch.Tensor.
return {
"quantized_data": cls.strip(v.quantized_data),
"ggml_quantization_type": v._ggml_quantization_type.name,
"tensor_shape": list(v.tensor_shape),
"compute_dtype": str(v.compute_dtype),
"fakeGGMLTensor": True,
}
case torch.Tensor():
return {"shape": v.shape, "dtype": str(v.dtype), "fakeTensor": True}
case dict():
return {k: cls.strip(v) for k, v in v.items()}
case list() | tuple():
return [cls.strip(x) for x in v]
case _:
return v
@classmethod
def dress(cls, v: Any):
match v:
case {
"quantized_data": quantized_data,
"ggml_quantization_type": qtype_name,
"tensor_shape": tensor_shape,
"compute_dtype": compute_dtype_str,
"fakeGGMLTensor": True,
}:
# Reconstruct the GGMLTensor from stripped data
qtype = gguf.GGMLQuantizationType[qtype_name]
compute_dtype = cls.STR_TO_DTYPE[compute_dtype_str]
dressed_quantized_data = cls.dress(quantized_data)
return GGMLTensor(
data=dressed_quantized_data,
ggml_quantization_type=qtype,
tensor_shape=torch.Size(tensor_shape),
compute_dtype=compute_dtype,
)
case {"shape": shape, "dtype": dtype_str, "fakeTensor": True}:
dtype = cls.STR_TO_DTYPE[dtype_str]
return torch.empty(shape, dtype=dtype, device="meta")
case dict():
return {k: cls.dress(v) for k, v in v.items()}
case list() | tuple():
return [cls.dress(x) for x in v]
case _:
return v
@classmethod
def load_stripped_model(cls, path: Path, *args, **kwargs):
with open(path, "r") as f:
contents = json.load(f)
contents.pop(cls.METADATA_KEY, None)
return cls.dress(contents)