Keras RNN层形状理解与训练报错问题咨询
机器翻译RNN模型报错问题解析
问题描述
数据示例
x[0] = [10, 15, 13] y[0] = [1, 4]
注:数字分别对应英文、法语词汇的索引值。
输入与训练数据形状
input: (137861, 15) training: (137861, 21)
模型摘要
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_59 (Embedding) (None, 15, 8) 1592 _________________________________________________________________ lstm_52 (LSTM) (None, 15) 1440 _________________________________________________________________ dropout_39 (Dropout) (None, 15) 0 _________________________________________________________________ dense_69 (Dense) (None, 21) 336 ================================================================= Total params: 3,368 Trainable params: 3,368 Non-trainable params: 0 _________________________________________________________________
模型理解
- 英文语句经Embedding层编码后形状为
(15,8),对应15个单词各8维编码; - LSTM层处理编码输入,输出长度为15的激活值;
- Dense层将15维激活值转换为21维,匹配法语索引编码。
报错信息
Error when checking target: expected dense_69 to have shape (None, 1) but got array with shape (137861, 21)
疑问
- 为何dense_69期望输入形状为
(None,1),但模型摘要显示前一层输出是(None,15)? - 为何模型接收的数组形状是
(137861,21)?已设置batch size为1024,不是应该是(1024,15)吗? - 输出形状相关:能否直接预测索引值,还是要对输出做one-hot编码?如果需要one-hot编码,是否要后续转成索引?模型能学会one-hot编码和索引的映射吗?
模型构建代码
learning_rate = .1 model = keras.Sequential() model.add(layers.Embedding(input_shape=(15,), input_dim=english_vocab_size, output_dim=8)) model.add(layers.LSTM(15, activation='relu')) model.add(layers.Dropout(.2)) model.add(layers.Dense(output_dim=(21))) model.summary() model.compile(loss=sparse_categorical_crossentropy, optimizer=SGD(lr=learning_rate), metrics=['accuracy']) simple_rnn_model.fit(preproc_english_sentences, preproc_french_sentances, batch_size=1024, epochs=10, validation_split=0.2)
问题解答
疑问1解答
报错里说的不是期望输入形状,是期望目标数据的形状是(None,1)。问题根源在损失函数和目标数据不匹配:你用了sparse_categorical_crossentropy损失,这个损失要求目标是单个索引值(形状得是(样本数,1)或者(样本数,)),但你的目标数据是(137861,21),模型输出是(None,21)——相当于你在做多分类任务,却用了针对稀疏索引的损失函数。
疑问2解答
报错里显示的是整个训练数据集的形状,不是单批次的。model.fit会先检查整个数据集的形状是否匹配模型输出,你设置的batch size是训练时每次喂给模型的样本数,但数据集本身的形状就是(137861,21),这才是和模型期望不匹配的地方。如果目标是单索引,它的形状应该是(137861,)或者(137861,1);如果是one-hot编码的目标,形状才是(137861,21),但这时候得用对应的损失函数。
疑问3解答
两种方式都能行,关键看你选哪种损失函数:
- 直接预测索引:目标保留原始索引(形状(样本数,)),用
sparse_categorical_crossentropy损失,输出层加softmax激活(输出每个类别的概率,维度等于法语词汇表大小)。预测后用np.argmax()取概率最高的索引就行。 - 用one-hot编码目标:把索引转成one-hot编码(形状(样本数, 词汇表大小)),用
categorical_crossentropy损失,输出层同样加softmax。模型能自己学会one-hot和索引的映射,预测后也是用np.argmax()转成索引。
修正后的代码示例
根据你的目标数据形状(137861,21),假设是one-hot编码的法语目标,修正代码如下:
learning_rate = .1 model = keras.Sequential() model.add(layers.Embedding(input_shape=(15,), input_dim=english_vocab_size, output_dim=8)) model.add(layers.LSTM(15, activation='relu')) model.add(layers.Dropout(.2)) # 输出层添加softmax激活,对应多分类 model.add(layers.Dense(21, activation='softmax')) model.summary() # 改用categorical_crossentropy损失 model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=learning_rate), metrics=['accuracy']) model.fit(preproc_english_sentences, preproc_french_sentances, batch_size=1024, epochs=10, validation_split=0.2)
如果你的目标数据其实是原始索引(只是形状写错了),那需要把目标数据调整为(137861,)的形状,保留sparse_categorical_crossentropy损失,同时输出层加softmax激活。
内容的提问来源于stack exchange,提问作者Patrick Ward
相关产品推荐
相关产品推荐

