238 lines
14 KiB
Markdown
238 lines
14 KiB
Markdown
# Per-layer parameter rules for merge, extraction, and resize
|
||
|
||
## 1. Summary and initial scope
|
||
|
||
Add one multiline configurator node that supplies optional per-layer numeric overrides to existing nodes. Matching layers receive the explicitly assigned values; unassigned parameters and unmatched layers retain the main node’s settings. Existing exclusions, inclusion filters, discard rules, mismatch handling, and safety guards remain authoritative.
|
||
|
||
The initial implementation covers these 39 nodes:
|
||
|
||
| Family | Included variants | Count |
|
||
|---|---|---:|
|
||
| Standard mergers | Two- and three-input checkpoint, diffusion-model, text-encoder, LoRA, and embedding mergers | 10 |
|
||
| Extraction | Fixed, Ratio, Quantile, Knee, and Frobenius for LoRA, DoRA, learned DoRA, text-encoder LoRA, and text-encoder DoRA | 25 |
|
||
| LoRA resize | Fixed, Ratio, Frobenius, and Cumulative | 4 |
|
||
|
||
Do not expand this implementation to CWB configuration, weighted multi-LoRA merging, LoRA application, Lodestone, optimizer settings, iteration counts, seeds, device selection, dtype selection, or new normalization behavior. These remain post-implementation considerations.
|
||
|
||
No changes are made during planning. After approval and execution is enabled, the first implementation action is to save this entire approved plan verbatim to `plans/per-layer-parameter-rules.md`. Commit that planning document before editing implementation files. Commit the completed feature after verification.
|
||
|
||
Preserve the pre-existing analysis/report edits currently outside the filter commit.
|
||
|
||
## 2. Public interface, syntax, and bindings
|
||
|
||
### Configurator and connection
|
||
|
||
Implement `LayerParameterConfiguration`, displayed as **Layer Parameter Configuration**, in a new `nodes/layer_parameters.py` module.
|
||
|
||
Its inputs are:
|
||
|
||
| Input | Type | Default | Meaning |
|
||
|---|---|---|---|
|
||
| `rules` | Multiline string | Empty | One pattern-and-assignment rule per line |
|
||
| `glob_patterns` | Boolean | False | False uses regex substring search; True uses glob substring matching |
|
||
|
||
Its outputs are:
|
||
|
||
| Output | Type | Meaning |
|
||
|---|---|---|
|
||
| `layer_parameters` | `io.Custom("MODELUTILS_LAYER_PARAMETERS")` | Immutable, parsed rules |
|
||
| `documentation` | String | Syntax, bindings, supported nodes, fallback behavior, errors, and examples |
|
||
|
||
This follows the existing `io.Custom(...)` configurator/socket mechanism already used by CWB. No frontend extension or dynamic socket-type changes are needed.
|
||
|
||
Append an optional `layer_parameters` input to each supported receiver. Append `layer_parameters=None` to its execution interface and forward it by keyword. Preserve every existing input identifier, widget order, output, and default.
|
||
|
||
An unconnected input or an empty rule set leaves the operation unchanged.
|
||
|
||
### Rule grammar
|
||
|
||
Accept the following forms:
|
||
|
||
```text
|
||
(blocks\.4[589]\.attn\.qkv_proj) a:0.5 b:0.25 c:0.75 d:1.0
|
||
(blocks\.4[589]\.attn\.qkv_proj) alpha:0.5, beta:0.25, gamma:0.75, delta:1.0
|
||
(blocks\.4[589]\.attn\.qkv_proj) a:64, b:32, c:0.99, d:0.0
|
||
(blocks\.4[589]\.attn\.qkv_proj) max_rank:128 min_rank:1 target:0.9
|
||
```
|
||
|
||
Rules:
|
||
|
||
- Require a parenthesized pattern followed by at least one `name:value` assignment.
|
||
- Accept whitespace, commas, or a mixture between assignments, including whitespace around colons.
|
||
- Preserve the pattern’s backslashes, internal whitespace, nested groups, and character classes.
|
||
- Accept signed decimal and scientific-notation numeric values. Reject nonfinite values.
|
||
- Ignore blank lines and whole-line comments whose first nonwhitespace character is `#`. Do not support inline comments.
|
||
- Reject empty patterns, missing values, trailing garbage, duplicate assignments, and invalid regex.
|
||
- Use `re.search` for regex matching. For glob matching, use case-sensitive `fnmatchcase` with surrounding wildcards to provide substring matching.
|
||
- Keep configurator pattern syntax independent of the main node’s existing exclusion-filter syntax.
|
||
|
||
Short aliases and full parameter names may be mixed. Two aliases assigning the same parameter on one line are an error, even when their values agree.
|
||
|
||
### Binding tables
|
||
|
||
The shared binding definitions must generate both receiver tooltips and configurator documentation, preventing the two from drifting.
|
||
|
||
#### Standard merge coefficients
|
||
|
||
Bindings remain stable across calculation modes:
|
||
|
||
| Short name | Full name |
|
||
|---|---|
|
||
| `a` | `alpha` |
|
||
| `b` | `beta` |
|
||
| `c` or `g` | `gamma` |
|
||
| `d` | `delta` |
|
||
| `e` | `epsilon` |
|
||
| `f` or `z` | `zeta` |
|
||
|
||
Accept only coefficients actually used by the selected calculation mode:
|
||
|
||
| Calculation mode | Supported coefficients |
|
||
|---|---|
|
||
| Weight-Sum; Train-Difference | alpha |
|
||
| Add-Difference; Power-Up (DARE) | alpha, beta |
|
||
| Comparative-Interpolation; Add-Dissimilarities; SVD LoRA Extraction; Enhanced Auto Interp; Weight-Sum Cutoff; Power-Up (DARE+TIES) | alpha, beta, gamma |
|
||
| Extract-Features; Enhanced Man Interp; Power-Up Enhanced (DARE) | alpha, beta, gamma, delta |
|
||
| Power-Up Enhanced (DARE+TIES) | beta, gamma, delta, epsilon, zeta |
|
||
|
||
Reject assignments to ignored coefficients rather than pretend they affect the selected mode. Seeds remain main-node settings.
|
||
|
||
#### Extraction
|
||
|
||
Use the same bindings across LoRA, DoRA, learned DoRA, and both text-encoder extraction families:
|
||
|
||
| Method | `a` | `b` | `c` | `d` | `e` | `f` |
|
||
|---|---|---|---|---|---|---|
|
||
| Fixed | linear_dim | conv_dim | clamp_quantile | min_diff | — | — |
|
||
| Ratio | linear_ratio | conv_ratio | clamp_quantile | min_diff | linear_max_rank | conv_max_rank |
|
||
| Quantile | linear_quantile | conv_quantile | clamp_quantile | min_diff | linear_max_rank | conv_max_rank |
|
||
| Frobenius | linear_target | conv_target | clamp_quantile | min_diff | linear_max_rank | conv_max_rank |
|
||
| Knee | linear_max_rank | conv_max_rank | clamp_quantile | min_diff | — | — |
|
||
|
||
Knee method selection, probe offsets, SVD iterations, chunking controls, and learned-DoRA optimization settings remain on the receiving node.
|
||
|
||
#### LoRA resize
|
||
|
||
| Method | `a` | `b` | `c` |
|
||
|---|---|---|---|
|
||
| Fixed | new_rank | — | — |
|
||
| Ratio | max_rank | ratio | — |
|
||
| Frobenius | max_rank | min_rank | target |
|
||
| Cumulative | max_rank | target | — |
|
||
|
||
### Value validation
|
||
|
||
Inherit values from the receiving node—not hardcoded configurator defaults.
|
||
|
||
For supplied overrides:
|
||
|
||
- Extraction dimensions and rank caps are integral values in `[1, 16384]`; ratios are `[1, 100]`; quantile/Frobenius targets are `[0, 1]`; `clamp_quantile` is `[0.5, 1]`; `min_diff` is `[0, 1]`.
|
||
- Resize ranks are integral values in `[1, 3072]`; ratios are `[1, 100]`; targets are `[0.1, 1]`.
|
||
- Validate resolved Frobenius resize `min_rank <= max_rank`, including values inherited from the main node.
|
||
- Standard merge coefficients retain existing widget bounds. Where a coefficient represents a quantile or probability, validate `[0, 1]`; generic SVD rank coefficients must also be positive integral values.
|
||
- Do not silently truncate fractional ranks or repair invalid assignments. Retain existing mathematical rank caps imposed by tensor dimensions.
|
||
|
||
## 3. Matching and implementation data flow
|
||
|
||
### Matching contract
|
||
|
||
For ordinary model merging and extraction, match the receiving operation’s target tensor names.
|
||
|
||
For LoRA inputs, match the normalized logical layer name after the existing parsing and normalization path. Do not match factor or alpha suffixes independently.
|
||
|
||
Use the established dotted naming produced by extraction and existing reference mapping. Preserve internal identifiers such as `qkv_proj`. Do not introduce underscore normalization as the new public convention, rewrite regex punctuation, or redesign model-format conversion.
|
||
|
||
Retain the existing unresolved flattened-name fallback when no reference mapping exists. Documentation must distinguish this fallback from the normal dotted path. A dotted rule that cannot match the resulting normalized input names produces the ordinary unmatched-rule error; do not silently reinterpret it.
|
||
|
||
A single rule matching multiple keys belonging to one logical LoRA layer counts as one match. That layer receives one parameter set shared by its factors.
|
||
|
||
### Strict errors and fallback
|
||
|
||
Validate all rules before opening the output writer or beginning tensor streaming:
|
||
|
||
1. Parse syntax and compile patterns once in the configurator.
|
||
2. At each receiver, resolve aliases and reject unsupported parameters.
|
||
3. Use header/key information to identify target layers and their existing normalized names.
|
||
4. Detect matching rules per logical layer.
|
||
5. Reject multiple matching rule lines for any one layer—even if their assignments concern different parameters.
|
||
6. Reject any rule line matching no target layer.
|
||
7. Combine the single matching rule with main-node values and validate the resulting parameters.
|
||
|
||
Errors identify the receiving node, configuration line number, pattern, and affected layer or parameter. Overlap errors include every conflicting line number.
|
||
|
||
Determine name matches before existing exclusions so an explicitly excluded layer is not falsely reported as nonexistent. Overrides never reactivate an excluded, discarded, guarded, or otherwise unprocessable layer.
|
||
|
||
### Shared implementation
|
||
|
||
Keep parsing, immutable rule records, binding definitions, and matching/error handling in the new shared module.
|
||
|
||
Store only lightweight per-layer assignments and resolved scalar parameters. Do not store tensors, mutate the shared configuration payload, or modify global/main-node parameter dictionaries between layers.
|
||
|
||
Register the configurator through the existing extension node list. Do not add dependencies.
|
||
|
||
### Standard merger integration
|
||
|
||
In `MergerLogic.execute_merge`:
|
||
|
||
- Prepare the rule-to-layer mapping alongside existing header-based work planning.
|
||
- For LoRA mode, use parsed logical groups to assign the same override to their factor keys; retain existing merge and alpha-normalization behavior.
|
||
- Immediately before `calc_mode_class.create_recipe`, construct a layer-local parameter dictionary containing the base settings plus that layer’s overrides.
|
||
- Keep tensor references and preloaded-source data local to the current work unit.
|
||
- Do not mutate `recipe_params` with overrides that could affect later layers.
|
||
|
||
Do not change recipe formulas, calculation-mode selection, or source-loading behavior.
|
||
|
||
### Extraction integration
|
||
|
||
Thread the optional rules through all 25 node entry points into the four extraction backends.
|
||
|
||
Prepare resolved parameters before streaming, then use them in each backend’s `_process_layer` before `min_diff` testing and SVD selection.
|
||
|
||
Specific requirements:
|
||
|
||
- Fixed-rank overrides update both the requested dimension and corresponding maximum-rank argument; otherwise the original cap would negate an increased rank.
|
||
- Adaptive overrides update the existing linear/conv method parameter and rank cap without altering method selection or probe settings.
|
||
- Normal execution, CPU retry, and chunked fallback use the same resolved layer values.
|
||
- Extend the existing chunked extraction helpers with a trailing `clamp_quantile` argument and pass the effective value through. These helpers currently omit it when calling `_svd_extract_linear`; text-encoder extraction shares the SVD helper.
|
||
- Perform configuration validation outside broad extraction exception handlers so a configuration error cannot become a silently skipped layer.
|
||
|
||
Do not alter SVD, chunk recombination, learned optimization, or tensor-lifecycle algorithms.
|
||
|
||
### Resize integration
|
||
|
||
Attach resolved rank/target values to the existing logical-layer work units.
|
||
|
||
When calling `_resize_lora_factors`, translate the public bindings into the existing arguments:
|
||
|
||
- Fixed `new_rank` → `new_rank`.
|
||
- Adaptive `max_rank` → `new_rank`.
|
||
- Ratio/target → `dynamic_param`.
|
||
- Frobenius `min_rank` → `min_rank`.
|
||
|
||
Leave `dynamic_method` on the main node. Preserve whole-layer factor handling, alpha behavior, passthrough data, low-bit handling, dtype selection, and CPU fallback.
|
||
|
||
## 4. Verification and delivery
|
||
|
||
Extend the repository-owned test selector with focused rule-parser and integration coverage. Map the new production module explicitly; do not rely solely on the broad repository-contract group.
|
||
|
||
Required tests:
|
||
|
||
- Both delimiter styles, mixed short/full names, scientific notation, nested regex groups, CRLF, blank lines, and comments.
|
||
- Invalid syntax, invalid regex, unsupported parameters, duplicate aliases, nonfinite values, fractional ranks, and invalid resolved rank bounds.
|
||
- Overlapping rules fail with layer and line numbers; unmatched rules fail before streaming or writing.
|
||
- Partial assignments inherit remaining main-node values. Unmatched layers retain main-node behavior.
|
||
- Existing include/exclude/discard and safety paths remain authoritative.
|
||
- LoRA matching uses normalized logical names, preserves internal underscores, and assigns one configuration to paired factors.
|
||
- All 39 receiver schemas append the optional socket without moving existing controls; every execution wrapper forwards it correctly.
|
||
- Standard merge outputs reflect different coefficients on different layers, without leaking overrides to later layers.
|
||
- Every extraction family uses the requested per-layer rank, clamp, and `min_diff`; cover adaptive methods, CPU retry, and forced chunk fallback.
|
||
- All four resize variants use their resolved rank/target values, including inherited `min_rank` validation.
|
||
- Absent or empty configuration preserves existing behavior.
|
||
- Configuration failures preserve any existing destination file.
|
||
|
||
Use small deterministic tensors and existing I/O fixtures. Do not run model inference or add unrelated performance, architecture, or normalization test projects.
|
||
|
||
Run focused groups during development, `--changed` after accumulated changes, and the required full gate before the feature commit. Run changed-file lint, compilation, and `git diff --check`; distinguish pre-existing lint findings from new ones.
|
||
|
||
Deliver the saved approved plan, implementation, generated binding documentation/tooltips, regression tests, and a verified feature commit. Leave unrelated analysis/report edits untouched.
|