Ptn Residual Connection Model
Building a residual block without a single line of Python
- 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.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| model | PTMODEL | — | |
| closureopt | PTCALLABLE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| PTMODEL | PTMODEL | — |