铰链损失的梯度


25

我正在尝试实现基本的梯度下降,并使用铰链损失函数对其进行测试,即lhinge=max(0,1y xw)。但是,我对铰链损耗的梯度感到困惑。我的印象是

wlhinge={y xif y xw<10if y xw1

但这是否不返回与\ boldsymbol {x}相同大小的矩阵x?我以为我们想返回长度为\ boldsymbol {w}的向量w?显然,我在某处有些困惑。有人可以在这里指出正确的方向吗?

我已经包括一些基本代码,以防我对任务的描述不清楚

#Run standard gradient descent
gradient_descent<-function(fw, dfw, n, lr=0.01)
{
    #Date to be used
    x<-t(matrix(c(1,3,6,1,4,2,1,5,4,1,6,1), nrow=3))
    y<-c(1,1,-1,-1)
    w<-matrix(0, nrow=ncol(x))

    print(sprintf("loss: %f,x.w: %s",sum(fw(w,x,y)),paste(x%*%w, collapse=',')))
    #update the weights 'n' times
    for (i in 1:n)
    {
      w<-w-lr*dfw(w,x,y)
      print(sprintf("loss: %f,x.w: %s",sum(fw(w,x,y)),paste(x%*%w,collapse=',')))
    }
}
#Hinge loss
hinge<-function(w,x,y) max(1-y%*%x%*%w, 0)
d_hinge<-function(w,x,y){ dw<-t(-y%*%x); dw[y%*%x%*%w>=1]<-0; dw}
gradient_descent(hinge, d_hinge, 100, lr=0.01)

更新:虽然下面的答案有助于我理解问题,但是对于给定的数据,此算法的输出仍然不正确。损失函数每次减少0.25,但收敛速度太快,因此产生的权重无法实现良好的分类。当前输出看起来像

#y=1,1,-1,-1
"loss: 1.000000, x.w: 0,0,0,0"
"loss: 0.750000, x.w: 0.06,-0.1,-0.08,-0.21"
"loss: 0.500000, x.w: 0.12,-0.2,-0.16,-0.42"
"loss: 0.250000, x.w: 0.18,-0.3,-0.24,-0.63"
"loss: 0.000000, x.w: 0.24,-0.4,-0.32,-0.84"
"loss: 0.000000, x.w: 0.24,-0.4,-0.32,-0.84"
"loss: 0.000000, x.w: 0.24,-0.4,-0.32,-0.84"
...  

梯度是一个向量,因为您的损失函数具有实数值。
炒锅2010年

3
您的功能无处不在。
罗宾吉拉德

2
如知更鸟所知,铰链损耗在x = 1时不可微分。这只是意味着你需要使用子梯度下降算法
亚历克赖默

Answers:


27

为了获得梯度,我们将损耗与第个分量进行区分。iw

将铰链损耗改写为,其中和wf(g(w))f(z)=max(0,1y z)g(w)=xw

使用链式规则,我们得到

wif(g(w))=fzgwi

当,一阶导数项在变为时求值,而当。二阶导数项变为。因此最后得到 g(w)=xwyxw<1xw>1xi

f(g(w))wi={y xiif y xw<10if y xw>1

由于范围是的分量,因此您可以将以上内容视为向量,并写出作为ixw(w1,w2,)


谢谢!那为我清除了一切。现在,我只需要在实际环境中正确设置它即可。您不会碰巧知道上面的代码为什么不起作用?它似乎在4次迭代中收敛,损耗从1开始,每次下降0.25,然后在0收敛。但是,它产生的权重似乎很错误。
brcs

1
您可以检查它对您的训练数据有什么预测。如果损失降为零,则所有实例均应进行完美分类
Yaroslav Bulatov 2010年

二进制分类就是这种情况。能否请您给出使用铰链损耗的多类分类的梯度的推导?
Shyamkkhadka '17

12

这晚了3年,但仍然可能与某人有关...

令表示点的样本和一组对应的标签的样本。我们搜索以找到能使总铰链损耗最小的超平面: 要找出,求取铰链总损耗的导数。每个组件的渐变为: SxiRdyi{1,1}w

w=argmin wLShinge(w)=argmin wilhinge(w,xi,yi)=argmin wimax{0,1yiwx}
w
lhingew={0yiwx1yixyiwx<1

和的梯度是梯度的和。 Python示例,该示例使用GD查找遵循铰链损耗最佳separatinig超平面(它可能不是最有效的代码,但它可以工作)

LShingew=ilhingew
import numpy as np
import matplotlib.pyplot as plt

def hinge_loss(w,x,y):
    """ evaluates hinge loss and its gradient at w

    rows of x are data points
    y is a vector of labels
    """
    loss,grad = 0,0
    for (x_,y_) in zip(x,y):
        v = y_*np.dot(w,x_)
        loss += max(0,1-v)
        grad += 0 if v > 1 else -y_*x_
    return (loss,grad)

def grad_descent(x,y,w,step,thresh=0.001):
    grad = np.inf
    ws = np.zeros((2,0))
    ws = np.hstack((ws,w.reshape(2,1)))
    step_num = 1
    delta = np.inf
    loss0 = np.inf
    while np.abs(delta)>thresh:
        loss,grad = hinge_loss(w,x,y)
        delta = loss0-loss
        loss0 = loss
        grad_dir = grad/np.linalg.norm(grad)
        w = w-step*grad_dir/step_num
        ws = np.hstack((ws,w.reshape((2,1))))
        step_num += 1
    return np.sum(ws,1)/np.size(ws,1)

def test1():
    # sample data points
    x1 = np.array((0,1,3,4,1))
    x2 = np.array((1,2,0,1,1))
    x  = np.vstack((x1,x2)).T
    # sample labels
    y = np.array((1,1,-1,-1,-1))
    w = grad_descent(x,y,np.array((0,0)),0.1)
    loss, grad = hinge_loss(w,x,y)
    plot_test(x,y,w)

def plot_test(x,y,w):
    plt.figure()
    x1, x2 = x[:,0], x[:,1]
    x1_min, x1_max = np.min(x1)*.7, np.max(x1)*1.3
    x2_min, x2_max = np.min(x2)*.7, np.max(x2)*1.3
    gridpoints = 2000
    x1s = np.linspace(x1_min, x1_max, gridpoints)
    x2s = np.linspace(x2_min, x2_max, gridpoints)
    gridx1, gridx2 = np.meshgrid(x1s,x2s)
    grid_pts = np.c_[gridx1.ravel(), gridx2.ravel()]
    predictions = np.array([np.sign(np.dot(w,x_)) for x_ in grid_pts]).reshape((gridpoints,gridpoints))
    plt.contourf(gridx1, gridx2, predictions, cmap=plt.cm.Paired)
    plt.scatter(x[:, 0], x[:, 1], c=y, cmap=plt.cm.Paired)
    plt.title('total hinge loss: %g' % hinge_loss(w,x,y)[0])
    plt.show()

if __name__ == '__main__':
    np.set_printoptions(precision=3)
    test1()

我的情况是二进制分类。能否请您给出使用铰链损耗的多类分类的梯度的推导?
Shyamkkhadka '17

1

我修复了您的代码。主要问题是铰链和d_hinge函数的定义。这些应一次施加一个样品。相反,您的定义会在取最大值之前汇总所有样本。

#Run standard gradient descent
gradient_descent<-function(fw, dfw, n, lr=0.01)
{
    #Date to be used
    x<-t(matrix(c(1,3,6,1,4,2,1,5,4,1,6,1), nrow=3))
    y<-t(t(c(1,1,-1,-1)))
    w<-matrix(0, nrow=ncol(x))


    print(sprintf("loss: %f,x.w: %s",sum(mapply(function(xr,yr) fw(w,xr,yr), split(x,row(x)),split(y,row(y)))),paste(x%*%w, collapse=',')))
    #update the weights 'n' times
    for (i in 1:n)
    {
      w<-w-lr*dfw(w,x,y)
      print(sprintf("loss: %f,x.w: %s",sum(mapply(function(xr,yr) fw(w,xr,yr), split(x,row(x)),split(y,row(y)))),paste(x%*%w,collapse=',')))
    }
}

#Hinge loss
hinge<-function(w,xr,yr) max(1-yr*xr%*%w, 0)
d_hinge<-function(w,x,y){ dw<- apply(mapply(function(xr,yr) -yr * xr * (yr * xr %*% w < 1),split(x,row(x)),split(y,row(y))),1,sum); dw}
gradient_descent(hinge, d_hinge, 100, lr=0.01)

我需要n = 10000才能收敛。

[1]“损失:0.090000,xw:1.08999999999995,0.909999999999905,-1.19000000000008,-1.69000000000011” [[1]“损失:0.100000,xw:1.33999999999995,1.1199999999999,-0.900000000000075,-1.42000000000011” [1]“损失:0.230000,xw: 0.939999999999948,0.829999999999905,-1.32000000000007,-1.77000000000011“ [1]”损失:0.370000,xw:1.64999999999995,1.2899999999999,-0.630000000000075,-1.25000000000011“ [1]”损失:0.000000,xw:1.24999999999995,0.999999999999905,-1.05000000000008“ -1.60000000000011” [1]“损失:0.240000,xw:1.49999999999995,1.2099999999999,-0.760000000000075,-1.33000000000011” [1]“”损失:0.080000,xw:1.09999999999995,0.919999999999905,-1.18000000000007,-1.68000000000011“ [1]”损失:0.110000,xw: 1.34999999999995,1.1299999999999,-0.890000000000075,-1.41000000000011“[1]“损耗:0.210000,xw:0.949999999999948,0.839999999999905,-1.31000000000007,-1.76000000000011” [1]“损耗:0.380000,xw:1.65999999999995,1.2999999999999,-0.620000000000074,-1.24000000000011” [1]“损耗:0.000000,xw: 1.25999999999995,1.0099999999999,-1.04000000000008,-1.59000000000011“ [1]”损耗:0.000000,xw:1.25999999999995,1.0099999999999,-1.04000000000008,-1.59000000000011“


3
伙计们,梯度下降就是关于WORST优化算法的问题,仅在没有选择的情况下才应使用。使用目标函数值和梯度的信任区域或线搜索拟牛顿算法会将梯度下降吹出水面,并且更加可靠地收敛。除非您知道自己在做什么,否则不要写自己的求解器,很少有人这样做。
Mark L. Stone

2
我同意这两种说法。但是,至少根据那里可用的开源库,在分布式环境中更容易实现具有各种风格的梯度下降。
约翰·姜
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.