225 Commits

Author SHA1 Message Date
CalamitousFelicitousness c67b4f499f fix(lora): read the pdd grid from the file header when the cache lacks it
The metadata cache keeps a failed read forever and --no-metadata returns
nothing, and in both cases the head loader returned None silently while
the backbone still applied. The grid is now read from the file's own
header when the cached metadata lacks it, and head-shaped tensors
without a grid log a warning.
2026-09-16 19:26:21 +01:00
Vladimir Mandic 059ccbaf0b Merge pull request #5091 from CalamitousFelicitousness/feat/lora-pdd
feat(lora): parallel decoding heads and minimax schedule controls
2026-09-16 07:45:57 +02:00
CalamitousFelicitousness b259a48448 fix(lora): give replaced pdd projections their own memory
The projection a parallel head replaces waits out of the module tree,
so nothing moves it, and a weight still viewing its checkpoint shard
keeps the whole shard mapped. The stash now clones the projection's
tensors.
2026-09-16 03:23:03 +01:00
CalamitousFelicitousness 09e861157f fix(offload): hand back the loaded cpu tensors on no-stream offload
Group hooks on the no-stream path and the on-demand hook return a
component to cpu through a device copy, so a memory-mapped text encoder
sits in memory twice, as the mapped file its never-run vision tower
keeps alive and as the copies, and every encode pays a device-to-host
transfer of unchanged weights. The engine now records the cpu tensors
at onload and hands them back at offload; a component moved by any
other path still takes the copy.
2026-09-16 01:57:23 +01:00
CalamitousFelicitousness 726907dd5b fix(video): count minimax steps as transformer evaluations
MiniMaxH3Scheduler counts the terminal sigma in num_inference_steps, so
Steps N ran N-1 evaluations while every other model runs N. The shim
hands the scheduler p.steps + 1, the slider starts at 1, and the PDD
pin records the evaluation count while passing the scheduler its grid
argument. Metadata written before this change counted grid points.
2026-09-16 00:47:46 +01:00
CalamitousFelicitousness 29fe895c0b feat(video): absolute per-request minimax shift on every path
Shift is a property of the trained schedule, not of the step count, so
the tab sliders take absolute values, defaulting to the shipped 12 and
3. video_minimax resolves each request from the request value or the
scheduler config inside apply_overrides, which the tab, the api and
the still path all call, so a request without values lands on the
shipped schedule. The api maps sampler_shift onto the video schedule
and gains audio_shift. Applied values are recorded as Video shift and
Audio shift; the PDD pin records what it enforces.
2026-09-15 23:01:41 +01:00
CalamitousFelicitousness 57328dc615 fix(lora): bind minimax extraction residuals
Layer-wise extractions (FastH3) ship diff_b on every projection and
diff on the norms; final_layer.norm had no rename onto norm_out.norm,
so its residual went unmapped.
2026-09-15 03:52:04 +01:00
CalamitousFelicitousness a800fe59cf fix(lora): accept lowercase lora_a and lora_b factor names
TaoLive adapters save the factors as lora_a and lora_b without the
.weight suffix, which no suffix table knew, so the file bound nothing.
2026-09-15 03:52:04 +01:00
CalamitousFelicitousness a0f0097e52 refactor(lora): make the fused chunk slicer public
The fidelity CLI slices fused saves the way try_load_lora does.
2026-09-15 03:52:04 +01:00
CalamitousFelicitousness 5860ea9153 feat(lora): parallel decoding heads for pdd acceleration files
PDD files pair a backbone LoRA with the output projections repeated per
interval of a training grid; each step fuses the heads of its block
into one projection. network_pdd reads the grid from the metadata,
swaps a ParallelHead in for each projection, fuses from the scheduler's
step_index and pins the step count and shift while heads are
installed. The MiniMax loader declares which scheduler each head
follows.
2026-09-15 00:23:27 +01:00
CalamitousFelicitousness 3e705bc4af feat(lora): project adaln deltas onto the pruned minimax basis
The pruned transformer stores W @ P for each AdaLN projection against
the rank-8 basis in time_embedder.basis, so deltas trained at the
released width failed the shape check. try_load_lora gains an
adapt_weights hook and the MiniMax loader refits lora_down as down @ P,
which is exact.
2026-09-15 00:23:09 +01:00
CalamitousFelicitousness 6d5c63d9fe fix(hashes): snapshot the stores under a lock before saving the cache
save_cache handed writefile the live HashStore objects, so an add_hash
from another thread during the deep copy raised "dictionary changed
size during iteration" and dropped the save. The stores are now copied
under a lock that also covers the write, so a later save never lands
under an earlier snapshot.
2026-09-13 20:35:37 +01:00
CalamitousFelicitousness 68c64fb4bc fix(json_helpers): write atomically by default and warn on empty reads
Every caller writes a whole JSON document, and a plain open/write can
leave a torn or empty file when the process dies or another writer
overlaps, which readfile then returns as {}. Writes now go through the
temp file and replace unless atomic=False or the mode is append. A read
waits out an open that Windows refuses while a replace of the same name
is in flight, and an empty file is reported when the read is not
silent, since a zero-byte config.json otherwise resets settings without
a trace.
2026-09-13 19:20:10 +01:00
CalamitousFelicitousness b39639ce2e fix(json_helpers): serialize file access per path within the process
The fasteners lock is inter-process only. On Linux fcntl record locks
belong to the process, so two threads writing the same file were never
serialized and could tear it; on Windows they were, until the lock
switched itself off. Every writer of these files runs inside one
multi-threaded process, so that is the case that matters.

