歡迎來到恐龍大陸! 6500萬年前,恐龍就已經存在,並且在該作業下它們又回來了。假設你負責一項特殊任務,領先的生物學研究人員正在創造新的恐龍品種,並計劃將它們帶入地球,而你的工作就是為這些新恐龍起名字。如果恐龍不喜歡它的名字,它可能會變得瘋狂,所以需要明智地選擇!
幸運的是,你掌握了深度學習的一些知識,你將使用它來節省時間。你的助手已收集了它們可以找到的所有恐龍名稱的列表,並將其編譯到此dataset中。(請單擊上一個鏈接查看)要創建新的恐龍名稱,你將構建一個字母級語言模型來生成新名稱。你的算法將學習不同的名稱模式,並隨機生成新名稱。希望該算法可以使你和你的團隊免受恐龍的憤怒!
完成此作業,你將學習:
外面將加載rnn_utils
中為你提供的一些函數開始。具體來說,你可以訪問諸如rnn_forward
和rnn_backward
之類的函數,這些函數與你在上一個作業中實現的函數等效。
import numpy as np
from utils import *
import random
from random import shuffle
運行以下單元格以讀取包含恐龍名稱的數據集,創建唯一字符列表(例如a-z),並計算數據集和詞匯量。
# 獲取名稱
data = open("datasets/dinos.txt", "r").read()
# 轉化為小寫字符
data = data.lower()
# 轉化為無序且不重復的元素列表
chars = list(set(data))
# 獲取大小信息
data_size, vocab_size = len(data), len(chars)
print(chars)
print("共計有%d個字符,唯一字符有%d個"%(data_size,vocab_size))
['y', 'o', 'm', 'q', 'g', 'v', 'j', 'i', 't', 'r', 'h', 's', 'b', 'n', 'd', 'k', 'p', 'c', '\n', 'w', 'e', 'a', 'z', 'l', 'u', 'f', 'x']
共計有19909個字符,唯一字符有27個
這些字符是a-z(26個字符)加上“\n”(換行符),在此作業中,其作用類似於我們在講座中討論的<EOS
>(句子結尾)標記,僅在此處表示恐龍名稱的結尾,而不是句子的結尾。在下面的單元格中,外面創建一個python字典(即哈希表),以將每個字符映射為0-26之間的索引。外面還創建了第二個python字典,該字典將每個索引映射回對應的字符。這將幫助你找出softmax層的概率分布輸出中哪個索引對應於哪個字符。下面的char_to_ix
和ix_to_char
是python字典。
char_to_ix = {
ch:i for i,ch in enumerate(sorted(chars)) }
ix_to_char = {
i:ch for i,ch in enumerate(sorted(chars)) }
print(ix_to_char)
{0: '\n', 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'}
你的模型將具有以下結構:
圖1:循環神經網絡,類似於你在上一個筆記本“手把手實現循環神經網絡”中構建的內容。
在每個時間步,RNN都會根據給定的先前字符來預測下一個字符。數據集 X = ( x * 1 * , x * 2 * , . . . , x * T x * ) X = (x^{\langle 1 \rangle}, x^{\langle 2 \rangle}, ..., x^{\langle T_x \rangle}) X=(x*1*,x*2*,...,x*Tx*)是訓練集中的字符列表,而 Y = ( y * 1 * , y * 2 * , . . . , y * T x * ) Y = (y^{\langle 1 \rangle}, y^{\langle 2 \rangle}, ..., y^{\langle T_x \rangle}) Y=(y*1*,y*2*,...,y*Tx*)使得每個時間步 t t t,我們有 y * t * = x * t + 1 * y^{\langle t \rangle} = x^{\langle t+1 \rangle} y*t*=x*t+1*。
在這一部分中,你將構建整個模型的兩個重要模塊:
然後,你將應用這兩個函數來構建模型。
在本節中,你將實現在優化循環中調用的clip
函數。回想一下,你的總體循環結構通常由正向傳播,損失計算,反向傳播和參數更新組成。在更新參數之前,你將在需要時執行梯度裁剪,以確保你的梯度不會“爆炸”,這意味著要采用很大的值。
在下面的練習中,你將實現一個函數clip
,該函數接收梯度字典,並在需要時返回裁剪後的梯度。梯度裁剪有很多方法。我們將使用簡單的暗元素裁剪程序,其中將梯度向量的每個元素裁剪為位於范圍 [ − N , N ] [-N, N] [−N,N]之間。通常,你將提供一個maxValue
(例如10).在此示例中,如果梯度向量的任何分量大於10,則將其設置為10;並且如果梯度向量的任何分量小於-10,則將其設置為-10.如果介於-10和10之間,則將其保留。
圖2:在網絡遇到輕微的“梯度爆炸”的情況下,使用與不使用梯度裁剪的梯度下降對比。
練習:實現以下函數以返回字典gradients
的裁剪梯度。你的函數接受最大阈值,並返回裁剪後的梯度。你可以查看此hint,以獲取有關如何裁剪numpy的示例。你將需要使用參數out = ...
。
def clip(gradients, maxValue):
""" 使用maxValue來修剪梯度 參數: gradients -- 字典類型,包含了以下參數:"dWaa", "dWax", "dWya", "db", "dby" maxValue -- 阈值,把梯度值限制在[-maxValue, maxValue]內 返回: gradients -- 修剪後的梯度 """
# 獲取參數
dWaa, dWax, dWya, db, dby = gradients['dWaa'], gradients['dWax'], gradients['dWya'], gradients['db'], gradients['dby']
# 梯度修剪
for gradient in [dWaa, dWax, dWya, db, dby]:
np.clip(gradient, -maxValue, maxValue, out=gradient)
gradients = {
"dWaa": dWaa, "dWax": dWax, "dWya": dWya, "db": db, "dby": dby}
return gradients
np.random.seed(3)
dWax = np.random.randn(5,3)*10
dWaa = np.random.randn(5,5)*10
dWya = np.random.randn(2,5)*10
db = np.random.randn(5,1)*10
dby = np.random.randn(2,1)*10
gradients = {
"dWax": dWax, "dWaa": dWaa, "dWya": dWya, "db": db, "dby": dby}
gradients = clip(gradients, 10)
print("gradients[\"dWaa\"][1][2] =", gradients["dWaa"][1][2])
print("gradients[\"dWax\"][3][1] =", gradients["dWax"][3][1])
print("gradients[\"dWya\"][1][2] =", gradients["dWya"][1][2])
print("gradients[\"db\"][4] =", gradients["db"][4])
print("gradients[\"dby\"][1] =", gradients["dby"][1])
gradients["dWaa"][1][2] = 10.0
gradients["dWax"][3][1] = -10.0
gradients["dWya"][1][2] = 0.2971381536101662
gradients["db"][4] = [10.]
gradients["dby"][1] = [8.45833407]
現在假設你的模型已經訓練好。你想生成新文本(字符)。下圖說明了生成過程:
圖3:在此圖中,我們假設模型已經訓練好。我們在第一步中傳入 x * 1 * = 0 ⃗ x^{\langle 1\rangle} = \vec{0} x*1*=0,然後讓網絡一次采樣一個字符。
練習:實現以下的sample
函數來采樣字母。你需要執行4個步驟:
softmax()
函數供你使用。np.random.choice
。np.random.choice()
的例子:np.random.seed(0)
p = np.array([0.1, 0.0, 0.7, 0.2])
index = np.random.choice([0, 1, 2, 3], p = p.ravel())
這意味著你將根據分布選擇`index`:$P(index = 0) = 0.1, P(index = 1) = 0.0, P(index = 2) = 0.7, P(index = 3) = 0.2$。
sample()
中實現的最後一步是覆蓋變量x
,該變量當前存儲 x * t * x^{\langle t \rangle } x*t*,其值為 x * t + 1 * x^{\langle t+1 \rangle } x*t+1*。通過創建與預測字符相對應的one-hot向量以表示為 x * t + 1 * x^{\langle t+1 \rangle } x*t+1*。然後,你將在步驟1中前向傳播 x * t + 1 * x^{\langle t+1 \rangle } x*t+1*,並繼續重復此過程,直到獲得"\n"字符,表明你已經到達恐龍名稱的末尾。def sample(parameters, char_to_is, seed):
""" 根據RNN輸出的概率分布序列對字符序列進行采樣 參數: parameters -- 包含了Waa, Wax, Wya, by, b的字典 char_to_ix -- 字符映射到索引的字典 seed -- 隨機種子 返回: indices -- 包含采樣字符索引的長度為n的列表。 """
# 從parameters 中獲取參數
Waa, Wax, Wya, by, b = parameters['Waa'], parameters['Wax'], parameters['Wya'], parameters['by'], parameters['b']
vocab_size = by.shape[0]
n_a = Waa.shape[1]
# 步驟1
## 創建獨熱向量x
x = np.zeros((vocab_size,1))
## 使用0初始化a_prev
a_prev = np.zeros((n_a,1))
# 創建索引的空列表,這是包含要生成的字符的索引的列表。
indices = []
# IDX是檢測換行符的標志,我們將其初始化為-1。
idx = -1
# 循環遍歷時間步驟t。在每個時間步中,從概率分布中抽取一個字符,
# 並將其索引附加到“indices”上,如果我們達到50個字符,
#(我們應該不太可能有一個訓練好的模型),我們將停止循環,這有助於調試並防止進入無限循環
counter = 0
newline_character = char_to_ix["\n"]
while (idx != newline_character and counter < 50):
# 步驟2:使用公式1、2、3進行前向傳播
a = np.tanh(np.dot(Wax, x) + np.dot(Waa, a_prev) + b)
z = np.dot(Wya, a) + by
y = softmax(z)
# 設定隨機種子
np.random.seed(counter + seed)
# 步驟3:從概率分布y中抽取詞匯表中字符的索引
idx = np.random.choice(list(range(vocab_size)), p=y.ravel())
# 添加到索引中
indices.append(idx)
# 步驟4:將輸入字符重寫為與采樣索引對應的字符。
x = np.zeros((vocab_size,1))
x[idx] = 1
# 更新a_prev為a
a_prev = a
# 累加器
seed += 1
counter +=1
if(counter == 50):
indices.append(char_to_ix["\n"])
return indices
np.random.seed(2)
_, n_a = 20, 100
Wax, Waa, Wya = np.random.randn(n_a, vocab_size), np.random.randn(n_a, n_a), np.random.randn(vocab_size, n_a)
b, by = np.random.randn(n_a, 1), np.random.randn(vocab_size, 1)
parameters = {
"Wax": Wax, "Waa": Waa, "Wya": Wya, "b": b, "by": by}
indices = sample(parameters, char_to_ix, 0)
print("Sampling:")
print("list of sampled indices:", indices)
print("list of sampled characters:", [ix_to_char[i] for i in indices])
Sampling:
list of sampled indices: [12, 17, 24, 14, 13, 9, 10, 22, 24, 6, 13, 11, 12, 6, 21, 15, 21, 14, 3, 2, 1, 21, 18, 24, 7, 25, 6, 25, 18, 10, 16, 2, 3, 8, 15, 12, 11, 7, 1, 12, 10, 2, 7, 7, 11, 17, 24, 12, 12, 0, 0]
list of sampled characters: ['l', 'q', 'x', 'n', 'm', 'i', 'j', 'v', 'x', 'f', 'm', 'k', 'l', 'f', 'u', 'o', 'u', 'n', 'c', 'b', 'a', 'u', 'r', 'x', 'g', 'y', 'f', 'y', 'r', 'j', 'p', 'b', 'c', 'h', 'o', 'l', 'k', 'g', 'a', 'l', 'j', 'b', 'g', 'g', 'k', 'q', 'x', 'l', 'l', '\n', '\n']
現在是時候建立用於文字生成的字母級語言模型了。
在本部分中,你將實現一個函數,該函數執行隨機梯度下降的一個步驟(梯度裁剪)。你將一次查看一個訓練示例,因此優化算法為隨機梯度下降。提醒一下,以下是RNN常見的優化循環的步驟:
練習:實現此優化過程(隨機梯度下降的一個步驟)。
我們來實現這一優化過程(單步隨機梯度下降),這裡我們提供了一些函數:
# 示例,請勿執行。
def rnn_forward(X, Y, a_prev, parameters):
""" 通過RNN進行前向傳播,計算交叉熵損失。 它返回損失的值以及存儲在反向傳播中使用的“緩存”值。 """
....
return loss, cache
def rnn_backward(X, Y, parameters, cache):
""" 通過時間進行反向傳播,計算相對於參數的梯度損失。它還返回所有隱藏的狀態 """
...
return gradients, a
def update_parameters(parameters, gradients, learning_rate):
""" 使用梯度下降更新參數 """
...
return parameters
我們來構建優化函數:
def optimize(X, Y, a_prev, parameters, learning_rate = 0.01):
""" 執行訓練模型的單步優化。 參數: X -- 整數列表,其中每個整數映射到詞匯表中的字符。 Y -- 整數列表,與X完全相同,但向左移動了一個索引。 a_prev -- 上一個隱藏狀態 parameters -- 字典,包含了以下參數: Wax -- 權重矩陣乘以輸入,維度為(n_a, n_x) Waa -- 權重矩陣乘以隱藏狀態,維度為(n_a, n_a) Wya -- 隱藏狀態與輸出相關的權重矩陣,維度為(n_y, n_a) b -- 偏置,維度為(n_a, 1) by -- 隱藏狀態與輸出相關的權重偏置,維度為(n_y, 1) learning_rate -- 模型學習的速率 返回: loss -- 損失函數的值(交叉熵損失) gradients -- 字典,包含了以下參數: dWax -- 輸入到隱藏的權值的梯度,維度為(n_a, n_x) dWaa -- 隱藏到隱藏的權值的梯度,維度為(n_a, n_a) dWya -- 隱藏到輸出的權值的梯度,維度為(n_y, n_a) db -- 偏置的梯度,維度為(n_a, 1) dby -- 輸出偏置向量的梯度,維度為(n_y, 1) a[len(X)-1] -- 最後的隱藏狀態,維度為(n_a, 1) """
# 前向傳播
loss, cache = rnn_forward(X, Y, a_prev, parameters)
# 反向傳播
gradients, a = rnn_backward(X, Y, parameters, cache)
# 梯度修剪,[-5 , 5]
gradients = clip(gradients,5)
# 更新參數
parameters = update_parameters(parameters,gradients,learning_rate)
return loss, gradients, a[len(X)-1]
np.random.seed(1)
vocab_size, n_a = 27, 100
a_prev = np.random.randn(n_a, 1)
Wax, Waa, Wya = np.random.randn(n_a, vocab_size), np.random.randn(n_a, n_a), np.random.randn(vocab_size, n_a)
b, by = np.random.randn(n_a, 1), np.random.randn(vocab_size, 1)
parameters = {
"Wax": Wax, "Waa": Waa, "Wya": Wya, "b": b, "by": by}
X = [12,3,5,11,22,3]
Y = [4,14,11,22,25, 26]
loss, gradients, a_last = optimize(X, Y, a_prev, parameters, learning_rate = 0.01)
print("Loss =", loss)
print("gradients[\"dWaa\"][1][2] =", gradients["dWaa"][1][2])
print("np.argmax(gradients[\"dWax\"]) =", np.argmax(gradients["dWax"]))
print("gradients[\"dWya\"][1][2] =", gradients["dWya"][1][2])
print("gradients[\"db\"][4] =", gradients["db"][4])
print("gradients[\"dby\"][1] =", gradients["dby"][1])
print("a_last[4] =", a_last[4])
Loss = 126.50397572165362
gradients["dWaa"][1][2] = 0.19470931534720892
np.argmax(gradients["dWax"]) = 93
gradients["dWya"][1][2] = -0.007773876032003782
gradients["db"][4] = [-0.06809825]
gradients["dby"][1] = [0.01538192]
a_last[4] = [-1.]
給定恐龍名稱數據集,我們將數據集的每一行(一個名稱)用作一個訓練示例。每100步隨機梯度下降,你將抽樣10個隨機選擇的名稱,以查看算法的運行情況。請記住要對數據集進行混洗,以便隨機梯度下降以隨機順序訪問示例。
練習:按照說明進行操作並實現model()
。當examples[index]
包含一個恐龍名稱(字符串)時,創建示例(X,Y),可以使用以下方法:
index = j % len(examples)
X = [None] + [char_to_ix[ch] for ch in examples[index]]
Y = X[1:] + [char_to_ix["\n"]]
注意,我們使用:index= j % len(examples)
,其中j = 1....num_iterations
,以確保examples[index]
始終是有效的語句(index
小於len(examples)
)。X
的第一個條目為None將被rnn_forward()
解釋為設置 x * 0 * = 0 ⃗ x^{\langle 0 \rangle} = \vec{0} x*0*=0。此外,這確保了Y
等於X
,但向左移動了一步,並附加了“\n
”以表示恐龍名稱的結尾。
def model(data, ix_to_char, char_to_ix, num_iterations=3500,
n_a=50, dino_names=7,vocab_size=27):
""" 訓練模型並生成恐龍名字 參數: data -- 語料庫 ix_to_char -- 索引映射字符字典 char_to_ix -- 字符映射索引字典 num_iterations -- 迭代次數 n_a -- RNN單元數量 dino_names -- 每次迭代中采樣的數量 vocab_size -- 在文本中的唯一字符的數量 返回: parameters -- 學習後了的參數 """
# 從vocab_size中獲取n_x、n_y
n_x, n_y = vocab_size, vocab_size
# 初始化參數
parameters = initialize_parameters(n_a, n_x, n_y)
# 初始化損失
loss = get_initial_loss(vocab_size, dino_names)
# 構建恐龍名稱列表
with open("datasets/dinos.txt") as f:
examples = f.readlines()
examples = [x.lower().strip() for x in examples]
# 打亂全部的恐龍名稱
np.random.seed(0)
np.random.shuffle(examples)
# 初始化LSTM隱藏狀態
a_prev = np.zeros((n_a,1))
# 循環
for j in range(num_iterations):
# 定義一個訓練樣本
index = j % len(examples)
X = [None] + [char_to_ix[ch] for ch in examples[index]]
Y = X[1:] + [char_to_ix["\n"]]
# 執行單步優化:前向傳播 -> 反向傳播 -> 梯度修剪 -> 更新參數
# 選擇學習率為0.01
curr_loss, gradients, a_prev = optimize(X, Y, a_prev, parameters)
# 使用延遲來保持損失平滑,這是為了加速訓練。
loss = smooth(loss, curr_loss)
# 每2000次迭代,通過sample()生成“\n”字符,檢查模型是否學習正確
if j % 2000 == 0:
print("第" + str(j+1) + "次迭代,損失值為:" + str(loss))
seed = 0
for name in range(dino_names):
# 采樣
sampled_indices = sample(parameters, char_to_ix, seed)
print_sample(sampled_indices, ix_to_char)
# 為了得到相同的效果,隨機種子+1
seed += 1
print("\n")
return parameters
#開始時間
start_time = time.clock()
#開始訓練
parameters = model(data, ix_to_char, char_to_ix, num_iterations=35000)
#結束時間
end_time = time.clock()
#計算時差
minium = end_time - start_time
print("執行了:" + str(int(minium / 60)) + "分" + str(int(minium%60)) + "秒")
第1次迭代,損失值為:23.087336085484605
Nkzxwtdmfqoeyhsqwasjkjvu
Kneb
Kzxwtdmfqoeyhsqwasjkjvu
Neb
Zxwtdmfqoeyhsqwasjkjvu
Eb
Xwtdmfqoeyhsqwasjkjvu
第2001次迭代,損失值為:27.884160491415777
Liusskeomnolxeros
Hmdaairus
Hytroligoraurus
Lecalosapaus
Xusicikoraurus
Abalpsamantisaurus
Tpraneronxeros
第4001次迭代,損失值為:25.90181489335302
Mivrosaurus
Inee
Ivtroplisaurus
Mbaaisaurus
Wusichisaurus
Cabaselachus
Toraperlethosdarenitochusthiamamumamaon
第6001次迭代,損失值為:24.608778900832394
Onwusceomosaurus
Lieeaerosaurus
Lxussaurus
Oma
Xusteonosaurus
Eeahosaurus
Toreonosaurus
第8001次迭代,損失值為:24.070350147705277
Onxusichepriuon
Kilabersaurus
Lutrodon
Omaaerosaurus
Xutrcheps
Edaksoje
Trodiktonus
第10001次迭代,損失值為:23.84444646002657
Onyusaurus
Klecalosaurus
Lustodon
Ola
Xusodonia
Eeaeosaurus
Troceosaurus
第12001次迭代,損失值為:23.291971267939104
Onyxosaurus
Kica
Lustrepiosaurus
Olaagrraiansaurus
Yuspangosaurus
Eealosaurus
Trognesaurus
第14001次迭代,損失值為:23.38233761730599
Meutromodromurus
Inda
Iutroinatorsaurus
Maca
Yusteratoptititan
Ca
Troclosaurus
第16001次迭代,損失值為:23.28294611567149
Mdyusaurus
Indaacosaupisaurus
Justolong
Maca
Yuspandosaurus
Cabaspadantes
Trodon
第18001次迭代,損失值為:22.85081326872384
Phyusaurus
Meja
Mystoosaurus
Pegamosaurus
Yusmaphosaurus
Eiahosaurus
Trolonosaurus
第20001次迭代,損失值為:22.929325599583475
Nlyusaurus
Logbalosaurus
Lvuslangosaurus
Necalosaurus
Ytrrangosaurus
Ekairus
Troenesaurus
第22001次迭代,損失值為:22.760728439539477
Onvusaroglolonoshareimus
Llecaerona
Myrrocephoeurus
Pedacosaurus
Ytrodonosaurus
Eiadosaurus
Trodonosaurus
第24001次迭代,損失值為:22.57720843347023
Meustrhe
Inca
Jurrollesaurus
Medaislleamlis
Yusaurus
Cabasigaansaurus
Trocerator
第26001次迭代,損失值為:22.616434369927045
Onyxosaurus
Lelealosaurus
Lustolialneusaurns
Olaahus
Yusichesaurus
Ehairuodan
Trochenomusaurus
第28001次迭代,損失值為:22.52468955468878
Meutosaurus
Kracafosaurus
Lvtosaurus
Necaisaurus
Yusiadgosaurus
Eiadosaurus
Trocephicrisaurus
第30001次迭代,損失值為:22.719787638280476
Peutroknethithosaurus
Llacalosaurus
Lutroenator
Pacalosaurus
Yusolonosaurus
Edacosaurus
Trocheshathystatepiscaptiuiman
第32001次迭代,損失值為:22.23296009953549
Meustrathus
Kojcanosaurus
Lustrasaurus
Macalosaurus
Yusiandon
Eeainor
Usianatorsaurus
第34001次迭代,損失值為:22.318447496893175
Olusaurus
Klacaesaurus
Lusnsaurus
Ola
Ytosaurus
Egaisaurus
Trhangosaurus
執行了:0分38秒
d:\vr\virtual_environment\lib\site-packages\ipykernel_launcher.py:8: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
你可以看到,在訓練即將結束時,你的算法已開始生成合理的恐龍名稱。剛開始時,它會生成隨機字符,但是到最後,你會看到恐龍名字的結尾很酷。運行該算法更長時間,並調整超參數來看看是否可以獲得更好的結果。我們的實現產生了一些非常酷的名稱,例如“maconucon”,“marloralus”和“macingsersaurus”。你的模型還有望了解到恐龍名稱往往以saurus
,don
,aura
,tor
等結尾。
如果你的模型生成了一些不酷的名字,請不要完全怪罪模型-並非所有實際的恐龍名字聽起來都很酷。(例如,dromaeosauroides是實際存在的恐龍名稱,並且也在訓練集中。)但是此模型應該給你提供了一組可以從中挑選的候選名字!
該作業使用了相對較小的數據集,因此你可以在CPU上快速訓練RNN。訓練英語模型需要更大的數據集,並且通常需要更多的計算,在GPU上也要運行多個小時。我們使用恐龍的名字已經有一段時間了,到目前為止,我們最喜歡的名字是great, undefeatable,且fierce的:Mangosaurus!
該筆記本的其余部分是可選的,尚未評分,但我們希望你都嘗試做一下,因為它非常有趣且內容豐富。
一個類似(但更復雜)的任務是生成莎士比亞詩歌。無需從恐龍名稱的數據集中學習,而是使用莎士比亞詩歌集。使用LSTM單元,你可以學習跨文本中許多字符的長期依賴關系。例如,某個字符出現在序列的某個地方可能會影響序列後面的其他字符。這些長期依賴關系對於恐龍名稱來說不太重要,因為它們的名稱很短。
讓我們成為詩人!
我們已經用Keras實現了莎士比亞詩歌生成器。運行以下單元格以加載所需的軟件包和模型。這可能需要幾分鐘的時間。
from __future__ import print_function
from keras.callbacks import LambdaCallback
from keras.models import Model, load_model, Sequential
from keras.layers import Dense, Activation, Dropout, Input, Masking
from keras.layers import LSTM
from keras.utils.data_utils import get_file
from keras.preprocessing.sequence import pad_sequences
from shakespeare_utils import *
import sys
import io
Using TensorFlow backend.
Loading text data...
Creating training set...
number of training examples: 31412
Vectorizing training set...
Loading model...
WARNING:tensorflow:From d:\vr\virtual_environment\lib\site-packages\tensorflow_core\python\ops\resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
WARNING:tensorflow:From d:\vr\virtual_environment\lib\site-packages\tensorflow_core\python\ops\math_grad.py:1424: where (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
WARNING:tensorflow:From d:\vr\virtual_environment\lib\site-packages\keras\backend\tensorflow_backend.py:422: The name tf.global_variables is deprecated. Please use tf.compat.v1.global_variables instead.
d:\vr\virtual_environment\lib\site-packages\keras\engine\saving.py:384: UserWarning: Error in loading the saved optimizer state. As a result, your model is starting with a freshly initialized optimizer.
warnings.warn('Error in loading the saved optimizer '
為了節省你的時間,我們已經在莎士比亞的十四行詩"The Sonnets"詩歌集上訓練了大約1000個epoch的模型。
讓我們再訓練模型完成一個新epoch,這也將花費幾分鐘。你可以運行generate_output
,這將提示你輸入小於40個字符的句子。這首詩將從你輸入的句子開始,我們的RNN-Shakespeare將為你完成其余的部分!例如,嘗試"Forsooth this maketh no sense "(不要輸入引號)。根據是否在末尾加上空格,你的結果也可能會有所不同,兩種方法都應嘗試,也可以嘗試其他輸入法。
print_callback = LambdaCallback(on_epoch_end=on_epoch_end)
model.fit(x, y, batch_size=128, epochs=1, callbacks=[print_callback])
Epoch 1/1
31412/31412 [==============================] - 31s 992us/step - loss: 2.7320
<keras.callbacks.callbacks.History at 0x20c382edb38>
# 運行此代碼嘗試不同的輸入,而不必重新訓練模型。
generate_output() # 博主輸入"Forsooth this maketh no sense"
Write the beginning of your poem, the Shakespeare machine will complete it. Your input is: Forsooth this maketh no sense
Here is your poem:
Forsooth this maketh no senses,
sin love that hiss of o no crusth,
and doth my berod fear i be two deared,
the hames for sichn three from when his biml age,
when thene his frotery i con dost,
whone knife whace a haor wor, wire not so,
the mesters shound be for yet befanot dight,
i unding thy beauty holl o lide to vears,
and bu thy grint hapl a do before.
that i hast to cell i pand
co whot i womd do bester is have racpeated,
RNN-Shakespeare模型與你為恐龍名稱構建的模型非常相似。唯一的區別是: