LSTM长短期记忆网络:原理、优势与文本生成实战
长短期记忆(Long Short-Term Memory,简称LSTM)是一种特殊的时间循环神经网络(RNN),由施密德胡伯于1997年首次提出。它的核心价值在于有效解决了传统RNN长期存在的痛点——准确处理序列数据中的长期依赖关系。LSTM能够记住并利用相隔较远的信息,这是许多序列建模任务的关键。

LSTM之所以能实现这一突破,关键在于其独特的设计结构:三个门控单元——遗忘门、输入门和输出门。这三个门协同工作,让网络能够选择性地记住哪些信息,遗忘哪些信息。因此,LSTM特别适合处理时间序列中间隔和延迟非常长的重要事件,例如文本中的远距离语义依赖、语音信号中的长程模式,以及时间序列预测中的长期趋势。
从应用效果来看,LSTM的表现通常优于传统RNN和隐马尔科夫模型(HMM)。在时间序列预测、自然语言处理和语音识别等任务中,LSTM已成为基础组件。此外,LSTM还显著缓解了RNN训练中一个挥之不去的顽疾:梯度消失和梯度爆炸问题,使得深层网络训练更加稳定。
可以这样理解:想象你在读一本错综复杂的小说,里面人物众多、情节交织。有些情节在几十页后突然被再次呼应。普通RNN就像是一个读过就忘的读者,只能记住最近的几句话。而LSTM不一样,它更像一个专注的读者,能判断哪些信息重要,哪些可以丢弃,然后牢牢抓住故事主线。在计算机的世界里,LSTM扮演的就是这个“记性好”的角色,帮助系统理解和处理序列数据,尤其是那些必须跨越长距离才能建立联系的场景。通过精准控制信息的流动,LSTM能更有效地学习和记忆长期依赖关系——这正是许多序列任务中最棘手的部分。
LSTM文本生成模型训练完整步骤详解
实际搭建一个文本生成模型,流程大致如下:
1、准备文本数据,并进行预处理——分词、标记化等基本操作缺一不可,这是模型训练的基础。
2、使用Tokenizer对文本进行编码,将文字转换为模型能够理解的数字形式。
3、将文本数据转换为模型所需的输入格式,也就是序列数据,确保每个样本长度一致。
4、构建神经网络模型,通常包括Embedding层、LSTM层、Dense层等,可根据任务调整层数和参数。
5、编译模型,指定损失函数、优化器和评估指标,常用Adam优化器和交叉熵损失。
6、训练模型,使用fit方法,并设置批量大小、迭代次数等参数,观察损失变化。
7、用训练好的模型生成文本,通过种子文本不断预测下一个词,得到完整输出。
本次使用的数据集是纽约时报数据集,包含abstract(摘要)、headline(标题)、keywords(关键词)等信息,适合用于新闻标题生成任务。
import numpy as np
import pandas as pd
import string
article_df = pd.read_csv(r".ArticlesApril2017.csv")
article_df.head()
# 将DataFrame中的文章标题(headline)提取出来,并添加到名为all_headlines的列表中。
all_headlines = []
all_headlines.extend(list(article_df.headline.values))
all_headlines[:3]
输出:
['Finding an Expansive View of a Forgotten People in Niger',
'And Now, the Dreaded Trump Curse',
'Venezuela’s Descent Into Dictatorship']
len(all_headlines)
886
# 用于过滤掉all_headlines列表中值为"Unknown"的元素
all_headlines = [line for line in all_headlines if line != "Unknown"]
len(all_headlines)
831
接下来对数据进行清洗:
# 清洁文本数据,去除文本中的标点符号,将文本转换为小写字母,并将文本编码为UTF-8再解码为ASCII编码
def clean_text(txt):
txt = "".join(t for t in txt if t not in string.punctuation).lower()
txt = txt.encode('utf8').decode('ascii','ignore')
return txt
corpus = [clean_text(x) for x in all_headlines]
print(corpus[:5])
输出:
['finding an expansive view of a forgotten people in niger',
'and now the dreaded trump curse',
'venezuelas descent into dictatorship',
'stain permeates basketball blue blood', 'taking things for granted']
Tokenizer类的作用是将文本转换为标记化的序列,方便模型处理:
from keras.preprocessing.text import Tokenizer
from keras.models import Sequential
from keras.layers import Embedding, LSTM, Dense, Dropout
from keras.preprocessing.sequence import pad_sequences
import keras.utils as ku
from keras.callbacks import EarlyStopping
import tensorflow as tf
tf.random.set_seed(2)
from numpy.random import seed
seed(1)
# Tokenizer 类可以帮助我们将文本转换为模型可以理解的数字表示形式,即将文本转换为标记化的序列。
tokenizer = Tokenizer()
定义一个函数 get_sequence_of_tokens(corpus),将文本语料库转换为模型训练所需的输入序列,这是构建训练数据的关键步骤:
def get_sequence_of_tokens(corpus):
tokenizer.fit_on_texts(corpus)
total_words = len(tokenizer.word_index) + 1
input_sequences = []
for line in corpus:
token_list = tokenizer.texts_to_sequences([line])[0]
for i in range(1,len(token_list)):
n_gram_sequence = token_list[:i+1]
input_sequences.append(n_gram_sequence)
return input_sequences,total_words
# 调用这行代码后,inp_sequences 将包含生成的输入序列列表,total_words 则是词汇表中的总单词数
inp_sequences,total_words = get_sequence_of_tokens(corpus)
print(inp_sequences[:10])
输出:
[[169, 17], [169, 17, 665], [169, 17, 665, 367],
[169, 17, 665, 367, 4], [169, 17, 665, 367, 4, 2],
[169, 17, 665, 367, 4, 2, 666], [169, 17, 665, 367, 4, 2, 666, 170],
[169, 17, 665, 367, 4, 2, 666, 170, 5],
[169, 17, 665, 367, 4, 2, 666, 170, 5, 667], [6, 80]]
# 词汇表中的总单词数
print(total_words)
2422
函数 generate_padded_sequence 的作用是对输入序列列表进行填充处理,确保所有序列长度一致,以便用于模型训练:
def generate_padded_sequence(input_sequences):
max_sequence_len = max([len(x) for x in input_sequences])
input_sequences = np.array(pad_sequences(input_sequences,maxlen=max_sequence_len,padding='pre'))
predictors,label = input_sequences[:,:-1],input_sequences[:,-1]
label = ku.to_categorical(label,num_classes=total_words)
return predictors,label,max_sequence_len
predictors,label,max_sequence_len = generate_padded_sequence(inp_sequences)
创建神经网络模型,包含Embedding层、LSTM层和Dropout层,以提升泛化能力:
def create_model(max_sequence_len,total_words):
input_len = max_sequence_len - 1
model = Sequential()
model.add(Embedding(total_words,10,input_length = input_len))
model.add(LSTM(100))
model.add(Dropout(0.1))
model.add(Dense(total_words,activation='softmax'))
model.compile(optimizer='adam',loss='categorical_crossentropy')
return model
# 创建了一个神经网络模型 model。这个模型将用于文本生成任务,其中 max_sequence_len 表示序列的最大长度,total_words 表示词汇表的大小。
model = create_model(max_sequence_len,total_words)
model.summary()
# 使用 predictors 作为输入数据,label 作为标签数据,进行了10个 epochs 的训练,并设置 verbose=1 以显示训练过程中的详细信息。
model.fit(predictors,label,epochs=100,verbose=1)
定义函数 generate_text,用于基于种子文本生成后续单词序列:
def generate_text(seed_text,next_words,model,max_sequence_len):
for _ in range(next_words):
token_list = tokenizer.texts_to_sequences([seed_text])[0]
token_list = pad_sequences([token_list],maxlen=max_sequence_len-1,padding='pre')
predicted = model.predict(token_list,verbose=0)
classes_x = np.argmax(predicted,axis=1)
output_words = ""
for word,index in tokenizer.word_index.items():
if index == classes_x:
output_word = word
break
seed_text = seed_text + " " + output_word
return seed_text.title()
最后验证一下模型效果,测试不同种子文本和生成长度:
1、generate_text("china",3,model,max_sequence_len)
输出:
'China Takes An Inspiring.'
generate_text("china",10,model,max_sequence_len)
输出:
'China Takes A Inspiring Turns To Its Rise On Coalition Airstrike.'
generate_text("china",30,model,max_sequence_len)
输出:
'China Takes A Inspiring Turns To Its Rise On Coalition Airstrike People You Safety Day Too Readers Without Trillions Northern Trillions Northern Pick Trillions At Pick This Trillions For Debate Trillions.'
这段文字是一个混合了一些词语和短语的随机组合,有点胡说八道,产生了“幻觉”问题。
2、generate_text("donald trump",30,model,max_sequence_len)
输出:
'Donald Trump Plays And The New York Be Obamacare World Event Battle Apart To Populism From From Medicine Teachers Them A Whats Yorks Door Today The Bahamas Falls Times Today Today Wall'
3、generate_text("science and technology",5,model,max_sequence_len)
输出:
'Science And Technology The Americans Of The Americans'
小结与优化方向
从上面的实验结果可以看出,仅靠一个基础的LSTM模型,生成文本的质量远未达到理想状态。虽然语法结构基本正确,但内容缺乏逻辑连贯性,甚至出现明显的“幻觉”问题——生成无意义或重复的词语组合。要改善这种情况,通常需要从以下几个方向入手:使用更大规模、更多样化的数据集进行训练;引入外部知识库或预训练语言模型进行约束;设计更复杂的模型结构,例如多层LSTM或双向LSTM;加入注意力机制或对抗训练等。这些方法对于提升生成文本的质量、减少幻觉现象,都是行之有效的路径。在实际应用中,结合这些技术可以显著提高LSTM模型在自然语言生成任务中的表现。
