ComfyUI Node

AddConvLayer

Putting real convolutional layers into your ComfyUI-built PyTorch model

By TashaSkyUp·Created about a year ago·Updated about a year ago· 1
AddConvLayer
  • model
  • TORCH_MODEL
one_dfalse
in_channels
out_channels
kernel_size
stride
padding(0,0)
bias
initialization
dtype

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 from SequentialModelProvider.
  • one_d - False gives you Conv2d (images), True gives Conv1d (sequences/time series).
  • in_channels / out_channels - number of input and output feature maps. in_channels must 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 with split(","), so a bare 0 becomes a one-element tuple that Conv2d will reject. Type (0,0) or (1,1), not 0 or 1.
  • initialization - default unless a paper tells you otherwise; xavier_uniform/xavier_normal init 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; Conv2d wants b,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), not 1. 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_features doesn'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.

CategoryETK/pytorch

Inputs (10)

NameTypeDefaultDescription
modelTORCH_MODEL
one_dBOOLEANfalse
in_channelsINT
out_channelsINT
kernel_sizeINT
strideINT
paddingSTRING(0,0)
biasCOMBO2 options: true, false
initializationCOMBO3 options: default, xavier_uniform, xavier_normal
dtypeCOMBO8 options: float32, float64, float16, int32, int64, int16, +2

Outputs (1)

NameTypeDescription
TORCH_MODELTORCH_MODEL