힌지 손실의 그라디언트


25

기본 그라디언트 하강을 구현하려고하는데 힌지 손실 기능으로 테스트하고 있습니다. . 그러나 힌지 손실의 그라디언트에 대해 혼란 스럽습니다. 나는 그것이lhinge=max(0,1y xw)

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

그러나 이것은 \ boldsymbol {x} 와 같은 크기의 행렬을 반환하지 x않습니까? 길이가 \ boldsymbol {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"
...  

손실 함수에 실제 값이 있으므로 그래디언트는 벡터입니다.
Wok

3
당신의 기능은 어디에서나 구별 할 수 없습니다.
로빈 지라드

2
로빈 메모에서 힌지 손실은 x = 1에서 차별화 할 수 없습니다. 이것은 하위 그라데이션 하강 알고리즘을 사용해야 함을 의미합니다.
Alex Kreimer

답변:


27

그래디언트를 얻으려면 w의 번째 구성 요소 와 관련하여 손실을 구분합니다 .iw

측면에서 힌지 손실 재 작성 로서 F ( g ( w ) ) 여기서 F ( z는 ) = 최대 ( 0 , 1 - Y , Z )g ( w를 ) = Xwwf(g(w))f(z)=max(0,1y z)g(w)=xw

체인 규칙을 사용하면

wif(g(w))=fzgwi

1 차 도함수 항은로 평가 되고 - YXw < 1 , 0 , Xw > 1 . 2 차 미분 항은 x i가 됩니다. 결국 당신은 f ( g ( w ) ) 를 얻습니다. g(w)=xwyxw<1xw>1xi

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

x 의 성분보다 범위가 넓으 므로 위의 벡터 수량으로보고 ∂를 쓸 수 있습니다ix 속기(w(w1,w2,)


감사! 그것은 나를 위해 일을 정리합니다. 이제는 실제 환경에서 올바르게 설정해야합니다. 왜 위의 코드가 작동하지 않는지 전혀 알지 못합니까? 손실은 1에서 시작하여 매번 0.25로 내려 가고 0에서 수렴하는 4 회 반복으로 수렴하는 것처럼 보입니다. 그러나 생성되는 가중치는 상당히 잘못된 것처럼 보입니다.
brcs

1
훈련 데이터에 어떤 예측이 제공되는지 확인할 수 있습니다. 손실이 제로로 다운되면, 모든 인스턴스를 완벽하게 구분되어야한다
야로 슬라브 Bulatov

이진 분류의 경우입니다. 경첩 손실을 사용하여 멀티 클래스 분류의 구배에 대한 유도를 제공 할 수 있습니까?
Shyamkkhadka

12

이것은 3 년 늦었지만 여전히 누군가와 관련이있을 수 있습니다 ...

SxiRdyi{1,1}w

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

The gradient of the sum is a sum of gradients.

LShingew=ilhingew
Python example, which uses GD to find hinge-loss optimal separatinig hyperplane follows (its probably not the most efficient code, but it works)
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()

I this is the case for binary classification. Could you please give derivation for gradient of multi class classification using hinge loss ?
Shyamkkhadka

1

I fixed your code. The main problem is your definition of hinge and d_hinge functions. These should be applied one sample at a time. Instead your definition aggregates all the samples before taking the maximum.

#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)

I need n=10000 to converge.

[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.0500000000000000011 " [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
Peoples, gradient descent is just about the WORST optimization algorithm there is, and should be used only when there is no choice. A trust region or line search Quasi-Newton algorithm, using objective function value and gradient, will blow gradient descent out of the water, and much more reliably converge. And don't write your own solver unless you know what you're doing, which very few people do.
Mark L. Stone

2
나는 두 진술에 동의합니다. 그러나 적어도 다양한 오픈 소스 라이브러리에 따르면 분산 환경에서 다양한 풍미를 가진 그라디언트 디센트를 구현하는 것이 훨씬 쉽습니다.
John Jiang
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.