摘要:介紹本文我們將使用網絡來學習莎士比亞小說,模型通過學習可以生成與小說風格相似的文本,如圖所示雖然有些句子并沒有實際的意思目前我們的模型是基于概率,并不是理解語義,但是大多數單詞都是有效的,文本結構也與我們訓練的文本相似。
介紹
本文我們將使用GRU網絡來學習莎士比亞小說,模型通過學習可以生成與小說風格相似的文本,如圖所示:
雖然有些句子并沒有實際的意思(目前我們的模型是基于概率,并不是理解語義),但是大多數單詞都是有效的,文本結構也與我們訓練的文本相似。
由于項目中使用到了Eager Execution和GRU,所以我們先進行簡單介紹:
Tensorflow在Eager Execution之前想要評估操作必須通過運行計算圖"sess.run()"的方式來獲取值,而使用Eager Execution可以立即評估操作。Eager Execution基于python流程控制并可以使用python的調試工具進行錯誤報告。
梯度計算:
先使用tf.GradientTape記錄然后再計算梯度,示例如下:
# tfe = tf.contrib.eager w = tfe.Variable([[1.0]]) with tf.GradientTape() as tape: loss = w * w grad = tape.gradient(loss, w)
常用函數:
tfe.gradients_function:返回一個函數,該函數會計算其輸入函數參數相對其參數的導數。
tfe.value_and_gradients_function:除了返回函數還會返回輸入函數的值。
其它:
在訓練大數據集的時候,Eager Execution 性能與Graph Execution相當,但在小數據集中Eager Execution會慢一些。
Eager Execution勝在開發和調試的便利性,但是在分布式訓練,性能優化,生產部署方面Graph Execution更好。
在未調用tf.enable_eager_execution(開啟后不能關閉)的情況下可以使用tfe.py_func啟用Eager Execution。
GRU是LSTM的一種變體,它將LSTM的遺忘門,輸入門,輸出門改為更新門(LSTM的遺忘門,輸入門合并),重置門。參數少,收斂快,不過在數據量較大的時候LSTM的表現更好。下圖是GRU網絡結構和前向傳播計算方法。
更新門:控制前一時刻的狀態信息被帶入到當前狀態中的程度。
重置門:控制忽略前一時刻的狀態信息,重置門的值越小說明忽略的越多(被寫入的信息越少)。
GRU訓練:
我們要學習的參數有Wr、Wz、Wh、Wo,其中Wr、Wz、Wh是和ht-1拼接而成,所以需要進行分割:
采用反向傳播對損失函數的各參數求偏導:
中間參數為:
算出每個參數的偏導數之后就可以更新參數了。GRU通過門控機制選擇性的保留特征,為長時傳播提供了保證。正因為門控機制的有效,門卷積目前也很受歡迎,感興趣的朋友可以閱讀相關文獻。
數據導入import tensorflow as tf import numpy as np import os import re import random import time # 開啟后不能關閉,只能重新啟動新的python會話 tf.enable_eager_execution() # 獲取數據,你也可以使用其他數據集 path_to_file=tf.keras.utils.get_file("shakespeare.txt", "https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt") text=open(path_to_file).read()
文字是不能直接放進模型的需要將其轉換為對應的ID表示:
# 去除重復字符并排序 unique=sorted(set(text)) # enumerate 返回value,index # 文本轉id char2idx={value:idx for idx,value in enumerate(unique)} # id轉文本 idx2char={idx:value for idx,value in enumerate(unique)}
部分參數配置:
# 每次輸入的最大文本長度,對應GRU模型的‘time_step’ max_length=100 vocab_size=len(unique) # 詞嵌入維度 embedding_dim=256 hidden_units=1024 BATCH_SIZE=64 BUFFER_SIZE=10000
獲取ID表示的數據并創建標簽
# 標簽的定義方式如: # data="ming" # input="min" labels="ing" input_text=[] labels_text=[] # 迭代獲取‘max_length’個數據 for i in range(0,len(text)-max_length,max_length): inputs=text[i:i+max_length] labels=text[i+1:i+1+max_length] input_text.append([char2idx[i] for i in inputs]) labels_text.append([char2idx[i] for i in labels])
dataset讀取數據:
dataset=tf.data.Dataset.from_tensor_slices((input_text,output_text)) # drop_remainder:小于batch_size 是否刪除,默認不刪除 dataset=dataset.batch(BATCH_SIZE,drop_remainder=True)創建模型
我們的模型包含三層:Embedding層,GRU層,全連接層。
class Model(tf.keras.Model): """ GRU:重置門,更新門 LSTM:遺忘門,輸入門,輸出門 GRU,參數少,容易收斂,數據量大的時候LSTM表現更好 """ def __init__(self,vocab_size,embedding_dim,units,batch_size): super(Model, self).__init__() self.units=units self.batch_size=batch_size self.embedding=tf.keras.layers.Embedding( input_dim=vocab_size, output_dim=embedding_dim ) if tf.test.is_gpu_available: # 使用GPU加速訓練 self.gru=tf.keras.layers.CuDNNGRU( units=self.units, return_sequences=True, return_state=True, recurrent_initializer="glorot_uniform" ) else: self.gru=tf.keras.layers.GRU( units=self.units, return_sequences=True, return_state=True, # 默認激活函數為:hard_sigmoid recurrent_activation="sigmoid", recurrent_initializer="glorot_uniform" ) self.fc=tf.keras.layers.Dense(units=vocab_size) def __call__(self, x,hidden): x=self.embedding(x) # output:[batch_size,max_length,hidden_size] # states:[batch_size,hidden_size] output,states=self.gru(x,initial_state=hidden) # 轉換至:(batch_size*max_length,hidden_size) output=tf.reshape(output,shape=(-1,output.shape[2])) # output:[batch_size*max_length,vocab_size] x=self.fc(output) return x,states為什么要使用Embedding
Embedding將高緯離散向量轉為低緯稠密的連續向量,并且表現出了向量間的相似性。
如圖所示,one-hot表示只有一個位置是1,其余為0,當文字較多時維度將會非常的大,并且由于one-hot編碼后的單詞存在獨立性,導致不能利用相似詞匯進行學習。那么Embedding又是怎么做的呢?
使用Embedding的第一步是通過索引對句子進行編碼,然后根據索引創建嵌入矩陣,這樣我們使用嵌入矩陣替代one-hot編碼向量。每個單詞向量不再是由一個獨立向量代替,而是替換成用于查找嵌入矩陣中向量的索引。
模型訓練# model初始化 model=Model(vocab_size,embedding_dim,hidden_units,BATCH_SIZE) optimizer=tf.train.AdamOptimizer(learning_rate=0.001) # 創建損失函數 def loss_fn(lables,preds): # 交叉熵損失函數在值域上邊界依然可以保持較高的激活值 return tf.losses.sparse_softmax_cross_entropy( labels=lables, logits=preds )
模型保存:
# 讀取checkpoint需要重新定義圖結構 checkpoint_dir = "./training_checkpoints" checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt") checkpoint = tf.train.Checkpoint(optimizer=optimizer, model=model)
開始訓練:
EPOCHS = 20 for epoch in range(EPOCHS): start = time.time() # 每迭代完成一次數據集重置hidden-state hidden = model.reset_states() for (batch, (inp, target)) in enumerate(dataset): # 使用GradientTape記錄 with tf.GradientTape() as tape: predictions, hidden = model(inp, hidden) target = tf.reshape(target, (-1,)) loss = loss_function(target, predictions) grads = tape.gradient(loss, model.variables) # 更新 optimizer.apply_gradients(zip(grads, model.variables)) if batch % 100 == 0: print ("Epoch {} Batch {} Loss {:.4f}".format(epoch+1, batch, loss)) # 每迭代5次數據集保存一次模型數據 if (epoch + 1) % 5 == 0: checkpoint.save(file_prefix = checkpoint_prefix)
讀取保存的checkpoint文件:
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))預測
要指定輸入字符以及希望模型生成的文本長度:
# 需要生成的文字長度 num_generate=1000 start_string="Q" # 將輸入字符轉為對應ID表示 input_eval=[char2idx[s] for s in start_string] # 擴展一維 batch_size input_eval=tf.expand_dims(input_eval,0) text_generated="" # hidden state shape:(batch_size,rnn units) # hidden 初始化 hidden=[tf.zeros((1,hidden_units))] for i in range(num_generate): precit,hidden=model(input_eval,hidden) # 注:這里batch_size == 1 # 代碼參考,很好理解: # output = tf.transpose(output,[1,0,2]) # last = tf.gather(output,int(output.get_shape()[0]-1) predict_id=tf.argmax(predict[-1]).numpy() # 將前一時刻的輸出作為下一時刻的輸入,一直到迭代完成 input_eval=tf.expand_dims(predict_id,0) # 轉換成對應字符 text_generated+=idx2char[predict_id] print(start_string+text_generated)總結
GRU網路作為LSTM網路的變體,參數少收斂快。Eager模式下代碼簡潔,調試便利雖然比Graph Execution功能遜色,但勝在便利性。RNN現在很多項目都會結合注意力機制使用,效果很好。注意力簡單來說就是對輸入不再是同等看待,而是根據權重值大小來區別訓練。
本文內容部分參考Yash Katariya,在此表示感謝。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42763.html
摘要:網絡所有的神經元都與另外的神經元相連每個節點功能都一樣。訓練的方法是將每個神經元的值設定為理想的模式,然后計算權重。輸入神經元在網絡整體更新后會成為輸入神經元。的訓練和運行過程與十分相似將輸入神經元設定為固定值,然后任網絡自己變化。 新的神經網絡架構隨時隨地都在出現,要時刻保持還有點難度。要把所有這些縮略語指代的網絡(DCIGN,IiLSTM,DCGAN,知道嗎?)都弄清,一開始估計還無從下...
摘要:通過將神經元的值設置為希望的模式來訓練網絡,之后可以計算權重。輸入神經元在完整網絡更新結束時變成輸出神經元。在某種程度上,這類似于峰值神經網絡,并不是所有的神經元始終都在發射并且點的生物合理性得分。 隨著新的神經網絡架構不時出現,很難跟蹤這些架構。知道所有縮寫(DCIGN,BiLSTM,DCGAN,任何人?)起初可能有點壓倒性。 所以我決定編寫一個包含許多這些體系結構的備忘單。這些大多...
摘要:作為解決方案的和和是解決短時記憶問題的解決方案,它們具有稱為門的內部機制,可以調節信息流。隨后,它可以沿著長鏈序列傳遞相關信息以進行預測,幾乎所有基于遞歸神經網絡的技術成果都是通過這兩個網絡實現的。和采用門結構來克服短時記憶的影響。 短時記憶RNN 會受到短時記憶的影響。如果一條序列足夠長,那它們將很難將信息從較早的時間步傳送到后面的時間步。 因此,如果你正在嘗試處理一段文本進行預測,RNN...
閱讀 3115·2023-04-25 15:02
閱讀 2803·2021-11-23 09:51
閱讀 2029·2021-09-27 13:47
閱讀 1984·2021-09-13 10:33
閱讀 954·2019-08-30 15:54
閱讀 2640·2019-08-30 15:53
閱讀 2853·2019-08-29 13:58
閱讀 881·2019-08-29 13:54