Merge pull request #5 from silveroxides/feature/resize-with-base

add new LoRA features and up to 4 way LoRA resize+merge node.
This commit is contained in:
Silver
2026-01-12 01:22:46 +01:00
committed by GitHub
4 changed files with 1042 additions and 83 deletions
+9 -1
View File
@@ -25,7 +25,10 @@ from .nodes.lora_extract_svd import (
)
from .nodes.lora_resize import (
LoRAResizeFixed, LoRAResizeRatio,
LoRAResizeFrobenius, LoRAResizeCumulative
LoRAResizeFrobenius, LoRAResizeCumulative,
LoRAResizeViaBaseFixed, LoRAResizeViaBaseRatio,
LoRAResizeViaBaseFrobenius, LoRAResizeViaBaseCumulative,
LoRAMultiMerge
)
@@ -54,6 +57,11 @@ class ModelUtilsExtension(ComfyExtension):
# LoRA Resize
LoRAResizeFixed, LoRAResizeRatio,
LoRAResizeFrobenius, LoRAResizeCumulative,
# LoRA Fast Resize (via base model)
LoRAResizeViaBaseFixed, LoRAResizeViaBaseRatio,
LoRAResizeViaBaseFrobenius, LoRAResizeViaBaseCumulative,
# LoRA Multi-Merge
LoRAMultiMerge,
]
+25
View File
@@ -294,3 +294,28 @@ ComfyUI-ModelUtils/
| Metadata reading | **100x+** (header only) |
| Parallel I/O | **2-4x** (ThreadPoolExecutor) |
| Memory management | Auto-unload models before heavy ops |
| **LoRA Resize Fast** | **~91x** (merge-to-base extraction) |
---
## Phase 13: Fast LoRA Resize (2026-01-11)
### Summary
Added fast LoRA resize via base model extraction path, achieving ~91x speedup.
### Changes
- Added `resize_lora_via_base()` function using extraction code path
- Added 4 new fast resize nodes requiring base model input
### Files Modified
| File | Changes |
|------|---------|
| `nodes/lora_resize.py` | Added `resize_lora_via_base()`, 4 new node classes |
| `__init__.py` | Registered new nodes |
### New Nodes
- `LoRAResizeViaBaseFixed` - Fast fixed rank resize
- `LoRAResizeViaBaseRatio` - Fast SV ratio resize
- `LoRAResizeViaBaseFrobenius` - Fast Frobenius resize
- `LoRAResizeViaBaseCumulative` - Fast cumulative resize
+998 -72
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -28,23 +28,23 @@ except ImportError:
class PinnedTensor:
"""Context manager for automatic pinned memory management.
Usage:
with PinnedTensor(cpu_tensor) as pinned:
gpu_tensor = pinned.to('cuda')
# Memory automatically unpinned after transfer
"""
def __init__(self, tensor: torch.Tensor, auto_pin: bool = True):
self.tensor = tensor
self.is_pinned = False
self.auto_pin = auto_pin and PINNING_AVAILABLE
def __enter__(self) -> torch.Tensor:
if self.auto_pin and self.tensor.device.type == 'cpu':
self.is_pinned = pin_memory(self.tensor)
return self.tensor
def __exit__(self, exc_type, exc_val, exc_tb):
if self.is_pinned:
unpin_memory(self.tensor)
@@ -57,12 +57,12 @@ def transfer_to_gpu_pinned(
dtype: Optional[torch.dtype] = None
) -> torch.Tensor:
"""Transfer tensor to GPU using pinned memory for faster transfer.
Args:
tensor: CPU tensor to transfer
device: Target GPU device
dtype: Optional dtype conversion
Returns:
Tensor on GPU device
"""
@@ -71,7 +71,7 @@ def transfer_to_gpu_pinned(
if dtype:
return tensor.to(device=device, dtype=dtype)
return tensor.to(device=device)
# Pin memory for faster transfer
was_pinned = pin_memory(tensor)
try:
@@ -162,7 +162,7 @@ class MemoryEfficientSafeOpen:
tensor_bytes = self.file.read(offset_end - offset_start)
return self._deserialize_tensor(tensor_bytes, metadata)
def get_tensor_to_gpu(
self,
key: str,
@@ -170,12 +170,12 @@ class MemoryEfficientSafeOpen:
dtype: Optional[torch.dtype] = None
) -> torch.Tensor:
"""Load a tensor and transfer to GPU using pinned memory for faster transfer.
Args:
key: Tensor key to load
device: Target GPU device (default 'cuda')
dtype: Optional dtype conversion
Returns:
Tensor on GPU device
"""