Keras中Embedding层输入形状不兼容问题求助
问题分析与解决
首先,你的代码存在两个核心问题:
- Tokenizer未拟合文本:你创建了Tokenizer但没有调用
tokenizer.fit_on_texts(X)来学习词汇表,导致texts_to_sequences无法正确转换文本为有效数字序列。 - 输入输出形状不匹配:你把形状为
(样本数, 20)的序列作为输入,同时把该序列的独热编码(形状变为(样本数, 20, 1000))作为输出,但模型最后一层Dense的输出形状是(样本数, 1000),两者维度完全不兼容,这就是报错Shapes (None, 20) and (None, 1000) are incompatible的直接原因。
文本生成/聊天机器人模型的核心逻辑是输入一段文本序列,预测下一个词(或对应回复),因此需要重新构建训练数据格式:将输入序列拆分为「前缀序列」和「目标词」,确保输入与输出的形状匹配模型结构。
以下是修正后的完整代码:
import numpy as np from keras.layers import Dense, LSTM, Embedding from keras.models import Sequential from keras.preprocessing.text import Tokenizer from keras.utils import pad_sequences, to_categorical # 输入文本(如果是聊天机器人,建议使用一问一答的配对语料) X = ["Hello!", "Greetings!"] # 1. 先让Tokenizer学习词汇表 tokenizer = Tokenizer(num_words=1000) tokenizer.fit_on_texts(X) total_words = len(tokenizer.word_index) + 1 # 加1适配Embedding层的0索引 # 2. 构建训练用的输入-目标对 input_sequences = [] for line in X: token_list = tokenizer.texts_to_sequences([line])[0] # 生成n-gram序列:针对单词文本,生成输入序列对应目标词的结构 for i in range(1, len(token_list)+1): n_gram_sequence = token_list[:i] input_sequences.append(n_gram_sequence) # 3. 填充序列到统一长度 max_sequence_len = 20 input_sequences = pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre') # 4. 拆分输入X和目标y:X是前缀序列,y是最后一个词的独热编码 X_train, y_train = input_sequences[:, :-1], input_sequences[:, -1] y_train = to_categorical(y_train, num_classes=total_words) # 5. 构建模型:输入长度为max_sequence_len-1(去掉目标词的位置) model = Sequential() model.add(Embedding(total_words, 100, input_length=max_sequence_len-1)) model.add(LSTM(100)) model.add(Dense(total_words, activation='softmax')) model.summary() model.compile(loss='categorical_crossentropy', metrics=['accuracy']) # 训练:样本量极少,batch_size设为1避免报错 history = model.fit(X_train, y_train, epochs=50, batch_size=1) # 预测示例 test_text = "Greetings!" token_list = tokenizer.texts_to_sequences([test_text])[0] token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre') predicted = np.argmax(model.predict(token_list, verbose=0), axis=-1) for word, index in tokenizer.word_index.items(): if index == predicted: print(f"预测输出: {word}")
关键修正点说明:
- Tokenizer必须拟合文本:调用
fit_on_texts让Tokenizer学习输入文本的词汇表,否则无法将文本转换为有效数字序列。 - 重构训练数据格式:将输入序列拆分为「前缀序列」和「目标词」,确保输入形状
(样本数, max_sequence_len-1)与模型输入匹配,目标输出(样本数, total_words)与最后一层Dense的输出形状一致,彻底解决维度不兼容问题。 - 适配小样本训练:你的输入样本量极少,训练时
batch_size需设为1,避免因样本数不足抛出错误。
如果要构建真正可用的聊天机器人,建议使用一问一答的配对对话语料库,而非单句自学习,这样模型才能学习到对话的上下文关联逻辑。
内容的提问来源于stack exchange,提问作者Avusar
相关产品推荐
相关产品推荐

