torch.nn.Conv1d计算过程简易图解

参考:
Pytorch 从 0 开始学(6)——Conv2d 详解 - 知乎 (zhihu.com)
Conv1d — PyTorch 1.11.0 documentation

本文结合图例说明Conv1d的基本计算过程。

Conv1d

torch.nn.Conv1d(in_channels, out_channels, kernel_size, 
	stride=1, padding=0, dilation=1, groups=1, 
	bias=True, padding_mode='zeros', device=None, dtype=None)

输入维度(N, Cin, Lin)
输出维度(N, Cout, Lout)

这里,N为batchsize, C i n , C o u t C_{in}, C_{out} Cin,Cout分别表示输入输出channel数, L i n , L o u t L_{in}, L_{out} Lin,Lout分别表示输入输出的channel内信号长度。
下文简写作Cin、Cout、Lin、Lout。

关键参数如下:

  • in_channels, out_channels: 输入输出通道数
  • kernel_size: 卷积核长度
  • stride=1: 卷积核步长
  • padding=0, padding_mode=‘zeros’: 边沿扩充, 目前略过
  • dilation=1: 采样间隔
  • bias=True: 是否加入bias

计算过程

输入输出维度

本文关注简单情形,假设采用默认参数(即 stride=1, padding=0, dilation=1),
L o u t = L i n − k e r n e l _ s i z e + 1 L_{out} = L_{in} - kernel\_size + 1 Lout=Linkernel_size+1

参数假设:

  • 模型:Cin = 4,Cout = 3,kernel_size = 2。
  • 输入:batchsize=1, Cin = 4, Lin = 3,即shape为(1, 4, 3)

Lout 计算

由上述公式:

Lout = 3 - 2 + 1 = 2,见下图:
torch.nn.Conv1d计算过程简易图解_第1张图片

因此输出维度 (Cout, Lout) 为 (3, 2)。

torch.nn.Conv1d计算过程简易图解_第2张图片

下面将由这个例子出发,说明计算过程。
in, out分别表示输入、输出tensor。

模型参数

模型有两类可学习参数:

  • weight: shape = (Cout, Cin, kernel_size) = (3, 4, 2)
  • bias: bias=True 时有效, shape = (Cout) = (3)

互相关(cross-correlation)计算

根据 pytorch 的计算公式:

o u t ( j ) = b i a s ( j ) + ∑ i = 0 C i n − 1 w e i g h t ( j , i ) ⋆ i n ( i ) out(j) = bias(j) + \sum_{i=0}^{C_{in}-1} weight(j, i) \star in(i) out(j)=bias(j)+i=0Cin1weight(j,i)in(i)

其中 ⋆ \star 表示互相关算符(cross-correlation operator), 下面以 w e i g h t ( j , i ) ⋆ i n ( i ) weight(j, i) \star in(i) weight(j,i)in(i) 为例, 取 j=1, i=2。

求和符号 Σ 后每一项的计算过程如下图:

torch.nn.Conv1d计算过程简易图解_第3张图片

weight 以"窗口滑动"的方式, 与 in(2) 中的元素(i0, i1, i2)依次运算。
计算结果为(j1, j2),构成输出的一部分。

最终 out(j) 的计算方式如下图:
torch.nn.Conv1d计算过程简易图解_第4张图片步骤如下:

  1. 求 out(1),需要用到 weight(1,*) 和 bias(1)。
  2. 对输入的每个 channel i,与 weight(1,i) 运算后得到 Cin 个新向量,这里是 4 个 (1, 2) 向量[蓝/白色]。
  3. 4 个向量直接相加,合并为 1 个向量[黄色]。
  4. 合并后的向量各个位置加上 bias(1) [灰色],就得到了最终的 out(1)[橙色]。

过程总结

最终的out由out(1)、out(2)、out(3)拼接而成, 整体过程总结如下:
torch.nn.Conv1d计算过程简易图解_第5张图片

对输入的每个 channel,都算出一个与输出 shape 一致的 tensor,然后叠加。最后再加上 bias,即为输出。

  • Cin 维度上:每个 in_channel 影响所有 out_channel,反过来每个 out_channel 也可包含所有 in_channel 的信息。
  • Lin 维度上:通过 weight 将长为 kernel_size 的一段元素联系起来。

验证

python 代码如下,可以验证上述过程:

import numpy as np
import torch
import torch.nn as nn
#print(torch.__version__) #1.8.0+cu111

#模型设置与参数赋值
conv = nn.Conv1d(in_channels=4, out_channels=3, kernel_size=2)
bias = torch.FloatTensor([0.1, 0.2, 0.3])
weight = np.arange(24).reshape(3,4,2)
weight = torch.FloatTensor(weight)
for name, param in conv.named_parameters():
    if name == 'weight':
        param.data = weight
    if name == 'bias':
        param.data = bias
    print(name, param.shape, param)

#构造输入并计算输出
input = [
    [0,0,0],
    [0,0,1],
    [0,1,1],
    [1,1,1]
]
input = torch.FloatTensor(input).reshape(1,4,3)
with torch.no_grad():
    print('\ninput:\n', input)
    output = conv(input)
    print('output:\n', output)

输出结果为:

#输出结果
weight torch.Size([3, 4, 2]) Parameter containing:
tensor([[[ 0.,  1.],
         [ 2.,  3.],
         [ 4.,  5.],
         [ 6.,  7.]],

        [[ 8.,  9.],
         [10., 11.],
         [12., 13.],
         [14., 15.]],

        [[16., 17.],
         [18., 19.],
         [20., 21.],
         [22., 23.]]], requires_grad=True)
bias torch.Size([3]) Parameter containing:
tensor([0.1000, 0.2000, 0.3000], requires_grad=True)

input:
 tensor([[[0., 0., 0.],
         [0., 0., 1.],
         [0., 1., 1.],
         [1., 1., 1.]]])
output:
 tensor([[[ 18.1000,  25.1000],
         [ 42.2000,  65.2000],
         [ 66.3000, 105.3000]]])

你可能感兴趣的:(学习记录,pytorch,cnn,python)