pytorch深度學習和自然語言處理入門
之前也提過,pytorch之於tensorflow,優雅不是一星半點。
pytorch學習是輕鬆愉快了。本期文章寫pytorch在nlp上的應用。(paul allen的allennlp也由tensorflow遷移到了pytorch平台,可見一斑)
導入模塊:
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.optim as optim
torch.manual_seed(1)
一、線性模塊,這裡需要注意是y = xw+b。不是我們數學上習慣的y=wx+b(矩陣是不滿足乘法交換率的)
定義一個全連接層,也就是線性仿射變換。W=(5,3),b=(3)
lin = nn.Linear(5,3)
這裡需要特別注意,輸入變數是n*5,輸出為n*3
data = autograd.Variable(torch.randn(2,5))
lin(data)
運算得到結果如下:
Variable containing:-0.2889 0.3574 0.6554-0.9682 0.0289 0.4426[torch.FloatTensor of size 2x3]
二、非線性激活函數
常用的Relu和tanh。sigmoid因為梯度消失的問題,反而不常用。從理論上講,非線性的激活函數可以無窮多,為什麼選這兩個?這是工程上的問題,因為它們的導數形式便於計算。
我們用隨機正態分布,初始化2*2的矩陣。
data = autograd.Variable(torch.randn(2,2))
Variable containing:-0.6331 0.8795-0.6842 0.4533[torch.FloatTensor of size 2x2]
把變數經由relu計算(Rectified Linear Unit,修正線性單元),relu的公式很簡單=max(0,x),就是如果x>0,就取x,否則取0,就是把負的信號給屏蔽了。
F.relu(data)
Variable containing: 0.0000 0.8795 0.0000 0.4533[torch.FloatTensor of size 2x2]
下圖的藍線是relu
對比sigmoid類函數主要變化是:
1)單側抑制
2)相對寬闊的興奮邊界
3)稀疏激活性。
這與人的神經皮層的工作原理接近。
另外一個很重要的激活函數就是softmax。
data = autograd.Variable(torch.randn(2,2))
Variable containing:-0.3968 -0.6571-1.6428 0.9803[torch.FloatTensor of size 2x2]
F.softmax(data,dim=0),dim=0,按第0維softmax,就是概率化。這個函數在輸出層很有用,比如mnist要分成10類,那softmax就是這10類對應的概率。概率最大者就是對應的分類。(概率思維也在這裡體現了)
Variable containing: 0.7766 0.1628 0.2234 0.8372[torch.FloatTensor of size 2x2]
還有一個類似的函數F.log_softmax()也是工程上的考慮,因為最小二乘損失函數求導要會帶來計算量的問題,所以考慮交叉熵損失。與之配合的就是這個對數softmax。
三、目標函數。也就是反身傳播要優化的目標。也稱為成本函數或損失函數。
四,詞袋模型(Bag-Of-Words=BOW),應該算最簡單的語言模型,不考慮詞的位置,就是數數。比如辭彙表如果就兩個詞,hello,world。那麼"hello hello hello hello" = [4,0],"hello world hello world"=[2,2],即所謂語言模型,就是對一個字元串,或文章內容,如何進行編碼,轉為計算機和pytorch可以處理的向量或矩陣類型。這裡的數字就是表達詞的出現次數。
用這個最簡單的BOW,來對西班牙語和英語做分類。
先定義最簡單的訓練語料和測試語料。
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_2_idx = {}
for sent,_ in data + test_data:
print(sent)
for word in sent:
if word not in word_2_idx:
#這裡用的是這個word首次出現的位置,比如me就是第1個出現的,下標為0
word_2_idx[word] = len(word_2_idx)
有了辭彙表,就可以算辭彙表的長度,以及我們需要把句子分成兩類。
VOCAB_SIZE = len(word_2_idx)
NUM_LABELS = 2
神經網路模型:
class BoWClassifier(nn.Module): # 從nn.Module繼承bow分類器
def __init__(self, num_labels, vocab_size):
#父類初始化
super(BoWClassifier, self).__init__()
self.linear = nn.Linear(vocab_size, num_labels)
def forward(self, bow_vec):
#bow_vec是詞的bow向量
return F.log_softmax(self.linear(bow_vec))
把句子變成向量:
就是用句子里的詞,去辭彙表裡查下標,在向量對應的位置加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
#vec本來是個向量,變形成1*N的矩陣
return vec.view(1, -1)
make_bow_vector("Give it to me".split(),word_2_idx)
在用戶手動定義Variable時,參數requires_grad默認值是False。而在Module中的層在定義時,相關Variable的requires_grad參數默認是True。
在計算圖中,如果有一個輸入的requires_grad是True,那麼輸出的requires_grad也是True。只有在所有輸入的requires_grad都為False時,輸出的requires_grad才為False。
關於作者:魏佳斌,互聯網產品/技術總監,北京大學光華管理學院(MBA),特許金融分析師(CFA),資深產品經理/碼農。偏愛python,深度關注互聯網趨勢,人工智慧,AI金融量化。致力於使用最前沿的認知技術去理解這個複雜的世界。
※實戰:基於django+nuxt前後端分離的web產品架構
TAG:AI量化實驗室 |