如何在Keras中设置1D卷积和LSTM

28

我想使用1D-Conv层接LSTM层来对一个16通道400时间步长的信号进行分类。

输入形状由以下组成:

  • X = (n_samples, n_timesteps, n_features),其中n_samples=476n_timesteps=400n_features=16是信号的样本数、时间步数和特征(或通道)数。

  • y = (n_samples, n_timesteps, 1)。每个时间步长都用0或1(二进制分类)标记。

我使用1D-Conv提取时间信息,如下图所示。F=32K=8是过滤器和内核大小。在1D-Conv之后使用1D-MaxPooling。32单元LSTM用于信号分类。模型应返回y_pred = (n_samples, n_timesteps, 1)

enter image description here

代码片段如下所示:

input_layer = Input(shape=(dataset.n_timestep, dataset.n_feature))
conv1 = Conv1D(filters=32,
               kernel_size=8,
               strides=1,
               activation='relu')(input_layer)
pool1 = MaxPooling1D(pool_size=4)(conv1)
lstm1 = LSTM(32)(pool1)
output_layer = Dense(1, activation='sigmoid')(lstm1)
model = Model(inputs=input_layer, outputs=output_layer) 

模型概要如下:

enter image description here

但是,我遇到了以下错误:

ValueError: Error when checking target: expected dense_15 to have 2 dimensions, but got array with shape (476, 400, 1).

我猜问题出在形状不正确。请告诉我如何修复它。

另一个问题是时间步数。因为input_shape被分配在1D卷积中,我们如何让LSTM知道时间步长必须为400?


我想根据@today的建议添加模型图。在这种情况下,LSTM的时间步将是98。这种情况下需要使用TimeDistributed吗?我试图在Conv1D中应用TimeDistributed失败了。

enter image description here

是否有一种方法可以在通道之间执行卷积,而不是时间步长?例如,一个过滤器(2, 1)遍历每个时间步,如下图所示。enter image description here

谢谢。


你是否需要使用“TimeDistributed(Dense(1”而不是“Dense(1”? - swiftg
回答你问题的最后一部分。理论上,由于数学运算的本质,卷积会将输入缩小一定因子。为了解决这个问题,您需要使用填充。即在CONV1D中设置填充padding ='same' - sgDysregulation
@GurmeetSingh 要应用 TimeDistributed,LSTM层的 return_sequences 参数必须等于 True。即使这样做了,TimeDistributed(Dense(1)) 仍然与 Dense(1) 相同。 - today
2个回答

14
如果您希望为每个时间步预测一个值,我想到了两个略有不同的解决方案:
1)删除MaxPooling1D层,在Conv1D层中添加padding='same'参数,并在LSTM中添加return_sequence=True参数,以便LSTM返回每个时间步的输出:
from keras.layers import Input, Dense, LSTM, MaxPooling1D, Conv1D
from keras.models import Model

input_layer = Input(shape=(400, 16))
conv1 = Conv1D(filters=32,
               kernel_size=8,
               strides=1,
               activation='relu',
               padding='same')(input_layer)
lstm1 = LSTM(32, return_sequences=True)(conv1)
output_layer = Dense(1, activation='sigmoid')(lstm1)
model = Model(inputs=input_layer, outputs=output_layer)

model.summary()

模型概要如下:

Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 400, 16)           0         
_________________________________________________________________
conv1d_4 (Conv1D)            (None, 400, 32)           4128      
_________________________________________________________________
lstm_4 (LSTM)                (None, 400, 32)           8320      
_________________________________________________________________
dense_4 (Dense)              (None, 400, 1)            33        
=================================================================
Total params: 12,481
Trainable params: 12,481
Non-trainable params: 0
_________________________________________________________________

2) 仅需将 Dense 层中的 units 数量更改为 400,并将 y 重塑为 (n_samples, n_timesteps)

from keras.layers import Input, Dense, LSTM, MaxPooling1D, Conv1D
from keras.models import Model

input_layer = Input(shape=(400, 16))
conv1 = Conv1D(filters=32,
               kernel_size=8,
               strides=1,
               activation='relu')(input_layer)
pool1 = MaxPooling1D(pool_size=4)(conv1)
lstm1 = LSTM(32)(pool1)
output_layer = Dense(400, activation='sigmoid')(lstm1)
model = Model(inputs=input_layer, outputs=output_layer)

model.summary()

模型概要如下:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_6 (InputLayer)         (None, 400, 16)           0         
_________________________________________________________________
conv1d_6 (Conv1D)            (None, 393, 32)           4128      
_________________________________________________________________
max_pooling1d_5 (MaxPooling1 (None, 98, 32)            0         
_________________________________________________________________
lstm_6 (LSTM)                (None, 32)                8320      
_________________________________________________________________
dense_6 (Dense)              (None, 400)               13200     
=================================================================
Total params: 25,648
Trainable params: 25,648
Non-trainable params: 0
_________________________________________________________________

不要忘记,在这两种情况下,你必须使用'binary_crossentropy'(而不是'categorical_crossentropy')作为损失函数。我预计这种解决方案的准确率会低于解决方案#1;但你必须尝试两种方案并尝试更改参数,因为它完全取决于您尝试解决的具体问题和数据的性质。
更新: 你要求一个卷积层只包括一个时间步和k个相邻的特征。是的,你可以使用Conv2D层来实现。
# first add an axis to your data
X = np.expand_dims(X)   # now X has a shape of (n_samples, n_timesteps, n_feats, 1)

# adjust input layer shape ...
conv2 = Conv2D(n_filters, (1, k), ...)   # covers one timestep and k features
# adjust other layers according to the output of convolution layer...

虽然我不知道你为什么要这么做,但是如果要使用卷积层的输出(即(?, n_timesteps, n_features, n_filters)),一种解决方法是使用嵌套在TimeDistributed层中的LSTM层。或者另一种解决方法是将最后两个维度展平。

@ThuanN。请阅读我在回复GurmeetSingh的评论 - today
如果我在通道之间进行卷积,是否需要转置数据集,即(无,400,16)->(无,16,400),还是需要使用conv2D?您能展示一些这种方法的片段吗?谢谢。 - Thuan N.
@ThuanN. 你的意思是如果有16个通道,那么你想要一个卷积层,核尺寸为1(即只覆盖一个时间步长),并且为每个通道分别配备16个独立的过滤器? - today
如上文所示,我想在每个时间步骤中的一个或多个通道中进行卷积。例如,在时间步0,内核将在(通道0,通道1),然后是(通道1,通道2),然后是(通道2,通道3)之间进行卷积。因此,内核大小为2x1。如果我们想在4个通道之间进行卷积,则使用4x1内核。您认为conv1D可以进行这样的配置吗?谢谢。 - Thuan N.
@ThuanN。您不能选择某些通道并仅对它们执行卷积。将内核大小设置为1,在每个时间步上执行卷积,但是在该时间步的所有通道上执行。 - today
显示剩余7条评论

3
输入和输出形状分别为(476, 400, 16) 和 (476, 1),这意味着每个完整序列只输出一个值。您的LSTM未返回序列(return_sequences = False)。但是即使在LSTM之前进行Conv1D和MaxPooling,也会压缩输入。因此,LSTM本身将得到一个样本(98,32)。我假设您希望每个输入步骤都有一个输出。假设Conv1D和MaxPooling对输入数据有用,您可以尝试一种seq to seq方法,其中您将第一个N/w的输出交给另一个网络以获取400个输出。我建议您查看一些模型,例如下面的编码器解码器seq2seq网络:https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html https://machinelearningmastery.com/define-encoder-decoder-sequence-sequence-model-neural-machine-translation-keras/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接