Значение потери линейной регрессии увеличивается после каждой итерации градиентного спуска

#python #numpy #machine-learning #scikit-learn #linear-regression

#python #numpy #машинное обучение #scikit-learn #линейная регрессия

Вопрос:

Я пытаюсь реализовать многомерную линейную регрессию (градиентный спуск и функция затрат mse), но значение потерь продолжает экспоненциально увеличиваться для каждой итерации градиентного спуска, и я не могу понять, почему?

 from sklearn.datasets import load_boston


class LinearRegression:

    def __init__(self):
        self.X = None  # The feature vectors [shape = (m, n)]
        self.y = None  # The regression outputs [shape = (m, 1)]
        self.W = None  # The parameter vector `W` [shape = (n, 1)]
        self.bias = None  # The bias value `b`
        self.lr = None  # Learning Rate `alpha`
        self.m = None
        self.n = None
        self.epochs = None

    def fit(self, X: np.ndarray, y: np.ndarray, epochs: int = 100, lr: float = 0.001):
        self.X = X  # shape (m, n)
        self.m, self.n = X.shape
        assert y.size == self.m and y.shape[0] == self.m
        self.y = np.reshape(y, (-1, 1))  # shape (m, ) or (m, 1)
        assert self.y.shape == (self.m, 1)
        self.W = np.random.random((self.n, 1)) * 1e-3  # shape (n, 1)
        self.bias = 0.0
        self.epochs = epochs
        self.lr = lr
        self.minimize()

    def minimize(self, verbose: bool = True):
        for num_epoch in range(self.epochs):
            predictions = np.dot(self.X, self.W)

            assert predictions.shape == (self.m, 1)
            grad_w = (1/self.m) * np.sum((predictions-self.y) * self.X, axis=0)[:, np.newaxis]
            self.W = self.W - self.lr * grad_w
            assert self.W.shape == grad_w.shape
            loss = (1 / 2 * self.m) * np.sum(np.square(predictions - self.y))

            if verbose:
                print(f'Epoch : {num_epoch 1}/{self.epochs} t Loss : {loss.item()}')


linear_regression = LinearRegression()
x_train, y_train = load_boston(return_X_y=True)
linear_regression.fit(x_train, y_train, 10)
  

Я использую набор данных boston housing от sklearn.

PS. Я хотел бы знать, что вызывает эту проблему и как ее исправить, и является ли моя реализация правильной.

Спасибо

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

1. Это называется дивергенцией. Это означает, что модель не обучается, так как веса увеличиваются в значениях.

2. Почему вы не изучаете смещение?

3. Это была грубая реализация, поэтому я решил на некоторое время отложить смещение и просто посмотреть на веса.

4. @filtertips… Я понял проблему с реализацией … можете ли вы предложить исправление, которое потенциально могло бы устранить проблему? [Как насчет таких вещей, как регуляризация или нормализация данных? будут ли они полезны?]

Ответ №1:

Ошибка в градиенте. Подобное расхождение для решателя алгоритмов итеративной усадки с пороговым значением (ISTA) — это не то, что вы должны видеть. Для вашего вычисления градиента: X имеет форму (m, n) и W формы (n,1), поэтому (предсказание — y) имеет форму (m, 1), затем вы умножаете на X слева? (m, 1) на (m, n)? Не уверен, что вычисляет numpy, но это не то, что вы хотите вычислить:

grad_w = (1/self.m) * np.sum((предсказания-self.y) * self.X, axis=0)[:, np.newaxis]

здесь код должен немного отличаться, чтобы a (n, m) умножалось на a (m,1), чтобы получить a (n,1) той же формы, что и W.

(1/ self.m) * np.sum(self.X.T *(предсказания-self.y) , ось = 0)[:, np.newaxis]

Чтобы вывод был правильным.

Я также не уверен, почему вы используете точку (что является хорошей идеей) для прогнозирования, но не для градиента.

Вам также не нужно так много изменений:

 from sklearn.datasets import load_boston

A,b = load_boston(return_X_y=True)
n_samples = A.shape[0]
n_features = A.shape[1]

def grad_linreg(x):
    """Least-squares gradient"""
    grad = (1. / n_samples) * np.dot(A.T, np.dot(A, x) - b)
    return grad

def loss_linreg(x):
    """Least-squares loss"""
    f = (1. / (2. * n_samples)) * sum((b - np.dot(A, x)) ** 2)
    return f
  

И затем вы проверяете, что ваш градиент хорош:

 from scipy.optimize import check_grad
from numpy.random import randn

check_grad(loss_linreg,grad_linreg,randn(n_features))
check_grad(loss_linreg,grad_linreg,randn(n_features))
check_grad(loss_linreg,grad_linreg,randn(n_features))
check_grad(loss_linreg,grad_linreg,randn(n_features))
  

Затем вы можете построить модель на этом.
Если вы хотите проверить это с помощью ISTA / FISTA и логистической / линейной регрессии и ЛАССО / РИДЖА, вот блокнот jupyter с теорией и рабочим примером