Conv1d原理解析
目录
今天碰上了需要使用Conv1d的场景,但是对于in_channel,out_channel和kernel_size所影响的Conv1d层而进行的操作还是十分的迷惑,因此写下此篇文章记录自己的学习过程。
公式
![formula](/assets/20210927 conv1d/Conv1d_formula.png)
从公式可以看出,输入到Conv1d中的数据有三个维度,第一个维度N一般是batch_size,第二个维度一般为in_channel,第三个维度为序列的时间维度,在NLP中为词向量大小;输出维度基本相同,但是输出的第二个维度为out_channel。
公式限定了第i个bathc_size中输出的第j个channel。在计算过程中,bias自然不必多讲,求和内的k指遍历所有的in_channel,然后使用对应的权重和指定的输入向量进行卷积操作。
计算例子
如果懂的人已经可以看懂这条公式了,可是我不懂……所以还是用例子来说明一下
import torch
import torch.nn as nn
test_layer = nn.Conv1d(in_channels=3, out_channels=2, kernel_size=4) # 设计一个测试层,不同数据不一样,方便后面查阅
print(test_layer.weight.shape) # [2,3,4],即公式中的weight。对于每一个out_channel和in_channel的对应,都有一个kernel_size大小的卷积核
test_data = torch.rand(1,3,10) # 输入测试数据,3个channel,时间维为10
# 概要测试
output = test_layer(test_data)
print(output.shape) # [1,2,7] 2为out_channel,7为L_out,具体计算公式可参见官方文档
# 具体计算,以out(0, 0, 0)为例,即Ni=0, Coutj=0的第一个元素
print(output[0,0]) # [0.2545, 0.3342, 0.3826, 0.1345, 0.0378, 0.2512, 0.2467]
print(test_data[0,0],test_data[0,1],test_data[0,2])
# tensor([0.4535, 0.6660, 0.1077, 0.7335, 0.8431, 0.2407, 0.2267, 0.1635, 0.8010, 0.5360])
# tensor([0.5334, 0.7020, 0.7540, 0.7194, 0.9105, 0.2495, 0.3046, 0.3894, 0.6813, 0.0660])
# tensor([0.5396, 0.6200, 0.7067, 0.9654, 0.8220, 0.8894, 0.5200, 0.9175, 0.6874, 0.8831])
print(test_layer.weight[0,0], test_layer.weight[0,1],test_layer.weight[0,2])
# tensor([-0.1468, -0.0057, 0.0926, 0.0263], grad_fn=<SelectBackward>)
# tensor([ 0.1042, 0.0158, 0.2408, -0.0116], grad_fn=<SelectBackward>)
# tensor([ 0.0223, -0.2104, 0.1971, -0.0318], grad_fn=<SelectBackward>
## 第0个元素的计算,即为所有的in_channel与weight上对应的kernel_size做卷积的结果
a1 = torch.sum(test_layer.weight[0,0]*test_data[0,0,0:4])
a2 = torch.sum(test_layer.weight[0,1]*test_data[0,1,0:4])
a3 = torch.sum(test_layer.weight[0,2]*test_data[0,2,0:4])
print(a1+a2+a3) # tensor(0.1890, grad_fn=<AddBackward0>)
## 但是第0个元素 output[0,0,0] = 0.2545,不对啊……这是因为少了bias。加上bias[0]就对了
print(test_layer.bias) # tensor([ 0.0655, -0.1095], requires_grad=True)
# 另外一个例子,output(0, 1, 2),即out_channel=1的第二个元素,值为0.3290
print(output[0,1])
print(test_data[0,0],test_data[0,1],test_data[0,2])
print(test_layer.weight[1,0], test_layer.weight[1,1],test_layer.weight[1,2])
a1 = torch.sum(test_layer.weight[1,0]*test_data[0,0,2:6])
a2 = torch.sum(test_layer.weight[1,1]*test_data[0,1,2:6])
a3 = torch.sum(test_layer.weight[1,2]*test_data[0,2,2:6])
print(a1+a2+a3) # 0.4385,减去bias[1](-0.1095),结果正确