PyTorch中自定义卷积核与环形卷积实现技术问询
Let's walk through solutions for your two custom convolution requirements—neither is natively supported in PyTorch, but we can build them with straightforward workarounds.
1. Fixed Custom Convolution Kernel (Non-Uniform Dilation-like Behavior)
From your code block, I assume you want a 5x5 kernel structured like this (adjusted to a square shape since standard convolutions use square kernels by default):
[0, 0, 0, 0, 1] [0, 0, 0, 0, 1] [1, 0, 0, 0, 1] [0, 0, 0, 0, 1] [0, 0, 0, 0, 1]
PyTorch's built-in dilation parameter only supports uniform spacing across all dimensions, so we need to manually define this kernel and lock it to prevent training updates.
Implementation Steps:
- Create a
nn.Conv2dlayer with matching input/output channels, kernel size 5x5, and disable bias (since we're using a fixed kernel). - Manually assign your custom kernel values to the layer's weight parameter.
- Freeze the weight by setting
requires_grad=False.
Code Example:
import torch import torch.nn as nn # Define your 5x5 custom kernel custom_kernel = torch.tensor([ [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1] ], dtype=torch.float32) # Reshape for Conv2d (out_channels, in_channels, kernel_h, kernel_w) # Adjust (1,1) to match your input/output channel count if needed kernel_shape = (1, 1) + custom_kernel.shape custom_kernel = custom_kernel.view(kernel_shape) # Initialize convolution layer conv_custom = nn.Conv2d( in_channels=1, out_channels=1, kernel_size=5, bias=False, padding=2 # Optional: keep input/output size identical ) # Assign and lock the custom kernel with torch.no_grad(): conv_custom.weight.copy_(custom_kernel) conv_custom.weight.requires_grad = False # Test with sample input sample_input = torch.randn(1, 1, 28, 28) # Batch size 1, 1 channel, 28x28 output = conv_custom(sample_input)
If you intended a non-square kernel (like 5x9), just adjust kernel_size and reshape your custom tensor accordingly.
2. Circular Convolution (Edge Wrapping Instead of Padding)
PyTorch doesn't have native circular convolution support for standard nn.Conv2d, but we can simulate it by manually creating a circularly extended input—this means wrapping the input's edges to the opposite side (e.g., right edge appended to the left, bottom edge appended to the top) before applying a regular convolution.
Implementation Steps:
- Calculate required padding based on your kernel size (typically
kernel_size // 2for same-sized output). - Use
torch.catto concatenate edge regions to the opposite sides of the input. - Apply a regular
nn.Conv2dwithpadding=0to the extended input.
Code Example:
def circular_pad(x, pad=(1, 1, 1, 1)): # pad = (pad_left, pad_right, pad_top, pad_bottom) pad_left, pad_right, pad_top, pad_bottom = pad B, C, H, W = x.shape # Wrap left/right edges x_padded = torch.cat([x[..., -pad_left:], x, x[..., :pad_right]], dim=-1) # Wrap top/bottom edges x_padded = torch.cat([x_padded[..., -pad_top:, :], x_padded, x_padded[..., :pad_bottom, :]], dim=-2) return x_padded # Example: 3x3 circular convolution (same output size as input) conv_circular = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, bias=False) # Sample input sample_input = torch.randn(1, 1, 28, 28) # Apply circular padding matching 3x3 kernel requirements padded_input = circular_pad(sample_input, pad=(1,1,1,1)) # Run convolution output_circular = conv_circular(padded_input) # Output shape matches sample_input: (1, 1, 28, 28)
For larger kernels (like 5x5), adjust the pad values to (2,2,2,2) to maintain same-sized output.
内容的提问来源于stack exchange,提问作者jmmcd

