흥미로운 점은 이전 기사 "Keras가 LSTM 문자 수준 모델링을 실현합니다"의 원칙에 따라 LSTM을 사용하여 이전 문서에 나타난 문자와 특정 "스타일"에 따라 다음 문자를 예측할 수 있다는 것입니다. 훈련 데이터 텍스트 또는 "보기"를 사용하여 새 텍스트를 생성합니다. 이것은 매우 흥미롭지 만, 우리는 독특한 스타일을 가진 사람인 윌리엄 셰익스피어를 선택하고, 이제 그의 기존 작품을 사용하여 언뜻보기에 셰익스피어처럼 보이는 텍스트를 생성합니다.
from nltk.corpus import gutenberg
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.layers import LSTM
from keras.optimizers import RMSprop
import numpy as np
import random
import sys
import time
# 导入古腾堡计划数据集
print(gutenberg.fileids())
# 预处理莎士比亚的戏剧
text = ''
for txt in gutenberg.fileids():
if 'shakespeare' in txt:
text += gutenberg.raw(txt).lower()
chars = sorted(list(set(text)))
# 为索引建立一个字符字典,以便在独热编码中引用
char_indices = dict((c, i) for i, c in enumerate(chars))
# 把一个独热编码解释回字符时,建立一个反向查找字典
indices_char = dict((i, c) for i, c in enumerate(chars))
print('corpus length: {} total chars: {}'.format(len(text), len(chars)))
print(text[:500])
'''
模型的目标是在给定前 40 个字符的情况下,学习预测任意序列中的第 41 个字符
'''
# 组装一个训练集
maxlen = 40
step = 3
sentences = []
next_chars = []
# 步长为 3 个字符,这样生成的训练样本会部分重叠,但不会完全相同
for i in range(0, len(text) - maxlen, step):
sentences.append(text[i: i + maxlen])
# 收集下一个预期字符
next_chars.append(text[i + maxlen])
print('nb sequences:', len(sentences))
# 训练样本的独热编码
X = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
for i, sentence in enumerate(sentences):
for t, char in enumerate(sentence):
X[i, t, char_indices[char]] = 1
y[i, char_indices[next_chars[i]]] = 1
# 组装一个基于字符的 LSTM 模型来生成文本
model = Sequential()
# 不返回整个序列,我们只需要最后一个输出字符
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
# 这里没有 dropout。因为我们要对这个数据集进行特定的建模,而没有兴
# 趣将其推广到其他问题,所以过拟合不仅是可以的,还是理想的。
model.add(Dense(len(chars)))
model.add(Activation('softmax'))
# RMSProp 的工作原理是通过使用“该权重最近梯度大小的平均值”,来调整学习率以更新各个权重
optimizer = RMSprop(lr=0.01)
# 使用 softmax 激活函数,因此输出向量将等效为整个50 维向量上的概率分布(该向量中的值之和总是为 1)
# 使用 categorical_crossentropy使结果的概率分布与独热编码预期字符之间的差异最小化
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
print(model.summary())
# 训练一个莎士比亚风格的聊天机器人
epochs = 6
batch_size = 128
model_structure = model.to_json()
with open("shakes_lstm_model.json", "w") as json_file:
json_file.write(model_structure)
# 每隔 6 个训练周期保存模型一次,并继续训练
for i in range(5):
model.fit(X, y, batch_size=batch_size, epochs=epochs)
model.save_weights("shake_lstm_weights_{}.h5".format(i+1))
# 产生字符序列的采样器:预测接下来会是什么词,从而从概率分布中生成全新的文本。
# log 函数除以 temperature 的效果是使概率分布变平(temperature > 1)或变尖
# (temperature < 1)。因此,小于 1 的 temperature(或称调用参数中的多样性)倾向于试
# 图更严格地重新创建原始文本。而大于 1 的 temperature 会产生更多样化的结果,但是随着分
# 布变平,学习到的模式开始被遗忘,我们就会回到胡言乱语的状态。多样性越高就会越有趣。
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)
# 使用 3 种多样化等级产生 3 种类型文本
start_index = random.randint(0, len(text) - maxlen - 1)
for diversity in [0.2, 0.5, 1.0, 1.2]:
print()
print('----- diversity:', diversity)
generated = ''
sentence = text[start_index: start_index + maxlen]
generated += sentence
print('----- Generating with seed: "' + sentence + '"')
sys.stdout.write(generated)
for i in range(400):
x = np.zeros((1, maxlen, len(chars)))
for t, char in enumerate(sentence):
x[0, t, char_indices[char]] = 1.
preds = model.predict(x, verbose=0)[0]
next_index = sample(preds, diversity)
next_char = indices_char[next_index]
generated += next_char
sentence = sentence[1:] + next_char
# 将预测的字符写入控制台(或字符串缓冲区)
sys.stdout.write(next_char)
# 执行 flush()函数,以便字符即刻进入控制台
sys.stdout.flush()
time.sleep(0.02)
print()
중요-텍스트 생성기의 향상 방법 :
재미로만 모델을 생성하려는 경우보다 일관성 있고 유용하게 만들기 위해 무엇을 할 수 있습니까?
1. 말뭉치 수 증가 및 품질 향상
2. 모델의 복잡성 증가 (뉴런 수)
3.보다 정제 된 문자 일관성 알고리즘 구현
4. 문장 분할
5. 문법 요구에 따라 맞춤법 및 어조에 필터 추가
6. 사용자에게 실제로 표시된 것보다 더 많은 결과 사례 생성
7. 대화 컨텍스트에서 선택한 시드 텍스트를 사용하여 챗봇을 유용한 주제로 안내
8. 각 대화 라운드에서 여러 가지 시드 사용 챗봇이 어떤 주제에 대해 잘 이야기하고 사용자가 어떤 콘텐츠가 도움이 될 것이라고 생각하는지 탐색하는 텍스트입니다.