PyTorch專欄(十九):序列模型和長短句記憶(LSTM)模型 | 文末開獎

2021-03-02 磐創AI

作者 | News

編輯 | 奇予紀

出品 | 磐創AI團隊出品

【磐創AI 導讀】:查看關於本專欄歷史文章,請點擊文末[閱讀全文]。查看本章歷史文章,請點擊下方藍色字體進入相應連結閱讀。

專欄目錄:

之前我們已經學過了許多的前饋網絡。所謂前饋網絡, 就是網絡中不會保存狀態。然而有時這並不是我們想要的效果。在自然語言處理(NLP, Natural Language Processing) 中, 序列模型是一個核心的概念。所謂序列模型, 即輸入依賴於時間信息的模型。一個典型的序列模型是隱馬爾科夫模型 (HMM, Hidden Markov Model)。另一個序列模型的例子是條件隨機場 (CRF, Conditional Random Field)。循環神經網絡是指可以保存某種狀態的神經網絡。比如說, 神經網絡中上個時刻的輸出可以作為下個 時刻的輸入的一部分, 以此信息就可以通過序列在網絡中一直往後傳遞。對於LSTM (Long-Short Term Memory) 來說, 序列中的每個元素都有一個相應的隱狀態,該隱狀態原則上可以包含序列當前結點之前的任一節點的信息。我們可以使用隱藏狀態來預測語言模型中的單詞, 詞性標籤以及其他。1.Pytorch中的LSTM

在正式學習之前,有幾個點要說明一下,Pytorch中 LSTM 的輸入形式是一個 3D 的Tensor,每一個維度都有重要的意義,第一個維度就是序列本身,第二個維度是mini-batch中實例的索引,第三個維度是輸入元素的索引,我們之前沒有接觸過mini-batch,所以我們就先忽略它並假設第二維的維度是1。如果要用」The cow jumped」這個句子來運行一個序列模型,那麼就應該把它整理成如下的形式:

除了有一個額外的大小為1的第二維度。

此外, 你還可以向網絡逐個輸入序列, 在這種情況下, 第一個軸的大小也是1。

來看一個簡單的例子。

# Author: Robert Guthrie

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

torch.manual_seed(1)

lstm = nn.LSTM(3, 3) # 輸入維度為3維,輸出維度為3維

inputs = [torch.randn(1, 3) for _ in range(5)] # 生成一個長度為5的序列

# 初始化隱藏狀態.

hidden = (torch.randn(1, 1, 3),

torch.randn(1, 1, 3))

for i in inputs:

# 將序列中的元素逐個輸入到LSTM.

# 經過每步操作,hidden 的值包含了隱藏狀態的信息.

out, hidden = lstm(i.view(1, 1, -1), hidden)

# 另外我們可以對一整個序列進行訓練.

# LSTM第一個返回的第一個值是所有時刻的隱藏狀態

# 第二個返回值是最後一個時刻的隱藏狀態

#(所以"out"的最後一個和"hidden"是一樣的)

# 之所以這樣設計:

# 通過"out"你能取得任何一個時刻的隱藏狀態,而"hidden"的值是用來進行序列的反向傳播運算, 具體方式就是將它作為參數傳入後面的 LSTM 網絡.

# 增加額外的第二個維度.

inputs = torch.cat(inputs).view(len(inputs), 1, -1)

hidden = (torch.randn(1, 1, 3), torch.randn(1, 1, 3)) # 清空隱藏狀態.

out, hidden = lstm(inputs, hidden)

print(out)

print(hidden)

tensor([[[-0.0187, 0.1713, -0.2944]],

[[-0.3521, 0.1026, -0.2971]],

[[-0.3191, 0.0781, -0.1957]],

[[-0.1634, 0.0941, -0.1637]],

[[-0.3368, 0.0959, -0.0538]]], grad_fn=<StackBackward>)

(tensor([[[-0.3368, 0.0959, -0.0538]]], grad_fn=<StackBackward>), tensor([[[-0.9825, 0.4715, -0.0633]]], grad_fn=<StackBackward>))

2.例子:用LSTM來進行詞性標註

