rnn - cccbook/py2gpt GitHub Wiki
RNN 循環神經網路
學過《數位電路/數位邏輯》的人,應該還記得《循序電路 (Sequential Logic) / 組合電路(Combinatorial Logic)》 這樣的區分。
其中的循序電路就是具有循環的電路,有了循環之後,我們就可以做出 Latch 去記憶一個位元。

但是沒有循環的《組合電路》,是沒有記憶的,因此只要輸入相同,輸出必然相同。(例如加法器,同樣的 a,b 必然會輸出同樣的 a+b)
傳統的神經網路模型,像是 MLP / CNN 等,就像《組合電路》一樣,對相同的輸入,會有相同的輸出,而不會記住你前面到底輸入了些甚麼?
而循環神經網路 RNN,就像《循序電路》一樣,會在《內部狀態》記住你之前輸入了甚麼,於是即使有同樣的輸入,未必有同樣的輸出,因為《內部狀態》的記憶可能不同。
RNN (Recurrent Neural Network) 循環神經網路透過加入循環,讓 RNN 可以記住過去的資訊在隱藏層 h 中 (如下圖左半部)

這種有循環的隱藏層,會有記憶效應,根據不同的內部狀態,就會有不同的輸出,即使輸入相同,輸出也有可能不同。
如果我們用 PyTorch 實作一個 RNN 循環神經網路,用來預測文章中的下一個詞,那麼就可以採用下列程式來實作。
class RNNLM(nn.Module):
def __init__(self, method, vocab_size, embed_size, hidden_size, num_layers):
super(RNNLM, self).__init__()
method = method.upper()
self.embed = nn.Embedding(vocab_size, embed_size)
self.rnn = nn.RNN(embed_size, hidden_size, num_layers, batch_first=True) # RNN 也可以改為 GRU
self.linear = nn.Linear(hidden_size, vocab_size)
def forward(self, x, h):
# Embed word ids to vectors
x = self.embed(x)
# Forward propagate
out, h = self.rnn(x, h)
# Reshape output to (batch_size*seq_length, hidden_size)
out = out.reshape(out.size(0)*out.size(1), out.size(2))
# Decode hidden states of all time steps
out = self.linear(out)
return out, h
上述程式中的 h 就是隱藏層的狀態 ...
RNN 神經網路出現後,很多人拿來訓練語言模型,讓 RNN 學習如何產生一篇文章。(通常是像文字接龍一樣,如果你先給定幾句話,RNN 就會開始接龍)
MinGPT / MicroGrad 的作者 Karpathy 曾經寫過下列文章,展示了 RNN 的神奇效用
Karpathy 用 RNN 做了一些實驗,發現若讓 RNN 學《莎士比亞小說》,然後 RNN 寫出來就會很像《莎士比亞小說》,同樣的,學 LaTex 論文後,就會寫出看來很漂亮的論文,學 Linux 程式碼之後,RNN 就會寫很漂亮的 C 語言了。
但是 RNN 的記憶,常常衰退的很快,因此後來發展出了像 LSTM/GRU 等 RNN 的變形,於是 RNN 的記憶就變得更好了。