python深度学习--LSTM生成文本

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunChao3555/article/details/88992927
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from pandas import DataFrame, Series
from keras import models, layers, optimizers, losses, metrics
from keras.utils.np_utils import to_categorical
import keras
plt.rcParams['font.sans-serif'] = ['SimHei']  #指定默认字体
plt.rcParams['axes.unicode_minus'] = False  #解决保存图像是负号'-'显示为方块的问题

# path=keras.utils.get_file('datasets/nietzsche.txt',origin='https://s3.amazonaws.com/text-datasets/nietzsche.txt')###there is somthing wrong

path='datasets/nietzsche.txt'
text=open(path).read().lower()
print('Corpus length:',len(text))
# print(text[:60])
#字符序列向量化
maxlen=60#字符长度
step=3
sentences=[]
next_chars=[]

for i in range(0,len(text)-maxlen,step):
    sentences.append(text[i:i+maxlen])
    next_chars.append(text[i+maxlen])
print('Number of sequences:',len(sentences))

chars=sorted(list(set(text)))#去重,得到语料中唯一字符组成的列表
print('Unique characters:',len(chars))
print(chars)
char_indices=dict((char,chars.index(char)) for char in chars )#字符编码
#字符级one-hot编码
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

#构建网络
from keras import layers
#循环神经网络并不是序列数据生成的唯一方法,也可以尝试一维卷积神经网络
model=keras.models.Sequential()
model.add(layers.LSTM(128,input_shape=(maxlen,len(chars))))
model.add(layers.Dense(len(chars),activation='softmax'))

#目标是经过 one-hot 编码的,所以训练模型需要使用 categorical_crossentropy 作为损失。
optimizer=keras.optimizers.RMSprop(lr=0.01)
model.compile(optimizer=optimizer,loss='categorical_crossentropy')

#训练语言模型并从中采样
'''
给定一个训练好的模型和一个种子文本片段,我们可以通过重复以下操作来生成新的文本。 
(1) 给定目前已生成的文本,从模型中得到下一个字符的概率分布。 
(2) 根据某个温度对分布进行重新加权。 
(3) 根据重新加权后的分布对下一个字符进行随机采样。
(4) 将新字符添加到文本末尾。
'''
#对于不同的 softmax 温度,对概率分布进行重新加权
'''
为什么需要有一定的随机性?考虑一个极端的例子——纯随机采样,即从均匀概率分布中 抽取下一个字符,其中每个字符的概率相同。这种方案具有最大的随机性,换句话说,这种概 率分布具有最大的熵。当然,它不会生成任何有趣的内容。
再来看另一个极端——贪婪采样。 贪婪采样也不会生成任何有趣的内容,它没有任何随机性,即相应的概率分布具有最小的熵。 从“真实”概率分布(即模型 softmax 函数输出的分布)中进行采样,是这两个极端之间的一 个中间点。
    为了在采样过程中控制随机性的大小,我们引入一个叫作 softmax 温度(softmax temperature)的参数,用于表示采样概率分布的熵,即表示所选择的下一个字符会有多么出人意料或多么可预测。
'''
def sample(preds,temperature=1.0):
    '''
    :param preds: 是概率值组成的一维numpy数组,和必须等于1.
    :param temperature: 是一个因子,用于定量描述输出分布的熵
    :return:
    '''
    preds=np.asarray(preds).astype('float64')
    preds=np.log(preds)/temperature
    exp_preds=np.exp(preds)
    preds=exp_preds/np.sum(exp_preds)#原始分布重新加权后的结果,distribution 的求和可能不再等1,因此需要将它除以求和,以得到新的分布
    probas=np.random.multinomial(1,preds,1)#multinomial(experiments number,float sequence,sample size)随机从多项式分布中抽取一个样本
    return np.argmax(probas)

#文本生成循环
import random,sys
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)#随机选择文本序列起始位置
    generated_text=text[start_index:start_index+maxlen]#文本序列
    print('--- Generating with seed:"'+generated_text+'"')
    for temperature in [0.2,0.5,1.0,1.2]:#观察随着模型收敛,生成的文本如何变化,以及温度对采样策略的影响
        print('------ temperature:', temperature)
        sys.stdout.write(generated_text)
        for i in range(400):#生成400个字符
            #one-hot
            sampled=np.zeros((1,maxlen,len(chars)))
            for t,char in enumerate(generated_text):
                sampled[0,t,char_indices[char]]=1
            preds=model.predict(sampled,verbose=0)[0]#得到预测序列
            next_index=sample(preds,temperature)#得到随机采样后的下一个预测字符序列的索引
            next_char=chars[next_index]

            generated_text+=next_char
            generated_text=generated_text[1:]#更新生成文本序列,预测下一个字符
            sys.stdout.write(next_char)

'''
'''
    较小的温度值会得到极端重复和可预测的文本,但局部结构是非常真实的,特别是 所有单词都是真正的英文单词(单词就是字符的局部模式)。
    随着温度值越来越大,生成的文本 也变得更有趣、更出人意料,甚至更有创造性,它有时会创造出全新的单词,听起来有几分可信(比 如 eterned 和 troveration)。
    对于较大的温度值,局部模式开始分解,大部分单词看起来像是半随 机的字符串。
    毫无疑问,在这个特定的设置下,0.5 的温度值生成的文本最为有趣。一定要尝试多种采样策略!在学到的结构与随机性之间,巧妙的平衡能够让生成的序列非常有趣。
    注意,利用更多的数据训练一个更大的模型,并且训练时间更长,生成的样本会比上面的 结果看起来更连贯、更真实。
    但是,不要期待能够生成任何有意义的文本,除非是很偶然的情况。 你所做的只是从一个统计模型中对数据进行采样,这个模型是关于字符先后顺序的模型。
'''

猜你喜欢

转载自blog.csdn.net/SunChao3555/article/details/88992927