python深度學習--LSTM生成文本

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,you can open above website in your browser,and save it to a txt

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 的溫度值生成的文本最爲有趣。一定要嘗試多種採樣策略!在學到的結構與隨機性之間,巧妙的平衡能夠讓生成的序列非常有趣。
    注意,利用更多的數據訓練一個更大的模型,並且訓練時間更長,生成的樣本會比上面的 結果看起來更連貫、更真實。
    但是,不要期待能夠生成任何有意義的文本,除非是很偶然的情況。 你所做的只是從一個統計模型中對數據進行採樣,這個模型是關於字符先後順序的模型。
'''

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章