Seq2Seq对话语言模型无法生成连贯句子问题求助
Seq2Seq对话模型生成随机单词问题修复
核心问题梳理
- 模型输入冗余与损失逻辑混乱
模型定义时引入了未使用的output_decoder输入,训练时该输入完全无效,同时损失计算的标签与模型输出的对应关系错误。 - 训练数据对齐错误
按照描述,y_tar_seq是带SOS/EOS的目标输出,y_out_seq是左移一位的解码器输入(应包含SOS),但训练时输入和标签的对应关系完全搞反。 - 生成函数多处逻辑错误
- 问题文本转序列时错误拆分单词,导致序列格式异常
- 预测时跳过词表第一个索引,导致生成的ID与词表不匹配
- 用序列滚动更新回复,破坏了已生成token的顺序
- 训练策略不合理
未设置早停机制,1000轮epoch易导致过拟合或无效训练,dropout比例可能过高影响模型收敛。
修复后的完整代码
import tensorflow as tf import numpy as np BATCH_SIZE = 32 EMBEDDING_DIM = 256 RNN_UNITS = 1024 EPOCHS = 100 # 数据处理(修正对齐关系) x_seq = tokenizer.texts_to_sequences(x) y_decoder_input = tokenizer.texts_to_sequences(y_tar) # y_tar是带SOS的解码器输入 y_decoder_target = tokenizer.texts_to_sequences(y_out) # y_out是带EOS的目标输出 max_seq_length = max(max(len(seq) for seq in x_seq), max(len(seq) for seq in y_decoder_target)) x_seq = tf.keras.preprocessing.sequence.pad_sequences(x_seq, maxlen=max_seq_length, padding='post') y_decoder_input = tf.keras.preprocessing.sequence.pad_sequences(y_decoder_input, maxlen=max_seq_length, padding='post') y_decoder_target = tf.keras.preprocessing.sequence.pad_sequences(y_decoder_target, maxlen=max_seq_length, padding='post') # 模型定义(移除冗余输入) input_encoder = tf.keras.layers.Input(shape=(None,)) input_decoder = tf.keras.layers.Input(shape=(None,)) encoder_embedding = tf.keras.layers.Embedding(vocab_size, EMBEDDING_DIM)(input_encoder) encoder_lstm = tf.keras.layers.LSTM(RNN_UNITS, return_state=True, dropout=0.1) encoder_outputs, state_h, state_c = encoder_lstm(encoder_embedding) encoder_states = [state_h, state_c] decoder_embedding = tf.keras.layers.Embedding(vocab_size, EMBEDDING_DIM)(input_decoder) decoder_lstm = tf.keras.layers.LSTM(RNN_UNITS, return_sequences=True, return_state=True, dropout=0.1) decoder_outputs, _, _ = decoder_lstm(decoder_embedding, initial_state=encoder_states) decoder_dense = tf.keras.layers.Dense(vocab_size, activation='softmax') output = decoder_dense(decoder_outputs) # 修正模型输入输出 model = tf.keras.models.Model([input_encoder, input_decoder], output) model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)) # 添加早停机制 early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit([x_seq, y_decoder_input], y_decoder_target, epochs=EPOCHS, batch_size=BATCH_SIZE, validation_split=0.2, callbacks=[early_stopping]) # 构建推理用模型(分离编码器和解码器) encoder_model = tf.keras.models.Model(input_encoder, encoder_states) decoder_state_input_h = tf.keras.layers.Input(shape=(RNN_UNITS,)) decoder_state_input_c = tf.keras.layers.Input(shape=(RNN_UNITS,)) decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c] decemb_infer = tf.keras.layers.Embedding(vocab_size, EMBEDDING_DIM)(input_decoder) decoder_outputs, state_h_infer, state_c_infer = decoder_lstm(decemb_infer, initial_state=decoder_states_inputs) decoder_states_infer = [state_h_infer, state_c_infer] decoder_outputs = decoder_dense(decoder_outputs) decoder_model = tf.keras.models.Model([input_decoder] + decoder_states_inputs, [decoder_outputs] + decoder_states_infer) def generate_response(question): # 处理输入问题 question_seq = tokenizer.texts_to_sequences([question]) question_seq = tf.keras.preprocessing.sequence.pad_sequences(question_seq, maxlen=max_seq_length, padding='post') states_value = encoder_model.predict(question_seq, verbose=0) # 初始化回复序列(SOS token) target_seq = np.zeros((1, 1)) target_seq[0, 0] = tokenizer.word_index['sos'] response_tokens = [] for _ in range(max_seq_length): output_tokens, h, c = decoder_model.predict([target_seq] + states_value, verbose=0) sampled_token_index = np.argmax(output_tokens[0, -1, :]) if sampled_token_index == tokenizer.word_index.get('eos', -1): break if sampled_token_index in tokenizer.index_word: response_tokens.append(tokenizer.index_word[sampled_token_index]) # 更新序列和状态 target_seq = np.zeros((1, 1)) target_seq[0, 0] = sampled_token_index states_value = [h, c] return ' '.join(response_tokens)
关键修复点说明
- 移除冗余输入:删除模型中未使用的
output_decoder输入,简化模型结构 - 修正数据对齐:确保解码器输入是带SOS的左移序列,目标输出是带EOS的完整序列
- 重构推理模型:分离编码器和解码器,采用标准的Seq2Seq推理流程,逐步生成每个token并更新状态
- 优化训练策略:添加早停机制防止过拟合,降低dropout比例帮助模型收敛
- 修复生成逻辑:修正问题序列处理方式,移除错误的索引跳过和序列滚动逻辑
内容的提问来源于stack exchange,提问作者Tyron
相关产品推荐
相关产品推荐

