字符级文本生成LSTM

import tensorflow.keras
import numpy as np

# 文件路径
path = tensorflow.keras.utils.get_file(
'nietzsche.txt',
origin = 'https://s3.amazonaws.com/text-datasets/nietzsche.txt')
# 读取文件,并转为小写
text = open(path).read().lower()
# 输出文本长度
print('文本长度:%s'%len(text))
maxlen = 60 # 提取60个字符组成的序列
step = 3 # 每隔3个字符提取一次新序列——步长
sequences = [] # 保留所有序列
lables = [] # 保留所有标签
# 构建数据集
for i in range(0,len(text)-maxlen,step): 
    sequences.append(text[i:i+maxlen]) # 数据
    lables.append(text[i+maxlen]) # 标签
print('sequences中的元素个数:%d'%len(sequences))
print('lables中的元素个数:%d'%len(lables))
# 统计数据中不同的字符
print(set(text))
chars = sorted(list(set(text)))
print('不同的字符类别:%d个'%len(chars))
# 根据chars构建一个字典,键为字符,值为索引
chars_dict = dict((c,chars.index(c)) for c in chars)
print(chars_dict)
# 向量化
x = np.zeros((len(sequences),maxlen,len(chars)),dtype=np.bool) # 初始化数据集0矩阵
y = np.zeros((len(sequences),len(chars)),dtype=bool) # 标签0矩阵

# one-hot编码
for i,sequence in enumerate(sequences):
    for j,char in enumerate(sequence):
        x[i,j,chars_dict[char]] = 1
    y[i,chars_dict[lables[i]]] = 1
# 这个网络是一个单层LSTM,然后是一个Dense分类器和对所有可能字符的softmax
from tensorflow.keras.layers import LSTM,Dense
from tensorflow.keras import Sequential

model = Sequential() # 创建序列模型
model.add(LSTM(128,input_shape=(maxlen,len(chars)))) # 添加LSTM层:128个神经元
model.add(Dense(len(chars),activation='softmax')) # 全连接层,激活函数:softmax

# 模型编译配置
optimizer = tensorflow.keras.optimizers.RMSprop(lr=0.01)
model.compile(optimizer=optimizer,loss='categorical_crossentropy') # 分类交叉熵损失函数
def sample(preds,temperature=0.1): # temperature是熵,这个函数是对数值进行归一化
    preds = np.asarray(preds).astype('float64') # 类型转换,转换为64位
    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) # 返回概率值最大的字符
import random
import sys

# 模型训练60轮
for epoch in range(1,60):
    print('epoch:',epoch)
    # 将模型在数据上训练一次
    model.fit(x,y,batch_size=128,epochs=1)
    # 随机产生一个样例(序列)
    start_index = random.randint(0,len(text)-maxlen-1) # 随机数,起始位置
    generate_text = text[start_index:start_index + maxlen] # 获取一个样本
    print('随机获取的样本:%s'%generate_text)
    # 尝试一系列不同的熵,熵值越大越无序,越小越稳定
    for t in [0.2,0.5,1.0,1.2]:
        print('----temperature:',t)
        print(generate_text)
        # 从样本开始,生成400个字符
        for i in range(400):
            # 对目前生成的字符进行one-hot编码
            sampled = np.zeros((1,maxlen,len(chars)))
            for t,char in enumerate(generate_text):
                sampled[0,t,chars_dict[char]] = 1
            # 预测下一个字符
            preds = model.predict(sampled,verbose=0)[0] # 获取概率值
            next_index = sample(preds,t) # 下一个字符的索引
            next_char = chars[next_index] # 下一个字符
            # 拼接字符串
            generate_text += next_char
            generate_text = generate_text[1:] # 往后移动一步
            # 输出新的字符串
            print(generate_text)

猜你喜欢

转载自blog.csdn.net/weixin_46489969/article/details/125525879