readfile(lock=True) and writefile now take a re-entrant lock per
normalized path, held from the snapshot through the replace so writes
to one path land in call order. Other processes are covered by the
atomic replace. A .lock file left next to a JSON file by the old lock
is removed the first time that path is used.
2026-09-13 19:20:10 +01:00
CalamitousFelicitousness cdc76c25c6 fix(json_helpers): make atomic saves work on windows, keep lock file
writefile(atomic=True) renamed the temp file while it was still open,
which Windows refuses, so every atomic save failed there and left a temp
file behind. The temp file is now created with mkstemp, closed before
os.replace and removed when the save fails; the replace retries briefly
when another handle holds the target, which Windows reports as a
permission error.

Both helpers removed the .lock file after releasing it. That removal
raced other holders on both platforms, and any failure switched locking
off for the whole process without a log line. The lock file now stays in
place; a failed release or a lock timeout is logged instead.

writefile deep-copied and validated the live object in Python, so a
concurrent insert into a shared dict raised "dictionary changed size
during iteration" and dropped the save. dict.copy and list.copy run
under the GIL, so the deep copy and the per-key validation now walk that
snapshot; nested containers remain the caller's responsibility.

test/test-json-helpers.py covers all three on Linux and Windows.
2026-09-13 18:41:33 +01:00
Vladimir Mandic da5d934f1f Merge branch 'dev' into feat/filter-sampler-upscaler-choices 2026-09-13 07:41:53 +02:00
Yifan Chen bae986e90b address selection filter review feedback 2026-09-12 00:08:08 -07:00
CalamitousFelicitousness 619a25eea6 fix(offload): key the group stats report by component
A checkpoint-name key survives unload, so a reload of the same checkpoint
never printed the per-module stats block again, even with a different
quantization. Each component now carries its own reported stamp: a task
switch rebuilds the pipe around the same modules and stays quiet, while a
reload or a component swap brings new modules and reports them.
2026-09-07 22:35:38 +01:00
CalamitousFelicitousness 8619dbc0af test(offload): address the split offload modules in the placement role tests
The group offload functions live in sd_offload_group, sd_offload_utils and
sd_offload_state rather than modules.sd_offload, so the tests and their
monkeypatches now import and patch those modules directly.
2026-09-07 22:32:54 +01:00
Yifan Chen a174e94183 feat(ui): filter generated sampler and upscaler lists 2026-09-07 08:29:37 -07:00
CalamitousFelicitousness b434eb0c1b refactor(lora): route every bare key through the resolver
The parser no longer takes reference-name prefixes to tell bare
reference keys from bare diffusers keys. Any bare key carries the
sentinel and the arch resolver renames what it knows and passes the rest
through. Flux2 keeps its list for file-format detection only.
2026-09-06 04:25:44 +01:00
CalamitousFelicitousness 783b66c3be refactor(lora): offer unknown bare keys to the resolver
A bare key that matches no known prefix is parsed with the
bare-diffusers sentinel and handed to the resolver instead of being
dropped at parse time. The per-arch lists of bare diffusers prefixes are
gone, and a path that names no live module counts as unmapped.
2026-09-06 04:25:44 +01:00
CalamitousFelicitousness 1c91fb2047 refactor(lora): make the fused row reorder a chunk capability
A ChunkSpec can reorder equal row blocks of the rows it selects, so an
arch declares a swapped SwiGLU projection on the target instead of
permuting the state dict first. Only the LoRA family applies it; the
others skip a reordered target with a warning.
2026-09-06 04:25:44 +01:00
CalamitousFelicitousness 4a5dc98cb2 fix(lora): match the diffusers minimax lora converter
The reference fc1 is a fused [gate; value] SwiGLU projection and the
diffusers port stores [value; gate]. The native mapping did not swap the
halves, so gate and value deltas landed on each other's rows. The
mapping now also renames the standalone projections, reads a
metadata-only alpha, and accepts the musubi, peft dit and diffusers-named
layouts.
2026-09-06 04:25:44 +01:00
CalamitousFelicitousness cd88d2ae34 fix(lora): route codebook layers on the mean level gap
SDNQ codebook layers keep their Lloyd levels in the scale slot, so reading
scale.mean() as the grid step returned the levels' near-zero mean and sent
sub-step deltas to requantize, where the grid erases them. grid_step returns
the mean adjacent-level gap for those layers and the plain scale mean otherwise.
2026-09-05 18:39:04 +01:00
CalamitousFelicitousness 5875cdd29e feat(lora): remap anima 1.0 lora block indices onto depth-expanded checkpoints
Anima 2.9B interleaves twelve new blocks among the 28 of Anima 1.0, so a block
index trained against 1.0 names a different block on the expanded model. Every
such key still resolves, since blocks 0 to 27 exist either way, so the
mismatch was silent. The Anima loader now shifts base-depth indices onto the
blocks that carry those weights, keyed by (base depth, expanded depth) and
applied only when the transformer is expanded and the LoRA stays inside the
base depth. Transformer keys move; llm_adapter and text encoder keys keep
their own numbering.
2026-09-05 02:24:04 +01:00
CalamitousFelicitousness 6b92f2ba03 feat(model): add anima 2.9b as a base reference model
Anima-2.9B is a depth-expanded finetune of Anima 1.0 Base carrying 40
transformer blocks against the base repo's 28. The reference entry points at
the Diffusers conversion. Single-file releases load through the native loader:
TransformerSpec gains an infer_config hook, the Anima spec uses it to size
num_layers to the block indices in the file, and model_anima routes a
checkpoint-selected safetensors through the loader with the remaining
components from the base repo.
2026-09-05 01:45:49 +01:00
nan f895b72863 Fix VDM trailing timestep spacing 2026-09-02 00:13:20 +08:00
CalamitousFelicitousness 35b935204b test(lora): assert every dispatched arch is native eligible
Two tables decide the native path: one says which architectures may take
it, the other says which loader they get. An entry in the second without
one in the first is a loader nothing can reach, and nothing checked that.
2026-08-30 06:23:07 +01:00
CalamitousFelicitousness 4886761980 fix(lora): finish the activation pass when it aborts
The error limiter halts a pass by raising, and nothing between the raise
and the caller put the model back. A halted pass left group offload hooks
stripped from every component the walk had reached, left a sequential
model on the cpu with offload disabled, and left the counters other
modules read describing the pass before it.

