Градієнт втрати петлі


25

Я намагаюся реалізувати базовий градієнт спуску і тестую його за допомогою функції втрати шарніра, тобто . Однак я плутаю градієнт втрат шарніра. Я під враженням, що це такlhinge=max(0,1y xw)

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

Але чи не повертає це матриця такого ж розміру, як ? Я думав, ми шукаємо повернути вектор довжини \ boldsymbol {w} ? Ясна річ, я десь щось заплутав. Може хтось тут вказує в правильному напрямку?шxw

Я включив базовий код на випадок, якщо мій опис завдання не був зрозумілим

#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"
...  

Градієнт є вектором, оскільки функція втрати має реальні значення.
Вок

3
Ваша функція не є диференційованою скрізь.
Робін Жирард

2
Оскільки відмічає Робін, втрата шарніру не диференціюється при x = 1. Це просто означає, що вам потрібно використовувати алгоритм спуску під градієнтом
Алекс Креймер

Відповіді:


27

Для отримання градієнта диференціюємо втрати по відношенню до го компонента .шiw

Перепишіть втрати шарніра у вигляді як де іf ( g ( w ) ) f ( z ) = max ( 0 , 1 - y z ) g ( w ) = xwwf(g(w))f(z)=max(0,1y z)g(w)=xw

Використовуючи правило ланцюга, ми отримуємо

wif(g(w))=fzgwi

Перший похідний доданок оцінюється при стає коли , і 0, коли . Другий похідний член стає . Отже, зрештою, ви отримуєте 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. Однак ваги, які він створює, здаються зовсім неправильними.
брч

1
Ви можете перевірити, які прогнози дають ваші дані про навчання. Якщо втрата знизиться до нуля, всі інстанції мають бути класифіковані ідеально
Ярослав Булатов

Це стосується бінарної класифікації. Чи можете ви, будь ласка, дати виведення для градієнта багатокласової класифікації за допомогою втрати шарніра?
Шямкхадка

12

Це запізнення на 3 роки, але все ще може бути актуальним для когось ...

Нехай позначає зразок точок 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 ,SxiRdyi{1,1}w Щоб знайти w ∗, отримаємо  похідну від загальної втрати шарніру. Градієнт кожного компонента: l h i n g e

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

LShingew=ilhingeш
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 це стосується двійкової класифікації. Чи можете ви, будь ласка, дати виведення для градієнта багатокласової класифікації за допомогою втрати шарніра?
Шямкхадка

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 ]000000000011 збиток "[1 ]00000000000011", 1 "0000000000011 ", 1 "000000000011" 0,21 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,240000 x0000 втрата" [0,00 ]000000000011 "[0,00 ]000000000011" [0,00 ]000000000011 "[0,00 ]000000000011" [0,00 ]000000000011 "[0,00 ]000000000011" [0,00 ]000000000011 "[0,00 ]000000000011" [0,00] "втрата: 0,210000, xw: 0,949999999999948,0,839999999999905, -1,31000000000007, -1,76000000000011" [1] " 1.25999999999995,1.0099999999999, -1.04000000000008, -1.59000000000011 "[1]" втрата: 0,000000, xw: 1,25999999999995,1,0099999999999, -1,04000000000008, -1,59000000000011 "


3
Народ, спуск градієнта - це якраз алгоритм оптимізації НАЙБІЛЬшого оптимізації, який слід використовувати лише тоді, коли вибору немає. Алгоритм Квазі-Ньютона, який довіряє регіону чи лінії пошуку, використовуючи значення об'єктивних функцій та градієнт, вибухне градієнтом із води та набагато надійніше сходиться. І не пишіть власну розв'язувальну машину, якщо ви не знаєте, чим займаєтесь, що мало хто робить.
Марк Л. Стоун

2
Я погодився б з обома твердженнями. Однак спуск градієнта з різними ароматами набагато простіше здійснити в розподіленому середовищі, принаймні відповідно до наявних бібліотек з відкритим кодом.
Джон Цзян
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.