https://web.stanford.edu/class/archive/cs/cs224n/cs224n.1174/syllabus.html 第一次作業(yè)筆記
Softmax
softmax常數(shù)不變性
由于,因此多余的可以上下消除,于是:
這里
發(fā)現(xiàn)了一個(gè)Softmax非常好的性質(zhì)笋轨,即使兩個(gè)數(shù)都很大比如 1000
與 1001
了讨,其結(jié)果與 1
和2
的結(jié)果相同,即其只關(guān)注數(shù)字之間的差放棒,而不是差占的比例死讹。
Python實(shí)現(xiàn)
之所以介紹Softmax
常數(shù)不變性推励,是因?yàn)榘l(fā)現(xiàn)給定的測(cè)試用例非常大悉默,直接計(jì)算次方
import numpy as np
def softmax(x):
orig_shape = x.shape
if len(x.shape) > 1:
# Matrix
### YOUR CODE HERE
x_max = np.max(x, axis=1).reshape(x.shape[0], 1)
x -= x_max
exp_sum = np.sum(np.exp(x), axis=1).reshape(x.shape[0], 1)
x = np.exp(x) / exp_sum
### END YOUR CODE
else:
# Vector
### YOUR CODE HERE
x_max = np.max(x)
x -= x_max
exp_sum = np.sum(np.exp(x))
x = np.exp(x) / exp_sum
### END YOUR CODE
#or: x = (np.exp(x)/sum(np.exp(x)))
assert x.shape == orig_shape
return x
def test_softmax_basic():
"""
Some simple tests to get you started.
Warning: these are not exhaustive.
"""
print("Running basic tests...")
test1 = softmax(np.array([1,2]))
print(test1)
ans1 = np.array([0.26894142, 0.73105858])
assert np.allclose(test1, ans1, rtol=1e-05, atol=1e-06)
test2 = softmax(np.array([[1001,1002],[3,4]]))
print(test2)
ans2 = np.array([
[0.26894142, 0.73105858],
[0.26894142, 0.73105858]])
assert np.allclose(test2, ans2, rtol=1e-05, atol=1e-06)
test3 = softmax(np.array([[-1001,-1002]]))
print(test3)
ans3 = np.array([0.73105858, 0.26894142])
assert np.allclose(test3, ans3, rtol=1e-05, atol=1e-06)
print("You should be able to verify these results by hand!\n")
if __name__ == "__main__":
test_softmax_basic()
神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
梯度檢查
Sigmoid導(dǎo)數(shù)
定義如下城豁,發(fā)現(xiàn)。
即:
交叉熵定義
當(dāng)使用交叉熵作為評(píng)價(jià)指標(biāo)時(shí)抄课,求梯度:
- 已知:
- 交叉熵:
其中是指示變量唱星,如果該類(lèi)別和樣本的類(lèi)別相同就是1,否則就是0跟磨。因?yàn)閥一般為one-hot類(lèi)型间聊。
而 表示每種類(lèi)型的概率,概率已經(jīng)過(guò)softmax計(jì)算吱晒。
對(duì)于交叉熵其實(shí)有多重定義的方式,但含義相同:
分別為:
二分類(lèi)定義
- y——表示樣本的label沦童,正類(lèi)為1仑濒,負(fù)類(lèi)為0
- p——表示樣本預(yù)測(cè)為正的概率
多分類(lèi)定義
- y——指示變量(0或1),如果該類(lèi)別和樣本的類(lèi)別相同就是1,否則是0偷遗;
- p——對(duì)于觀測(cè)樣本屬于類(lèi)別c的預(yù)測(cè)概率墩瞳。
但表示的意思都相同,交叉熵用于反映 分類(lèi)正確時(shí)的概率情況氏豌。
Softmax導(dǎo)數(shù)
進(jìn)入解答:
- 首先定義和分子分母喉酌。
-
對(duì)求導(dǎo):
注意: 分子是 ,分母是所有的 泵喘,而求偏微的是 泪电。
- 因此,根據(jù)i與j的關(guān)系纪铺,分為兩種情況:
- 當(dāng) 時(shí):
$f_i' = e^{\theta_i}$,$g_i' = e^{\theta_j}$
$\begin{align} \frac{\partial{S_i}}{\partial{\theta_j}} &=\frac{e^{\theta_i}\sum^{k}_{k=1}e^{\theta_k} - e^{\theta_i}e^{\theta_j}}{(\sum^{k}_{k=1}e^{\theta_k})^2} \\ &= \frac{e^{\theta_{i}}}{\sum_{k} e^{\theta_{k}}} \times \frac{\sum_{k} e^{\theta_{k}} – e^{\theta_{j}}}{\sum_{k} e^{\theta_{k}}} \nonumber \\ &= S_{i} \times (1 – S_{i}) \end{align}$
- 當(dāng)時(shí):
$f'_{i} = 0 $,$g'_{i} = e^{\theta_{j}}$
$\begin{align} \frac{\partial{S_i}}{\partial{\theta_j}} &= \frac{0 – e^{\theta_{j}} e^{\theta_{i}}}{(\sum_{k} e^{\theta_{k}})^{2}} \\&= – \frac{e^{\theta_{j}}}{\sum_{k} ^{\theta_{k}}} \times \frac{e^{\theta_{i}}}{\sum_{k} e^{\theta_{k}}} \\ &=-S_j \times S_i\end{align}$
交叉熵梯度
計(jì)算 相速,根據(jù)鏈?zhǔn)椒▌t,
$\begin{align} \frac{\partial CE}{\partial \theta_{i}} &= – \sum_{k} y_{k} \frac{\partial log S_{k}}{\partial \theta_{i}} \\&= – \sum_{k} y_{k} \frac{1}{S_{k}} \frac{\partial S_{k}}{\partial \theta_{i}} \\ &= – y_{i} (1 – S_{i}) – \sum_{k \ne i} y_{k} \frac{1}{S_{k}} (-S_{k} \times S_{i}) \\ &= – y_{i} (1 – S_{i}) + \sum_{k \ne i} y_{k} S_{i} \\ &= S_{i}(\sum_{k} y_{k}) – y_{i}\end{align}$
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=%5Csum_%7Bk%7D%20y_%7Bk%7D%3D1" alt="\sum_{k} y_{k}=1" mathimg="1">鲜锚,所以
反向傳播計(jì)算神經(jīng)網(wǎng)絡(luò)梯度
根據(jù)題目給定的定義:
已知損失函數(shù)突诬,,
求,,,,
解答:
反向傳播,定義芜繁, :
對(duì)于輸出層來(lái)說(shuō)旺隙,的輸入為 ,而輸出則為
上小節(jié)計(jì)算得到 的梯度為 ,
可以使用 替代 骏令,得到
# 推測(cè)這里使用點(diǎn)乘的原因是經(jīng)過(guò)計(jì)算后蔬捷,應(yīng)該是一個(gè)標(biāo)量,而不是向量榔袋。
于是得到:
與計(jì)算相似抠刺,計(jì)算
如果仍然對(duì)反向傳播有疑惑
可以參考一文弄懂神經(jīng)網(wǎng)絡(luò)中的反向傳播法——BackPropagation塔淤,畫(huà)圖出來(lái)推導(dǎo)一下。
如何直觀地解釋 backpropagation 算法速妖? - Anonymous的回答 - 知乎
https://www.zhihu.com/question/27239198/answer/89853077
參數(shù)數(shù)量
代碼實(shí)現(xiàn)
- sigmoid和對(duì)應(yīng)的梯度
def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s
def sigmoid_grad(s):
ds = s * (1-s)
return ds
- 梯度檢查
import numpy as np
import random
# First implement a gradient checker by filling in the following functions
def gradcheck_naive(f, x):
""" Gradient check for a function f.
Arguments:
f -- a function that takes a single argument and outputs the
cost and its gradients
x -- the point (numpy array) to check the gradient at
"""
rndstate = random.getstate()
random.setstate(rndstate)
fx, grad = f(x) # Evaluate function value at original point
h = 1e-4 # Do not change this!
# Iterate over all indexes in x
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
ix = it.multi_index
print(ix)
# Try modifying x[ix] with h defined above to compute
# numerical gradients. Make sure you call random.setstate(rndstate)
# before calling f(x) each time. This will make it possible
# to test cost functions with built in randomness later.
### YOUR CODE HERE:
x[ix] += h
new_f1 = f(x)[0]
x[ix] -= 2*h
random.setstate(rndstate)
new_f2 = f(x)[0]
x[ix] += h
numgrad = (new_f1 - new_f2) / (2 * h)
### END YOUR CODE
# Compare gradients
reldiff = abs(numgrad - grad[ix]) / max(1, abs(numgrad), abs(grad[ix]))
if reldiff > 1e-5:
print("Gradient check failed.")
print("First gradient error found at index %s" % str(ix))
print("Your gradient: %f \t Numerical gradient: %f" % (
grad[ix], numgrad))
return
it.iternext() # Step to next dimension
print("Gradient check passed!")
- 反向傳播
def forward_backward_prop(data, labels, params, dimensions):
"""
Forward and backward propagation for a two-layer sigmoidal network
Compute the forward propagation and for the cross entropy cost,
and backward propagation for the gradients for all parameters.
Arguments:
data -- M x Dx matrix, where each row is a training example.
labels -- M x Dy matrix, where each row is a one-hot vector.
params -- Model parameters, these are unpacked for you.
dimensions -- A tuple of input dimension, number of hidden units
and output dimension
"""
### Unpack network parameters (do not modify)
ofs = 0
Dx, H, Dy = (dimensions[0], dimensions[1], dimensions[2])
W1 = np.reshape(params[ofs:ofs+ Dx * H], (Dx, H))
ofs += Dx * H
b1 = np.reshape(params[ofs:ofs + H], (1, H))
ofs += H
W2 = np.reshape(params[ofs:ofs + H * Dy], (H, Dy))
ofs += H * Dy
b2 = np.reshape(params[ofs:ofs + Dy], (1, Dy))
### YOUR CODE HERE: forward propagation
h = sigmoid(np.dot(data,W1) + b1)
yhat = softmax(np.dot(h,W2) + b2)
### END YOUR CODE
### YOUR CODE HERE: backward propagation
cost = np.sum(-np.log(yhat[labels==1]))
d1 = (yhat - labels)
gradW2 = np.dot(h.T, d1)
gradb2 = np.sum(d1,0,keepdims=True)
d2 = np.dot(d1,W2.T)
# h = sigmoid(z_1)
d3 = sigmoid_grad(h) * d2
gradW1 = np.dot(data.T,d3)
gradb1 = np.sum(d3,0)
### END YOUR CODE
### Stack gradients (do not modify)
grad = np.concatenate((gradW1.flatten(), gradb1.flatten(),
gradW2.flatten(), gradb2.flatten()))
return cost, grad
word2vec
關(guān)于詞向量的梯度
在以softmax為假設(shè)函數(shù)的word2vec中
是中央單詞的詞向量
() 是第 個(gè)詞語(yǔ)的詞向量高蜂。
假設(shè)使用交叉熵作為損失函數(shù), 為正確單詞 (one-hot向量的第 維為1)罕容,請(qǐng)推導(dǎo)損失函數(shù)關(guān)于的梯度备恤。
提示:
其中 = ,,, 是所有詞向量構(gòu)成的矩陣。
解答:
首先明確本題給定的模型是skip-gram
锦秒,通過(guò)給定中心詞露泊,來(lái)發(fā)現(xiàn)周?chē)~的。
定義 旅择, 表示所有詞向量組成的矩陣惭笑,而 也表示的是一個(gè)詞向量。
hint: 如果兩個(gè)向量相似性越高生真,則乘積也就越大沉噩。想象一下余弦?jiàn)A角,應(yīng)該比較好明白柱蟀。
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=U" alt="U" mathimg="1">中所有的詞向量川蒙,都和乘一下獲得。
是干嘛用的呢长已? 內(nèi)就有W個(gè)值畜眨,每個(gè)值表示和 相似程度,通過(guò)這個(gè)相似度選出最大值术瓮,然后與實(shí)際對(duì)比康聂,進(jìn)行交叉熵的計(jì)算。
已知: 和
因此:
除了上述表示之外胞四,還有另一種計(jì)算方法
[圖片上傳失敗...(image-53cc75-1557025564256)]
于是:
仔細(xì)觀察這兩種寫(xiě)法早抠,會(huì)發(fā)現(xiàn)其實(shí)是一回事,都是 觀察與期望的差()撬讽。
推導(dǎo)lookup-table梯度
與詞向量相似
負(fù)采樣時(shí)的梯度推導(dǎo)
假設(shè)進(jìn)行負(fù)采樣蕊连,樣本數(shù)為,正確答案為游昼,那么有甘苍。負(fù)采樣損失函數(shù)定義如下:
其中:
解答:
首先說(shuō)明一下,從哪里來(lái)的烘豌,參考note1 第11頁(yè)载庭,會(huì)有一個(gè)非常詳細(xì)的解釋。
全部梯度
推導(dǎo)窗口半徑的上下文[word ,...,word ,word ,word ,...,word ]時(shí),skip-gram 和 CBOW的損失函數(shù) ( 是正確答案的詞向量)或說(shuō) 或 關(guān)于每個(gè)詞向量的梯度囚聚。
對(duì)于skip-gram來(lái)講靖榕,的上下文對(duì)應(yīng)的損失函數(shù)是:
這里? 是離中心詞距離的那個(gè)單詞。
而CBOW稍有不同顽铸,不使用中心詞而使用上下文詞向量的和作為輸入去預(yù)測(cè)中心詞:
然后CBOW的損失函數(shù)是:
解答:
根據(jù)前面的推導(dǎo)茁计,知道如何得到梯度和。那么所求的梯度可以寫(xiě)作:
skip-gram
CBOW
補(bǔ)充部分:
-
矩陣的每個(gè)行向量的長(zhǎng)度歸一化
x = x/np.linalg.norm(x,axis=1,keepdims=True)
-
在斯坦福情感樹(shù)庫(kù)上訓(xùn)練詞向量
直接運(yùn)行
q3_run
即可
情感分析
特征向量
最簡(jiǎn)單的特征選擇方法就是取所有詞向量的平均
sentence_index = [tokens[i] for i in sentence]
for index in sentence_index:
sentVector += wordVectors[index, :]
sentVector /= len(sentence)
正則化
values = np.logspace(-4, 2, num=100, base=10)
調(diào)參
bestResult = max(results, key= lambda x: x['dev'])
懲罰因子對(duì)效果的影響
confusion matrix
關(guān)聯(lián)性排序的一個(gè)東西谓松,對(duì)角線上的元素越多星压,預(yù)測(cè)越準(zhǔn)確。