pytorch學習體會(三)NLP詞袋
邏輯回歸的詞袋分類器
當然這個例子不是我寫的,我在學習過程中看到這篇文章http://nbviewer.jupyter.org/github/rguthrie3/DeepLearningForNLPInPytorch/blob/master/Deep%20Learning%20for%20Natural%20Language%20Processing%20with%20Pytorch.ipynb
尊重版權,尊重作者的努力,我僅僅是翻譯一下,加入自己的部分理解,不妥之處請留言。
這部分又做什麼,作者寫例子的時候很明確,就是根據給定的單詞或詞語判斷其是哪個語種的單詞,這個有什麼用?翻譯啊,你連分析的文字都不知道是什麼語種你怎麼翻譯,不知道語種你怎麼做合適的自然語言處理,當然你會有疑問,這個現在都是爛大街的東西,還要神經網路,僅僅是個演示,過去我么寫程序是處理業務邏輯,主要目的是把業務邏輯運轉過程中數據記錄和存儲下來,我們現在機器學習和深度學習的主要任務是從一堆數據中找規律,扯遠了,回到詞袋的例子
詞袋模型是什麼?它本質上就是把我們的每個句子映射為一個詞袋向量。每個向量都是等長的,假設我們有包括n個單詞的單詞表,那麼我們每個詞袋向量的長度就是n。
舉個例子來說,假設我們的整個單詞表只有兩個詞「hello」和「world」,那麼
語句「hello hello hello hello」的詞袋向量就是:[4, 0]。
語句「hello world hello world」的詞袋向量是[2,2]。
總結來說,對於我們這個單詞表只有「hello」,「world」這兩個單詞的詞袋模型,所有語句的詞袋向量可以表示為:[Count(hello),Count(world)]
以此類推,更大的單詞表,更長的詞袋向量也是用同樣的方法來計算。對於我們馬上要搭建的神經網路來說,把將要輸入的詞袋變數設為x,那麼神經網路的輸出為:
log Softmax(Ax+b)
其代表的意義就是:輸入的數據會首先經過仿射映射運算,然後再進行log Softmax運算,最後輸出。
原例子給出的數據,我也就不修改了
data = [ ("me gusta comer en la cafeteria".split(), "SPANISH"),
("Give it to me".split(), "ENGLISH"),("No creo que sea una buena idea".split(), "SPANISH"),
("No it is not a good idea to get lost at sea".split(), "ENGLISH") ]test_data = [ ("Yo creo que si".split(), "SPANISH"), ("it is lost on me".split(), "ENGLISH")]# word_to_ix 將單詞表中的每個單詞映射成一個唯一的整數,就是建立一個單詞和索引的對應關係,構建各個詞在辭彙表中的索引位置。word_to_ix = {}for sent, _ in data + test_data: for word in sent: if word not in word_to_ix: word_to_ix[word] = len(word_to_ix)print(word_to_ix)
VOCAB_SIZE = len(word_to_ix)NUM_LABELS = 2{me: 0, gusta: 1, comer: 2, en: 3, la: 4, cafeteria: 5, Give: 6, it: 7, to: 8, No: 9, creo: 10, que: 11, sea: 12, una: 13, buena: 14, idea: 15, is: 16, not: 17, a: 18, good: 19, get: 20, lost: 21, at: 22, Yo: 23, si: 24, on: 25}
class BoWClassifier(nn.Module): #使用Pytorch定義神經網路要從nn.Moudule繼承
def __init__(self, num_labels, vocab_size): #初始化神經網路,我當初在這裡迷惑過,可能是因為我們系統學習過神經網路理論的原因, #num_labels做什麼的?網路訓練過程中;輸入數據可能的輸出種類 #vocab_size可能的輸入輸入輸入維度,super(BoWClassifier, self).__init__()
#簡單一句話,就是我現在搭一個線性的轉換單元來,輸入是vocab_size大小的數據,會輸出這個數據可能的num_labels分類 #記住這裡使用了SoftMax,嘿嘿,輸出的會是一個向量在各個分量的概率,也就是各個分類的概率。 self.linear = nn.Linear(vocab_size, num_labels) def forward(self, bow_vec): #輸入的數據為bow_vec,就是一個句子或者是一段話所有的詞用辭彙表的表示的向量統計,每個詞出現了多少次的向量。return F.log_softmax(self.linear(bow_vec),dim=1)
def make_bow_vector(sentence, word_to_ix):
#把每個句子轉換成詞袋向量,也就是句子入袋
vec = torch.zeros(len(word_to_ix)) for word in sentence: vec[word_to_ix[word]] += 1 return vec.view(1, -1)def make_target(label, label_to_ix):#給出目標分類,本例是英語還是西班牙語
return torch.LongTensor([label_to_ix[label]])model = BoWClassifier(NUM_LABELS, VOCAB_SIZE)
#建立模型,也就是隨便搭一個神經網路的空架子,係數矩陣A和偏置b都是隨機確定,這個時候的神經網路模型不具備任何的預測能力#通過調用__init函數,建立一個可以處理長度VOCAB_SIZE的詞袋的句子,進過線性變換和分類後確定是那種語言的概率高點for param in model.parameters(): #為了更好的理解,我可以列印這個模型的參數 第一個是係數矩陣A,第二個是偏置b,都是初始化的時候隨機確定的。 print(param)Parameter containing:
Columns 0 to 9
-0.0456 0.0742 0.0238 -0.1171 0.1426 0.1221 0.0429 -0.1775 0.0922 0.1303
0.0831 0.0734 -0.1721 0.1112 0.1503 0.1489 0.1107 -0.0308 0.1314 0.1535
Columns 10 to 19
0.0546 -0.0758 0.0132 -0.0753 0.1846 0.1894 -0.0229 -0.1319 0.1154 0.1001
0.1022 -0.1411 -0.0684 0.1554 0.1495 0.1251 -0.0820 -0.0388 -0.1461 -0.1118
Columns 20 to 25
0.1040 -0.1476 0.0665 -0.0837 -0.1724 -0.1369
0.1505 -0.1610 -0.0485 0.0416 -0.1177 0.0457
[torch.FloatTensor of size 2x26]
Parameter containing:
1.00000e-02 *
-3.1527
7.8431
[torch.FloatTensor of size 2]
sample = data[0] #從數據集集中取出第一條數據。
bow_vector = make_bow_vector(sample[0], word_to_ix)#變換成詞袋向量,也就是統計這個這個句子中各個出現的次數log_probs = model(autograd.Variable(bow_vector))#使用這個模型預測下print(log_probs)#列印出來,發覺好像不對啊,不對哦,結論是英語其實西班牙語,正如上面描述的,這個時候模型的係數是#是隨機確定的,現在這個時候的模型什麼都預測不出來。可能你初試化的時候會正好契合結果,但記住了,#那僅僅是瞎貓碰到死耗子了,怎麼辦,使用數據訓練網路,讓其預測能力增強Variable containing:
-0.8570 -0.5524
[torch.FloatTensor of size 1x2]
label_to_ix = { "SPANISH": 0, "ENGLISH": 1 } #只有兩個分類,西班牙語和英語
for instance, label in test_data:
bow_vec = autograd.Variable(make_bow_vector(instance, word_to_ix)) log_probs = model(bow_vec) print (log_probs)#我就不相信,對每條數據,我都試試看看對不對,一測試,拔涼拔涼的,怎麼都是一個結論,# 顯然初試模型不合適,怎麼辦?訓練print(next(model.parameters())[:,word_to_ix["creo"]])Variable containing:
-0.8386 -0.5662
[torch.FloatTensor of size 1x2]
Variable containing:
-0.9713 -0.4758
[torch.FloatTensor of size 1x2]
Variable containing:
0.0546
0.1022
[torch.FloatTensor of size 2]
loss_function = nn.NLLLoss()
#選擇損失函數,具體函數說明見 pytorch學習體會二optimizer = optim.SGD(model.parameters(), lr=0.1)#選擇優化函數,具體說明見pytorch學習體會二#下面就是訓練,也就是那和數據反覆跑多次,我們這裡跑100次,每次都根據預測結果和實際值分類不同的差值優化模型參數。for epoch in range(100): for instance, label in data: #因為pytorch的梯度是累積的,每次訓練前要幹嘛?清除上次梯度的餘孽,嘿嘿。 model.zero_grad() #句子中所有的詞語入袋, bow_vec = autograd.Variable(make_bow_vector(instance, word_to_ix)) #target是這個句子的真是分類 target = autograd.Variable(make_target(label, label_to_ix)) # 使用模型做個預測是什麼分類 log_probs = model(bow_vec) #求出兩者之間的差 loss = loss_function(log_probs, target) #反向求導 loss.backward() #優化參數矩陣A和偏置B optimizer.step()#使用測試數據對模型進行測試,嘿嘿,預測的好多了,和真實的語種符合
for instance, label in test_data: bow_vec = autograd.Variable(make_bow_vector(instance, word_to_ix)) log_probs = model(bow_vec) print(log_probs)print (next(model.parameters())[:,word_to_ix["creo"]] )Variable containing:
-0.1181 -2.1948
[torch.FloatTensor of size 1x2]
Variable containing:
-3.3590 -0.0354
[torch.FloatTensor of size 1x2]
Variable containing:
0.5657
-0.4088
[torch.FloatTensor of size 2]
源代碼見https://github.com/oliverwy/pytorchex/blob/master/nlpex.ipynb
推薦閱讀:
※【Python3網路爬蟲開發實戰】1.8.3-Scrapy-Splash的安裝
※廢話少說:Python 這麼牛逼的 6 個原因是?
※來編寫你的 setup 腳本(二)
※為什麼關於Python的UI框架 kivy ,在中國無人問津,而且相關的書籍很少?
※如何寫python2和3兼容代碼?