Skip to content

cs224n作业一

📅 发表于 2017/12/17
🔄 更新于 2017/12/17
👁️ 次访问
📝 0 字
0 分钟
cs224n
#cs224n
#assignment
#word2vec
#cbow
#skip-gram

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

Softmax

Softmax常数不变性

softmax(x)i=exijexj

一般在计算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=figifigigi2

其中两个导数

fi(θj)={eθj,i=j0,ijgi(θj)=eθj

i=j

Siθj=eθjkeθkeθieθj(keθk)2=eθjkeθk(1eθjkeθk)=Si(1Si)

ij

Siθj=eθieθj(keθk)2=SiSj

交叉熵求梯度

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

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

CEθi=logy^iθi=1y^iy^iθi=1SiSiθi=Si1=y^iyi

不带入求导

CEθi=kyk×logSkθi=kyk×1Sk×Skθi=yi(1Si)kiyk1Sk(SiSk)=yi(1Si)+kiykSi=Siyi

所以,交叉熵的导数是

CEθi=y^iyi,CE(y,y^)θ=y^y

CE(y,y^)θi={y^i1,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=Jz2=y^yJh=δ2z2h=δ2W2Tδ1=Jz1=Jhhz1=δ2W2Tσ(z1)Jx=δ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 中心词向量,输入词向量,VRW×d
  • uo 上下文词向量,输出词向量,U=[u1,u2,,uw] , Rd×W

前向

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

y^o=p(oc)=softmax(o)=exp(uoTvc)wexp(uwTvc)

得分向量:

z=UTvc,[W,d]×[d],RW

loss及梯度

JsoftmaxCE(vc,o,U)=CE(y,y^),其中CE(y,y^)θ=y^y
梯度中文计算维数
Jzsoftmaxy^yW
Jvc中心词Jzzvc=(y^y)UTd
JU上下文JzzUT=(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 - 2025