Commit Graph
54 Commits
Author SHA1 Message Date
EthanfelandClaude Opus 4.6 a51580f9d9 fix: make combo progress seed-independent and prevent auto-randomization
Root cause: ComfyUI auto-randomizes INT inputs named "seed", generating
a new seed each queue run. Progress was keyed by seed, so each new seed
started from scratch.

- Rename "seed" input to "shuffle_order" to prevent auto-randomization
- Store completed combo hashes in a flat set instead of per-seed keys
  (combo hashes are already order-independent, so progress persists
  regardless of shuffle order)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 18:10:14 +02:00
Ethanfel 75076b4efe Merge branch 'speed/autotuner-loop-optimizations' into feat/acestep-merge-optimization 2026-04-19 13:01:40 +02:00
EthanfelandClaude Opus 4.6 3e03a048b9 feat: require folder_filter and support multiple comma-separated prefixes
Empty filter no longer allowed — there's no point merging across
incompatible architectures. Users must specify prefixes like
'zit/,zib/' to combine compatible LoRA pools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:59:17 +02:00
EthanfelandClaude Opus 4.6 9d90ee728e feat: add folder_filter input to LoRA Combination Generator
Filters the LoRA pool by path prefix (e.g. "zimage/" or "sdxl/")
so users can generate combos only for compatible architectures.
Empty string includes all LoRAs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:56:07 +02:00
EthanfelandClaude Opus 4.6 f76b2d7a84 feat: add ComfyUI node interface to LoRACombinationGenerator
Add INPUT_TYPES, RETURN_TYPES, IS_CHANGED, __init__, and get_next_combo
methods so the class works as a ComfyUI node. Register in
NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS. Add 3 tests for the
node interface (input fields, return types, IS_CHANGED returns NaN).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:28:33 +02:00
EthanfelandClaude Opus 4.6 9c9c7390d4 fix: use string combo_size and seed_ prefix in LoRACombinationGenerator
combo_size now accepts ComfyUI dropdown strings ("2", "3", "2_and_3")
instead of integers. Progress JSON keys use "seed_42" format instead
of bare "42" for clarity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:24:02 +02:00
EthanfelandClaude Opus 4.6 b56d973542 feat: add LoRACombinationGenerator with combo generation and progress tracking
Implements core static methods for generating, shuffling, hashing, and
tracking LoRA combinations (pairs/triples) with deterministic seeding
and JSON-based progress persistence. Includes 11 TDD tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:21:18 +02:00
EthanfelandClaude Opus 4.6 fe9becfe73 feat: add ACE-Step 1.5 merge optimization for voice preservation
Add dedicated architecture support for ACE-Step music generation model LoRAs
with optimizations informed by the v1.5 hybrid attention architecture — cross-
attention is the primary voice-identity pathway (always global, attending to
timbre+lyric+text conditioning), while self-attention alternates sliding window
(local timbre) and global GQA (long-range structure).

Changes:
- New `acestep_dit` preset: wider orthogonal band (0.30), higher TIES threshold
  (0.35), full magnitude preservation (floor 1.0) — biases toward SLERP over
  TIES to prevent voice signal trimming in cross-attn layers
- Fix `to_out` → `o_proj` normalization bug (was producing `out_proj`)
- Add v1.0 detection and normalization (transformer_blocks, speaker_embedder,
  lyric_encoder mapped to v1.5 canonical form)
