1. 基本定义
torch.nn.Conv2d(
in_channels, # 输入通道数
out_channels, # 输出通道数(卷积核个数)
kernel_size, # 卷积核大小
stride=1, # 步长
padding=0, # 填充方式
dilation=1, # 空洞卷积系数
groups=1, # 分组卷积
bias=True, # 是否有偏置
padding_mode='zeros', # 填充模式
device=None,
dtype=None
)
2. 数学原理
对于输入特征图 x∈RCin×H×Wx \in \mathbb{R}^{C_{in} \times H \times W}x∈RCin×H×W,二维卷积的输出为:
ycout(i,j)=∑c=1Cin(xc∗wcout,c)(i,j)+bcout y_{c_{out}}(i,j) = \sum_{c=1}^{C_{in}} (x_c * w_{c_{out},c})(i,j) + b_{c_{out}} ycout(i,j)=c=1∑Cin(xc∗wcout,c)(i,j)+bcout
其中:
- CinC_{in}Cin:输入通道数
- CoutC_{out}Cout:输出通道数(卷积核数量)
- w∈RCout×Cin×kH×kWw \in \mathbb{R}^{C_{out} \times C_{in} \times k_H \times k_W}w∈RCout×Cin×kH×kW:卷积核权重
- b∈RCoutb \in \mathbb{R}^{C_{out}}b∈RCout:偏置
*
表示 cross-correlation(互相关),PyTorch 中的卷积实际是 互相关 而非严格卷积。
3. 参数详解
参数 | 说明 |
---|---|
in_channels |
输入通道数。例如 RGB 图像 = 3 |
out_channels |
输出通道数(卷积核数量),即 feature map 个数 |
kernel_size |
卷积核大小,可以是 int 或 (kH, kW) |
stride |
步长,控制滑动步幅,默认 1 |
padding |
边缘填充,默认 0,可为 int/tuple 或 'same' |
dilation |
空洞卷积扩张系数,默认 1 |
groups |
分组卷积:groups=1 (普通卷积),groups=in_channels (深度卷积),groups>1 (分组卷积) |
bias |
是否添加偏置,默认 True |
padding_mode |
填充模式:'zeros' , 'reflect' , 'replicate' , 'circular' |
4. 输入 / 输出形状
输入:
(N,Cin,Hin,Win) (N, C_{in}, H_{in}, W_{in}) (N,Cin,Hin,Win)
输出:
(N,Cout,Hout,Wout) (N, C_{out}, H_{out}, W_{out}) (N,Cout,Hout,Wout)
其中:
Hout=⌊Hin+2×padding[0]−dilation[0]×(kH−1)−1stride[0]+1⌋ H_{out} = \Bigg\lfloor \frac{H_{in} + 2 \times \text{padding}[0] - \text{dilation}[0] \times (k_H - 1) - 1}{\text{stride}[0]} + 1 \Bigg\rfloor Hout=⌊stride[0]Hin+2×padding[0]−dilation[0]×(kH−1)−1+1⌋
Wout=⌊Win+2×padding[1]−dilation[1]×(kW−1)−1stride[1]+1⌋ W_{out} = \Bigg\lfloor \frac{W_{in} + 2 \times \text{padding}[1] - \text{dilation}[1] \times (k_W - 1) - 1}{\text{stride}[1]} + 1 \Bigg\rfloor Wout=⌊stride[1]Win+2×padding[1]−dilation[1]×(kW−1)−1+1⌋
5. 权重与偏置
weight
:[out_channels, in_channels/groups, kH, kW]
bias
:[out_channels]
(若有)
conv = nn.Conv2d(3, 16, 3)
print(conv.weight.shape) # torch.Size([16, 3, 3, 3])
print(conv.bias.shape) # torch.Size([16])
6. 源码解析(PyTorch 2.x)
torch/nn/modules/conv.py
(简化版):
class Conv2d(_ConvNd):
def __init__(self, in_channels, out_channels, kernel_size, stride=1,
padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros',
device=None, dtype=None):
kernel_size = _pair(kernel_size)
stride = _pair(stride)
padding = _pair(padding)
dilation = _pair(dilation)
super(Conv2d, self).__init__(
in_channels, out_channels, kernel_size, stride, padding,
dilation, False, _pair(0), groups, bias, padding_mode,
device=device, dtype=dtype)
def forward(self, input):
return F.conv2d(
input, self.weight, self.bias, self.stride,
self.padding, self.dilation, self.groups)
核心点:
- 参数封装到
_ConvNd
基类 - 前向传播调用
F.conv2d
(高效 C++/CUDA 实现)
7. 初始化方式
PyTorch 默认采用 Kaiming 正态初始化(He init):
权重:
N(0,2/fan_in) \mathcal{N}(0, \sqrt{2/fan\_in}) N(0,2/fan_in)
偏置:均匀分布
[-bound, bound]
,其中bound = 1/sqrt(fan_in)
8. 实际使用案例
(1) 基本卷积
conv = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
x = torch.randn(1, 3, 32, 32) # batch=1, 3通道, 32x32图像
y = conv(x)
print(y.shape) # torch.Size([1, 16, 32, 32])
(2) 卷积 + 激活 + 池化
model = nn.Sequential(
nn.Conv2d(3, 16, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
(3) 分组卷积
# 深度卷积 (groups=in_channels)
depthwise = nn.Conv2d(32, 32, 3, padding=1, groups=32)
(4) 空洞卷积
dilated = nn.Conv2d(16, 16, 3, dilation=2, padding=2)
9. 常见技巧与注意事项
保持输入输出尺寸相同
使用padding="same"
(PyTorch >= 1.10),或手动计算填充量:padding=kernel_size−12 padding = \frac{kernel\_size - 1}{2} padding=2kernel_size−1
去掉偏置(如 BatchNorm 后面接卷积层时)
nn.Conv2d(64, 128, 3, bias=False)
查看参数量
sum(p.numel() for p in conv.parameters())
可视化卷积核(比如在图像任务中)
kernels = conv.weight.detach().cpu()
10.综合示例:小型 CNN 分类器
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super(SimpleCNN, self).__init__()
# 输入: (N, 3, 32, 32) 例如 CIFAR-10
self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(16) # 批归一化
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 下采样一半
# 输入: (N, 16, 16, 16)
self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
self.bn2 = nn.BatchNorm2d(32)
self.pool2 = nn.MaxPool2d(2, 2)
# 输入: (N, 32, 8, 8)
self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
self.bn3 = nn.BatchNorm2d(64)
self.pool3 = nn.AdaptiveAvgPool2d((1, 1)) # 自适应全局平均池化到 (1,1)
# 全连接层 (输入: 64, 输出: num_classes)
self.fc = nn.Linear(64, num_classes)
def forward(self, x):
x = self.pool1(F.relu(self.bn1(self.conv1(x))))
x = self.pool2(F.relu(self.bn2(self.conv2(x))))
x = self.pool3(F.relu(self.bn3(self.conv3(x))))
# 展平: (N, 64, 1, 1) → (N, 64)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
## 测试网络
if __name__ == "__main__":
model = SimpleCNN(num_classes=10)
x = torch.randn(4, 3, 32, 32) # batch=4, 3通道彩色图像
y = model(x)
print("输入:", x.shape) # torch.Size([4, 3, 32, 32])
print("输出:", y.shape) # torch.Size([4, 10])
网络结构流程
- 输入: (N, 3, 32, 32)
- Conv1+BN+ReLU+MaxPool → (N, 16, 16, 16)
- Conv2+BN+ReLU+MaxPool → (N, 32, 8, 8)
- Conv3+BN+ReLU+AvgPool → (N, 64, 1, 1)
- Flatten + FC → (N, 10)
特点
- 使用
Conv2d
提取局部特征 BatchNorm2d
加快收敛、防止过拟合ReLU
激活非线性MaxPool2d
/AdaptiveAvgPool2d
控制特征图大小Linear
映射到分类结果
总结
nn.Conv2d
= 二维卷积层,本质是输入张量和可学习卷积核的互相关运算。- 参数控制卷积核大小、步长、填充、扩张、分组等。
- 广泛应用于 CNN 特征提取、图像识别、目标检测等任务。
- PyTorch 内部实现高效,支持 GPU/自动求导。