Rotate
Align two models by rotation, not by averaging
- a (delta|param|weight)
- b (delta|param|weight)
- alignment (1.0)
- alpha (0.0)
- centralization (1.0)
- stiefel_eps (1e-08)
- stiefel_max_iters (100)
- cache
- recipe
Rotate (class Rotate Mecha Recipe) aligns model A to model B with an orthogonal transform - the Procrustes / SVD rotation problem - before any interpolation happens. Where rebasin permutes weights to line models up, Rotate finds the rotation matrix that minimizes the distance between A and B's tensors, then applies it to A.
This is the "obviously you must align before you merge" tool. Two fine-tunes of the same base start in the same neighborhood of weight space, but their coordinate systems drift. If you rotate one model's weights to best match the other's before blending, the merged result keeps more of both models instead of canceling them out. It's a subtler, cheaper cousin of rebasin, and for many merges it's the practical choice over full permutation alignment.
How it works
Per tensor, sd-mecha computes the optimal orthogonal transform mapping A toward B (SVD-based), then applies it. A few niceties are worth knowing:
- alignment (1.0) - how far to rotate: 1 fully aligns A to B by rotation; fractional values rotate partway toward B (fractional alignment on wide matrices uses a Stiefel-manifold solver).
- alpha (0.0) - interpolates the scale component between A and B, the part rotation can't affect. With both
alignmentandalphaat 0 you get A back; both at 1 you get B. - centralization (1.0) - how much to center the rows of A and B before aligning. Centering lets the rotation match much more closely; the default is fully on.
- stiefel_eps (1e-8) and stiefel_max_iters (100) - solver tolerances for fractional-alignment cases. You almost never touch these.
- cache - an optional
MECHA_MERGE_METHOD_CACHEinput. Rotation is expensive enough that the method supports caching intermediate solves per key, so repeated runs with the same inputs don't recompute everything. - recipe (output, weight space) - model A, rotated toward B. Feed it into an average or weighted sum and merge.
There's also a merge_checkpointing toggle on every mecha recipe node - worth mentioning because Rotate is exactly the kind of expensive branch you'd checkpoint: it caches the node's output in fp16 on CPU so unchanged branches skip re-rotation on later runs.
Install
Part of the Mecha Merge Node Pack (ljleb/comfy-mecha):
- ComfyUI Manager → Install Custom Nodes → search "mecha" → Mecha Merge Node Pack, or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/ljleb/comfy-mecha.git
pip install -r comfy-mecha/requirements.txt
Restart ComfyUI; it's under mecha. The only declared dependency is sd-mecha==1.1.7; no model downloads.
Common issues
- It's the slow node in the room. SVD per tensor adds up. If a run is dragging, try
merge_checkpointing: true(or the cache input) so repeated executions don't redo the rotation. - Scalar/small tensors bypass the rotation. Tensors with ≤1 dimension, or ones where A and B already match, fall back to a plain lerp - that's by design, not a bug.
- Don't rotate into the wrong direction. The output is a rotated copy of A, aligned to B - it is not a merge. Rotate first, blend second, and keep the rotation early in the graph so everything downstream sees aligned weights.
Rotate is the pragmatic middle ground between "average two models and hope" and "run a full rebasin." If your models come from the same base and you just want blending to hurt less, this is the node that quietly makes the average better.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| a (delta|param|weight) | MECHA_RECIPE | — | |
| b (delta|param|weight) | MECHA_RECIPE | — | |
| alignment (1.0)opt | MECHA_RECIPE | 1 | — |
| alpha (0.0)opt | MECHA_RECIPE | 0 | — |
| centralization (1.0)opt | MECHA_RECIPE | 1 | — |
| stiefel_eps (1e-08)opt | MECHA_RECIPE | 1e-8 | — |
| stiefel_max_iters (100)opt | MECHA_RECIPE | 100 | — |
| cacheopt | MECHA_MERGE_METHOD_CACHE | — | |
| merge_checkpointingopt | BOOLEAN | false | Speeds up an entire branch of a merge graph that does not change often in exchange of memory. - true: store the first output of this recipe node on cpu memory in fp16. On subsequent workflow executions, as long as the inputs do not change, the cached keys are returned after being cast to the original device and dtype. - false: do not store the output. The recipe and its inputs will re-execute on subsequent workflow executions. Note that the memory used to checkpoint the output is distinct from the cache feature. In general, you probably want to either use this *or* a cache unit, but not both at the same time because the memory adds up. The difference between merge checkpointing and cache is that merge checkpointing completely re-merges from scratch if any input changes. Merge checkpointing is also generally much faster than cache in the fast path. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| recipe | MECHA_RECIPE | — |