Show more information about LoRAs when loading loras in generate page
This commit is contained in:
1 parent
ef8110cef7
commit
1db6083645
2 files changed
+46
-8
No files matched your search
@@ -152,6 +152,9 @@ class InferenceLoRA:
|
|||||||
self.name = name or os.path.splitext(os.path.basename(path))[0]
|
self.name = name or os.path.splitext(os.path.basename(path))[0]
|
||||||
self.entries: List[LoRAEntry] = []
|
self.entries: List[LoRAEntry] = []
|
||||||
self.unmatched: List[str] = []
|
self.unmatched: List[str] = []
|
||||||
|
self.num_keys = 0 # tensors in the file
|
||||||
|
self.num_skipped_keys = 0 # keys with no recognized lora/diff/lokr suffix
|
||||||
|
self.convert_error: Optional[str] = None
|
||||||
self._hooks: List = []
|
self._hooks: List = []
|
||||||
|
|
||||||
# ---- loading / key resolution ----
|
# ---- loading / key resolution ----
|
||||||
@@ -163,18 +166,23 @@ class InferenceLoRA:
|
|||||||
# self.path stays as given: it is the spec identity the engine keys its
|
# self.path stays as given: it is the spec identity the engine keys its
|
||||||
# loaded stack on.
|
# loaded stack on.
|
||||||
self.local_path = resolve_lora_file(self.path, status_fn=status_fn)
|
self.local_path = resolve_lora_file(self.path, status_fn=status_fn)
|
||||||
|
if status_fn:
|
||||||
|
status_fn(f"Loading LoRA {self.name} from {self.local_path}")
|
||||||
sd = load_file(self.local_path)
|
sd = load_file(self.local_path)
|
||||||
|
self.num_keys = len(sd)
|
||||||
convert = getattr(holder, "convert_lora_weights_before_load", None)
|
convert = getattr(holder, "convert_lora_weights_before_load", None)
|
||||||
if callable(convert):
|
if callable(convert):
|
||||||
try:
|
try:
|
||||||
sd = convert(sd)
|
sd = convert(sd)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
pass
|
self.convert_error = f"{type(e).__name__}: {e}"
|
||||||
roots = self._roots(holder)
|
roots = self._roots(holder)
|
||||||
grouped: Dict[Tuple[int, str], dict] = {}
|
grouped: Dict[Tuple[int, str], dict] = {}
|
||||||
|
self.num_skipped_keys = 0
|
||||||
for key, tensor in sd.items():
|
for key, tensor in sd.items():
|
||||||
base, part = self._split(key)
|
base, part = self._split(key)
|
||||||
if part is None:
|
if part is None:
|
||||||
|
self.num_skipped_keys += 1
|
||||||
continue
|
continue
|
||||||
grouped.setdefault(base, {})[part] = tensor
|
grouped.setdefault(base, {})[part] = tensor
|
||||||
self.entries = []
|
self.entries = []
|
||||||
@@ -378,6 +386,35 @@ class InferenceLoRA:
|
|||||||
m_marker = getattr(self, "_marker", None)
|
m_marker = getattr(self, "_marker", None)
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
|
def report(self, max_unmatched: Optional[int] = None) -> str:
|
||||||
|
"""Multi-line load report: file, key counts, matched/unmatched modules, unmatched names."""
|
||||||
|
n_groups = len(self.entries) + len(self.unmatched)
|
||||||
|
lines = [
|
||||||
|
f"LoRA {self.name}: {self.local_path or self.path}",
|
||||||
|
f" {self.num_keys} keys in file -> {n_groups} modules: {len(self.entries)} matched, {len(self.unmatched)} unmatched"
|
||||||
|
+ (f", {self.num_skipped_keys} keys ignored (unrecognized suffix)" if self.num_skipped_keys else ""),
|
||||||
|
]
|
||||||
|
if self.convert_error:
|
||||||
|
lines.append(f" convert_lora_weights_before_load failed, using raw keys: {self.convert_error}")
|
||||||
|
shown = self.unmatched if max_unmatched is None else self.unmatched[:max_unmatched]
|
||||||
|
for u in shown:
|
||||||
|
lines.append(f" unmatched: {u}")
|
||||||
|
if len(shown) < len(self.unmatched):
|
||||||
|
lines.append(f" ... {len(self.unmatched) - len(shown)} more unmatched")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def report_line(self, max_unmatched: int = 5) -> str:
|
||||||
|
"""One-line form of report() for status strips."""
|
||||||
|
n_groups = len(self.entries) + len(self.unmatched)
|
||||||
|
line = f"LoRA {self.name}: {len(self.entries)}/{n_groups} modules matched ({self.num_keys} keys)"
|
||||||
|
if self.unmatched:
|
||||||
|
shown = ", ".join(self.unmatched[:max_unmatched])
|
||||||
|
more = len(self.unmatched) - max_unmatched
|
||||||
|
line += f"; {len(self.unmatched)} unmatched: {shown}" + (f" +{more} more" if more > 0 else "")
|
||||||
|
if self.convert_error:
|
||||||
|
line += f"; convert failed: {self.convert_error}"
|
||||||
|
return line
|
||||||
|
|
||||||
def summary(self) -> dict:
|
def summary(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
@@ -404,13 +441,14 @@ class LoRAStack:
|
|||||||
lora = InferenceLoRA(spec["path"], spec.get("strength", 1.0), spec.get("name")).load(
|
lora = InferenceLoRA(spec["path"], spec.get("strength", 1.0), spec.get("name")).load(
|
||||||
self.holder, status_fn=status_fn
|
self.holder, status_fn=status_fn
|
||||||
)
|
)
|
||||||
|
print(f"[AITK] {lora.report()}", flush=True)
|
||||||
if status_fn:
|
if status_fn:
|
||||||
status_fn(
|
status_fn(lora.report_line())
|
||||||
f"LoRA {lora.name}: {len(lora.entries)} modules"
|
|
||||||
+ (f", {len(lora.unmatched)} unmatched" if lora.unmatched else "")
|
|
||||||
)
|
|
||||||
if not lora.entries:
|
if not lora.entries:
|
||||||
raise ValueError(f"LoRA {lora.name} matched no modules of this model (unmatched: {lora.unmatched[:3]})")
|
raise ValueError(
|
||||||
|
f"LoRA {lora.name} matched no modules of this model "
|
||||||
|
f"({lora.num_keys} keys, {len(lora.unmatched)} unmatched; see the engine job log for the list)"
|
||||||
|
)
|
||||||
self.loras.append(lora)
|
self.loras.append(lora)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -823,7 +823,7 @@ function GeneratePageInner() {
|
|||||||
{/* status strip over the stage */}
|
{/* status strip over the stage */}
|
||||||
<div className="absolute top-0 left-0 right-0 z-10 px-3 py-1.5 flex items-center gap-2 text-xs text-gray-300 bg-gradient-to-b from-gray-950/80 to-transparent">
|
<div className="absolute top-0 left-0 right-0 z-10 px-3 py-1.5 flex items-center gap-2 text-xs text-gray-300 bg-gradient-to-b from-gray-950/80 to-transparent">
|
||||||
{running && <Loader2 className="w-3.5 h-3.5 animate-spin text-blue-400" />}
|
{running && <Loader2 className="w-3.5 h-3.5 animate-spin text-blue-400" />}
|
||||||
<span className="truncate">
|
<span className="truncate" title={running ? statusLine : undefined}>
|
||||||
{running
|
{running
|
||||||
? statusLine
|
? statusLine
|
||||||
: selected
|
: selected
|
||||||
|
|||||||
Reference in new issue
Block a user