VAE Merge (Tensor Prism)
The forgotten third network gets its own blend
- vae_a
- vae_b
- merged_vae
- merge_info
Most merging attention goes to the UNet, but your images don't come from the UNet - they come out of the VAE, the component that turns latent space back into pixels. And as the KB's VAE section hammers home, the VAE is a real quality lever: it's why colors come out grey and washed out, why images look over-smoothed, why two checkpoints "render differently" even with the same UNet. VAE Merge (Tensor Prism) treats that third network as a first-class citizen: it blends two VAEs with ten merge modes and even per-block controls.
When would you merge a VAE? When one checkpoint's decoder gives you the colors you love and another's gives you the sharpness - you blend the decoders instead of accepting one whole. It's niche, but it's the kind of niche that separates "the merge is fine" from "the merge is exactly what I wanted."
How it works
Connect vae_a and vae_b, then pick merge_mode from ten: weighted_sum, slerp, gradient_merge, adaptive_merge, harmonic_merge, tensor_sum, geometric_mean, cosine_similarity_merge, percentile_merge, smooth_step_merge. For a beginner, weighted_sum and slerp are the sane ones; the rest are the pack being ambitious.
alpha (0.5, "Weight for VAE A - remember: 0.50 = balanced" per the tooltip) is the main blend point, beta (0.5) a secondary weight for tensor_sum mode, and device (auto/cuda/cpu) picks where it runs. Three post-blend adjustment dials do real work: brightness, contrast, saturation (each −1 to +1, default 0) tweak the merged VAE's output look without re-blending - a cheap way to fix the grey-and-washed symptom the KB warns about.
Turn on use_block_weights and you get per-component controls for the whole VAE anatomy: encoder_conv_in, encoder_block_0 through 3, encoder_mid, encoder_norm_out, encoder_conv_out, the decoder equivalents (decoder_conv_in, decoder_block_0–3, decoder_mid, decoder_norm_out, decoder_conv_out), plus quant_conv and post_quant_conv. The decoder blocks are where image quality mostly lives, so those are the ones to move.
Outputs: merged_vae (VAE) - wire it into the VAEDecode - and merge_info (STRING), a text report of what happened.
The settings that matter
Start with alpha only, weighted_sum. Then use brightness/contrast/saturation to fix tone before you ever touch block weights - it's faster and far easier to reason about. Only go per-block when the whole-VAE blend is close but one region (say, fine detail in the decoder) is off.
Installing it
Part of ComfyUI-Tensor-Prism-Node-Pack. ComfyUI Manager → search "Tensor Prism" → Install, restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/AstrionX/ComfyUI-Tensor-Prism-Node-Pack
No model downloads; deps are torch, numpy, psutil. Skip the typo'd clone URL in the README.
The honest caveat
A real constraint: VAEs are architecture-specific - the KB notes a VAE from one channel count produces noise or flat color on another, so only merge VAEs of the same family (SDXL with SDXL, and both matching the UNet you pair them with). And this is a young first-author pack, so the exotic merge modes are unproven; weighted_sum and slerp are the ones you can trust the math of. When in doubt, remember the community's blunt rule from the KB: if colors look grey and washed, the VAE is the suspect - and a merged VAE is a tool for exactly that problem.
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| merge_mode | COMBO | 10 options: weighted_sum, slerp, gradient_merge, adaptive_merge, harmonic_merge, tensor_sum, +4 | |
| device | COMBO | 3 options: auto, cuda, cpu | |
| alpha | FLOAT | 0.500–1 | Weight for VAE A (remember: 0.50 = balanced) |
| beta | FLOAT | 0.500–1 | Secondary weight (for tensor_sum mode) |
| brightness | FLOAT | 0.00-1–1 | Adjust output brightness |
| contrast | FLOAT | 0.00-1–1 | Adjust output contrast |
| saturation | FLOAT | 0.00-1–1 | Adjust color saturation |
| use_block_weights | BOOLEAN | false | Enable per-block weight control (remember 0.50 default) |
| vae_aopt | VAE | — | |
| vae_bopt | VAE | — | |
| encoder_conv_inopt | FLOAT | 0.500–1 | — |
| encoder_block_0opt | FLOAT | 0.500–1 | — |
| encoder_block_1opt | FLOAT | 0.500–1 | — |
| encoder_block_2opt | FLOAT | 0.500–1 | — |
| encoder_block_3opt | FLOAT | 0.500–1 | — |
| encoder_midopt | FLOAT | 0.500–1 | — |
| encoder_norm_outopt | FLOAT | 0.500–1 | — |
| encoder_conv_outopt | FLOAT | 0.500–1 | — |
| decoder_conv_inopt | FLOAT | 0.500–1 | — |
| decoder_block_0opt | FLOAT | 0.500–1 | — |
| decoder_block_1opt | FLOAT | 0.500–1 | — |
| decoder_block_2opt | FLOAT | 0.500–1 | — |
| decoder_block_3opt | FLOAT | 0.500–1 | — |
| decoder_midopt | FLOAT | 0.500–1 | — |
| decoder_norm_outopt | FLOAT | 0.500–1 | — |
| decoder_conv_outopt | FLOAT | 0.500–1 | — |
| quant_convopt | FLOAT | 0.500–1 | — |
| post_quant_convopt | FLOAT | 0.500–1 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| merged_vae | VAE | — |
| merge_info | STRING | — |