SVM梯度求导及实现

640?wx_fmt=png

SVM梯度求导及实现


0.说在前面1.梯度推导2.实现3.作者的话


0.说在前面

昨晚看了一部电影,叫做我是马布里,非常正能量,推荐给各位,看完这部电影的总结话是:

640?wx_fmt=jpeg

冠军与非冠军的区别在于你一直并没有将两者进行明确界定,只是模糊了两者的边缘,我们不是适应边缘化的人,而是打破边缘化的创造者!

今天重点来推导SVM梯度及代码实现,下面一起来实战吧!

1.梯度推导

loss fuction

SVM损失函数想要SVM在正确分类上的得分始终比不正确的得分高出一个边界值!

下面来进行梯度下降的推导!

loss vector

数学推导如下:

X表示如下(1式):640?wx_fmt=png640?wx_fmt=png640?wx_fmt=png

X*W=S
f(S)=L # f表示loss function

这里使用链式求导法对w进行求导(4式):640?wx_fmt=png

对(4)内部进行求导拆分,如(5)式

s1只跟L1有关,si只跟Lj有关,于是求和可以去掉,转化为后面那个Lj对Sj求导!

(5式)640?wx_fmt=png640?wx_fmt=png

2.实现

loss native

def svm_loss_vectorized(W, X, y, reg):
    loss = 0.0
    dW = np.zeros(W.shape) # initialize the gradient as zero
    # (N,D)
    # N
    num_train = X.shape[0]
    # (D,C)
    # C
    num_classes = W.shape[1]
    # (N,C)
    scores = X.dot(W)
    # 获取每个样本对应label的得分
    # (N,1)
    y_score =scores[np.arange(num_train),y].reshape(-1,1)
    mask = (scores-y_score+1)>0
    scores = (scores-y_score+1)*mask
    loss =(np.sum(scores)-num_train*1)/num_train
    loss += reg * np.sum(W * W)  
    # 初始化ds,
    ds = np.ones_like(scores)
    # 有效的score梯度为1,无效的为0
    ds*=mask
    # 去掉k=yj的情况
    ds[np.arange(num_train),y]=-1*(np.sum(mask,axis=1)-1)
    # 对应公式(4)
    dW=np.dot(X.T,ds)/num_train
    dW+=2*reg*W
    return loss, dW

这里的代码引自训练营老师代码,这里写的很精辟,非常值得学习,特别是对于这个逻辑处理,下面来深入分析一下。

模拟实验

首先是找到有效分数,也就是上述max()函数大于0与小于0的情况,这里直接通过先判断,这里来模拟一下操作:

首先定义两个二维数组,分别是x1与x2:x1表示上面公式推导的(3)式子,S矩阵,也就是通过X与W相乘后的矩阵!x2表示预测结果为真实label的yj。

下面一起来学习一下模拟操作以及老师在这里的运算精髓!

In

x1 = np.array(np.arange(6)).reshape(3,2)
x2 = np.array([2,3,3]).reshape(-1,1)
x1
x2

Out

array([[0, 1],
       [2, 3],
       [4, 5]])
array([[2],
       [3],
       [3]])

In

mask = x1-x2+1>0

通过这个操作可以得到什么?

Out

array([[False, False],
       [False,  True],
       [ True,  True]])

发现没,得到了一个布尔类型的同shape多维数组,那么是不是可以这样说,思路就是首先通过得到有效无效分数的布尔高维数组,有效就是True,无效就是False,在运算的时候,直接可以将False看作0,True看作1。

那么我们接下来计算真实的得分:

In

scores=(x1-x2+1)*mask
scores

Out

array([[0, 0],
       [0, 1],
       [2, 3]])

这个就是我们期望通过下面公式得到的结果!640?wx_fmt=png

这样做的好处是可以避免循环及使用max函数!!

上述的代码等价于:

In

for i in range(x1.shape[0]):
    for j in range(x1.shape[1]):
        x1[i][j]=max(0,x1[i][j]-x2[i][0]+1)

Out

array([[0, 0],
       [0, 1],
       [2, 3]])

注意点

由于上述公式(6)在计算得分时候不涉及yj也就是预测为真正label这一项,而在计算的时候,实际上把所有的都计算了,所以得减去这一项,对于每一行操作都多算了一个:640?wx_fmt=png

loss =(np.sum(scores)-num_train*1)/num_train

另外就是在计算ds的时候,这个ds就是上述(5)式,L对S求导,最终求导结论就是:

(1)当对Sjk求导时(k不等于yj),若为有效得分,则为1,否则为0;

(2)当对Sjk求导时(k等于yj)时,若为有效得分,则为多个-1,否则为0;

第(1)点主要说的是下面这个式子当中的Sjk,第(2)主要说的是下面这个式子中的Sjyj求导,因为是多个max函数累加,那么对于Sjyj求导的话是每一个max都有一项,所以如果max得分是正数,则表示求导结果是-1,将多个求导的-1叠加就是最后对Sjyj的求导总和;而对于Sjk求导,虽然是多个max,以求Sj1为例,只有一个max中存在Sj1,所以总的求导要么为1,要么为0640?wx_fmt=png

# 有效的score梯度为1,无效的为0
ds*=mask
# 去掉k=yj的情况
ds[np.arange(num_train),y]=-1*(np.sum(mask,axis=1)-1)

上面说了mask是将预测为yj的也算进去了,对于当碰到下面这个式子:640?wx_fmt=png

3.作者的话

如果您觉得本公众号对您有帮助,欢迎转发,更多内容欢迎关注本公众号深度学习系列!

640?wx_fmt=png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值