The epilogue moves into finish_pass under a finally, so the model returns
to its offload mode and the counters describe the pass that just ran. The
abort still reaches the caller.

Pass state is reset in one place in lora_sdnq now. Two of the six
accumulators were not being cleared at the start of a pass, and a stale
routed layer suppresses the fallback count for that layer next time.
2026-08-30 06:22:43 +01:00
CalamitousFelicitousness 3f86973bc6 refactor(lora): split the activation ladder into atomic mechanisms
The per-module walk carried four mechanisms inline, each repeating the
same tail: count the layer, stamp the pair that marks it current, advance
the bar, continue. Five copies of that tail and three of the backup probe
put the deepest arm nine levels in.

Each mechanism is now a function that either takes the layer or declines
to the next, and the walk reads as the four of them in order. The pass
state they share moves onto one object built before the walk starts, with
the accept tail, the stamp and the bar tick as its methods. That takes
network_activate from 218 lines to 55, none of it deeper than the module
loop.

Two shapes are deliberately not folded into that tail: the weight path
counts weights and bias separately and tracks what the module refused,
and the factor-strip restore stamps without counting. Hosting hands a
declined delta back rather than leaving it in a flag, so a pair of Nones
still reads as assembled and no layer is calculated twice.
2026-08-30 06:21:13 +01:00
CalamitousFelicitousness 88d263ba14 fix(lora): let stack degradation warnings recur after a settings change
The keys that mark a degradation as reported lived for the life of the
process, so a user who saw "flip=skipped weight=offloaded", changed the
offload mode and hit the same wall again was told nothing the second
time. Tie the set to the settings the warnings speak about: the stack
signature, the offload mode, the host rank and the checkpoint. Repeating
under one context still says it once.
2026-08-30 06:04:09 +01:00
CalamitousFelicitousness 2db573d283 fix(lora): bind 4-d oft files to the boft module type
The generic loader never offered a file to the boft type, so butterfly
OFT adapters reached the oft type instead, which claims any oft_blocks
key without checking its rank and then reads the block count as the lora
dim. Register boft ahead of oft; files with 3-d blocks still land on oft.
2026-08-30 06:04:02 +01:00
CalamitousFelicitousness fd2e082be5 fix(lora): keep the loaded-network type contract under nunchaku
The nunchaku path replaced the loaded network list with the on-disk
entries it composed from, so reading a loaded network back hit an object
without the fields it expects: choosing the reported method reads
len(net.modules) and raised on every set change, costing that generation
its infotext and trigger tags. The adapter was already composed by then,
so the image was unaffected. Wrap the composed set in Network objects
and mutate the list in place.
2026-08-30 06:03:54 +01:00
Vladimir Mandic 62bedf8834 update attention handlers and settings
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2026-08-29 13:05:20 +02:00
Vladimir Mandic da856522a8 Merge branch 'dev' into feat/lora-sdnq-stack 2026-08-29 09:46:42 +02:00
CalamitousFelicitousness 5cfa07fb5e test(lora): extend apply-method coverage to select riding
The mechanism gate tests assert select_candidate declines under
requantize, and the apply-method hint names the cache option among
those the requantize choice disables.
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 999224e91a test(lora): pin the upstream fixes in the campaign suite
The in-place weight installs, the promote-after-deactivate fuse
ordering, and the dynamo reset at model unload live in the shared
loader code; their regression pins belong in the campaign suite beside
the paths they protect.
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 2620b0cc5b feat(lora): per-block strength
<lora:name:1.0:lbw=VALUE> scales each targeted layer's delta by a slot of a
per-architecture block vector. VALUE is a preset name, a scalar, or a comma
vector; presets stretch onto the block count of the current model and the
a1111 17-slot and 12-slot layouts are accepted on sd and sdxl. The factor
enters through the module multiplier, so every apply path carries it: the
exact factor channel, hosting, requantize routing, dense stack combines and
select scoring.

