训练好的RNN集成Hangman游戏guess函数时索引错误修复求助
问题修复:Hangman游戏RNN嵌入层索引错误
错误原因
你的Tokenizer未将游戏中的空白字符-纳入词汇表,导致Tokenizer遇到-时返回**-1**(未知token默认值),而嵌入层仅配置处理[0,26)范围的索引,因此触发越界错误。
修复方案
1. 训练阶段更新Tokenizer,添加-字符
在Tokenizer初始化时,显式将-加入词汇表,确保它被分配合法索引;同时配置oov_token处理其他未知字符。
2. 游戏集成时统一字符映射逻辑
确保游戏传入模型的字符串(含-)能被正确转换为模型可识别的索引,同时过滤已猜字符避免无效预测。
完整修复代码
训练RNN模型代码
import numpy as np from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense import pickle # 加载25万单词数据集(替换为你的数据集路径) with open("250k_words.txt", "r") as f: words = [line.strip().lower() for line in f.readlines()] # 关键:Tokenizer添加'-'字符,配置oov_token处理未知字符 tokenizer = Tokenizer(char_level=True, oov_token="<OOV>") # 手动将'-'加入词汇表 tokenizer.word_index['-'] = len(tokenizer.word_index) + 1 tokenizer.index_word[len(tokenizer.word_index)] = '-' # 拟合词汇表 tokenizer.fit_on_texts(words) # 准备训练数据:预测下一个字符,用'-'填充固定长度 max_len = 10 X, y = [], [] for word in words: padded_word = word.ljust(max_len, '-') for i in range(len(padded_word)-1): X.append(padded_word[:i+1]) y.append(padded_word[i+1]) # 转换为模型可接受的序列格式 X_seq = tokenizer.texts_to_sequences(X) X_pad = np.array([np.pad(seq, (max_len - len(seq), 0), mode='constant') for seq in X_seq]) y_seq = np.array([tokenizer.word_index[c] for c in y]) # 构建模型:嵌入层输入尺寸为词汇表大小+1(索引从1开始) vocab_size = len(tokenizer.word_index) + 1 model = Sequential([ Embedding(input_dim=vocab_size, output_dim=32, input_length=max_len), LSTM(64), Dense(vocab_size, activation='softmax') ]) model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(X_pad, y_seq, epochs=5, batch_size=256) # 保存模型和Tokenizer model.save("hangman_rnn.h5") with open("tokenizer.pkl", "wb") as f: pickle.dump(tokenizer, f)
Hangman游戏集成代码
import numpy as np from tensorflow.keras.models import load_model import pickle # 加载预训练模型和Tokenizer model = load_model("hangman_rnn.h5") with open("tokenizer.pkl", "rb") as f: tokenizer = pickle.load(f) max_len = 10 def guess(current_state): # 统一处理输入:转小写、填充到固定长度 processed_state = current_state.lower().ljust(max_len, '-') # 转换为模型可接受的序列 seq = tokenizer.texts_to_sequences([processed_state]) padded_seq = np.array([np.pad(seq[0], (max_len - len(seq[0]), 0), mode='constant')]) # 预测字符概率 pred_probs = model.predict(padded_seq, verbose=0)[0] # 过滤已猜字符和'-',仅保留未猜字母 forbidden_chars = set(current_state.replace('-', '')) forbidden_chars.add('-') char_probs = [] for idx, prob in enumerate(pred_probs): char = tokenizer.index_word.get(idx, '') if char not in forbidden_chars and char.isalpha(): char_probs.append((prob, char)) # 返回概率最高的字符 char_probs.sort(reverse=True, key=lambda x: x[0]) return char_probs[0][1] if char_probs else 'a' # 测试示例 if __name__ == "__main__": # 模拟游戏初始状态(比如目标单词是"apple") current_state = "-----" print(f"当前状态: {current_state}") guessed_char = guess(current_state) print(f"模型猜测字符: {guessed_char}")
关键修复点说明
- 词汇表扩展:手动添加
-到Tokenizer词汇表,避免被识别为未知字符;oov_token处理其他意外字符。 - 训练数据对齐:用
-填充单词到固定长度,让模型学习空白字符的上下文逻辑。 - 输入标准化:游戏状态统一转小写、填充长度,避免格式或长度不匹配问题。
- 预测过滤:排除已猜字符和
-,确保模型返回有效猜测。
内容的提问来源于stack exchange,提问作者Saumya Dwivedi
相关产品推荐
相关产品推荐