在這部分, 我們將會使用一個 LSTM 網絡來進行詞性標註。在這裡我們不會用到維特比算法, 前向-後向算法或者任何類似的算法,而是將這部分內容作為一個 (有挑戰) 的練習留給讀者, 希望讀者在了解了這部分的內容後能夠實現如何將維特比算法應用到 LSTM 網絡中來。

該模型如下:輸入的句子是,其中,標籤的集合定義為 T,為單詞的標籤,用表示對單詞詞性的預測。這是一個結構預測模型, 我們的輸出是一個序列, 其中。在進行預測時, 需將句子每個詞輸入到一個 LSTM 網絡中。將時刻 i 的隱藏狀態標記為,同樣地, 對每個標籤賦一個獨一無二的索引 (類似 word embeddings 部分 word_to_ix 的設置). 然後就得到了的預測規則:即先對隱狀態進行一個仿射變換, 然後計算一個對數 softmax, 最後得到的預測標籤即為對數 softmax 中最大的值對應的標籤. 注意, 這也意味著 A 空間的維度是|T|。2.1 準備數據

def prepare_sequence(seq, to_ix):

idxs = [to_ix[w] for w in seq]

return torch.tensor(idxs, dtype=torch.long)

training_data = [

("The dog ate the apple".split(), ["DET", "NN", "V", "DET", "NN"]),

("Everybody read that book".split(), ["NN", "V", "DET", "NN"])

]

word_to_ix = {}

for sent, tags in training_data:

for word in sent:

if word not in word_to_ix:

word_to_ix[word] = len(word_to_ix)

print(word_to_ix)

tag_to_ix = {"DET": 0, "NN": 1, "V": 2}

# 實際中通常使用更大的維度如32維, 64維.

# 這裡我們使用小的維度, 為了方便查看訓練過程中權重的變化.

EMBEDDING_DIM = 6

HIDDEN_DIM = 6

{'The': 0, 'dog': 1, 'ate': 2, 'the': 3, 'apple': 4, 'Everybody': 5, 'read': 6, 'that': 7, 'book': 8}

2.2 創建模型

class LSTMTagger(nn.Module):

def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size):

super(LSTMTagger, self).__init__()

self.hidden_dim = hidden_dim

self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)

# LSTM以word_embeddings作為輸入, 輸出維度為 hidden_dim 的隱藏狀態值

self.lstm = nn.LSTM(embedding_dim, hidden_dim)

# 線性層將隱藏狀態空間映射到標註空間

self.hidden2tag = nn.Linear(hidden_dim, tagset_size)

self.hidden = self.init_hidden()

def init_hidden(self):

# 一開始並沒有隱藏狀態所以我們要先初始化一個

# 關於維度為什麼這麼設計請參考Pytoch相關文檔

# 各個維度的含義是 (num_layers, minibatch_size, hidden_dim)

return (torch.zeros(1, 1, self.hidden_dim),

torch.zeros(1, 1, self.hidden_dim))

def forward(self, sentence):

embeds = self.word_embeddings(sentence)

lstm_out, self.hidden = self.lstm(

embeds.view(len(sentence), 1, -1), self.hidden)

tag_space = self.hidden2tag(lstm_out.view(len(sentence), -1))

tag_scores = F.log_softmax(tag_space, dim=1)

return tag_scores

2.3 訓練模型

model = LSTMTagger(EMBEDDING_DIM, HIDDEN_DIM, len(word_to_ix), len(tag_to_ix))

loss_function = nn.NLLLoss()

optimizer = optim.SGD(model.parameters(), lr=0.1)

# 查看訓練前的分數

# 注意: 輸出的 i,j 元素的值表示單詞 i 的 j 標籤的得分

# 這裡我們不需要訓練不需要求導,所以使用torch.no_grad()

with torch.no_grad():

inputs = prepare_sequence(training_data[0][0], word_to_ix)

tag_scores = model(inputs)

print(tag_scores)

for epoch in range(300): # 實際情況下你不會訓練300個周期, 此例中我們只是隨便設了一個值

for sentence, tags in training_data:

# 第一步: 請記住Pytorch會累加梯度.

# 我們需要在訓練每個實例前清空梯度

