CS224N作业A2:词向量训练

本文最后更新于:几秒前

手写题目 答案

注:本答案只包括公式推导的答案,部分主观题答案不包含(因为没做(笑

(a)

对任意一个单词$w$,有
$$
\begin{cases}
1\ \ \ \ \ \ w=o \\
0\ \ \ \ \ \ w\ne o
\end{cases}
$$

$$
\therefore -\sum_{w\in V}y_w\log(\hat{y_w}) = - 0 \cdot \log(\hat{y_w}) - 1\cdot \log(\hat{y_o}) = -\log(\hat{y_o})$​
$$

(b)

(i)

$$
\begin{align}
\frac{\partial J}{\partial v_c} & = \frac{\partial }{\partial v_c} \left ( -\log(\exp(u_o^\top v_c))+\log(\sum_{w\in V}\exp(u_w^\top v_c)) \right ) \\
& = -u_o+\sum_{w\in V}{ {\exp (u_w^\top v_c)} \over {\sum_{j\in V}\exp(u_j^\top v_c) } }\cdot u_w = -u_o + \sum_{w\in V}P(w|c)\cdot u_w \\
& = U^\top ( {y-\hat{y}} )
\end{align}
$$

(c)

$$
\begin{align}
\frac{\partial J}{\partial u_w} & = \frac{\partial }{\partial u_w} \left( -\log \left ( { {\exp(u_o^\top v_c) } \over {\sum_{w\in V}\exp(u_w^\top v_c) } } \right ) \right ) \\
& = - { {\partial u_o^\top v_c} \over {\partial u_w} } + \sum_{w\in V} { {\exp (u_w^\top v_c)} \over {\sum_{j\in V}\exp(u_j^\top v_c) } } \cdot v_c \\
& = - { {\partial u_o^\top v_c} \over {\partial u_w} } + \sum_{w\in V}P(w|c)\cdot v_c \\
①\ w=o\ 时 \ \ {\partial J \over \partial u_o } &= -v_c+\hat{y_w}v_c = (y-\hat{y_w})v_c\\
②\ w\ne o\ 时\ \ {\partial J \over \partial u_o } &=\hat{y_w}v_c
\end{align}
$$

(d)

$$
{\partial J\over \partial U} = \left [ { \partial J\over\partial U_1} , { \partial J\over\partial U_2} , …,{\partial J\over\partial U_{|V|} } \right]
$$

(e)

$$
\frac{\partial f(x) }{\partial x} =
\begin{cases}
\begin{matrix}
& a & x<0 \\
& 1 & otherwise
\end{matrix}
\end{cases}
$$

(f)

$$
\frac{\partial \sigma(x)}{\partial x} = \frac{e^x (e^x+1)- e^x\cdot e^x}{(e^x+1)^2} = \sigma(x)(1-\sigma(x))
$$

(g)

(i)

$$
\begin{align}
\frac{\partial J}{\partial v_c} & = \frac{\partial }{\partial v_c} \left( -\log\left(\sigma(u_o^\top v_c) - \sum_{s=1}^K \log(\sigma(-u_{w_s}^\top v_c)) \right) \right) \\
& = -(1 - \sigma(u_o^\top v_c)) ·u_o - \sum_{s=1}^K (1-\sigma(-u_{w_s}^\top v_c))(-u_{w_s})\\
\frac{\partial J}{\partial u_o} &= -(1-\sigma(u_o^\top v_c)) ·v_c \\
\frac{\partial J}{\partial u_k} &= -(1-\sigma(-u_k^\top v_c)) ·(-v_c)
\end{align}
$$

(ii)

$$
U_{o,[w_1,…,w_k]}^\top v_c = \begin{bmatrix}
u_o^\top v_c\\
-u_{w_1}^\top v_c\\
… \\
-u_{w_k}^\top v_c\
\end{bmatrix},\ \ \ \
\therefore
\sigma(U^\top v_c)-1 = \begin{bmatrix}
\sigma(u_o^\top v_c)-1\\
\sigma(-u_{w_1}^\top v_c)-1\\
… \\
\sigma(-u_{w_k}^\top v_c)-1\
\end{bmatrix}
$$

(iii)

因为使用负对数损失,其没有分母,便于计算,且不用迭代所有词汇

(h)

$$
\begin{align}
{ \partial J \over \partial {u_{w_s} } } &= { \partial \over \partial {u_{w_s} } }\left( -\sum_{j=1}^K \log \sigma(-u_{w_j}^\top v_c) \right) \\
& = - \sum_{j=1}^K \left(1-\sigma(-u_{w_j}^\top v_c) (-v_c) \right) \\
& = \sum_{j=1}^K \sigma(u_{w_j}^\top v_c) ·v_c = \sum_{w_j=w_s} \sigma(u_{w_s}^\top v_c)·v_c
\end{align}
$$

(i)

(i-iii)

$$
\begin{align}
{ \partial J_{skip-gram (v_c,w_{t-m},…,w_{t+m},U )} \over \partial U } & = \sum_{j\in \lbrace -m,m \rbrace \wedge j\notin \lbrace 0 \rbrace} { \partial J(v_c,w_{t+j},U ) \over \partial U } \\
{ \partial J_{skip-gram (v_c,w_{t-m},…,w_{t+m},U )} \over \partial v_c } &= \sum_{j\in \lbrace -m,m \rbrace \wedge j\notin \lbrace 0 \rbrace} { \partial J(v_c,w_{t+j},U ) \over \partial v_c } \\
{ \partial J_{skip-gram (v_c,w_{t-m},…,w_{t+m},U )} \over \partial v_w } & = 0
\end{align}
$$

编程答案

(a)

(i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def sigmoid(x):
"""
Compute the sigmoid function for the input here.
Arguments:
x -- A scalar or numpy array.
Return:
s -- sigmoid(x)
"""

### YOUR CODE HERE (~1 Line)
s = 1. / (1. + np.exp(-x))
### END YOUR CODE

return s

image-20230327162935340

(ii)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def naiveSoftmaxLossAndGradient(
centerWordVec,
outsideWordIdx,
outsideVectors,
dataset
):
""" Naive Softmax loss & gradient function for word2vec models

Implement the naive softmax loss and gradients between a center word's
embedding and an outside word's embedding. This will be the building block
for our word2vec models. For those unfamiliar with numpy notation, note
that a numpy ndarray with a shape of (x, ) is a one-dimensional array, which
you can effectively treat as a vector with length x.

Arguments:
centerWordVec -- numpy ndarray, center word's embedding
in shape (word vector length, )
(v_c in the pdf handout)
outsideWordIdx -- integer, the index of the outside word
(o of u_o in the pdf handout)
outsideVectors -- outside vectors is
in shape (num words in vocab, word vector length)
for all words in vocab (tranpose of U in the pdf handout)
dataset -- needed for negative sampling, unused here.

Return:
loss -- naive softmax loss
gradCenterVec -- the gradient with respect to the center word vector
in shape (word vector length, )
(dJ / dv_c in the pdf handout)
gradOutsideVecs -- the gradient with respect to all the outside word vectors
in shape (num words in vocab, word vector length)
(dJ / dU)
"""

### YOUR CODE HERE (~6-8 Lines)
U,u_o,v_c,o = outsideVectors,outsideVectors[outsideWordIdx],centerWordVec,outsideWordIdx
#整体的softmax
y_hat = softmax(np.dot(U,v_c))
y = np.zeros(np.shape(y_hat))
y[o]=1
#单独的o的损失
loss = -np.log(y_hat[o])
gradCenterVec=np.dot(U.T,(y_hat-y))
gradOutsideVecs = np.dot((y_hat-y)[:,np.newaxis],v_c[:,np.newaxis].T)
# print(np.shape(gradCenterVec),np.shape(gradOutsideVecs))
### Please use the provided softmax function (imported earlier in this file)
### This numerically stable implementation helps you avoid issues pertaining
### to integer overflow.

### END YOUR CODE

return loss, gradCenterVec, gradOutsideVecs

image-20230327163002002

(iii)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def negSamplingLossAndGradient(
centerWordVec,
outsideWordIdx,
outsideVectors,
dataset,
K=10
):
""" Negative sampling loss function for word2vec models

Implement the negative sampling loss and gradients for a centerWordVec
and a outsideWordIdx word vector as a building block for word2vec
models. K is the number of negative samples to take.

Note: The same word may be negatively sampled multiple times. For
example if an outside word is sampled twice, you shall have to
double count the gradient with respect to this word. Thrice if
it was sampled three times, and so forth.

Arguments/Return Specifications: same as naiveSoftmaxLossAndGradient
"""

# Negative sampling of words is done for you. Do not modify this if you
# wish to match the autograder and receive points!
negSampleWordIndices = getNegativeSamples(outsideWordIdx, dataset, K)
indices = [outsideWordIdx] + negSampleWordIndices
'''
Arguments:
centerWordVec -- numpy ndarray, center word's embedding
in shape (word vector length, )
(v_c in the pdf handout)
outsideWordIdx -- integer, the index of the outside word
(o of u_o in the pdf handout)
outsideVectors -- outside vectors is
in shape (num words in vocab, word vector length)
for all words in vocab (tranpose of U in the pdf handout)
dataset -- needed for negative sampling, unused here.
'''
### YOUR CODE HERE (~10 Lines)
### Please use your implementation of sigmoid in here.
U,u_o,v_c,o,s= outsideVectors,outsideVectors[outsideWordIdx],centerWordVec,outsideWordIdx,negSampleWordIndices
gradCenterVec = np.zeros(v_c.shape)
gradOutsideVecs = np.zeros(U.shape)
u_negsam = U[s]
center_o = np.dot(u_o, v_c)
center_s = -np.dot(u_negsam,v_c)
# U_sampled = np.concatenate((u_o[np.newaxis,:],-u_negsam),axis=0)
loss = -np.log(sigmoid(center_o))-np.sum(np.log(sigmoid(center_s)))
gradCenterVec += np.dot(u_o,sigmoid(center_o)-1)
gradOutsideVecs[o] = np.dot(sigmoid(center_o)-1,v_c)
for i in s:
u_k = U[i]
gradCenterVec += np.dot(u_k, 1-sigmoid(-np.dot(u_k,v_c)))
gradOutsideVecs[i] += np.dot(1-sigmoid(-np.dot(u_k,v_c)),v_c)
### END YOUR CODE

return loss, gradCenterVec, gradOutsideVecs

image-20230327163033096

(iv)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def skipgram(currentCenterWord, windowSize, outsideWords, word2Ind,
centerWordVectors, outsideVectors, dataset,
word2vecLossAndGradient=naiveSoftmaxLossAndGradient):
""" Skip-gram model in word2vec

Implement the skip-gram model in this function.

Arguments:
currentCenterWord -- a string of the current center word
windowSize -- integer, context window size
outsideWords -- list of no more than 2*windowSize strings, the outside words
word2Ind -- a dictionary that maps words to their indices in
the word vector list
centerWordVectors -- center word vectors (as rows) is in shape
(num words in vocab, word vector length)
for all words in vocab (V in pdf handout)
outsideVectors -- outside vectors is in shape
(num words in vocab, word vector length)
for all words in vocab (transpose of U in the pdf handout)
word2vecLossAndGradient -- the loss and gradient function for
a prediction vector given the outsideWordIdx
word vectors, could be one of the two
loss functions you implemented above.

Return:
loss -- the loss function value for the skip-gram model
(J in the pdf handout)
gradCenterVecs -- the gradient with respect to the center word vector
in shape (num words in vocab, word vector length)
(dJ / dv_c in the pdf handout)
gradOutsideVecs -- the gradient with respect to all the outside word vectors
in shape (num words in vocab, word vector length)
(dJ / dU)
"""

loss = 0.0
gradCenterVecs = np.zeros(centerWordVectors.shape)
gradOutsideVectors = np.zeros(outsideVectors.shape)

### YOUR CODE HERE (~8 Lines)
#获取center word的vector
#当前中心词的idx到vec
c_i = word2Ind[currentCenterWord]
v_c = centerWordVectors[c_i]
for word in outsideWords:
#对每个outside word都求一次loss和gradient
o_i=word2Ind[word]
ls,gc,go = word2vecLossAndGradient(v_c,o_i,outsideVectors,dataset)
loss += ls
#梯度方法返回的是一个中心词的梯度,这里需要对应到idx
gradCenterVecs[c_i] += gc
#梯度方法返回的已经是整体的梯度,因此不用再用o_idx
gradOutsideVectors += go
### END YOUR CODE

return loss, gradCenterVecs, gradOutsideVectors

image-20230327163115298

(b)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def sgd(f, x0, step, iterations, postprocessing=None, useSaved=False,
PRINT_EVERY=10):
""" Stochastic Gradient Descent

Implement the stochastic gradient descent method in this function.

Arguments:
f -- the function to optimize, it should take a single
argument and yield two outputs, a loss and the gradient
with respect to the arguments
x0 -- the initial point to start SGD from
step -- the step size for SGD
iterations -- total iterations to run SGD for
postprocessing -- postprocessing function for the parameters
if necessary. In the case of word2vec we will need to
normalize the word vectors to have unit length.
PRINT_EVERY -- specifies how many iterations to output loss

Return:
x -- the parameter value after SGD finishes
"""

# Anneal learning rate every several iterations
ANNEAL_EVERY = 20000

if useSaved:
start_iter, oldx, state = load_saved_params()
if start_iter > 0:
x0 = oldx
step *= 0.5 ** (start_iter / ANNEAL_EVERY)

if state:
random.setstate(state)
else:
start_iter = 0

x = x0

if not postprocessing:
postprocessing = lambda x: x

exploss = None

for iter in range(start_iter + 1, iterations + 1):
# You might want to print the progress every few iterations.

loss = None
### YOUR CODE HERE (~2 lines)
#f函数计算loss和grad
loss,grad = f(x)
#更新x,sgd的主要思想就是在负梯度方向下降某个步长,这里题目已经给出。
x = x - step*grad
### END YOUR CODE

x = postprocessing(x)
if iter % PRINT_EVERY == 0:
if not exploss:
exploss = loss
else:
exploss = .95 * exploss + .05 * loss
print("iter %d: %f" % (iter, exploss))

if iter % SAVE_PARAMS_EVERY == 0 and useSaved:
save_params(iter, x)

if iter % ANNEAL_EVERY == 0:
step *= 0.5

return x

image-20230327163146208

(c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
iter 10: 19.824024
iter 20: 20.136629
iter 30: 20.151500
iter 40: 20.211374
...
iter 11400: 12.003779
iter 11410: 12.043692
iter 11420: 12.086623
iter 11430: 12.043952
...
iter 39970: 9.330720
iter 39980: 9.410215
iter 39990: 9.418270
iter 40000: 9.367644

image-20230327162701627

词向量:

word_vectors


CS224N作业A2:词向量训练
http://paopao0226.site/post/38d31aac.html
作者
Ywj226
发布于
2023年3月24日
更新于
2023年9月23日
许可协议