1.2 RNN 介紹

循環神經網絡(RNN)是基于序列數據(如語言、語音、時間序列)的遞歸性質而設計的,是一種反饋類型的神經網絡,它專門用于處理序列數據,如逐字生成文本或預測時間序列數據(例如股票價格、詩歌生成)。

RNN和全連接神經網絡的本質差異在于“輸入是帶有反饋信息的”,RNN除了接受每一步的輸入x(t) ,同時還有輸入上一步的歷史反饋信息——隱藏狀態h (t-1) ,也就是當前時刻的隱藏狀態h(t) 或決策輸出O(t) 由當前時刻的輸入 x(t) 和上一時刻的隱藏狀態h (t-1) 共同決定。從某種程度,RNN和大腦的決策很像,大腦接受當前時刻感官到的信息(外部的x(t) )和之前的想法(內部的h (t-1) )的輸入一起決策。

RNN的結構原理可以簡要概述為兩個公式。

RNN的隱藏狀態為:h(t) = f( U * x(t) + W * h(t-1) + b1), f為激活函數,常用tanh、relu;

RNN的輸出為:o(t) = g( V * h(t) + b2),g為激活函數,當用于分類任務,一般用softmax;

1.3 從RNN到LSTM

但是在實際中,RNN在長序列數據處理中,容易導致梯度爆炸或者梯度消失,也就是長期依賴(long-term dependencies)問題,其根本原因就是模型“記憶”的序列信息太長了,都會一股腦地記憶和學習,時間一長,就容易忘掉更早的信息(梯度消失)或者崩潰(梯度爆炸)。

梯度消失:歷史時間步的信息距離當前時間步越長,反饋的梯度信號就會越弱(甚至為0)的現象,梯度被近距離梯度主導,導致模型難以學到遠距離的依賴關系。

改善措施:可以使用 ReLU 激活函數;門控RNN 如GRU、LSTM 以改善梯度消失

梯度爆炸:網絡層之間的梯度(值大于 1)重復相乘導致的指數級增長會產生梯度爆炸,導致模型無法有效學習。

改善措施:可以使用 梯度截斷;引導信息流的正則化;ReLU 激活函數;門控RNN 如GRU、LSTM(和普通 RNN 相比多經過了很多次導數都小于 1激活函數,因此 LSTM 發生梯度爆炸的頻率要低得多)以改善梯度爆炸。

所以,如果我們能讓 RNN 在接受上一時刻的狀態和當前時刻的輸入時,有選擇地記憶和遺忘一部分內容(或者說信息),問題就可以解決了。比如上上句話提及”我去考試了“,然后后面提及”我考試通過了“,那么在此之前說的”我去考試了“的內容就沒那么重要,選擇性地遺忘就好了。這也就是長短期記憶網絡(Long Short-Term Memory, LSTM)的基本思想。

二、LSTM原理

LSTM是種特殊RNN網絡,在RNN的基礎上引入了“門控”的選擇性機制,分別是遺忘門、輸入門和輸出門,從而有選擇性地保留或刪除信息,以能夠較好地學習長期依賴關系。如下圖RNN(上) 對比 LSTM(下):

2.1 LSTM的核心

在RNN基礎上引入門控后的LSTM,結構看起來好復雜!但其實LSTM作為一種反饋神經網絡,核心還是歷史的隱藏狀態信息的反饋,也就是下圖的Ct:

對標RNN的ht隱藏狀態的更新,LSTM的Ct只是多個些“門控”刪除或添加信息到狀態信息。由下面依次介紹LSTM的“門控”:遺忘門,輸入門,輸出門的功能,LSTM的原理也就好理解了。

2.2 遺忘門

LSTM 的第一步是通過”遺忘門”從上個時間點的狀態Ct-1中丟棄哪些信息。

具體來說,輸入Ct-1,會先根據上一個時間點的輸出ht-1和當前時間點的輸入xt,并通過sigmoid激活函數的輸出結果ft來確定要讓Ct-1,來忘記多少,sigmoid后等于1表示要保存多一些Ct-1的比重,等于0表示完全忘記之前的Ct-1。