model.zero_grad()

# 此外還需要清空 LSTM 的隱狀態,

# 將其從上個實例的歷史中分離出來.

model.hidden = model.init_hidden()

# 準備網絡輸入, 將其變為詞索引的 Tensor 類型數據

sentence_in = prepare_sequence(sentence, word_to_ix)

targets = prepare_sequence(tags, tag_to_ix)

# 第三步: 前向傳播.

tag_scores = model(sentence_in)

# 第四步: 計算損失和梯度值, 通過調用 optimizer.step() 來更新梯度

loss = loss_function(tag_scores, targets)

loss.backward()

optimizer.step()

# 查看訓練後的得分

with torch.no_grad():

inputs = prepare_sequence(training_data[0][0], word_to_ix)

tag_scores = model(inputs)

# 句子是 "the dog ate the apple", i,j 表示對於單詞 i, 標籤 j 的得分.

# 我們採用得分最高的標籤作為預測的標籤. 從下面的輸出我們可以看到, 預測得

# 到的結果是0 1 2 0 1. 因為 索引是從0開始的, 因此第一個值0表示第一行的

# 最大值, 第二個值1表示第二行的最大值, 以此類推. 所以最後的結果是 DET

# NOUN VERB DET NOUN, 整個序列都是正確的!

print(tag_scores)

tensor([[-1.1389, -1.2024, -0.9693],

[-1.1065, -1.2200, -0.9834],

[-1.1286, -1.2093, -0.9726],

[-1.1190, -1.1960, -0.9916],

[-1.0137, -1.2642, -1.0366]])

tensor([[-0.0858, -2.9355, -3.5374],

[-5.2313, -0.0234, -4.0314],

[-3.9098, -4.1279, -0.0368],

[-0.0187, -4.7809, -4.5960],

[-5.8170, -0.0183, -4.1879]])

3.練習:使用字符級特徵來增強 LSTM 詞性標註器在上面的例子中, 每個詞都有一個詞嵌入, 作為序列模型的輸入. 接下來讓我們使用每個的單詞的 字符級別的表達來增強詞嵌入。我們期望這個操作對結果能有顯著提升, 因為像詞綴這樣的字符級信息對於詞性有很大的影響。比如說, 像包含詞綴 -ly 的單詞基本上都是被標註為副詞。具體操作如下:用的字符級表達, 同之前一樣,我們使用來表示詞嵌入。序列模型的輸入就變成了的拼接。因此, 如果的維度是5, 的維度是3,那麼我們的 LSTM 網絡的輸入維度大小就是8。為了得到字符級別的表達, 將單詞的每個字符輸入一個 LSTM 網絡, 而則為這個 LSTM 網絡最後的隱狀態。一些提示:新模型中需要兩個 LSTM, 一個跟之前一樣, 用來輸出詞性標註的得分, 另外一個新增加的用來獲取每個單詞的字符級別表達。為了在字符級別上運行序列模型,你需要用嵌入的字符來作為字符 LSTM 的輸入。
為了鼓勵大家踴躍在文章留言區分享自己的看法,磐創AI推出了「留言送書」活動~在本文文末留言即可參與活動,留言內容需為主題相關。歡迎大家在日常推文中留言,以後將不定期推出「留言送書」活動。恭喜上期留言讀者9527,獲贈書籍一本。請 9527 老鐵聯繫小編:cellerai

長按掃碼,關注我們

