Изменение стоимости логистической регрессии становится постоянным

1

После нескольких итераций градиентного спуска изменение стоимости стоимости становится постоянным, что наиболее определенно, как это не должно выполняться:

Изображение 174551

Первоначальный результат функции спуска градиента кажется правильным, так же как и результат функции стоимости и, следовательно, функция гипотезы, поэтому я полагаю, что проблема не лежит там. Извините, если вопрос слишком неопределен, но я больше не мог сузить проблему. Если бы вы могли объяснить, что не так в моей программе, я был бы благодарен.

Вот как выглядят данные, которые я использую:

34.62365962451697,78.0246928153624,0

30.28671076822607,43.89499752400101,0

35.84740876993872,72.90219802708364,0

60.18259938620976,86.30855209546826,1

79.0327360507101,75.3443764369103,1

45.08327747668339,56.3163717815305,0

И это код:

import numpy as np
from matplotlib import pyplot as plt


data = np.genfromtxt("ex2data1.txt", delimiter=",")

X = data[:,0:-1]
X = np.array(X)
m = len(X)
ones = np.ones((m,1))
X = np.hstack((ones,X))

Y = data[:,-1]
Y = np.array(Y)
Y = Y.reshape((m,1))

Cost_History = [[],[]]

def Sigmoid(z):
    G = float(1/float(1+np.exp(-1.0*z)))
    return G

def Hypothesis(theta, x):
    z = np.dot(x,theta)
    return Sigmoid(z)

def Cost_Function(X, Y, theta, m):
    sumOfErrors = 0
    for i in range(m):
        xi = X[i]
        yi = Y[i]
        hi = Hypothesis(theta, xi)
        sumOfErrors += yi*np.log(hi) + (1-yi)*np.log(1-hi)
    const = -(1/m)
    J = const * sumOfErrors
    return J

def Cost_Function_Derivative(X, Y, theta, feature, alpha, m):
    sumErrors = 0
    for i in range(m):
        xi = X[i]
        yi = Y[i]
        hi = Hypothesis(theta, xi)
        error = (hi - yi)*xi[feature]
        sumErrors += error
    constant = float(alpha)/float(m)
    J = constant * sumErrors
    return J

def Gradient_Descent(X, Y, theta, alpha, m):
    new_theta = np.zeros((len(theta),1))
    for feature in range(len(theta)):
        CFDerivative = Cost_Function_Derivative(X, Y, theta, feature, alpha, m)
        new_theta[feature] = theta[feature] - CFDerivative
    return new_theta


def Logistic_Regression(X,Y,alpha, theta, iterations, m):
    for iter in range(iterations):
        theta = Gradient_Descent(X, Y, theta, alpha, m)
        cost = Cost_Function(X, Y, theta, m)
        Cost_History[0].append(cost)
        Cost_History[1].append(iter)
        if iter % 100 == 0:
            print(theta, cost, iter)
    return theta

alpha = 0.001
iterations = 1500

theta = np.zeros((len(X[0]),1))
theta = Logistic_Regression(X, Y, alpha, theta, iterations, m)
print(theta)
test = np.array((1,85,45))
print(Hypothesis(theta, test))

wrong = 0
for i in range(m):
    xi = X[i]
    yi = Y[i]
    hi = Hypothesis(theta, xi)
    if yi != round(hi):
        wrong+=1
print(wrong/m)

plt.plot(Cost_History[1], Cost_History[0], "b")
plt.show()
Теги:
machine-learning
numpy
logistic-regression
gradient-descent

1 ответ

2
Лучший ответ

Из данного сюжета видно, что стоимость фактически все еще уменьшается. Быстрый поиск показывает, что ваши данные в настоящее время можно найти здесь, и, запустив код для 500000 итераций, я получаю следующее, которое выглядит так, как вы ожидали:

Изображение 174551

После приблизительно 20000000 шагов значение theta становится [-25.15510086, 0.20618186, 0.20142117]. Чтобы гарантировать, что это то, чего мы ожидаем, мы можем сравнить значение с параметрами, полученными при использовании реализации обучения sci-kit, с большим значением C:

from sklearn.linear_model import LogisticRegression
model = LogisticRegression(C=1e10, tol=1e-6).fit(X, Y.ravel())
model.coef_[0] + np.array([model.intercept_[0], 0, 0])
# array([-25.16127356,   0.20623123,   0.20147112])

Или то же самое в statsmodels:

from statsmodels.discrete.discrete_model import Logit
model = Logit(Y.ravel(), X)
model.fit().params
# array([-25.16133357,   0.20623171,   0.2014716 ])

Теперь, конечно, запуск алгоритма для этого множества шагов неизбежно займет некоторое время. На практике вы обычно обращаетесь к подпрограмме оптимизации второго порядка или стохастическому градиентному спускам, но, как оказалось, большая часть вашего кода может быть сформулирована в терминах векторизованных операций, таких как умножения матриц, что добавит достаточную производительность, чтобы сходиться относительно быстро. В частности, ваши методы можно переписать следующим образом, с той лишь разницей, что Y больше не нужно изменять:

def hypothesis(theta, X):
    return 1/(1+np.exp(-np.dot(X, theta)))

def cost_function(X, Y, theta):
    h = hypothesis(theta, X)
    return -np.mean(Y*np.log(h) + (1-Y)*np.log(1-h))

def gradient_descent(X, Y, theta, alpha):
    h = hypothesis(theta, X)
    return theta - alpha*np.dot(X.T, h - Y)/len(X)

def logistic_regression(X, Y, alpha, theta, iterations):
    for iter in range(iterations):
        theta = gradient_descent(X, Y, theta, alpha)     
        if iter % 100000 == 0:
            cost = cost_function(X, Y, theta)
            cost_history[0].append(cost)
            cost_history[1].append(iter)
            print(theta, cost, iter)
    return theta

Ещё вопросы

Сообщество Overcoder
Наверх
Меню