- modules/lora/lora_blocks.py: slot classification from network_layer_mapping
  (namespace-first, anchored chain prefixes), preset resolution reusing the
  merge block-weight tables with BASE forced neutral, generated classic
  segment names plus DOUBLE/SINGLE chain names, per-model memoization
- the raw spec stages through pending_config and promotes with the other
  multipliers, keeping fuse removal consistent
- block weights join the activation signature, the per-module apply stamp
  and the factor cache identity; entries without block weights keep their
  existing signature bytes
- non-native load methods warn once and ignore the argument
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness c762bfec18 perf(lora): materialize select winners on the accelerator and time the reset
The weight-kind schedule reset ran each winner's calc_updown on the target
weight's device, which on a block-swapped denoiser is the cpu; at hundreds
of layers per pass the cpu matmuls dominated every select generation. The
delta now computes on the accelerator and moves back, matching the activate
walk's convention.

- reset and flip execution log a debug timing line (materialize, select
  loop, move/calc/apply split); the reset runs outside the activate walk,
  so its cost was invisible to the load timers
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness de5e94073c perf(lora): chunk select scoring and cache select scores for replay
Select scoring staged full fp32 copies, an abs copy and top-k workspace per
layer (hundreds of MB of transients that collide with block swapping on
offloaded denoisers) and recomputed scores from freshly assembled deltas on
every apply, which kept select modes out of the factor-cache fast path.

- score_pair: row-chunked fp32 interiors, fp64 accumulators, one device sync
- select scores persist in the factor cache as additive per-layer records
  under the existing configuration signature
- apply_select_cached and register_weight_pair_cached replay a pair without
  assembling deltas; the weight-kind winner is still computed at schedule
  time
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 72d9fd1b78 fix(lora): derive select stack balances from live schedule entries
The klora and estlora balance factors accumulated across registrations
without ever resetting, so a multiplier change or pair swap blended the
previous registration into every later schedule. Balances now sum over
the live entries at finalize time, which keeps drop and re-register
consistent by construction.

- key flips one step early: step callbacks fire after the denoise, so
  the winner is now live during the crossover step forward and a
  final-step crossover engages instead of expiring
- include the calibration toggle in the factor cache signature so a hit
  never replays factors computed under the other setting
- fall back to summation with a warning when hosting is disabled on a
  quantized model instead of registering schedules that cannot flip
