最近老师让做一个比较多个池化操作的作业。其中包含了max,min,avg,k-max, dynamic k-max。
前面四种还好说,max和avg在pytorch.nn.functional里面就有,min只需要给输入值加个负号,然后在外面加个负号会正即可。k-max也是网上有很多的实现方式。但是关于dynamic k-max的资料在百度里面实在太少。谷歌里面也都是一些tf,或者别的实现方式的,而我要的是pytorch的。
好吧!其实pytorch的我也在github里面找到了,只是当时我已经用我自己的方式实现了,所以也就没有用他的那种方法。
先还是讲一下dynamic k-max 具体是怎么回事吧!
首先dynamic k-max 出现在这篇论文里面:A Convolutional Neural Network for Modelling Sentences
论文里是这样讲的:
动态k-max池化操作是在k-max池化操作的基础上以k为句子长度和网络深度的池化操作。 尽管可以使用许多功能,但我们仅按如下所示对池参数建模:
其中l是当前应用池化的卷积层的数量,L是网络中卷积层的总数; ktop是最顶层卷积层的固定池参数(第3.2节)。 例如,在具有三个卷积层且ktop = 3的网络中,对于长度为s = 18的输入语句,第一层的合并参数为k1 = 12,第二层的合并参数为k2 = 6; 第三层具有固定的合并参数k3 = ktop =3。公式4是描述长度为s的句子中l阶特征的相关部分所需的值数量的模型。 例如,在情感预测中,根据等式,在长度为s的句子中,一阶特征(如肯定词)最多出现k1次,而二阶特征(如否定短语或从句)最多出现k2次。
我英语差,机翻的别介意。
其实里面最重要的就是(4)公式。
我现在将我实现的代码贴出来,
#x是输入,numoflayers是L,numlayer是l,k_top就不用说了,就是k-max的k
def dynamic_kmax_pooling(self,x,numoflayers,numlayer,dim,k_top):
tmepnum=int(((numoflayers - numlayer) * x.size()[dim]) / numoflayers) + 1#向上取整,x.size()[dim]是输入向量中max_len,也就是s
k=(tmepnum if tmepnum>k_top else k_top)#max操作
index = x.topk(k, dim=dim)[1].sort(dim=dim)[0]
return x.gather(dim, index)
你可以结合着上面的公式看,这段代码你会发现挺好理解的。完完本本的上面的那个公式好吧。
你看到你就以为结束了吗?
不,你错了。
还有一个点,非常的重要,那就是你没有发现吗?这样输出的向量是不固定的,也就是这样输出的向量的维数会随着k的变化而变化。因此也就不能使用全连接层去直接分类。
至少都需要在中间再加入一个卷积层,将经过的卷积层通过k-max转换为固定长度的向量,然后通过全连接层区分类。
#经过动态k-最大池化层,维度变为(batch_size, out_chanel, w=k, h=1)
x = [self.dynamic_kmax_pooling(x_item,numoflayers=2,numlayer=1,dim=2, k_top=self.args.k) for x_item in x]
x = [F.relu(conv(x_item)) for x_item in x for conv in self.conv2]#因为filter_sizes有3层,所以每增加一次卷积维数都会增加3
# 经过动态k-最大池化层,维度变为(batch_size, out_chanel, w=self.args.k, h=1)
x = [self.kmax_pooling(x_item, 2, self.args.k) for x_item in x]
# 将不同卷积核运算结果维度(batch,out_chanel,w,h=1)展平为(batch, outchanel*w*h)
x = [x_item.view(x_item.size(0), -1) for x_item in x]
# 将不同卷积核提取的特征组合起来,维度变为(batch, sum:outchanel*w*h)
x = torch.cat(x, 1)
# dropout层
x = self.dropout(x)
# 全连接层
logits = self.linear(x)
这样卷积层的总层数至少也得是2,经过dynamic k-max的层数也至少要比总层数少1,可以避免出现就是L-l==0的情况。
不知道,你现在懂了吗?没懂,我也没办法?自己查资料去!