2.3 輸入門

下一步是通過輸入門,決定我們將在狀態中存儲哪些新信息。

我們根據上一個時間點的輸出ht-1和當前時間點的輸入xt 生成兩部分信息i t 及C~t,通過sigmoid輸出i t,用tanh輸出C~t。之后通過把i t 及C~t兩個部分相乘,共同決定在狀態中存儲哪些新信息。

在輸入門 + 遺忘門控制下,當前時間點狀態信息Ct為:

2.4 輸出門

最后,我們根據上一個時間點的輸出ht-1和當前時間點的輸入xt 通過sigmid 輸出Ot,再根據Ot 與 tanh控制的當前時間點狀態信息Ct 相乘作為最終的輸出。

綜上,一張圖可以說清LSTM原理:

三、LSTM簡單寫詩

本節項目利用深層LSTM模型,學習大小為10M的詩歌數據集,自動可以生成詩歌。

如下代碼構建LSTM模型。

## 本項目完整代碼:github.com/aialgorithm/Blog
# 或“算法進階”公眾號文末閱讀原文可見

model = tf.keras.Sequential([
# 不定長度的輸入
tf.keras.layers.Input((None,)),
# 詞嵌入層
tf.keras.layers.Embedding(input_dim=tokenizer.vocab_size, output_dim=128),
# 第一個LSTM層,返回序列作為下一層的輸入
tf.keras.layers.LSTM(128, dropout=0.5, return_sequences=True),
# 第二個LSTM層,返回序列作為下一層的輸入
tf.keras.layers.LSTM(128, dropout=0.5, return_sequences=True),
# 對每一個時間點的輸出都做softmax,預測下一個詞的概率
tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(tokenizer.vocab_size, activation='softmax')),
])

# 查看模型結構
model.summary()
# 配置優化器和損失函數
model.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.categorical_crossentropy)

模型訓練,考慮訓練時長,就簡單訓練2個epoch。

class Evaluate(tf.keras.callbacks.Callback):
"""
訓練過程評估,在每個epoch訓練完成后,保留最優權重,并隨機生成SHOW_NUM首古詩展示
"""

def __init__(self):
super().__init__()
# 給loss賦一個較大的初始值
self.lowest = 1e10

def on_epoch_end(self, epoch, logs=None):
# 在每個epoch訓練完成后調用
# 如果當前loss更低,就保存當前模型參數
if logs['loss'] <= self.lowest:
self.lowest = logs['loss']
model.save(BEST_MODEL_PATH)
# 隨機生成幾首古體詩測試,查看訓練效果
print("cun'h")
for i in range(SHOW_NUM):
print(generate_acrostic(tokenizer, model, head="春花秋月"))

# 創建數據集
data_generator = PoetryDataGenerator(poetry, random=True)
# 開始訓練
model.fit_generator(data_generator.for_fit(), steps_per_epoch=data_generator.steps, epochs=TRAIN_EPOCHS,
callbacks=[Evaluate()])

加載簡單訓練的LSTM模型,輸入關鍵字(如:算法進階)后,自動生成藏頭詩。可以看出詩句粗略看上去挺優雅,但實際上經不起推敲。后面增加訓練的epoch及數據集應該可以更好些。

# 加載訓練好的模型
model = tf.keras.models.load_model(BEST_MODEL_PATH)

keywords = input('輸入關鍵字:\n')

# 生成藏頭詩
for i in range(SHOW_NUM):
print(generate_acrostic(tokenizer, model, head=keywords),'\n')

參考資料:https://colah.github.io/posts/2015-08-Understanding-LSTMs/ https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21 https://www.zhihu.com/question/34878706

文章轉自微信公眾號@算法進階

上一篇:

神經網絡學習到的是什么?(Python)

下一篇:

時序預測的深度學習算法介紹
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費