本文目录导读:

我来为你详细介绍如何使用LSTM进行文本生成,包含完整的案例代码。
基础原理
LSTM文本生成的核心思想:根据前面的字符/词语预测下一个字符/词语。
完整案例:生成莎士比亚风格文本
1 导入必要的库
import numpy as np import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Embedding, Dropout from tensorflow.keras.optimizers import Adam from tensorflow.keras.callbacks import ModelCheckpoint import random import sys
2 加载和预处理数据
# 加载文本数据
# 这里使用莎士比亚的作品作为示例
def load_text(file_path="shakespeare.txt"):
# 如果没有文件,就用示例文本
sample_text = """To be, or not to be, that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them. To die: to sleep;
No more; and by a sleep to say we end
The heart-ache and the thousand natural shocks
That flesh is heir to, 'tis a consummation
Devoutly to be wish'd."""
try:
with open(file_path, 'r', encoding='utf-8') as file:
text = file.read()
except:
text = sample_text
return text.lower()
# 加载文本
text = load_text()
print(f"文本长度: {len(text)} 字符")
print("前200个字符:", text[:200])
3 文本向量化
def prepare_data(text, seq_length=40):
"""
准备训练数据
seq_length: 输入序列长度
"""
# 获取所有唯一字符
chars = sorted(list(set(text)))
char_to_int = {ch: i for i, ch in enumerate(chars)}
int_to_char = {i: ch for i, ch in enumerate(chars)}
n_chars = len(text)
n_vocab = len(chars)
print(f"总字符数: {n_chars}")
print(f"唯一字符数: {n_vocab}")
# 创建输入序列和输出序列
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
seq_in = text[i:i + seq_length]
seq_out = text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])
dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print(f"总模式数: {n_patterns}")
# 重塑X为LSTM输入格式 [samples, time steps, features]
X = np.reshape(dataX, (n_patterns, seq_length, 1))
# 标准化
X = X / float(n_vocab)
# one-hot编码Y
y = tf.keras.utils.to_categorical(dataY, num_classes=n_vocab)
return X, y, chars, char_to_int, int_to_char, n_vocab
# 准备数据
seq_length = 40
X, y, chars, char_to_int, int_to_char, n_vocab = prepare_data(text, seq_length)
print(f"X形状: {X.shape}")
print(f"y形状: {y.shape}")
4 构建LSTM模型
def build_model(vocab_size, seq_length):
"""
构建LSTM模型
"""
model = Sequential([
# LSTM层1
LSTM(256, input_shape=(seq_length, 1), return_sequences=True),
Dropout(0.2),
# LSTM层2
LSTM(256),
Dropout(0.2),
# 全连接层
Dense(128, activation='relu'),
Dropout(0.2),
# 输出层
Dense(vocab_size, activation='softmax')
])
# 编译模型
model.compile(loss='categorical_crossentropy',
optimizer=Adam(learning_rate=0.001),
metrics=['accuracy'])
return model
# 构建模型
model = build_model(n_vocab, seq_length)
model.summary()
5 训练模型
def train_model(model, X, y, epochs=50, batch_size=128):
"""
训练模型
"""
# 设置检查点保存最佳模型
checkpoint = ModelCheckpoint(
'best_model.h5',
monitor='loss',
save_best_only=True,
mode='min',
verbose=1
)
# 训练
history = model.fit(
X, y,
epochs=epochs,
batch_size=batch_size,
callbacks=[checkpoint],
verbose=1
)
return history
# 训练模型(如果数据量大,建议只训练少量epochs测试)
# history = train_model(model, X, y, epochs=20, batch_size=128)
6 文本生成函数
def generate_text(model, seed_text, char_to_int, int_to_char, n_vocab,
seq_length, gen_length=500, temperature=1.0):
"""
生成文本
temperature: 温度参数,控制随机性(0.0-1.0)
"""
def sample(preds, temperature=1.0):
"""从概率分布中采样"""
preds = np.asarray(preds).astype('float64')
preds = np.log(preds) / temperature
exp_preds = np.exp(preds)
preds = exp_preds / np.sum(exp_preds)
probas = np.random.multinomial(1, preds, 1)
return np.argmax(probas)
generated_text = seed_text.lower()
for i in range(gen_length):
# 准备输入序列
pattern = seed_text[-seq_length:]
x = np.array([char_to_int[char] for char in pattern])
x = x.reshape(1, seq_length, 1) / float(n_vocab)
# 预测
prediction = model.predict(x, verbose=0)[0]
# 采样下一个字符
index = sample(prediction, temperature)
result = int_to_char[index]
# 更新生成文本和种子
generated_text += result
seed_text = (seed_text + result)[-seq_length:]
return generated_text
# 文本生成示例
def demonstrate_generation(model, seed_texts, chars, char_to_int,
int_to_char, n_vocab, seq_length):
"""
演示文本生成
"""
print("="*50)
print("文本生成演示")
print("="*50)
temperatures = [0.2, 0.5, 0.8, 1.0]
for seed in seed_texts:
print(f"\n种子文本: '{seed}'")
print("-"*30)
for temp in temperatures:
print(f"\n温度: {temp}")
print("-"*20)
generated = generate_text(
model, seed, char_to_int, int_to_char,
n_vocab, seq_length, gen_length=200,
temperature=temp
)
print(generated)
print()
# 示例种子文本
seed_texts = [
"to be or not to be",
"the slings and arrows",
"to die to sleep"
]
7 完整的训练和生成流程
def main():
"""
主函数:完整的训练和生成流程
"""
# 1. 准备数据
print("步骤1: 加载和预处理数据...")
text = load_text()
seq_length = 40
X, y, chars, char_to_int, int_to_char, n_vocab = prepare_data(text, seq_length)
# 2. 构建模型
print("\n步骤2: 构建LSTM模型...")
model = build_model(n_vocab, seq_length)
# 3. 训练模型(这里只训练少量epochs作为演示)
print("\n步骤3: 训练模型(仅5 epochs作为演示)...")
model.fit(X, y, epochs=5, batch_size=128, verbose=1)
# 4. 生成文本
print("\n步骤4: 生成文本...")
demonstrate_generation(
model,
["to be or not", "the slings"],
chars, char_to_int, int_to_char,
n_vocab, seq_length
)
# 5. 保存模型
model.save('text_generator.h5')
print("\n模型已保存为 'text_generator.h5'")
# 运行主函数(可选)
# if __name__ == "__main__":
# main()
进阶版本:使用更大数据集
import requests
def download_shakespeare():
"""下载莎士比亚全集"""
url = "https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt"
response = requests.get(url)
return response.text
# 使用更大的数据集
# big_text = download_shakespeare()
# 然后使用上面的流程处理
class TextGenerator:
"""高级文本生成器类"""
def __init__(self, seq_length=40):
self.seq_length = seq_length
self.model = None
self.char_to_int = {}
self.int_to_char = {}
self.n_vocab = 0
def load_and_prepare_data(self, file_path='shakespeare.txt'):
"""加载和准备数据"""
text = load_text(file_path)
X, y, chars, self.char_to_int, self.int_to_char, self.n_vocab = \
prepare_data(text, self.seq_length)
return X, y, text
def build_lstm_model(self, lstm_units=[256, 256], dropout_rate=0.2):
"""构建LSTM模型"""
self.model = Sequential()
# 第一层LSTM
self.model.add(LSTM(lstm_units[0], return_sequences=True,
input_shape=(self.seq_length, 1)))
self.model.add(Dropout(dropout_rate))
# 中间层LSTM
for units in lstm_units[1:]:
self.model.add(LSTM(units))
self.model.add(Dropout(dropout_rate))
# 输出层
self.model.add(Dense(128, activation='relu'))
self.model.add(Dropout(dropout_rate))
self.model.add(Dense(self.n_vocab, activation='softmax'))
# 编译
self.model.compile(loss='categorical_crossentropy',
optimizer=Adam(learning_rate=0.001),
metrics=['accuracy'])
return self.model
def train(self, X, y, epochs=50, batch_size=128):
"""训练模型"""
history = self.model.fit(
X, y,
epochs=epochs,
batch_size=batch_size,
verbose=1
)
return history
def generate(self, seed_text, gen_length=500, temperature=0.5):
"""生成文本"""
return generate_text(
self.model, seed_text, self.char_to_int, self.int_to_char,
self.n_vocab, self.seq_length, gen_length, temperature
)
使用示例
# 快速使用示例
if __name__ == "__main__":
# 创建生成器
generator = TextGenerator(seq_length=40)
# 准备数据
X, y, text = generator.load_and_prepare_data()
# 构建模型
model = generator.build_lstm_model([256, 256])
# 训练(小数据集,仅演示)
generator.train(X, y, epochs=3, batch_size=64)
# 生成文本
generated = generator.generate("to be or not to be", temperature=0.5)
print("生成的文本:")
print(generated)
优化技巧
# 1. 使用学习率调度
from tensorflow.keras.callbacks import ReduceLROnPlateau
reduce_lr = ReduceLROnPlateau(
monitor='loss',
factor=0.2,
patience=5,
min_lr=0.00001
)
# 2. 使用早停
from tensorflow.keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(
monitor='loss',
patience=10,
restore_best_weights=True
)
# 3. 批处理生成
def batch_generate(model, seed_texts, char_to_int, int_to_char,
n_vocab, seq_length, gen_length=100):
"""批量生成文本"""
results = []
for seed in seed_texts:
generated = generate_text(
model, seed, char_to_int, int_to_char,
n_vocab, seq_length, gen_length, temperature=0.5
)
results.append(generated)
return results
注意事项
- 数据量: LSTM需要大量数据才能生成有意义的文本
- 训练时间: 建议使用GPU加速训练
- 温度参数:
- 低温(0.2-0.5): 更确定,重复性高
- 高温(0.8-1.0): 更随机,创造性高
- 序列长度: 影响生成的连贯性
这个案例提供了从基础到进阶的完整实现,你可以根据具体需求调整参数和网络结构。