標籤:

pytorch學習體會(三)NLP詞袋

邏輯回歸的詞袋分類器

當然這個例子不是我寫的,我在學習過程中看到這篇文章nbviewer.jupyter.org/gi

尊重版權,尊重作者的努力,我僅僅是翻譯一下,加入自己的部分理解,不妥之處請留言。

這部分又做什麼,作者寫例子的時候很明確,就是根據給定的單詞或詞語判斷其是哪個語種的單詞,這個有什麼用?翻譯啊,你連分析的文字都不知道是什麼語種你怎麼翻譯,不知道語種你怎麼做合適的自然語言處理,當然你會有疑問,這個現在都是爛大街的東西,還要神經網路,僅僅是個演示,過去我么寫程序是處理業務邏輯,主要目的是把業務邏輯運轉過程中數據記錄和存儲下來,我們現在機器學習和深度學習的主要任務是從一堆數據中找規律,扯遠了,回到詞袋的例子

詞袋模型是什麼?它本質上就是把我們的每個句子映射為一個詞袋向量。每個向量都是等長的,假設我們有包括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]

源代碼見github.com/oliverwy/pyt


推薦閱讀:

【Python3網路爬蟲開發實戰】1.8.3-Scrapy-Splash的安裝
廢話少說:Python 這麼牛逼的 6 個原因是?
來編寫你的 setup 腳本(二)
為什麼關於Python的UI框架 kivy ,在中國無人問津,而且相關的書籍很少?
如何寫python2和3兼容代碼?

TAG:Python | PyTorch |