cs231n学习之路:3. softmax求导

本篇博客承接上文,主要介绍softmax的求导和为啥在线性分类器的self.loss函数中,求导部分是那样写的。

原理

softmax公式:
a i = e i ∑ j e j a_i = \frac{e^i}{ \sum\limits_{j} e^j} ai=jejei

交叉熵公式:
l o s s = − ∑ k y k × l o g ( a k ) loss = -\sum\limits_{k} y_k \times log(a_k) loss=kyk×log(ak)

现在有一个线性分类器:
z = x × W + b z = x \times W + b z=x×W+b
x是单样本的reshape之后的向量,这里的y则是one hot编码。
经过softmax:
a = s o f t m a x ( z ) a = softmax(z) a=softmax(z)
最后计算loss:
l o s s = − ∑ k y k ∗ l o g ( a k ) loss = -\sum_k y_k * log(a_k) loss=kyklog(ak)

我们想计算W的导数,用梯度下降法更新w,根据链式法则:
∂ l o s s ∂ w = ∂ l o s s ∂ a × ∂ a ∂ z × ∂ z ∂ x \frac{\partial loss}{\partial w} = \frac{\partial loss}{\partial a} \times \frac{\partial a}{\partial z} \times \frac{\partial z}{\partial x} wloss=aloss×za×xz

现在假想我们要处理的情况是单样本,y是one hot编码的label。
∂ l o s s ∂ z i = ∑ k ∂ l o s s ∂ a k × ∂ a k ∂ z i \frac{\partial loss}{\partial z_i}=\sum_k \frac{\partial loss}{\partial a_k} \times \frac{\partial a_k}{ \partial z_i} ziloss=kakloss×ziak
k的范围是从1到类别数M,i是z的每一个单元输出,自然也是从1到M变化。
之所以对z的第i个单元的求导,会涉及到所有的a,是因为在softmax中,分母就是所有值的指数求和,因此 a a a的所有值都对 a i a_i ai有作用,自然, z i z_i zi的导数就应该包含loss对所有a的导数。
∂ l o s s ∂ a k = − y k a k \frac{\partial loss}{\partial a_k}=-\frac{y_k}{a_k} akloss=akyk
接下来就是求:
∂ a k ∂ z i \frac{\partial a_k}{\partial z_i} ziak
分两种情况, i = k i =k i=k或者 i ̸ = k i \not= k i̸=k (i不等于在markdown中怎么是这么显示的?)
当i=k:
∂ a i ∂ z i = ∂ ( e z i ∑ j e z j ∂ z i ) \frac{\partial a_i}{\partial z_i} = \frac{\partial(\frac{e^{z_i}}{\sum_j e^{z_j}}}{\partial z_i}) ziai=zi(jezjezi)
注意因为j里面是有i的,分子分母都有 z i z_i zi
∂ a i ∂ z i = ∂ ( e z i ∑ j e z j ∂ z i ) = e z i ( ∑ j e z j ) − e z i e z j ( ∑ j e z j ) 2 = e z i ∑ j e z j × ( 1 − e z i ∑ j e z j ) = a i ( 1 − a i ) \frac{\partial a_i}{\partial z_i} = \frac{\partial(\frac{e^{z_i}}{\sum_j e^{z_j}}}{\partial z_i}) =\frac{e^{z_i} (\sum_j e^{z_j}) - e^{z_i} e^{z_j}}{(\sum_j e^{z_j})^2}=\frac{e^{z_i}}{\sum_j e^{z_j}} \times (1-\frac{e^{z_i}}{\sum_j e^{z_j}}) \\ =a_i(1-a_i) ziai=zi(jezjezi)=(jezj)2ezi(jezj)eziezj=jezjezi×(1jezjezi)=ai(1ai)

当 i != k时,分子中就没有和 z i z_i zi相关的项了。
∂ a k ∂ z i = ∂ e z k ∑ j e z j ∂ z i = − e z i e z k ( ∑ j e z j ) 2 = − a i a k \frac{\partial a_k}{\partial z_i}=\frac{\partial \frac{e^{z_k}}{\sum_j e^{z_j}}}{\partial z_i} = - \frac{e^{z_i} e^{z_k}}{(\sum_j e^{z_j})^2} = -a_i a_k ziak=zijezjezk=(jezj)2eziezk=aiak

汇总之后:

∂ l o s s ∂ z i = ∑ k ∂ l o s s ∂ a k × ∂ a k ∂ z i = ∑ i = k ∂ l o s s ∂ a k ∂ a k ∂ z i + ∑ i ≠ k ∂ l o s s ∂ a k ∂ a k ∂ z i = y i ( a i − 1 ) + a i ∑ i ≠ k y k = a i ∑ j y j − y k \frac{\partial loss}{\partial z_i}=\sum_k \frac{\partial loss}{\partial a_k} \times \frac{\partial a_k}{ \partial z_i} = \sum_{i=k} \frac{\partial loss}{\partial a_k}\frac{\partial a_k}{\partial z_i}+ \sum_{i \neq k} \frac{\partial loss}{\partial a_k}\frac{\partial a_k}{\partial z_i}\\ =y_i(a_i-1) + a_i \sum_{i \neq k} y_k= a_i\sum_j y_j - y_k ziloss=kakloss×ziak=i=kaklossziak+i̸=kaklossziak=yi(ai1)+aii̸=kyk=aijyjyk

因为y是one hot 编码,所以 ∑ j y j = 1 \sum_j y_j=1 jyj=1,则:
∂ l o s s ∂ z i = a i − y i \frac{\partial loss}{\partial z_i}=a_i - y_i ziloss=aiyi
这就是softmax的导数了。
原来就是概率值a 减去 在对应的类别的标签。即,如果 z i z_i zi对应是正例,则loss对它的导数就是softmax之后的值减1。

!!!这个时候在回顾上一篇博客求导数的位置。

  # 求导
        # softmax的求导是经过softmax得到的矩阵,在每个正例位置减一
        # z = x*w +b
        # a = softmax(z)
        # loss = -y*log(a)
        grad_z = softmax_scores
        grad_z[np.arange(batch_size),y] -= 1
        grad_w = x.T.dot(grad_z)
        grad_w /= batch_size # 梯度求平均
        grad_w += reg*self.W

grad_z就是求loss对z的求导,它等于softmax_scores,即公式里面的a,然后在正例的位置减1.
w的导数按照链式法则,乘上去就行了。根据链式法则,代码这里:

grad_w = x.T.dot(grad_z)

按照正常顺序,应该写为

grad_z * x

只因为我们推到是考虑单样本的情况,如果是多样本的情况,grad_z实质上是 a T a^T aT

a T × x = x T × a a^T \times x = x^T \times a aT×x=xT×a

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值