AddConvLayer
Putting real convolutional layers into your ComfyUI-built PyTorch model
- model
- TORCH_MODEL
Most of what you can build with the EternalKernel PyTorch Nodes pack is feed-forward toy models. AddConvLayer is the node that breaks you out of that: it appends a real torch.nn.Conv2d (or Conv1d) to your nn.Sequential, which means you can start doing actual image-classification-style networks - small CNNs, feature extractors, anything where a sliding window over pixels beats a giant dense layer.
If you're coming at this from the image-gen side of ComfyUI, here's the thing that trips everyone up first: PyTorch's Conv2d works on (batch, channels, height, width) tensors, but ComfyUI images are (batch, height, width, channels). The pack's ComfyUIImageToPytorchTENSOR passes through that channel-last layout untouched. So before a conv layer touches a ComfyUI image, you need to permute it into channel-first - this pack has no permute node (you'd do it with FuncModifyModel or another pack), which is the single most common reason a conv model trains but never converges, or errors on shape.
How it works
The node builds nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, bias, dtype=...) (or Conv1d when the one_d toggle is on), marks it trainable, optionally applies xavier initialization to the weight, and inserts it at the end of your Sequential. Your model is mutated in place and returned.
Inputs that matter
- model (
TORCH_MODEL) - the Sequential to extend. Start fromSequentialModelProvider. - one_d -
Falsegives youConv2d(images),TruegivesConv1d(sequences/time series). - in_channels / out_channels - number of input and output feature maps.
in_channelsmust equal the channel count of whatever tensor arrives (after you've moved it to channel-first). - kernel_size / stride - the window and its step. A 3×3 kernel with stride 1 is the boring default and, again, the right one for most things.
- padding - this is a string, and it must be typed as a tuple:
(0,0)by default, or(1,1)if you want the classic "keep spatial size the same" padding. The node parses it withsplit(","), so a bare0becomes a one-element tuple thatConv2dwill reject. Type(0,0)or(1,1), not0or1. - initialization -
defaultunless a paper tells you otherwise;xavier_uniform/xavier_normalinit only this layer's weight. - dtype -
float32. The int options in the dropdown will create a layer that errors on real data.
Output: one TORCH_MODEL to chain onward.
Install
ComfyUI Manager, search "EternalKernel PyTorch Nodes", or:
cd ComfyUI/custom_nodes
git clone https://github.com/TashaSkyUp/EternalKernelPytorchNodes
cd EternalKernelPytorchNodes
pip install -r requirements.txt
Restart ComfyUI; the node is under ETK/pytorch. No model files to download - this pack builds networks from scratch rather than loading pretrained weights. requirements.txt adds scipy, scikit-learn, transformers, einops (and a few others) on top of what ComfyUI already has.
Common issues
- Channel-last vs channel-first. The classic. ComfyUI hands you
b,h,w,c;Conv2dwantsb,c,h,w. If you're feeding an un-permuted ComfyUI image, your "channels" are actually spatial positions and training will be nonsense. - Padding string format. Remember:
(1,1), not1. This is the pack's own quirk - the field is a string, not a number. - Spatial size math. Conv layers shrink or keep size depending on kernel/stride/padding. If your later linear layer's
in_featuresdoesn't match the flattened output of the conv stack, that's the classic "size mismatch at the head" failure - compute the output size or flatten and count.
Small pack, no tutorials, no community threads - but the source is one readable file, so the answers are greppable. And remember the pack-wide quirk: it patches ComfyUI's validator to ignore return_type_mismatch errors, so a bad wire might not scream at you. Check your types.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| model | TORCH_MODEL | — | |
| one_d | BOOLEAN | false | — |
| in_channels | INT | — | |
| out_channels | INT | — | |
| kernel_size | INT | — | |
| stride | INT | — | |
| padding | STRING | (0,0) | — |
| bias | COMBO | 2 options: true, false | |
| initialization | COMBO | 3 options: default, xavier_uniform, xavier_normal | |
| dtype | COMBO | 8 options: float32, float64, float16, int32, int64, int16, +2 |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| TORCH_MODEL | TORCH_MODEL | — |