You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

疑问

  1. 为何dense_69期望输入形状为(None,1),但模型摘要显示前一层输出是(None,15)?
  2. 为何模型接收的数组形状是(137861,21)?已设置batch size为1024,不是应该是(1024,15)吗?
  3. 输出形状相关:能否直接预测索引值,还是要对输出做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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:50:33