Gradient des Scharnierverlustes

25

Ich versuche, eine grundlegende Gradientenabsenkung zu implementieren und teste sie mit einer Scharnierverlustfunktion, dh . Ich bin jedoch verwirrt über den Gradienten des Scharnierverlustes. Ich habe den Eindruck, dass es so istlhinge=max(0,1y xw)

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

Gibt dies aber nicht eine Matrix mit der gleichen Größe wie x ? Ich dachte, wir wollten einen Vektor mit der Länge \ boldsymbol {w} zurückgebenw ? Offensichtlich habe ich irgendwo etwas verwirrt. Kann hier jemand in die richtige Richtung zeigen?

Ich habe einen Basiscode eingefügt, falls meine Beschreibung der Aufgabe nicht klar war

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

Update: Während die Antwort unten mein Verständnis des Problems erleichterte, ist die Ausgabe dieses Algorithmus für die angegebenen Daten immer noch falsch. Die Verlustfunktion verringert sich jedes Mal um 0,25, konvergiert jedoch zu schnell, und die resultierenden Gewichte führen nicht zu einer guten Klassifizierung. Derzeit sieht die Ausgabe so aus

#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"
...  
brcs
quelle
Der Gradient ist ein Vektor, da Ihre Verlustfunktion reale Werte hat.
Wok
3
Ihre Funktion ist nicht überall unterscheidbar.
Robin Girard
2
Nach Robin Notes ist der Scharnierverlust bei x = 1 nicht differenzierbar. Dies bedeutet nur, dass Sie den Subgradienten-Abstiegs-Algorithmus verwenden müssen
Alex Kreimer

Antworten:

27

Um den Gradienten zu erhalten, differenzieren wir den Verlust in Bezug auf die te Komponente von .wiw

Schreiben Sie den Scharnierverlust in Bezug auf als wobei undf ( g ( w ) ) f ( z ) = max ( 0 , 1 - y z ) g ( w ) = xwwf(g(w))f(z)=max(0,1y z)g(w)=xw

Mit Kettenregel bekommen wir

wif(g(w))=fzgwi

Der Term der ersten Ableitung wird ausgewertet , wenn wenn , und 0, wenn . Der zweite abgeleitete Term wird zu . Ende erhalten Sie also - y xw < 1 xw > 1 x i f ( g ( w ) )g(w)=xwyxw<1xw>1xi

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

Da über den Komponenten von , können Sie das Obige als Vektorgröße anzeigen und als Kurzform für schreibenx ix (w(w1,w2,)

Jaroslaw Bulatow
quelle
Vielen Dank! Das klärt die Dinge für mich auf. Jetzt muss ich es nur noch in einer praktischen Umgebung richtig machen. Sie hätten keine Ahnung, warum der obige Code nicht funktioniert? Es scheint in 4 Iterationen zu konvergieren, wobei der Verlust bei 1 beginnt und jedes Mal um 0,25 sinkt und bei 0 konvergiert. Die Gewichte, die es erzeugt, scheinen jedoch ziemlich falsch zu sein.
brcs
1
Sie können überprüfen, welche Vorhersagen es für Ihre Trainingsdaten gibt. Wenn der Verlust auf null sinkt, sollten alle Instanzen perfekt klassifiziert werden
Jaroslaw Bulatow,
Dies ist bei der binären Klassifikation der Fall. Könnten Sie bitte eine Ableitung für den Gradienten der Mehrfachklassifizierung unter Verwendung des Scharnierverlusts geben?
Shyamkkhadka
12

Dies ist 3 Jahre zu spät, kann aber dennoch für jemanden relevant sein ...

Es sei eine Stichprobe von Punkten und die Menge der entsprechenden Bezeichnungen . Wir suchen nach einer Hyperebene , die den gesamten Scharnierverlust minimiert: Zum Ermitteln von die Ableitung des gesamten Scharnierverlusts verwendet. Der Gradient jeder Komponente ist: x iR d y i{ - 1 , 1 } w w = argmin  w L h i n g e S ( w ) = argmin  w i l h i n g e ( w , x i , y i ) = argmin  w i max { 0 ,SxiRdyi{1,1}ww * l h i n g e

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

Der Gradient der Summe ist eine Summe von Gradienten. Python-Beispiel, das GD verwendet, um zu finden Es folgt die optimale Trennung der Hyperebene durch Scharnierverlust (es ist wahrscheinlich nicht der effizienteste Code, aber es funktioniert)

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()
Alex Kreimer
quelle
Dies ist bei der binären Klassifikation der Fall. Könnten Sie bitte eine Ableitung für den Gradienten der Mehrfachklassifizierung unter Verwendung des Scharnierverlusts geben?
Shyamkkhadka
1

Ich habe deinen Code repariert. Das Hauptproblem ist Ihre Definition von Scharnier- und d_hinge-Funktionen. Diese sollten jeweils einzeln aufgetragen werden. Stattdessen aggregiert Ihre Definition alle Stichproben, bevor Sie das Maximum nehmen.

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

Ich brauche n = 10000, um zu konvergieren.

[1] Verlust: 0,090000, xw: 1,0899999999999995,0,909999999999905, -1,190000000008, -1,69000000000011 [1] Verlust: 0,100000, xw: 1,33999999999995,1,119999999999999, -0,90000000000000000, 0,20,49 0,939999999999999,0,829999999999905, -1,32000000000007, -1,77000000000011 [1] Verlust: 0,370000, xw: 1,64999999999995,1,28999999999999999, -0,630000000000075, -1,25000000000011 [0,0070099999: 9999: 9999 [1] Verlust: 0,240000, xw: 1,49999999999995,1,2099999999999, -0,760000000000075, -1,33000000000011 [1] Verlust: 0,080000, xw: 1,0999999999999995,0,91999999999999905, -1,1800000000000000, -1,6905 1.34999999999995,1.1299999999999, -0,890000000000075, -1,41000000000011[1] Verlust: 0,210000, xw: 0,949999999999948,0,839999999999905, -1,310000000007, -1,76000000000011 [1] Verlust: 0,380000, xw: 1,6599999999999995,1,2999999999999, -0,620000000000000, -1,299 1.25999999999995,1.0099999999999, -1.04000000000008, -1.59000000000011 [1] Verlust: 0.000000, xw: 1.25999999999995,1.0099999999999, -1.0400000000000008, -1.59000000000011

John Jiang
quelle
3
Völker, Gradientenabstieg ist nur ungefähr der schlimmste Optimierungsalgorithmus, den es gibt, und sollte nur verwendet werden, wenn es keine andere Wahl gibt. Ein Quasi-Newton-Algorithmus für die Vertrauensregion- oder Liniensuche, der den objektiven Funktionswert und den Gradienten verwendet, bläst den Gradientenabstieg aus dem Wasser und konvergiert viel zuverlässiger. Und schreiben Sie nicht Ihren eigenen Löser, es sei denn, Sie wissen, was Sie tun, was nur sehr wenige Leute tun.
Mark L. Stone
2
Ich würde beiden Aussagen zustimmen. Gradient Descent mit verschiedenen Geschmacksrichtungen ist jedoch in einer verteilten Umgebung viel einfacher zu implementieren, zumindest entsprechend den verfügbaren Open Source-Bibliotheken.
John Jiang