最近在用一维卷积做分类,所以看了一维卷积的API和各种博客。
主要的参考博客是(两个博客综合起来看很不错):
https://blog.csdn.net/qq_36323559/article/details/102937606
https://blog.csdn.net/sunny_xsc1994/article/details/82969867
Conv1
class torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
in_channels(int) – 输入信号的通道。在文本分类中,即为词向量的维度,也可以理解为特征向量的维度
out_channels(int) – 卷积产生的通道。可以理解为卷积核的数量
kernel_size(int or tuple) - 卷积核的尺寸,卷积核的大小为(k,),第二个维度是由in_channels来决定的,所以实际上卷积大小为kernel_size*in_channels
stride(int or tuple, optional) - 卷积步长
padding (int or tuple, optional)- 输入的每一条边补充0的层数
dilation(int or tuple, `optional``) – 卷积核元素之间的间距
groups(int, optional) – 从输入通道到输出通道的阻塞连接数
bias(bool, optional) - 如果bias=True,添加偏置
这一点需要特别注意:
kernel_size(int or tuple) - 卷积核的尺寸,卷积核的大小为(k,),第二个维度是由in_channels来决定的,所以实际上卷积大小为kernel_size*in_channels
例子1:
一维卷积的例子(batchsize是50,也只有一个kernel):
conv1 = nn.Conv1d(in_channels=256,out_channels=1,kernel_size=2)
input = torch.randn(50,35,256)
# batch_size x text_len x embedding_size -> batch_size x embedding_size x text_len
input = input.permute(0,2,1)
out = conv1(input)
print(out.size())
输出维度是:
torch.Size([50, 1, 34])
输入:
一个长度为35的序列,序列中的每个元素有256维特征,故输入可以看作(batch_size,35,256)
卷积核: size = (k,) , (k = 2),但是实际上卷积大小是2*256
例子2:
图中输入的词向量维度为5,输入大小为7*5,一维卷积核的大小分别为2、3、4,每个都有两个,总共6个特征。
对于k=4,见图中红色的大矩阵,卷积核大小为4*5,步长为1。这里是针对输入从上到下扫一遍,输出的向量大小为((7-4)/1+1)*1=4*1,最后经过一个卷积核大小为4的max_pooling,变成1个值。最后获得6个值,进行拼接,在经过一个全连接层,输出2个类别的概率。
假设我们有一句句子需要对其进行分类。句子中每个词是由n维词向量组成的,也就是说输入矩阵大小为m*n,其中m为句子长度。CNN需要对输入样本进行卷积操作,对于文本数据,filter不再横向滑动,仅仅是向下移动,有点类似于N-gram在提取词与词间的局部相关性。图中共有三种步长策略,分别是2,3,4,每个步长都有两个filter(实际训练时filter数量会很多)。在不同词窗上应用不同filter,最终得到6个卷积后的向量。然后对每一个向量进行最大化池化操作并拼接各个池化值,最终得到这个句子的特征表示,将这个句子向量丢给分类器进行分类,至此完成整个流程。