- Refine WAN detection to exclude transformer_blocks (prevents v1.0 misdetect)
- Add `acestep_dit` to all architecture_preset UI dropdowns
- 25 new tests (detection, normalization, preset)
- Technical reference doc with architecture analysis and design rationale

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 12:59:13 +02:00
EthanfelandClaude Opus 4.6 2bc4af3580 perf: cache single-LoRA merge results across Phase 2 candidates
Single-LoRA prefixes produce identical patches regardless of merge config
(forced to weighted_sum, early return at _merge_diffs). Cache results keyed
by (label_prefix, auto_strength) to skip diff recomputation for candidates
2+ sharing the same auto_strength value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 00:52:01 +02:00
EthanfelandClaude Opus 4.6 36334bbdbb perf: cache single-LoRA patch scoring across Phase 2 candidates
Single-LoRA patches bypass all merge strategies (early return at line
2868). Score them once on the first candidate and merge as baseline
for subsequent candidates. All composite_score components (norm_cv,
effective_rank, sparsity) are scale-invariant, so auto_strength
differences between candidates don't affect correctness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 00:21:13 +02:00
EthanfelandClaude Opus 4.6 376f304b4c perf: cache LoRA format detection per lora_dict
A LoRA file uses one key format consistently. Caching the winning
format index (0-3) after first detection avoids up to 6 wasted
dict lookups per prefix on subsequent calls. Cache miss on stale
entries is safe — falls through to full cascade.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 00:17:28 +02:00
EthanfelandClaude Opus 4.6 19780e20f6 perf: transfer LoRA factors before float conversion in scoring
Moving fp16/bf16 tensors to score_device then converting to fp32
halves the PCIe transfer bandwidth vs converting first. For ~240
LoRAAdapter patches per candidate, saves meaningful transfer time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 00:12:43 +02:00
EthanfelandClaude Sonnet 4.6 4921fa3e7e test: verify absent enabled_{i} defaults to enabled (old workflow compatibility)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 11:59:55 +02:00
EthanfelandClaude Sonnet 4.6 e2b6c94467 feat: add enabled_{i} toggle to LoRAStackDynamic — skips disabled slots in build_stack
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 11:57:26 +02:00
EthanfelandClaude Sonnet 4.6 620399d3c1 feat: add community_cache — HF-backed shared analysis results
Replaces dead record_dataset param with community_cache dropdown
(disabled / download_only / upload_and_download).

Downloads are anonymous via urllib; uploads require HF_TOKEN and
huggingface_hub. LoRA filenames are never shared — content hashes
(SHA256[:16]) are used as keys. Per-LoRA/pair conflict metrics and
winning merge configs are shared; network errors fall back silently to
the full local sweep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 13:39:56 +02:00
Ethanfel 5d9e980667 fix: use eff_s for sign-flip check in pair/lora cache reconstruction (clip_strength support) 2026-04-03 19:39:45 +02:00
EthanfelandClaude Sonnet 4.6 e947decc73 feat: wire pair/lora cache load and save through auto_tune
Loads lora/pair caches before _run_group_analysis and merges new entries
back into on-disk cache files after successful analysis, completing the
analysis cache feature end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:33:06 +02:00
EthanfelandClaude Sonnet 4.6 2f29e6e727 feat: wire pair/lora cache hit/miss into _run_group_analysis
Add lora_caches/pair_caches/lora_hashes params to _run_group_analysis,
skip _analyze_target_group on full cache hit via _pair_lora_cache_hit,
and populate new_lora_entries/new_pair_entries in the return dict on miss.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:28:34 +02:00
EthanfelandClaude Sonnet 4.6 d0746aad55 feat: add _reconstruct_from_pair_lora_cache
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:22:16 +02:00
Ethanfel b5db2bc6fa fix: remove dead guard and fix test docstring in extraction helpers 2026-04-03 19:20:08 +02:00
EthanfelandClaude Sonnet 4.6 4680f94c3f feat: add per-lora and per-pair cache extraction helpers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:34:05 +02:00
EthanfelandClaude Sonnet 4.6 732f684b69 feat: add pair cache I/O methods
Add _pair_cache_path, _pair_cache_load, _pair_cache_save static methods
to LoRAAutoTuner, plus TestPairCacheIO with 6 tests covering path
sorting, missing/stale miss, roundtrip, commutativity, and atomicity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:30:23 +02:00
EthanfelandClaude Sonnet 4.6 e20e43b9da feat: add lora identity hash and lora cache I/O methods
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:03:07 +02:00
EthanfelandClaude Sonnet 4.6 b2dd00c189 fix: ensure clean test state in partial promotion test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:03:37 +02:00
EthanfelandClaude Sonnet 4.6 b2bb81ee1e fix: partial log prefix, stuck-state promotion, and resume test
- Correct log prefix in _analysis_partial_save except block from
  [AutoTuner Analysis Cache] to [AutoTuner Analysis Partial]
- Add using_partial flag so partial is promoted to full cache even
  when all prefixes were already cached (stuck-state fix)
