可以使用帮助为 Keras SimpleRNN 正确格式化数据

Posted

技术标签:

【中文标题】可以使用帮助为 Keras SimpleRNN 正确格式化数据【英文标题】:Could use help formatting data correctly for a Keras SimpleRNN 【发布时间】:2018-12-23 06:32:56 【问题描述】:

我在为简单的RNN 将数据转换为正确的格式时遇到了一些困难,或者我在正确地定义模型时遇到了困难。我希望有人能发现问题?

我正在尝试对长度为 278 的向量列表 X 进行分类,这些向量包含从长度为 9026 的字典 vocab 中选择的整数值,这些特征属于 0 类或 1 类。这是我的示例输入数据:

X=[[1,822,773,54,51,...],[2,3,1,41,3,...],[121,17,311,4,12,...],...]
y=[0,1,1,...]

例如np.array(X).shape=(1000,278)len(y)=1000 我的模型是:

model.add(L.InputLayer([None],dtype='int32'))
model.add(L.Embedding(input_dim=len(vocab)+1,\
                      output_dim=64,\
                      input_length=278))
model.add(L.SimpleRNN(64,return_sequences=True))
model.add(L.TimeDistributed(L.Dense(1,activation='softmax')))
model.compile(optimizer='adam',\
              loss='categorical_crossentropy',\
              metrics=['accuracy']
             )
print(model.summary())

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_8 (Embedding)      (None, 278, 64)           577728    
_________________________________________________________________
simple_rnn_7 (SimpleRNN)     (None, 278, 64)           8256      
_________________________________________________________________
time_distributed_7 (TimeDist (None, 278, 1)            65        
=================================================================
Total params: 586,049
Trainable params: 586,049
Non-trainable params: 0
_________________________________________________________________
None

我准备它们如下:

X=np.array(X)
y=keras.utils.to_categorical(y)

frac=0.3
random_state=42
X_train,X_tmp,y_train,y_tmp = \
    train_test_split(X,y,test_size=frac,random_state=random_state,\
                         stratify=y)
train=(X_train,y_train)
test=(X_tmp,y_tmp)

当我运行模型时:

model.fit(train[0],train[1],verbose=0,\
              batch_size=batch_size,\
              epochs=epochs,validation_data=test)

我收到以下错误:

ValueError: Error when checking target: expected time_distributed_1 
to have 3 dimensions, but got array with shape (5450, 2)

如果我将输入数据更改为

train=(X_train,y_train[:,:,np.newaxis])
test=(X_tmp,y_tmp[:,:,np.newaxis])

运行模型,我得到这个错误:

ValueError: Error when checking target: expected time_distributed_1 
to have shape (278, 2) but got array with shape (2, 1)

好吧,很明显我有问题,因为我的最后一个密集层正在寻找形状 278 而不是 2。所以我尝试了这个模型,但没有明确定义 input_length:

model.add(L.InputLayer([None],dtype='int32'))
model.add(L.Embedding(input_dim=len(vocab)+1,\
                      output_dim=64))
model.add(L.SimpleRNN(64,return_sequences=True))
model.add(L.TimeDistributed(L.Dense(1,activation='softmax')))
model.compile(optimizer='adam',\
              loss='categorical_crossentropy',\
              metrics=['accuracy']
             )
print(model.summary())

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_10 (Embedding)     (None, None, 64)          577728    
_________________________________________________________________
simple_rnn_9 (SimpleRNN)     (None, None, 64)          8256      
_________________________________________________________________
time_distributed_9 (TimeDist (None, None, 2)           130       
=================================================================
Total params: 586,114
Trainable params: 586,114
Non-trainable params: 0

当我运行模型时,我得到了

ValueError: Error when checking target: expected time_distributed_9
to have shape (None, 2) but got array with shape (2, 1)

我很困惑。谁能帮我诊断一下?

【问题讨论】:

【参考方案1】:

您为什么使用TimeDistributed?你根本不需要那个。对于每个长度为 278 的向量,您希望预测一个且只有一个介于 0 和 1 之间的数字。因此,最后一层的输出形状应为(None,1)。删除SimpleRNN 层的return_sequences 参数。你也不需要那个。像这样:

model.add(L.SimpleRNN(64))
model.add(L.Dense(1,activation='sigmoid'))

此外,你应该使用'sigmoid'作为激活函数,使最后一层输出一个介于0和1之间的值。并将'categorical_crossentropy'更改为'binary_crossentropy'。您也不需要将y 转换为分类。它已经是零和一,这很好(只需将其转换为 numpy 数组);请记住,您在这里进行二进制分类。

另外,使用第一个模型。您的第二个模型没有意义,因为您提到所有输入向量的长度都相同(即 278)。

最后一点:删除 InputLayer。这是多余的。您已经在嵌入层中设置了输入形状。

【讨论】:

我认为TimeDistributed 是必需的,因为Dense 本身会在所有时间步上同时应用一个密集层,而TimeDistributed 会在每个时间步上单独应用一个密集层。跨度> @AstroBen 为什么需要单独考虑每个时间步?你想找到一个从 278 个时间步到只有一个值的映射,对吧?因此,您必须有充分的理由单独考虑每个时间步长。您是否首先尝试在不使用 TimeDistributed 的情况下训练模型并查看您的准确率是否低? @AstroBen 如你所见,最后一个 Dense 层的输出形状是(None, 278, 1)。这意味着对于每个样本(即长度为 278 的向量),您正在预测一个形状为 (278,1) 的数组,即 278 个值?!!!你不想要 278 个值,你想要一个值(即介于 0 和 1 之间)。 @AstroBen 换句话说,您不想对每个时间步进行分类。相反,您想对 278 个时间步长(即时间序列)进行分类。 @AstroBen 请举个具体的例子。假设您有一句话:“这是美好的一天,我是一个快乐的人”。所以模型的输入就是这个句子(或者它的基于索引的表示)。现在你想根据这个输入预测(即输出)或学习(即无监督学习)什么?

以上是关于可以使用帮助为 Keras SimpleRNN 正确格式化数据的主要内容,如果未能解决你的问题,请参考以下文章

当 input_shape 指定为 3-d 时,Keras SimpleRNN 上的错误

当数据是单变量时,如何设置 keras.layers.SimpleRNN 的“input_shape”?

将 shap 与 SimpleRNN 顺序模型一起使用时出错

如何将多个向量发送到 SimpleRNN?

Tensorflow.keras:RNN 对 Mnist 进行分类

keras中双向LSTM流程的验证