Nodes/ComfyUI-Pt-Wrapper/Ptn Residual Connection Model
ComfyUI Node

Ptn Residual Connection Model

Building a residual block without a single line of Python

By HowToSD·Created about a year ago·Updated about a year ago· 7
Ptn Residual Connection Model
  • model
  • closure
  • PTMODEL

PtnResidualConnectionModel is the reason deep networks are trainable, packaged as a node. It takes any model you've built in ComfyUI-Pt-Wrapper and wraps it so its output gets added back to its input instead of just passed along. That little x + model(x) is the entire "skip connection" trick from ResNet, and it's why the pack's from-scratch Transformer workflows actually converge instead of stalling.

Why you'd reach for it

If you're building a model out of the pack's component nodes - linear layers, multi-head attention, layer norm, whatever - you'll find that stacking layers straight on top of each other gets you a network that's hard to train past a few layers. Gradients vanish, accuracy plateaus, nothing happens. A residual connection gives the gradient a clean highway from the output back to the input, so the wrapped sub-model only has to learn the difference it should make. In the author's "Building Transformer From Scratch" guide, this is exactly how the feed-forward blocks inside each encoder layer are assembled: chain a couple of layers, wrap them in this node, and the residual path is automatic.

How it works

The mechanism is embarrassingly simple. In the pack's source, the forward pass is:

res = inputs
x = self.model(inputs)
x = res + x
if self.closure:
    x = self.closure(x)
return x

Feed a tensor in, run it through the wrapped model, add the original input back, then optionally push the result through a closure (a differentiable function, like an activation). Because it's just tensor addition, gradients flow back through both branches during training - the direct shortcut and the learned path - which is the whole point.

The inputs that matter

There are only two, and both are the pack's custom types:

  • model (PTMODEL) - the sub-network you're wrapping. Wire any model-building node's output here.
  • closure (PTCALLABLE, optional) - a function applied after the residual add. Leave it empty if you're chaining this block further and want the add to be the last step.

The single PTMODEL output plugs straight into a Pt Chained Model node, or directly into a trainer like Pt Train Classification Model. Note there's no trainable flag here - the wrapped model's parameters are whatever the inner nodes created.

Where people get burned

The one real footgun is shape. model(input) and input have to be addable, so the sub-model must preserve the tensor's shape - same channel count, same sequence length. If your wrapped layers change the feature dimension, the add raises an error the moment you run. That's a feature, really: a residual connection that silently broadcast mismatched shapes would be far worse than the loud crash you get. Keep the sub-model shape-preserving and this node is one of the least surprising things in the pack.

Installing it

This node ships in ComfyUI-Pt-Wrapper, HowToSD's "PyTorch without code" pack - a focused spin-off of ComfyUI-Data-Analysis that brings model building and training into the node graph. Install the pack once and you get all 200+ nodes, this one included. ComfyUI Manager (search "ComfyUI-Pt-Wrapper") is the easy route; by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/HowToSD/ComfyUI-Pt-Wrapper

Then restart ComfyUI. The first launch after install is slow - requirements.txt pulls in pandas, scikit-learn, transformers, sentencepiece, peft and friends. No model files needed for this node; the example workflows download their own datasets when you run them.

CategoryTraining

Inputs (2)

NameTypeDefaultDescription
modelPTMODEL
closureoptPTCALLABLE

Outputs (1)

NameTypeDescription
PTMODELPTMODEL