cnn 最大池化 – 非连续滑动窗口(类似于跳元模型)?

当使用 Keras 构建如下的简单 CNN 模型并将其应用于基于文本的问题(如文档分类)时,我理解这相当于从文本中提取 4-gram(核大小为 4)并将其用作特征。

    model = Sequential()    model.add(embedding_layer)    model.add(Conv1D(filters=100, kernel_size=4, padding='same', activation='relu'))    model.add(MaxPooling1D(pool_size=4))          model.add(Dense(4, activation='softmax'))    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

在这种情况下,Conv1D 层的核大小就像一个大小为 4 的滑动窗口,沿着文本中的标记序列滑动以发出 4-gram。

我想知道是否有办法在卷积中创建“非连续滑动窗口”,即生成类似于“跳元”的效果。例如,给定以下一维向量:

[a, b, c, d, e, f]

一个具有 kernel_size=3 和 skip=1 的 Conv1D 将会扫描以下序列:

[(a,c,d),(b,d,e),(c,e,f),(d,f,padding),(e,padding,padding)] union [(a,b,d),(b,c,e),(c,d,f),(d,e,padding),(e,f,padding),(f,padding,padding)]

我之所以说“union”,是因为从实现的角度来看,可能更容易生成第一部分或第二部分的序列,为修改后的 Conv1D 层提供另一个参数。如果可行,我可以通过连接多个层来解决这个问题。但最低要求是有一个扩展的 Conv1D 层,它可以接受额外的参数,以执行扫描的第一部分或第二部分。

这个想法并不新颖,因为这篇论文已经对此进行了实验:http://www.aclweb.org/anthology/D/D16/D16-1085.pdf

但由于我对 Keras 的深入了解不足,我不知道如何实现它。请提供一些建议,

提前感谢


回答:

你可以通过创建一个自定义的卷积层来实现这一点,其中权重矩阵中的某些元素为零。

你可以将常规的 Conv1D 层作为基类。

但在这样做之前,请注意,你可以通过在创建常规卷积层时传递 dilation_rate=n 参数来创建“扩张”卷积。这将在窗口中每个取用的 gram 之间跳过 n-1 个 gram。你的窗口将具有固定的规则间隔。

创建自定义层如下:

import keras.backend as K#a 1D convolution that skips some entriesclass SkipConv1D(Conv1D):    #in the init, let's just add a parameter to tell which grams to skip    def __init__(self, validGrams, **kwargs):        #for this example, I'm assuming validGrams is a list        #it should contain zeros and ones, where 0's go on the skip positions        #example: [1,1,0,1] will skip the third gram in the window of 4 grams           assert len(validGrams) == kwargs.get('kernel_size')        self.validGrams = K.reshape(K.constant(validGrams),(len(validGrams),1,1))            #the chosen shape matches the dimensions of the kernel            #the first dimension is the kernel size, the others are input and ouptut channels        #initialize the regular conv layer:        super(SkipConv1D,self).__init__(**kwargs)        #here, the filters, size, etc, go inside kwargs, so you should use them named        #but you may make them explicit in this __init__ definition        #if you think it's more comfortable to use it like this    #in the build method, let's replace the original kernel:    def build(self, input_shape):        #build as the original layer:        super(SkipConv1D,self).build(input_shape)        #replace the kernel           self.originalKernel = self.kernel        self.kernel = self.validGrams * self.originalKernel

请注意本回答中未处理的一些问题:

方法 get_weights() 仍然会返回原始的内核,而不是带有跳过掩码的内核。(如果有必要,可以修复这个问题,但这将需要额外的工作,请告诉我)

这个层中有未使用的权重。这是一个简单的实现。这里的重点是尽可能与现有的 Conv 层保持相似,保留其所有功能。也可以仅使用严格必要的权重,但这将大大增加复杂性,并且需要重写 Keras 的原始代码以重新创建所有原始的可能性。

如果你的 kernel_size 太长,定义 validGrams 变量将会非常繁琐。你可能想要创建一个版本,该版本接受一些跳过的索引,然后将其转换为上述类型的列表。

不同通道跳过不同的 gram:

在层内也可以这样做,如果你使用形状为 (length,)validGrams,你可以使用形状为 (length,outputFilters)validGrams

在创建 validGrams 矩阵的点上,我们应该像这样重塑它:

validGrams = np.asarray(validGrams)shp = (validGrams.shape[0],1,validGrams.shape[1])validGrams = validGrams.reshape(shp)self.validGrams = K.constant(validGrams)

你也可以简单地使用多个具有不同参数的并行 SkipConv1D 层,然后连接它们的结果。

inputs = Input(yourInputShape)out = embedding_layer(inputs)out1 = SkipConv1D(filters=50,kernel_size=4,validGrams=[1,0,1,1])(out)out2 = SkipConv1D(filters=50,kernel_size=4,validGrams=[1,1,0,1])(out)out = Concatenate()([out1,out2]) #if using 'channels_first' use Concatenate(axis=1)out = MaxPooling1D(pool_size=4)(out)out = Dense(4, activation='softmax')(out)model = Model(inputs,out)

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注