卷积操作

卷积核和扫过的小区域对应位置相乘再求和的操作,卷积完成后一般要加个偏置bias。一种Kernel如果分成多个通道上的子Kernel做卷积运算,最后运算结果还要加在一起后,再加偏置。

nn.Conv2d(类式接口)

基本用法

  1. import torch
  2. from torch import nn
  3. """2维的卷积层,用于图片的卷积"""
  4. # 输入图像的通道数=1(灰度图像),卷积核的种类数=3
  5. # 卷积核的shape是3乘3的,扫描步长为1,不加padding
  6. layer = nn.Conv2d(1, 3, kernel_size=3, stride=1, padding=0)
  7. """要输入的原始图像"""
  8. # 样本数=1,通道数=1,图像的shape是28乘28的
  9. x = torch.rand(1, 1, 28, 28)
  10. """使用上面定义的卷积层layer和输入x,完成一次卷积的前向运算"""
  11. out = layer.forward(x)
  12. # 得到的还是1张图片,因为用了3种kernel所以输出的通道数变成3了
  13. # 因为没加padding,原来28乘28的图像在3乘3卷积下得到的边长是28-3+1=26
  14. print(out.shape) # torch.Size([1, 3, 26, 26])
  15. """添加padding看看"""
  16. # 这次使用padding为1.所以原始图像上下左右都加了一层0
  17. layer = nn.Conv2d(1, 3, kernel_size=3, stride=1, padding=1)
  18. print(layer.forward(x).shape) # torch.Size([1, 3, 28, 28])
  19. """步长设置为2看看"""
  20. # stride设置为2,也就是每次移动2格子(向上或者向右)
  21. layer = nn.Conv2d(1, 3, kernel_size=3, stride=2, padding=1)
  22. # 相当于每次跳1个像素地扫描,输出的Feature Map直接小了一半
  23. print(layer.forward(x).shape) # torch.Size([1, 3, 14, 14])
  24. """实际使用时,应该这样用!"""
  25. out = layer(x)
  26. print(out.shape) # torch.Size([1, 3, 14, 14])

运行结果

  1. torch.Size([1, 3, 26, 26])
  2. torch.Size([1, 3, 28, 28])
  3. torch.Size([1, 3, 14, 14])
  4. torch.Size([1, 3, 14, 14])

查看卷积层信息

  1. # 查看一下卷积层的权重(即卷积核)信息和偏置信息
  2. print(layer.weight)
  3. print(layer.bias)
  4. # 查看卷积层形状
  5. print(layer.weight.shape)
  6. print(layer.bias.shape)

运行结果

  1. tensor([[[[ 0.1277, -0.1672, 0.1102],
  2. [ 0.3176, 0.0236, 0.2537],
  3. [ 0.0737, 0.0904, 0.0261]]],
  4. [[[ 0.0349, -0.2042, 0.1766],
  5. [-0.0938, -0.0470, 0.2011],
  6. [-0.2460, 0.0876, 0.3124]]],
  7. [[[-0.2361, -0.0971, -0.1031],
  8. [-0.0756, -0.3073, 0.3227],
  9. [-0.1951, -0.2395, -0.0769]]]], requires_grad=True)
  10. Parameter containing:
  11. tensor([ 0.0790, -0.3261, 0.0697], requires_grad=True)
  12. torch.Size([3, 1, 3, 3])
  13. torch.Size([3])

F.conv2d(函数式接口)

PyTorch里一般小写的都是函数式的接口,相应的大写的是类式接口。可以这样理解:nn.Conv2d 是 [2D卷积层],而 F.conv2d 是 [2D卷积操作]。

基本用法

  1. import torch
  2. from torch.nn import functional as F
  3. """手动定义卷积核(weight)和偏置"""
  4. w = torch.rand(16, 3, 5, 5) # 16种3通道的5乘5卷积核
  5. b = torch.rand(16) # 和卷积核种类数保持一致(不同通道共用一个bias)
  6. """定义输入样本"""
  7. x = torch.randn(1, 3, 28, 28) # 1张3通道的28乘28的图像
  8. """2D卷积得到输出"""
  9. out = F.conv2d(x, w, b, stride=1, padding=1) # 步长为1,外加1圈padding
  10. print(out.shape)
  11. out = F.conv2d(x, w, b, stride=2, padding=2) # 步长为2,外加2圈padding
  12. print(out.shape)

运行结果

  1. torch.Size([1, 16, 26, 26])
  2. torch.Size([1, 16, 14, 14])

原大小nn.Conv2d和F.conv2d - 图1, 卷积核大小 nn.Conv2d和F.conv2d - 图2,池化大小 nn.Conv2d和F.conv2d - 图3padding(填充)=nn.Conv2d和F.conv2d - 图4strids(滑动步长)=nn.Conv2d和F.conv2d - 图5,公式通用:
nn.Conv2d和F.conv2d - 图6


引用

知乎地址:https://zhuanlan.zhihu.com/p/161660908