- Move _analysis_partial_delete outside the new_entries guard so it
  is always called (safe no-op when file doesn't exist)
- Add test_partial_promoted_to_full_cache_when_all_prefixes_already_done
  to TestAnalysisPartialLifecycle exercising the stuck-state fix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 16:54:30 +02:00
EthanfelandClaude Sonnet 4.6 6fe84804f6 feat: wire analysis partial checkpoint lifecycle into auto_tune
On startup, fall back to partial checkpoint when no full cache exists.
Define _on_prefix_done callback that writes partial file after each
fresh prefix. Pass callback to _run_group_analysis. Delete partial on
successful full cache write. Delete partial on clear_and_run. Also fix
log prefixes in _analysis_partial_load/save (carry-forward from Task 1
review).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 16:49:38 +02:00
EthanfelandClaude Sonnet 4.6 79b8353d51 feat: add on_prefix_done callback to _run_group_analysis
Callers can now pass on_prefix_done=lambda prefix, entry: ... to receive
a callback after each freshly-computed prefix is extracted. The callback
fires only on cache misses and only when track_new_entries=True, so all
existing call sites (which pass neither argument) are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 16:44:56 +02:00
EthanfelandClaude Sonnet 4.6 deb69182ee feat: add analysis partial checkpoint I/O methods
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 16:41:30 +02:00
EthanfelandClaude Sonnet 4.6 c387c94841 fix: analysis cache never written on first run (add track_new_entries flag)
On first run cached_analysis is None, causing new_analysis_entries to
stay empty and the cache to never be saved. Replace the
'cached_analysis is not None' guard with an explicit 'track_new_entries'
flag so auto_tune opts in while other callers of _run_group_analysis
avoid the extraction overhead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:30:13 +02:00
EthanfelandClaude Sonnet 4.6 c40f5af458 feat: add raw_analysis field to AutoTuner dataset entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:07:48 +02:00
EthanfelandClaude Sonnet 4.6 1b886d9ebc feat: integrate analysis cache into _run_group_analysis
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:02:51 +02:00
EthanfelandClaude Sonnet 4.6 2820800c70 feat: add _reconstruct_from_analysis_cache on LoRAOptimizer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:59:47 +02:00
EthanfelandClaude Sonnet 4.6 2f70a2b6f9 feat: add _extract_for_analysis_cache on LoRAOptimizer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:56:59 +02:00
EthanfelandClaude Sonnet 4.6 18bedcc361 feat: add analysis cache I/O methods (_analysis_cache_path/load/save)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:53:19 +02:00
EthanfelandClaude Sonnet 4.6 260fd5c6ad refactor: improve _compute_names_only_hash docstring and remove unused setUp
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:51:28 +02:00
EthanfelandClaude Sonnet 4.6 cdfeeb67cc feat: add _compute_names_only_hash for analysis cache key
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:46:33 +02:00
EthanfelandClaude Sonnet 4.6 42a23a996e fix: guard 1D inputs in _extract_lora_svd; add CLIP inputs to LoRAExtractFromModel
- _extract_lora_svd: return None early for 1D tensors (bias vectors) to
  prevent torch.linalg.svd crash; add test_1d_delta_returns_none
- LoRAExtractFromModel: add optional base_clip/finetuned_clip inputs;
  fix model_lora_keys_clip to use cond_stage_model instead of model;
  merge CLIP state dicts into base_sd/fine_sd when both CLIPs provided;
  warn when only one CLIP is connected; remove redundant import comfy.lora

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:38:54 +02:00
EthanfelandClaude Sonnet 4.6 aae488bc00 feat: add _extract_lora_svd helper for LoRA extraction
Adds module-level _extract_lora_svd() that SVD-decomposes a weight
delta into (lora_up, lora_down, alpha), supporting fixed-rank and
auto-rank (energy threshold) modes with a singular value noise floor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 23:27:23 +02:00
EthanfelandClaude Sonnet 4.6 02daae172e test: add failing tests for _extract_lora_svd helper
Adds TestExtractLoRAFromDelta test class and _load_module() helper
to support TDD for the upcoming LoRAExtractFromModel node.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 17:49:57 +02:00
EthanfelandClaude Opus 4.6 5ab9ec3e2d test: add sub-merge flags, single-item passthrough, and nested formula tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:39:30 +01:00
EthanfelandClaude Opus 4.6 7f6df901d5 feat: integrate formula detection into AutoTuner with reviewed bug fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:30:48 +01:00
EthanfelandClaude Opus 4.6 285f4e7080 feat: add _autotune_resolve_tree for per-sub-merge AutoTuner
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:23:53 +01:00
EthanfelandClaude Opus 4.6 926490bf7c fix: address code quality issues in merge formula executor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:29:05 +01:00
EthanfelandClaude Opus 4.6 6a55178d7b feat: merge formula tree executor with optimize_merge integration
Add _execute_merge_tree, _resolve_tree_to_stack, and
_model_to_virtual_lora methods to LoRAOptimizer. Modify optimize_merge
to detect formula metadata in the stack and delegate to the tree
executor for hierarchical sub-group merging. Add safety filter in
_normalize_stack to strip formula metadata entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:09:09 +01:00
EthanfelandClaude Opus 4.6 8c8c3de053 feat: add LoRAMergeFormula passthrough node
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:04:59 +01:00
EthanfelandClaude Opus 4.6 4ae2478feb feat: add merge formula parser with recursive descent
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:02:22 +01:00
EthanfelandClaude Opus 4.6 db1591a693 feat: embed metadata in saved LoRAs and tuner files
- SaveMergedLoRA now writes safetensors metadata (source LoRAs, merge
  settings, architecture) plus optional user prompt/description
- SaveTunerData accepts optional prompt/description, embeds in JSON
- LoadTunerData outputs prompt, description, and metadata_info strings
- AutoTuner records source_loras in tuner_data for provenance
- New LoRAMetadataReader passthrough node extracts metadata from any
  safetensors LoRA in a stack (prompt, description, merge info)
- LoRAStack attaches file metadata at load time; _normalize_stack
  preserves it through both tuple and dict paths
- Graceful degradation: missing metadata produces empty strings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 00:11:58 +01:00
EthanfelandClaude Opus 4.6 dd42043766 feat: Compatibility Analyzer solo LoRA nodes, create_nodes toggle, and settings cleanup
- Solo LoRAs now create LoraLoader/LoraLoaderModelOnly nodes (based on CLIP)
- Merge groups continue creating LoRAStackDynamic nodes
- Use original strengths instead of auto-strengths for created nodes
- Add create_nodes toggle to disable automatic node creation
- Move smooth_slerp_gate from AutoTunerSettings to shared MergeSettings
- Add smooth_slerp_gate to main LoRAOptimizer and _SIMPLE_DEFAULTS
- Add decision_smoothing (0.25) to _SIMPLE_DEFAULTS
- Remove output_mode from AutoTunerSettings (hardcode "merge")
- Rewrite all settings node tooltips for clarity
- Update tests for new settings structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:30:13 +01:00
EthanfelandClaude Opus 4.6 66095dec68 refactor: extract common settings into LoRAMergeSettings node
Create a new LoRAMergeSettings node holding the 6 shared parameters
(normalize_keys, architecture_preset, auto_strength_floor,
decision_smoothing, vram_budget, cache_patches) that were duplicated
across LoRAOptimizerSettings and LoRAAutoTunerSettings.

Both mode nodes now accept an optional MERGE_SETTINGS input and fall
back to identical defaults when unconnected — output dicts are unchanged
so execute_simple needs zero modifications.

Also fixes:
- v1 scoring: de-dent composite_score recomputation so it always runs
  under scoring_formula=="v1", not only when sparsification is enabled
- RAM leak: clear _autotuner_delegate caches on model change and when
  switching between advanced/autotuner modes in LoRAOptimizerSimple

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:02:50 +01:00
EthanfelandClaude Opus 4.6 d1e6282c41 feat: add LoRA Optimizer Settings and AutoTuner Settings nodes
Add two pure-data nodes (LoRAOptimizerSettings, LoRAAutoTunerSettings)
that output OPTIMIZER_SETTINGS dicts. Connecting either to the Simple
node's new 'settings' input transforms it into the Advanced Optimizer
or AutoTuner respectively, so users never need to swap node types.

Settings take priority over tuner_data and defaults. The AutoTuner
delegate is persisted on the Simple instance so cache_patches works
across re-executions. Unknown mode values raise ValueError.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:31:35 +01:00