個人原文:2019-CS224n-Assignment2html
此次複習cs224n主要是先熟悉python和pytorch,方便以後進行論文復現等工做,同時也回顧一下模型和數學公式推導,找找感受。python
咱們先快速回顧一下word2vec算法,它的核心思想是「一個詞的含義取決於它周圍的詞」。具體來講,咱們有一箇中心詞(center word) c,和這個詞 c 周圍上下文構成的窗口,這個窗口內的除了 c 以外的詞叫作外圍詞(outside words)。好比下圖中,中心詞是「banking」,窗口大小爲2,因此上下文窗口是:「turning」、」into「、」crises「和」as「。web
Skip-gram模型(word2vec的一種實現)目的是習得機率分佈 。這樣一來,就能計算給定的一個詞 o 和詞 c 的機率 (意爲,在已知詞 c 出現的狀況下,詞 o 出現的機率), c 是中心詞,o 是外圍詞。算法
在word2vec中,這個條件機率分佈是經過計算向量點積(dot-products),再應用naive-softmax函數獲得的:shell
這裏, 向量表明外圍詞, 向量表明中心詞。爲了包含這些向量,咱們有兩個矩陣 和 。 的列是外圍詞, 的列是中心詞,這兩矩陣都有全部詞 的表示 。網絡
對於詞 c 和詞 o,損失函數爲對數概率:app
能夠從交叉熵的角度看這個損失函數。真實值爲 ,是一個獨熱向量,預測值 是由公式(1)計算獲得。具體來講, 若是是第k個單詞,那麼它的第k維爲1,其他維都是0,而 的第k維表示這是第k個詞的機率大小。ide
證實公式(2)給出的naive-softmax的損失函數,和 與 的交叉熵損失函數是同樣的,均以下所示(答案控制在一行)函數
答:優化
由於除了 以外的詞都不在窗口內,因此只有詞 對損失函數有貢獻
計算損失函數 對中心詞 的偏導數,用 , 和 來表示。
答:
爲了方便表述,對於該外圍詞 咱們設:
,, , ,下面對 求導
∴ (這裏的log蘊含意思是ln)
∵ ,
∵
∴
則對 的導數爲:
,引入矩陣得:
計算損失函數 對上下文窗口內的詞 的偏導數,考慮兩種狀況,即 w 是外圍詞 ,和 w 不是 ,用 , 和 來表示。
答:
在問題(b)基礎上,對 求導。
當 時:
則 ,
故
當 時,由問題(b)得:
綜合上述兩種狀況,因此有:
∴
sigmoid函數如公式(4)所示
請計算出它對於 的導數, 是一個向量
答:
如今咱們考慮負採樣的損失函數。假設有K個負樣本,表示爲 ,它們對應的向量爲 ,外圍詞 ,則外圍詞 在中心詞是 時產生的損失函數如公式(5)所示。
根據該損失函數,從新計算問題(b)、問題(c)的偏導數,用 、、 來表示。
完成計算後,簡要解釋爲何這個損失函數比naive-softmax效率更高。
注意:你能夠用問題(d)的答案來幫助你計算導數
答:
(略,詳見代碼)
提示:
詞庫從 變成了這K+1個詞
在求內層導數的時候用了sigmoid函數
假設中心詞是 ,上下文窗口是 , 是窗口大小,回顧skip-gram的word2vec實現,在該窗口下的總損失函數是:
這裏, 是外圍詞 在中心詞 下產生的損失,損失函數能夠是naive-softmax或者是neg-sample(負採樣),這取決於具體實現。
計算:
(i) 損失函數對 的偏導數
(ii) 損失函數對 的偏導數
(iii) 損失函數對 ( )的偏導數
答:
(略,詳見代碼)
提示:把上下文窗口全部詞的損失加起來便可
點擊 此處 下載代碼,python版本 >= 3.5,須要安裝numpy,你利用conda來配置環境:
conda env create -f env.yml
conda activate a2
複製代碼
寫完代碼後,運行:
conda deactivate
複製代碼
首先,實現 word2vec.py 裏的 sigmoid函數,要支持向量輸入。接着實現同一個文件裏的 softmax 、負採樣損失和導數。而後實現skip-gram的損失函數和導數。所有作完以後,運行python word2vec.py來檢查是否正確。
答:
沒什麼好講的,numpy會本身廣播,最終獲得向量輸出
s = 1 / (1 + np.exp(-x))
複製代碼
這個模型其實就是一個三層的前饋神經網絡(詳解),只須要注意維度便可,註釋裏已經標記出了維度。
須要注意的是,單詞表示是在行,而不是列。
# forward
a, W, target = centerWordVec, outsideVectors, outsideWordIdx
a = a.reshape((a.shape[0], 1))
# assume N words, V dimentions, so
# a.shape == (V, 1) W.shape == (N, V)
z = np.dot(W, a) # (N, 1)
preds = softmax(z.reshape(-1)).reshape(-1, 1) # (N, 1)
loss = -np.log(preds[target])
# backprop
delta = preds.copy() # (N, 1)
delta[target] -= 1.0
gradCenterVec = np.dot(W.T, delta) # (V, 1)
gradOutsideVecs = np.dot(delta, a.T) # (N, V)
gradCenterVec = gradCenterVec.flatten() # (V, )
複製代碼
與native-softmax不一樣的是:
注意,反向傳播獲得的是這K+1個詞的梯度,因此須要挨個更新到 梯度矩陣 中去
### Please use your implementation of sigmoid in here.
# indices might have same index
# extract W
W = np.zeros((len(indices), outsideVectors.shape[1]))
for i in range(len(indices)):
W[i] = outsideVectors[indices[i]]
# forward
a = centerWordVec
a = a.reshape((a.shape[0], 1))
z = np.dot(W, a) # (K+1, 1)
preds = sigmoid(z)
# backprop
y = np.zeros((preds.shape[0], 1))
y[0] = 1 # index 0 is target
loss = -(y*np.log(preds) + (1 - y)*np.log(1 - preds)).sum()
delta = preds - y
gradCenterVec = np.dot(W.T, delta) # (V, 1)
gradW = np.dot(delta, a.T) # (K+1, V)
gradCenterVec = gradCenterVec.flatten()
# apply gradW into gradOutsideVecs
gradOutsideVecs = np.zeros_like(outsideVectors)
for i in range(len(indices)):
oi = indices[i]
gradOutsideVecs[oi] += gradW[i]
複製代碼
遍歷全部的外圍詞,求和損失函數
ci = word2Ind[currentCenterWord]
vc = centerWordVectors[ci]
for o in outsideWords:
oi = word2Ind[o]
loss_, gradVc, gradUo = word2vecLossAndGradient(vc, oi, outsideVectors, dataset)
gradCenterVecs[ci] += gradVc
gradOutsideVectors += gradUo
loss += loss_
複製代碼
完成sgd.py文件的SGD優化器,運行python sgd.py來檢查是否正確。
答:
調用函數獲得損失值和梯度,更新便可
loss, grad = f(x)
x = x - step*grad
複製代碼
至此全部的代碼都寫完了,接下來是下載數據集,這裏咱們使用Stanform Sentiment Treebank(SST)數據集,它能夠用在簡單的語義分析任務中去。經過運行 sh get_datasets.sh 能夠得到該數據集,下載完成後運行 python run.py 便可。
注意:訓練的時間取決於代碼是否高效(即使是高效的實現,也要跑接近一個小時)
通過40,000次迭代後,最終結果會保存到 word_vectors.png 裏。
答:
[1] CS224n: Natural Language Processing with Deep Learning, 2019-03-14. web.stanford.edu/class/cs224….
[2] CS224n Assignment 1, 2019-03-14. www.hankcs.com/nlp/cs224n-…