2019年3月5日 星期二

深度學習 - LSTM生成文本 - 唐詩 - 生成唐詩

深度學習 - LSTM生成文本 - 唐詩 - 生成唐詩

最後,我們利用訓練好的模型來生成唐詩。
以下函式def function 通通寫在class PoetryModel(object): 底下。
import 所用到的庫
import random import os import keras import numpy as np from keras.callbacks import LambdaCallback from keras.models import Input, Model, load_model from keras.layers import LSTM, Dropout, Dense from keras.optimizers import Adam from data_utils import * from config import Config
class PoetryModel(object):
與先前練習的差不多,也是加入softmax temperature 參數,使得在不同溫度的情況下,模型產生出得文章會有不同的創造力。
這邊與先前不同的是,這裡使用np.power,是冪次函數,而先前練習的是指數函數。不過都是利用加入 temperature 參數,使得預測的文字具有創造性。
#給定模型預測,採樣下一個字符的函數 def sample(self, preds, temperature=1.0): ''' 當temperature=1.0時,模型輸出正常 當temperature=0.5時,模型輸出比較open 當temperature=1.5時,模型輸出比較保守 在訓練的過程中可以看到temperature不同,結果也不同 就是一個概率分佈變換的問題,保守的時候概率大的值變得更大,選擇的可能性也更大 ''' preds = np.asarray(preds).astype('float64') exp_preds = np.power(preds,1./temperature) preds = exp_preds / np.sum(exp_preds) pro = np.random.choice(range(len(preds)),1,p=preds) return int(pro.squeeze())
再來,將預測文字的函數先寫好,供class內部使用。
#根據一串輸入,返回單個預測字符 def _pred(self,sentence,temperature =1): '''因為模型是用 max_len 長度輸入訓練,預測下個字符。 所以要排除輸入一串文字小於 max_len 的情況''' if len(sentence) < self.config.max_len: print('in def _pred,length error ') return '''輸入字串向量化,丟入模型預測''' sentence = sentence[-self.config.max_len:] x_pred = np.zeros((1, self.config.max_len, len(self.words))) for t, char in enumerate(sentence): x_pred[0, t, self.word2numF(char)] = 1. preds = self.model.predict(x_pred, verbose=0)[0] next_index = self.sample(preds,temperature=temperature) #輸出再由向量轉回文字 next_char = self.num2word[next_index] return next_char def _preds(self,sentence,length = 23,temperature =1): '''sentence:預測輸入值;lenth:預測出的字符串長度; 供 class 內部調用,輸入max_len長度字符串, 返回length長度的預測值字符串''' sentence = sentence[:self.config.max_len] generate = '' for i in range(length): pred = self._pred(sentence,temperature) generate += pred sentence = sentence[1:]+pred return generate
以上寫好後,就可以來試著生成唐詩。
先練習最基本的,如同訓練時給前六個字,預測下一個字,一直迴圈到預測整首詩。
'''根據給出的前max_len個字,生成詩句''' def predict_sen(self, text,temperature =1): '''此例中,即根據給出的第一句詩句(含逗號),來生成古詩''' if not self.model: return max_len = self.config.max_len if len(text) < max_len: print('length should not be less than ', max_len) #排除輸入一串文字長度小於 max_len 的情況 return sentence = text[-max_len:] # print('the first line:',sentence) generate = str(sentence) generate += self._preds(sentence,length = 24-max_len,temperature=temperature) return generate
我們試試以下練習:給三種溫度看看輸出。
for temperature in [0.5, 1, 1.5]: poetry1 = model.predict_sen("柯批好市長,",temperature = 1.5) print(poetry1)
柯批好市長,丹齣天杯上。齣南門荷春,將對愁華馬。
柯批好市長,新間與照想。還為碧茲陵,親國葉白上。
柯批好市長,飛坐孤何平。氣還還高得,竹時相州過。
呵,還蠻有趣的!
接著試試看隨機選一首詩的開頭,當作輸入會不會讓模型寫的詩好看一些?
def predict_random(self,temperature = 1): '''隨機從庫中選取一句開頭的詩句,生成五言絕句''' if not self.model: print('model not loaded') return index = random.randint(0, self.poems_num) sentence = self.poems[index][: self.config.max_len] generate = self.predict_sen(sentence,temperature=temperature) return generate
for temperature in [0.5, 1, 1.5]: poetry_Random = model.predict_random(temperature = temperature) print(poetry_Random)
午醉醒來晚,人日何雲從。花日池東見,林同無下得。
何處鞦風至,流鍾虛日北。有月吾間人,吹臨早相連。
流品是鴛鴦,遠長夜十四。愛時來齣何,今方空石意。
原詩為:
午醉醒來晚,無人夢自驚。夕陽如有意,長傍小窗明。
何處鞦風至,蕭蕭送雁群。朝來入庭樹,孤客最先聞。
流品是鴛鴦,翻飛雲水鄉。風高離極浦,煙暝下方塘。比鷺行藏彆,穿荷羽翼香。雙雙浴輕浪,誰見在瀟湘。
若不知原詩為何,模型寫的以假亂真,真是難以想像。今天要是寫給外國人看,可能真的會相信呢!!
接著來玩玩藏頭詩,我們要將想藏頭的字串,逐個丟進max_len的最後一個字然後丟進模型預測下一個字,直至完整的詩句。此例為四字藏頭,如下:
'''根據給4個藏頭字,生成藏頭詩五言絕句''' def predict_hide(self, text,temperature = 1): if not self.model: print('model not loaded') return if len(text)!=4: print('藏頭詩的輸入必須是4個字!') return #選取隨機一首詩的最後(max_len-1)個字符(含句號)+給出的首個文字作為初始輸入 ex.前明月光。+text[0] (共6個字) #此練習輸入共6個字,同訓練模型時的條件。 index = random.randint(0, self.poems_num) sentence = self.poems[index][-self.config.max_len:-1] + text[0] generate = str(text[0]) print('first line = ',sentence) #給出藏頭詩後五個字(含逗號) for i in range(5): next_char = self._pred(sentence,temperature) sentence = sentence[1:] + next_char generate+= next_char #將藏頭詩的第二個字以後加入 for i in range(3): generate += text[i+1] sentence = sentence[1:] + text[i+1] #完成後面每個藏頭詩的句子 for i in range(5): next_char = self._pred(sentence,temperature) sentence = sentence[1:] + next_char generate+= next_char return generate
藏頭詩的藏頭"華碩石頭",丟進模型看看:
for temperature in [0.5, 1, 1.5]: hide_poetry = model.predict_hide('華碩石頭', temperature = temperature) print(hide_poetry)
first line =  意在浮花。華
華見不心故,碩道一水久。石人天關子,頭是花如鞦。
first line =  欲媚濃妝。華
華度曉可堂,碩長颱欲帝。石是青長待,頭驚齣朝相。
first line =  應在十洲。華
華清東色齊,碩王虎月顔。石山在逢歸,頭道公林共。
只給模型第一個字,完成整個詩(共24個字,含逗號、句號)
'''根據給出的首個文字,生成五言絕句''' def predict_first(self, char,temperature =1): if not self.model: print('model not loaded') return index = random.randint(0, self.poems_num) #選取隨機一首詩的最後max_len個字符+給出的首個文字作為初始輸入 sentence = self.poems[index][-self.config.max_len:-1] + char generate = str(char) # print('first line = ',sentence) # 直接預測後面23個字符 generate += self._preds(sentence,length=23,temperature=temperature) return generate
for temperature in [0.5, 1, 1.5]: poetry_first = model.predict_first("中", temperature = temperature) print(poetry_first)
中來不故君,在林中雨有。夜新月山時,聞傢誰歸空。
中平知世相,見可微得西。清城有意齣,裏正君相風。
中望微翻草,常月玉雪外。木州颱水上,林所州上願。
以上都是參考作者的編碼做練習,以下我也來利用一下 predict_first 做為內部調用,寫一個函式,把每一首詩的開頭當作藏頭,想輸入多少字,就有幾首詩:
'''每一首詩的開頭當作藏頭,想輸入多少字,就有幾首詩''' def hide_poetry(self,text,temperature = 1,): generate = '' for i in text: sen = model.predict_first(i,temperature) generate += sen +"\n" return generate
for temperature in [0.5, 1, 1.5]: hide_poetry = model.hide_poetry("花好月圓") print("temperature : %s" %temperature) print(hide_poetry)
temperature : 0.5
花期雲曉照,鍾發上傢月。為中水城子,門願為期宿。
好今君裏蒼,樓傢復地同。群春事人多,相重山中東。
月寒空中山,且成往當一。與為君不色,中過清待外。
圓行誰陽不,國衣有山吹。華二光歸安,客夜東中春。

temperature : 1
花吳天欲水,去見今閣詩。軒惜相子得,寄聞寒高荷。
好為山滿陵,雲有香春攀。不高彆待容,知名作人殊。
月恩安帶葉,期山倚王寒。君為州上長,已長藏朝莫。
圓裏子來三,散風馀關對。君雲鞦人著,為不遲水正。

temperature : 1.5
花當未已是,中持老日門。窗不已韆在,居眾夜彆恩。
好憶天上驚,聲對朝發日。風已空來罷,樹裏煙草鳥。
月春露應清,起金閑水平。來寒起前不,晚愛前何不。
圓夜為正暮,時齣堪海池。終幾亦落思,隱颱林山白。
用AI寫詩,還蠻有趣的!! 雖然不能寫出有押韻的詩,但模型還是能寫出有模有樣的句子。
神經網絡已經可以記住逗號、句號出現在詩中的位置,且詩句都很假掰,很有詩的味道。
LSTM 模型的練習還有很多,可以應用面很廣,算是 NLP 領域的入門,身為初學者一定要好好練習。

沒有留言:

張貼留言