Skip to content

cs224n作业一

📅 发表于 2017/12/17
🔄 更新于 2025/07/23
👁️ — 次访问
📝 728 字
⏳ 4 分钟
cs224n
#cs224n
#assignment
#word2vec
#cbow
#skip-gram

cs224n的第一个作业,包括softmax、神经网络基础和词向量

Softmax ​

Softmax常数不变性 ​

softmax(x)i=exi∑jexj

一般在计算softmax的时候,避免太大的数,要加一个常数。 一般是减去最大的数。

softmax(x)=softmax(x+c)

关键代码 ​

python
def softmax(x):
    exp_func = lambda x: np.exp(x - np.max(x))
    sum_func = lambda x: 1.0 / np.sum(x)
    x = np.apply_along_axis(exp_func, -1, x)
    denom = np.apply_along_axis(sum_func, -1, x)
    denom = denom[..., np.newaxis]
    x = x * denom
   	return x

神经网络基础 ​

Sigmoid实现 ​

我的sigmoid笔记

σ(z)=11+exp⁡(−z),σ(z)∈(0,1)σ′(z)=σ(z)(1−σ(z))

关键代码

python
def sigmoid(x):
    s = 1.0 / (1 + np.exp(-x))
    return s


def sigmoid_grad(s):
    """ 对sigmoid的函数值,求梯度
    """
    ds = s * (1 - s)
    return ds

Softmax求梯度 ​

交叉熵和softmax如下,记softmax的输入为θ ,y是真实one-hot向量。

CE(y,y^)=−∑iyi×log⁡(y^i)y^=softmax(θ)

softmax求导

引入记号:

fi=eθi分子gi=∑k=1Keθk分母,与i无关y^i=Si=figisoftmax

则有Si​对其中的一个数据θj​ 求梯度:

∂Si∂θj=fi′gi−figi′gi2

其中两个导数

fi′(θj)={eθj,i=j0,i≠jgi′(θj)=eθj

i=j时

∂Si∂θj=eθj⋅∑keθk−eθi⋅eθj(∑keθk)2=eθj∑keθk⋅(1−eθj∑keθk)=Si⋅(1−Si)

i≠j时

∂Si∂θj=−eθi⋅eθj(∑keθk)2=−Si⋅Sj

交叉熵求梯度 ​

CE(y,y^)=−∑iyi×log⁡(y^i)y^=S(θ)

只关注有关系的部分,带入yi=1 :

∂CE∂θi=−∂log⁡y^i∂θi=−1y^i⋅∂y^i∂θi=−1Si⋅∂Si∂θi=Si−1=y^i−yi

不带入求导

∂CE∂θi=−∑kyk×∂log⁡Sk∂θi=−∑kyk×1Sk×∂Sk∂θi=−yi(1−Si)−∑k≠iyk⋅1Sk⋅(−Si⋅Sk)=−yi(1−Si)+∑k≠iyk⋅Si=Si−yi

所以,交叉熵的导数是

∂CE∂θi=y^i−yi,∂CE(y,y^)∂θ=y^−y

即

∂CE(y,y^)∂θi={y^i−1,i是labely^i,其它

简单网络 ​

前向计算

z1=xW1+b1h=sigmoid(z1)z2=hW2+b2y^=softmax(z2)

关键代码:

python
def forward_backward_prop(data, labels, params, dimensions):
    h = sigmoid(np.dot(data, W1) + b1)
    yhat = softmax(np.dot(h, W2) + b2)

loss函数

J=CE(y,y^)

关键代码:

python
def forward_backward_prop(data, labels, params, dimensions):
    # yhat[labels==1]实际上是boolean索引,见我的numpy_api.ipynb
    cost = np.sum(-np.log(yhat[labels == 1])) / data.shape[0]

反向传播

δ2=∂J∂z2=y^−y∂J∂h=δ2⋅∂z2∂h=δ2W2Tδ1=∂J∂z1=∂J∂h⋅∂h∂z1=δ2W2T∘σ′(z1)∂J∂x=δ1W1T

一共有(dx+1)⋅dh+(dh+1)⋅dy 个参数。

关键代码:

python
def forward_backward_prop(data, labels, params, dimensions):
    # 前面推导的softmax梯度公式
    gradyhat = (yhat - labels) / data.shape[0]
    # 链式法则
    gradW2 = np.dot(h.T, gradyhat)
    # 本地导数是1,把第1维的所有加起来
    gradb2 = np.sum(gradyhat, axis=0, keepdims=True)
    gradh = np.dot(gradyhat, W2.T)
    gradz1 = gradh * sigmoid_grad(h)
    gradW1 = np.dot(data.T, gradz1)
    gradb1 = np.sum(gradz1, axis=0, keepdims=True)
    
    grad = np.concatenate((gradW1.flatten(), gradb1.flatten(),
            gradW2.flatten(), gradb2.flatten()))
    return cost, grad

梯度检查 ​

我的梯度检查

python
def gradcheck_naive(f, x):
    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
        # 关键代码
        x[ix] += h
        random.setstate(rndstate)
        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)

        # 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

Word2Vec ​

我的word2vec笔记

词向量的梯度 ​

符号定义

  • vc 中心词向量,输入词向量,V, RW×d
  • uo 上下文词向量,输出词向量,U=[u1,u2,⋯,uw] , Rd×W

前向

预测o是c的上下文概率,o为正确单词

y^o=p(o∣c)=softmax(o)=exp⁡(uoTvc)∑wexp⁡(uwTvc)

得分向量:

z=UT⋅vc,[W,d]×[d]∈,RW

loss及梯度

Jsoftmax−CE(vc,o,U)=CE(y,y^),其中∂CE(y,y^)∂θ=y^−y
梯度中文计算维数
∂J∂zsoftmaxy^−yW
∂J∂vc中心词∂J∂z⋅∂z∂vc=(y^−y)⋅UTd
∂J∂U上下文∂J∂z⋅∂z∂UT=(y^−y)⋅vcd×W

关键代码

python
def softmaxCostAndGradient(predicted, target, outputVectors, dataset):
    """ Softmax cost function for word2vec models
    Args:
        predicted: 中心词vc
        target: 上下文uo, index
        outputVectors: 输出,上下文矩阵U,W*d,未转置
        dataset: 
    Returns:
        cost: 交叉熵loss
        gradv: 一维向量
        gradU: W*d
    """
    vhat = predicted
    z = np.dot(outputVectors,vhat)
    preds = softmax(z)
    #  Calculate the cost:
    cost = -np.log(preds[target])
    #  Gradients
    gradz = preds.copy()
    gradz[target] -= 1.0
    gradU = np.outer(z, vhat)
    gradv = np.dot(outputVectors.T, z)
    ### END YOUR CODE
    return cost, gradv, gradU
总访客数:— · 总访问量:—
PLM's Blog @ 2016 - 2026