首先明确一点,PyTorch中的一维卷积是从左往右做的,不是从上往下。
然后明确第二点,一维卷积和二维卷积最大的区别在于,一维卷积的卷积方向只有一个维度,一维卷积的卷积核不像二维卷积核一样可以左右和上下两个维度移动,在PyTorch中,一维卷积核仅仅可以在左右这个单一的一维方向上移动,移动的步长由stride参数确定,而卷积核是否会移动出待卷积的数据由padding参数确定,这里的“移动出”意味着卷积核的某些部分可能会移动到待卷积数据之外,而仍然有某些卷积核数据和待卷积数据相重合,具体例子请见后续说明。
torch.nn.Conv1d(
in_channels: int,
out_channels: int,
kernel_size: _size_1_t,
stride: _size_1_t = 1,
padding: _size_1_t | str = 0,
dilation: _size_1_t = 1,
groups: int = 1,
bias: bool = True,
padding_mode: str = 'zeros',
device: Any | None = None,
dtype: Any | None = None
)
上述是PyTorch中一维卷积函数的声明,其中的参数很重要,这里主要只用到前面几个。
考虑一个一维卷积的使用:
nn.Conv1d(
in_channels=32,
out_channels=128,
kernel_size=20,
stride=1,
padding='same',
),
我有一个batch的数据:
其中 N 为我的 batch size。
那么首先第一点,从整体上来看,我的数据可以理解为,对于 32×500的矩阵,我有N个,那么一共会有out_channels个卷积核,其中每个卷积核都会在32×500的矩阵上做卷积,每个卷积核要对N个矩阵都做一次,那么最终会得到的数据应该是 N×out_channels×A,其中A不知道,要看具体的卷积情况而言。
这里很重要的一点是,对于一个卷积核,它的size是a×b,但在函数中的kernel_size我们只给了一个单值,事实上,一个一维卷积核的size会是in_channels×kernel_size,没错,对于batch size为N的批量数据中的每一个数据而言,对于其中每一个32×500的矩阵而言,其对应的卷积核的高度和矩阵的高度是一致的,也就是说,对于N×32×500的数据而言,它的一维卷积参数的in_channels应该为32。
然后卷积核会在横向的方向上移动,接下来就很好理解了,如果padding为valid,那么最终得到的数据维度应该为N×out_channels×,如果padding为same,那么意味着卷积核可以移动到待卷积的矩阵之外,最终得到的数据维度应该还为N×out_channels×500。
下面以N×3×10的批量数据为例,下面的表格显示的是其中一个矩阵3×10的情况,然后conv1d的声明为
nn.Conv1d(
in_channels=3,
out_channels=2,
kernel_size=4,
stride=1,
padding='same',
),
那么首先我们会得到一个3×4的卷积核,其中卷积核的高度3(in_channels)和矩阵的高度3一致(如果矩阵的高度为4,或者别的什么高度,那么in_channels也要为4,高度这里是定死的,卷积核只能够向右边一个维度移动,不能够上下移动,这也是一维卷积的含义),然后卷积核的宽度为4,卷积方向一直朝右走。
后面的就省略了,一直到卷积核移动到最后的部分。
然后到此时注意看padding参数的值,如果是'valid',那么卷积核就不能再走了,如果是'same'那么还可以往右继续移动,移动出去的部分没有覆盖到数据,这些没有数据的地方由矩阵最外面那一圈的数据替代,需要注意的是,当出现下面这种情况的时候
如果padding是same,仍然是ok的,最右边多出来的数据全部由矩阵(待卷积数据)最右边一列的数据替代。因此,如果Conv1d的kernel_size是999999,而padding是same,那么哪怕给定的批数据的shape为N×in_channels×1都没有问题,多出来的数据全部由边界来替代。
same的另一个含义是最终得到的维度和原数据维度相同,如果是valid卷积,那么宽度为W的数据卷积出来的最终宽度应为,而如果是same,那么卷积出来的数据的宽度仍然为W。
上述内容讲述了一个一维卷积核在一个批数据中单个矩阵中的操作,仍然沿用上面例子中的各个参数,padding为same,对于一个批数据N×3×10中的一个3×10的矩阵进行一维卷积而言,得到一个一维的数据1×10,而out_channels=2,这意味着会有两个卷积核同时对每个矩阵进行卷积,最后仍然会得到一个批量数据,批量维度N是不变的,最后得到的数据维度为N×2(out_channels)×10(原矩阵的宽度,因为padding是same)。