只写一下比较关键和细节的地方,还有我遇到的问题。具体的公式推导,不是很难(主要是求导)。代码和公式可以参考这篇博客:http://www.hankcs.com/nlp/cs224n-assignment-1.html/2。
第一个比较关键和细节的地方,是softmax函数,向量化就不说了。。。
这里实现的时候,遇到了一个问题,对于样例中[1001,1002],一开始直接用公式exp(1001),出现inf,无穷值(e的1001次方,不无穷才怪),查阅资料计算指数函数的和的对数,发现要减去一个最大值,用来解决此类上溢、下溢问题。
def softmax(x):
if len(x.shape) > 1:
# Matrix
x = np.exp(x - (np.max(x, axis=1).reshape(-1, 1)))
x = x / np.sum(x, axis=1)
else:
# Vector
x = np.exp(x - (np.max(x)))
x = x / np.sum(x)
return x
第二个是标准化,一开始没看“使x的长度等于1”,直接用x/x.sum,错了。
def normalizeRows(x):
""" Row normalization function
Implement a function that normalizes each row of a matrix to have
unit length.
"""
### YOUR CODE HERE
x = x / np.sqrt(np.sum(np.square(x), axis=1)).reshape(-1, 1)
### END YOUR CODE
return x
第三个用softmax方法的损失函数和梯度函数就比较重要了。
这里用了交叉熵损失函数:
=
,其中yhat是softmax后的结果。
函数的输入:predicted(D*1),是中心词的词向量,target是上下文词在词汇表的索引,outputVectors(W*D)就是上下文词的Word Embedding矩阵。
函数的输出:cost不用多说,gradPred是中心词向量的梯度,grad是上下文词向量的梯度。
求损失函数,第一步就是要得到神经网络的输出,即outputVectors.dot(predicted),得到一个(W*1)的向量,对该向量进行softmax就得到了yhat向量(W*1)。
下面计算,yi是一个W*1的one-hot。这里是yi和yhati对应元素相乘,得到一个W*1的向量,然后对该向量求和,就得到了损失值。由于只有y[target]才=1,其他位置全部为0,与yhat相乘为0,所以直接用yhat[target]*1就行了,免去了求和的计算,这样就计