perf(lora): oversample the hosted-factor sketch to near-exact svd

Sketch hosted deltas at rank+64 with eight power iterations and keep the
top rank columns; this lands within noise of the exact decomposition at
roughly twice a sketch cost the factor cache pays once per configuration.
Bump the cache format so narrower-sketch entries reload as misses.
This commit is contained in:
CalamitousFelicitousness
2026-07-18 01:25:03 +01:00
parent 03dfddaa96
commit 74e68b58ce
3 changed files with 7 additions and 5 deletions
+2 -2
View File
@@ -96,7 +96,7 @@ def begin_pass(wanted_names):
from safetensors import safe_open
with safe_open(path, framework='pt', device='cpu') as f:
meta = f.metadata() or {}
if meta.get('sig') == sig and meta.get('fmt') == '2':
if meta.get('sig') == sig and meta.get('fmt') == '3':
for k in f.keys():
entries[k] = f.get_tensor(k)
os.utime(path, None) # freshness for LRU eviction
@@ -190,7 +190,7 @@ def flush():
from safetensors.torch import save_file
os.makedirs(cache_root, exist_ok=True)
tmp = state['path'] + '.tmp'
save_file(state['store'], tmp, metadata={'sig': state['sig'], 'fmt': '2'})
save_file(state['store'], tmp, metadata={'sig': state['sig'], 'fmt': '3'})
os.replace(tmp, state['path'])
evict()
except Exception as e:
+3 -1
View File
@@ -274,7 +274,9 @@ def apply_hosted(self, network_layer_name, updown, wanted_names, use_previous=Fa
# svd_lowrank draws random projections; fork so user generation seeds are untouched and re-applies are deterministic
with torch.random.fork_rng(devices=[D.device] if D.device.type == 'cuda' else []):
torch.manual_seed(0)
U, S, V = torch.svd_lowrank(D, q=q, niter=4)
# oversampled sketch with extra power iterations lands within noise of exact svd; only the top q columns are kept
U, S, V = torch.svd_lowrank(D, q=min(q + 64, *D.shape), niter=8)
U, S, V = U[:, :q], S[:q], V[:, :q]
energy = float(S.square().sum() / D.square().sum().clamp(min=1e-30)) # captured fraction, in the weighted domain when calibrated
up_h = (U * S).to(dtype=dtype)
down_h = V.t()