- drop the unused score_topk helper
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness f156026150 feat(lora): balance estlora layer scores by network magnitude
EST-LoRA scores each layer by squared Frobenius energy, so a magnitude gap
between the two networks enters squared and the louder network wins nearly
every layer, starving the quieter one. The style side is now scaled by the
total-energy ratio (mirroring klora's gamma), making selection scale-invariant
so a network cannot take layers on magnitude alone. On the krea2 subject+style
pair this lifts the style network from 18% to 65% of the layer-step budget.

- lora_stack: accumulate per-mode energy totals, apply the balance in the est ramp
- test: content-louder est pair now hands over mid-schedule where raw scoring never would
- locale: note the est magnitude balance, and that a select mode gives each layer
  to one network so both can be under-applied, while dense modes blend more fully
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 30ca66fe5f fix(lora): host dense stack deltas on sdnq at any bit width
Requantizing a dense-combined delta into 8-bit weights is checkpoint-fragile:
on some checkpoints the round trip visibly damages the render while the same
combination hosted on the svd channel is clean. Dense-mode sets with two or
more contributing networks on a layer now ride the hosted path regardless of
bit width; single-set behavior at 8 bits and above is unchanged.

- host_candidate: dense multi-net layers qualify at any width
- suite: dense pair at int8 hosts; single non-factorable set at int8 keeps
  the requantize fallback
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness cf36f879a1 fix(lora): harden select stack modes on quantized and offloaded models
Select pairs now ride the svd side channel on any SDNQ linear, not
only sub-8-bit ones: quantized backups are packed tensors, so the
weight rewrite path cannot recompute a winner from them and left
layers stripped mid-requantize. The sub-8-bit gate stays for dense
hosting, where requantize retains the delta at 8 bits and above.

Weight selection now only serves unquantized modules: finalize
iterates a snapshot so dead entries drop cleanly, materializes
balanced-offload modules before rewriting weights and skips modules
with stripped or quantized weights instead of corrupting the layer.
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 734215cc6d fix(lora): keep select stack modes dormant without a qualifying pair
A select mode forced backup mode whenever it was merely set, so a
leftover setting changed behavior for ordinary single-network loads.
The fuse gate now engages only when the loaded set could actually
select (exactly two networks, compile permitting) or while selection
segments are still live on model layers. Re-application drops any
stale per-layer schedule so a later pass reset can never replay an
old winner over freshly applied weights. Fallback notices log per
activation instead of once per session; only the in-loop flip notice
stays latched.
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness e2202bfbdf feat(lora): log exact side-channel applies
The exact factor path was the only apply route with no log line; its
success read as silence. Track layers taking it beside the hosted and
fallback lists and report all three as key=value apply lines
(apply=exact/hosted/requantize); the stack fallback notices use the
same form. The suite pins its stack-mode baseline to sum so a mode
left set in user config cannot reroute tests that assume plain
summation.
2026-08-28 13:09:26 +01:00
CalamitousFelicitousness 259e15fafe feat(lora): per-layer select stack modes klora and estlora
Two-network subject+style sets select a winner per layer instead of
summing: scores are top-K magnitude sums (klora) or Frobenius energies
(estlora), and a timestep ramp shifts layers from the subject network
toward the style network across sampling, reduced to at most one
precomputed flip per layer per pass. On sub-8-bit SDNQ the pair rides
the side-channel as separate segments flipped in place; other layers
recompute the winner from the pristine backup, so select modes force
backup mode. Selection resets per pass from the callback setup and is
gated off under model compile. estlora's measured style-discrepancy
term is exposed as an option. Adds XYZ axes for the stack settings.
2026-08-28 13:09:25 +01:00
CalamitousFelicitousness 2396185393 feat(lora): dense stack modes for multi-network sets
Add lora_stack_mode with ties, dare_ties, dare_linear and
magnitude_prune combination of per-network deltas when several loaded
networks target one layer; sum stays the default and the exact factor
path. Combined deltas ride the existing tail: hosted svd on sub-8-bit
SDNQ, requantize at int8 and above, direct add elsewhere. Text-encoder
layers and single-network sets keep plain summation. DARE masks draw
from per-layer sha256 seeds so re-applies and cache entries stay
deterministic; the stack settings join the activation and factor-cache
signatures so settings changes re-apply without a reload.
2026-08-28 13:09:00 +01:00
CalamitousFelicitousness 0b56e36a2a feat(attention): exclude known bad models from sparse attention
sparse_attention_exclude is a comma separated denylist matched case insensitively against the architecture, the pipeline class and the denoiser class, so one entry works whichever name is to hand. It resolves once per model rather than per call and declines with a log line. Seeded with CosmosTransformer3DModel, the transformer Anima runs, which returns banded noise at every budget tested against a sound dense baseline; listing the class rather than the architecture covers the other models built on it, none of which have been checked.
2026-08-28 12:40:23 +01:00