相關焦點

  • 時間序列的LSTM模型預測——基於Keras
    一、問題背景    現實生活中,在一系列時間點上觀測數據是司空見慣的活動,在農業、商業、氣象軍事和醫療等研究領域都包含大量的時間序列數據。時間序列的預測指的是基於序列的歷史數據,以及可能對結果產生影響的其他相關序列,對序列未來的可能取值做出預測。
  • pytorch入門-使用PyTorch進行LSTM時間序列預測
    本節將介紹另一種常用的門控循環神經網絡:長短期記憶(long short-term memory,LSTM)。它 比門控循環單元的結構稍微複雜一點。接下來,我們將數據集分為訓練集和測試集。LSTM算法將在訓練集上進行訓練。然後將使用該模型對測試集進行預測。將預測結果與測試集中的實際值進行比較,以評估訓練後模型的性能。前132條記錄將用於訓練模型,後12條記錄將用作測試集。以下腳本將數據分為訓練集和測試集。
  • LSTM模型結構的可視化
    1、傳統的BP網絡和CNN網絡2、LSTM網絡3、LSTM的輸入結構4、pytorch中的LSTM4.1 pytorch中定義的LSTM模型4.2 餵給LSTM的數據格式4.3 LSTM的output格式5、LSTM和其他網絡組合BP網絡和CNN網絡沒有時間維,和傳統的機器學習算法理解起來相差無幾,CNN
  • PyTorch Bi-LSTM+CRF NER標註代碼精讀
    https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html#bi-lstm-conditional-random-field-discussion然後,要搞清楚為什麼要用它而不是其它序列模型,如LSTM、Bi-LSTM。
  • 使用LSTM深度學習模型進行溫度的時間序列單步和多步預測
    本文的目的是提供代碼示例,並解釋使用python和TensorFlow建模時間序列數據的思路。本文展示了如何進行多步預測並在模型中使用多個特徵。本文的簡單版本是,使用過去48小時的數據和對未來1小時的預測(一步),我獲得了溫度誤差的平均絕對誤差0.48(中值0.34)度。
  • 序列模型簡介:RNN, 雙向RNN, LSTM, GRU,有圖有真相
    ,為什麼還需要序列模型呢?介紹:我們為什麼需要序列模型?既然我們已經有了前饋網絡和CNN,為什麼還需要序列模型呢?這些模型的問題在於,當給的數據是序列數據時,它們的性能很差。序列數據的一個例子是一個音頻,其中包含一系列口語單詞,另一個例子是英語中包含一系列單詞的句子。
  • PyTorch:Bi-LSTM的文本生成
    我們可以認為「建模自然語言」是指對構成語言的語義和語法進行推理,本質上是這樣,但它更進一步。目前,自然語言處理(NLP)領域通過不同的方法和技術處理不同的任務,即對語言進行推理、理解和建模。自然語言處理(NLP)領域在過去的十年裡發展非常迅速。許多模型都從不同的角度提出了解決不同NLP任務的方法。同樣,最受歡迎的模型中的共同點是實施基於深度學習的模型。
  • 【重溫序列模型】再回首DeepLearning遇見了LSTM和GRU
    寫在前面學習時空序列, 會需要很多序列模型的相關知識,所以借著這次機會想重新學習一下深度學習裡面的序列模型模塊,並做一個知識的梳理,主要會包括RNN, LSTM和GRU, seq2seq, embedding和Attention。
  • 【乾貨】基於pytorch的CNN、LSTM神經網絡模型調參小結
    這是最近兩個月來的一個小總結,實現的demo已經上傳github,裡面包含了CNN、LSTM、BiLSTM、GRU以及CNN與LSTM、BiLSTM的結合還有多層多通道CNN、LSTM、BiLSTM等多個神經網絡模型的的實現
  • 【NER】NLP-入門實體命名識別(NER)+Bilstm-CRF模型原理Pytorch代碼詳解——最全攻略
    希望能夠以這篇文章為載體,幫助其他跟我一樣的學習者梳理、串起NER的各個小知識點,最後上手NER的主流模型(Bilstm+CRF)(文中講的是pytorch,但是懂了pytorch去看keras十分容易相信我哈)全文結構:一、NER資料(主要介紹NER)二、主流模型Bilstm-CRF實現詳解(Pytorch篇)三、實現代碼的拓展(在第二點的基礎上進行拓展
  • 常見的時序模型:RNN/LSTM/GRU
    Ian Googfellow Deep Learning可見,只有前面序列更新完成,才能更新之後的序列,也就是說,RNN在更新時,是串行的。梯度反向傳播BPTT過程:U、V、W、b參數的梯度更新都需要後續的序列的梯度傳播,而且是包含後續梯度的連乘項。RNN步驟之間共享參數,最終的輸出包含參數比如W的n次冪。當序列很長時,如果W的特徵值大於1,會使數值很大;如果小於1,最終輸出很小。而這些又會影響到反向傳播的梯度大小,可能出現梯度爆炸(很大)或梯度消失(很小)的情況。
  • NLP-入門實體命名識別(NER)+Bilstm-CRF模型原理Pytorch代碼詳解——最全攻略
    希望能夠以這篇文章為載體,幫助其他跟我一樣的學習者梳理、串起NER的各個小知識點,最後上手NER的主流模型(Bilstm+CRF)(文中講的是pytorch,但是懂了pytorch去看keras十分容易相信我哈)二、主流模型Bilstm-CRF實現詳解(Pytorch篇)一、NER資料參考:NLP之CRF應用篇(序列標註任務)(CRF++的詳細解析、Bi-LSTM+CRF
  • 【深度學習】PyTorch:Bi-LSTM的文本生成
    許多模型都從不同的角度提出了解決不同NLP任務的方法。同樣,最受歡迎的模型中的共同點是實施基於深度學習的模型。如前所述,NLP領域解決了大量的問題,特別是在本博客中,我們將通過使用基於深度學習的模型來解決文本生成問題,例如循環神經網絡LSTM和Bi-LSTM。
  • 時間序列深度學習:狀態 LSTM 模型預測太陽黑子(一)
    隨著這些 ML/DL 工具的發展,企業和金融機構現在可以通過應用這些新技術來解決舊問題,從而更好地進行預測。在本文中,我們展示了使用稱為 LSTM(長短期記憶)的特殊類型深度學習模型,該模型對涉及自相關性的序列預測問題很有用。我們分析了一個名為「太陽黑子」的著名歷史數據集(太陽黑子是指太陽表面形成黑點的太陽現象)。
  • python在Keras中使用LSTM解決序列問題
    p=8461時間序列預測是指我們必須根據時間相關的輸入來預測結果的問題類型。時間序列數據的典型示例是股市數據,其中股價隨時間變化。 遞歸神經網絡(RNN)已被證明可以有效解決序列問題。特別地,作為RNN的變體的長期短期記憶網絡(LSTM)當前正在各種領域中用於解決序列問題。序列問題的類型序列問題可以大致分為以下幾類:一對一:其中有一個輸入和一個輸出。
  • 序列模型簡介——RNN, Bidirectional RNN, LSTM, GRU
    既然我們已經有了前饋網絡和CNN,為什麼我們還需要序列模型呢?這些模型的問題在於,當給定一系列的數據時,它們表現的性能很差。序列數據的一個例子是音頻的剪輯,其中包含一系列的人說過的話。另一個例子是英文句子,它包含一系列的單詞。前饋網絡和CNN採用一個固定長度作為輸入,但是,當你看這些句子的時候,並非所有的句子都有相同的長度。
  • 一個Seq2seq模型的Pytorch實現庫
    機器學習算法與自然語言處理出品@公眾號原創專欄作者 憶臻
  • 使用PyTorch建立你的第一個文本分類模型
    處理詞彙表外單詞 處理可變長度序列 包裝器和預訓練模型理解問題實現文本分類為什麼使用PyTorch進行文本分類?在深入研究技術概念之前,讓我們先快速熟悉一下將要使用的框架——PyTorch。PyTorch的基本單位是張量,類似於python中的「numpy」數組。
  • Pytorch實現LSTM時間序列預測
    但是普通的RNN對於長期依賴問題效果比較差,當序列本身比較長時,由於神經網絡模型的訓練是採用backward進行,在梯度鏈式法則中容易出現梯度消失和梯度爆炸的問題,需要進一步改進RNN的模型結構。
  • 獨家 :教你用Pytorch建立你的第一個文本分類模型!
    現在得益於深度學習框架,比如說PyTorch,Keras和 TensorFlow,實現先進的架構已經變得更簡單了。這些深度學習框架提供了一種實現複雜模型架構和算法的簡單方式,不需要你掌握大量的專業知識和編程技能。總結來說,這是數據科學的金礦。在本文中,我們將使用PyTorch框架,它以其快速的計算能力而聞名。因此,在本文中,我們將介紹解決文本分類問題的關鍵點。