Machine learning cnn最大池-非连续滑动窗口(类似跳过克)?

Machine learning cnn最大池-非连续滑动窗口(类似跳过克)?,machine-learning,deep-learning,keras,convolution,Machine Learning,Deep Learning,Keras,Convolution,当使用keras构建一个简单的cnn(如下面的代码)时,当它用于基于文本的问题(如文档分类)时,我理解这就像我们从文本中提取4克(内核大小为4)并将其用作特征 model = Sequential() model.add(embedding_layer) model.add(Conv1D(filters=100, kernel_size=4, padding='same', activation='relu')) model.add(MaxPooling1D(po

当使用keras构建一个简单的cnn(如下面的代码)时,当它用于基于文本的问题(如文档分类)时,我理解这就像我们从文本中提取4克(内核大小为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克的信号

我想知道是否有一种方法可以让我们在卷积中创建“非连续滑动窗口”,也就是说,生成“跳过克”等价物。例如,给定以下1d向量:

[a, b, c, d, e, f]
内核_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’,只是因为我认为从实现的角度来看,生成第1部分或第2部分可能更容易,为修改后的conv1d层提供了另一个参数。如果是这样并且可行的话,我可以通过连接多个层来解决这个问题。但最起码要有一个扩展的conv1d层,它需要额外的参数,这样它就可以进行第一部分或第二部分的扫描

这一想法并不新鲜,因为本文已经对其进行了试验:

但请原谅我缺乏对keras的深入了解,我不知道如何实施它。有什么建议吗


非常感谢您提前

您可以创建一个自定义卷积层,其中权重矩阵中的某些元素为零

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

但在执行此操作之前,请注意,您可以通过在创建常规卷积层时传递
diagration\u rate=n
参数来创建“扩展”卷积。这将在窗口中的每个克之间跳过
n-1
g。您的窗口将具有固定的规则空间

为其创建自定义图层:

import keras.backend as K


#a 1D convolution that skips some entries
class 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原始代码以重新创建所有原始可能性

如果您的内核大小太长,那么定义
validGrams
var将非常枯燥。您可能需要创建一个版本,该版本采用一些跳过的索引,然后将其转换为上面使用的列表类型

不同的频道跳过不同的克数: 也可以在层内执行此操作,如果不使用带形状
(长度,)
)的
有效图形,而使用带形状
(长度,输出过滤器)

在这种情况下,在我们创建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)

这是否定期跳过具有固定步骤的令牌?或者您正在定义要跳过的特定标记?您的意思是跳过1、读取3、跳过1、读取3、跳过1、读取3……?是的,它经常跳过,但与您在第二次答复中描述的不太一样。我已经用一个详细的例子修改了这个问题。因此,就像你有一个窗口,有一个特定大小的间隙,可以忽略某些元素。随着你的更新(不同的频道跳过不同的克),我更新了下面的答案。谢谢你提供的详细信息。我将尝试Expanded conv,因为尽管它没有实现我想要的功能,但它是类似的,并且可能有用。我还将尝试连接多个skipconv1d层,每个层查看不同形状的skip gram,这似乎比您提到的其他实现更容易解决—我不太熟悉底层实现,因此这似乎是最安全的选择。我将在接下来的几天内汇报代码中有一个问题:K.重塑,什么是“K”?是“backend”作为“from keras import backend as K”吗?是的,它是
import keras.backend作为K
。我得到了一个堆栈跟踪很长的错误,但最终原因是“ValueError:max_poolg1d_12/MaxPool”(op:'MaxPool')的输入形状从1中减去4导致的负维度大小:[?,1,1100],当我构建一个连接4个skipconv1d层的模型时,每个层的内核大小为6,并且具有以下掩码:[1,1,1,1,0,1,1],[1,1,0,1,1],[1,1,0,1,1,1],[1,0,1,1,1,1,1]。下面是一个最大池层,大小为4。“model.add(maxpoolg1d(pool_size=4))时出错。”。我不确定这是否足够详细,但我只是想问我做错了什么?我假设你的句子长度等于6是对的吗?这个错误很明显:数据的长度(在卷积之后)不足以实现长度为4的池。