Ошибка реализации простого градиентного спуска

#python #algorithm #optimization

#python #алгоритм #оптимизация

Вопрос:

Я попытался использовать игрушечную задачу линейной регрессии для внедрения оптимизации в функцию MSE с использованием алгоритма gradient decent.

 import numpy as np

# Data points
x = np.array([1, 2, 3, 4])
y = np.array([1, 1, 2, 2])

# MSE function
f = lambda a, b: 1 / len(x) * np.sum(np.power(y - (a * x   b), 2))


# Gradient
def grad_f(v_coefficients):
    a = v_coefficients[0, 0]
    b = v_coefficients[1, 0]
    return np.array([1 / len(x) * np.sum(2 * (y - (a * x   b)) * x),
                     1 / len(x) * np.sum(2 * (y - (a * x   b)))]).reshape(2, 1)


# Gradient Decent with epsilon as tol vector and alpha as the step/learning rate
def gradient_decent(v_prev):
    tol = 10 ** -3
    epsilon = np.array([tol * np.ones([2, 1], int)])
    alpha = 0.2
    v_next = v_prev - alpha * grad_f(v_prev)
    if (np.abs(v_next - v_prev) <= epsilon).all():
        return v_next
    else:
        gradient_decent(v_next)


# v_0 is the initial guess
v_0 = np.array([[1], [1]])


gradient_decent(v_0)
 

Я пробовал разные альфа-значения, но код никогда не сходится (бесконечная рекурсия) кажется, что проблема связана с условием остановки рекурсии, но после нескольких запусков v_next и v_prev отскакивают от -infinte до бесконечности

Комментарии:

1. Вы пробовали отлаживать его?

2. @MadPhysicist да, конечно, вся математика кажется в порядке, и я ее отладил.

Ответ №1:

Здорово, что вы изучаете машинное обучение (^_^), самостоятельно реализуя некоторые базовые алгоритмы. Что касается вашего вопроса, в вашем коде есть две проблемы, первая из которых — математическая, вход в систему:

 def grad_f(v_coefficients):
    a = v_coefficients[0, 0]
    b = v_coefficients[1, 0]
    return np.array([1 / len(x) * np.sum(2 * (y - (a * x   b)) * x),
                     1 / len(x) * np.sum(2 * (y - (a * x   b)))]).reshape(2, 1)
 

должно быть

 return -np.array(...)
 

поскольку
E=mc^2

второй — это программирование, такой код не вернет вам результат в Python:

 def add(x):
    new_x = x   1
    if new_x > 10:
        return new_x
    else:
        add(new_x)
 

вы должны использовать return в обоих предложениях if инструкции, поэтому оно должно быть

 def add(x):
    new_x = x   1
    if new_x > 10:
        return new_x
    else:
        return add(new_x)
 

Существует также небольшая проблема с коэффициентом альфа для этих конкретных точек данных alpha=0.2 , который слишком велик для сходимости алгоритма, вам нужно использовать меньший alpha . Я также слегка реорганизовал ваш исходный код, используя numpy broadcasting convention (https://numpy.org/doc/stable/user/basics.broadcasting.html ), чтобы получить следующий результат:

 import numpy as np

# Data points
x = np.array([1, 2, 3, 4])
y = np.array([1, 1, 2, 2])

# MSE function
f = lambda a, b: np.mean(np.power(y - (a * x   b), 2))


# Gradient
def grad_f(v_coefficients):
    a = v_coefficients[0, 0]
    b = v_coefficients[1, 0]
    return -np.array([np.mean(2 * (y - (a * x   b)) * x),
                     np.mean(2 * (y - (a * x   b)))]).reshape(2, 1)


# Gradient Decent with epsilon as tol vector and alpha as the step/learning rate
def gradient_decent(v_prev):
    tol = 1e-3
    # epsilon = np.array([tol * np.ones([2, 1], int)]) do not need this, due to numpy broadcasting rules
    alpha = 0.1
    v_next = v_prev - alpha * grad_f(v_prev)
    if (np.abs(v_next - v_prev) <= alpha).all():
        return v_next
    else:
        return gradient_decent(v_next)


# v_0 is the initial guess
v_0 = np.array([[1], [1]])


gradient_decent(v_0)