参考链接
pytorch官方文档
应用一个2D卷积在由多个输入平面组成的输入信号上。
在最简单的情况下,具有输入大小 $(N, C_{in}, H, W)$ 和输出 $(N, C_{out}, H_{out}, W_{out})$ 的层的输出值可以精确描述为:
- *是有效的2D互相关运算符
- N 是批大小
- C 表示通道数
- H 是像素中输入平面的高度
- W 是像素中的宽度。
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) |
stride: 控制交叉相关的步长,可以是一个数字或一个元组。padding: 控制应用于输入的填充量。可以是字符串{'valid', 'same'}或一个整数/整数元组,指定在两侧应用的隐式填充量。dilation: 控制核心点之间的间距;也称为à trous算法。这个比较难描述,但是这个链接有一个很好的视觉化示例,展示了dilation的作用。groups: 控制输入和输出之间的连接。in_channels和out_channels必须都能被groups整除。例如:- 当
groups=1时,所有输入都与所有输出进行卷积。 - 当
groups=2时,操作相当于并行地拥有两个卷积层,每个层看到一半的输入通道并产出一半的输出通道,然后将两者的输出连接起来。 - 当
groups=in_channels时,每个输入通道都与其自己的一组滤波器(尺寸为 $(\frac{out_-channels}{in_-channels})$ 进行卷积。
- 当
参数 kernel_size、stride、padding、dilation 可以是:
- 一个
int单个整数 - 在这种情况下,相同的值用于高度和宽度维度 - 一个由两个整数组成的
tuple元组 - 在这种情况下,第一个int用于高度维度,第二个int用于宽度维度
注意
注意:当
groups == in_channels且out_channels == K * in_channels,其中K是一个正整数时,该操作也被称为“深度可分卷积”。- 换句话说,对于输入大小为$(N, C_{in}, L_{in})$ 的情况,可以使用深度乘数K进行深度可分卷积,其参数为 $(C_{in} = C_{in}, C_{out} = C_{in} \times K, …, groups = C_{in})$。
注意:在某些情况下,当在CUDA设备上给定张量并使用CuDNN时,此操作可能选择一个非确定性算法以提高性能。如果这不可取,你可以尝试通过设置
torch.backends.cudnn.deterministic = True来使操作变为确定性(可能以牺牲性能为代价)。更多信息请参见可重现性。注意:
padding='valid'相当于无填充。padding='same'会填充输入,使输出具有与输入相同的形状。然而,这种模式不支持步长值不为1的任何情况。注意:该模块支持复杂的数据类型,即
complex32,complex64,complex128。
参数
in_channels(int) - 输入图像的通道数。out_channels(int) - 卷积产生的通道数。kernel_size(int 或 tuple) - 卷积核的大小。stride(int 或 tuple, 可选) - 卷积的步长。默认值:1。padding(int, tuple 或 str, 可选) - 填充到输入的所有四边。默认值:0。padding_mode(str, 可选) -'zeros','reflect','replicate'或'circular'。默认:'zeros'。dilation(int 或 tuple, 可选) - 核元素之间的间距。默认值:1。groups(int, 可选) - 从输入通道到输出通道的阻塞连接数。默认值:1。bias(bool, 可选) - 如果为True,则向输出添加可学习的偏置。默认值:True。
形状
- 输入:$(N, C_{in}, H_{in}, W_{in})$ 或 $(C_{in}, H_{in}, W_{in})$
- 输出:$(N, C_{out}, H_{out}, W_{out})$ 或 $(C_{out}, H_{out}, W_{out})$,其中
变量
weight(Tensor): 模块可学习的权重,其形状为 (out_channels, in_channels / groups, kernel_size[0], kernel_size[1])。这些权重的值是从均匀分布 U(-√k, √k) 中采样的,其中 k = $\frac{1}{C_{in} * \prod_{i=0}^{groups} kernel_size[i]}$。bias(Tensor): 如果bias为True,则模块形状为 (out_channels) 的可学习偏置。这些权重的值是从 U(-√k, √k) 中采样的,其中 k = $\frac{1}{C_{in} * \prod_{i=0}^{groups} kernel_size[i]}$。
示例
1 | # 使用正方形核和相同步长 |
测试
nn.Conv2d(类式接口)
基本用法:
1 | import torch |
运行结果:
1 | torch.Size([1, 3, 26, 26]) |
特别注意,在使用时应该直接使用layer(x)而不是layer.forward(x),因为前者实际是调用了__call__(),而PyTorch在这个函数中定义了一些hooks,如果要使用这些钩子的功能就只能用前者了!它会先运行hooks再运行.forward()函数。
在前面定义的卷积层的基础上,查看一下卷积层的权重(即卷积核)信息和偏置信息:
1 | print(layer.weight) |
运行结果:
1 | tensor([[[[ 0.1277, -0.1672, 0.1102], |
查看一下shape:
1 | print(layer.weight.shape) |
运行结果:
1 | torch.Size([3, 1, 3, 3]) |
F.conv2d(函数式接口)
PyTorch里一般小写的都是函数式的接口,相应的大写的是类式接口。函数式的更加low-level一些,如果不需要做特别复杂的配置只要用类式接口就够了。
可以这样理解:nn.Conv2d是[2D卷积层],而F.conv2d是[2D卷积操作]。
1 | import torch |
运行结果:
1 | torch.Size([1, 16, 26, 26]) |