Подгонка полиномов различной степени для работы с пользовательской функцией потерь - PullRequest
0 голосов
/ 28 ноября 2018

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

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

#y(x) = sin(x) + noise
def F(x_in_rad):
    return np.sin(x_in_rad) + noise*np.random.normal(0,1,N)

noise = 0.5
N = 50
#X - N datapoints in radians
X = np.deg2rad(np.random.normal(0,1,N) * 359)
Y = F(X)


X = np.atleast_2d(X).T
Y = np.atleast_2d(Y).T
#split data
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.33, random_state=42)

#mean of the squared residuals
def sq_res_mean(Y_pred,Y_real):
    return np.mean((Y_pred - Y_real)**2)

#create design matrix
def designmatpoly(X,degree):
    X = X[:,0]
    eye = np.ones(X.shape)
    rows = []
    rows.append(eye)
    for i in range(1,degree+1):
        rows.append(X**i)
    return np.stack(rows).T


#L2 norm squared; gradient = 2w
def C(w):
    return np.sum(w**2)


def gradientdescent(Amat, y, rate, numiter, lam, deg):
    n, p = Amat.shape
    whistory = []
    w_analytical = np.dot((np.dot(Amat.T,Amat) + lam*np.eye(deg+1, dtype=int))**(-1),np.dot(Amat.T,Y_train))
    losshistory = [] 
    #random weights initialized
    w = np.atleast_2d(np.random.randn(deg+1)).T
    for i in range(numiter): 
        loss = np.square(y - w[0] - np.dot(Amat, w)) + lam*C(w_analytical)
        whistory.append(w)
        losshistory.append(loss)
        grad = np.dot(-2*Amat.T, y - w[0] - Amat.dot(w)) + lam*2*w_analytical
        w = w - rate*grad
    return w, np.asarray(whistory), np.asarray(losshistory)

def model(degree,rate=0.0001, num_iters = 50, lam = 0.5):
    A_test =  designmatpoly(X_test,degree)
    A_train = designmatpoly(X_train,degree)
    wfin, whist, meanlosstrace = gradientdescent(A_train, Y_train, rate, num_iters, lam, degree)
    return wfin, A_test

degrees = []
sq_res_means = []
for i in range(1,10):
    wfin, A_test = model(degree=i)
    degrees.append(i)
    Y_pred = np.dot(A_test,wfin)
    sqrm = sq_res_mean(Y_pred,Y_test)
    sq_res_means.append(sqrm)
    print("deg",i,"sq_res_mean",sqrm)

Функция потери: enter image description here

1 Ответ

0 голосов
/ 28 ноября 2018

Я не уверен, учитывая все числа, пролетающие с разреженными именами переменных, но численная проблема заключается в том, что при любом градусе выше линейного ваш вектор w экспоненциально выходит из-под контроля, пока не переполнится;вот почему вы получаете значения NaN.

Функционально ваш вычисленный градиент имеет величину, не пропорциональную вашему вектору w;даже при низкой скорости обучения достаточно быстро ввести w в дивергенцию.rate*grad по-прежнему имеет большую величину, чем w.

Я предлагаю вам инициализировать вашу матрицу простой системой с известным решением и наблюдать первые 2 или 3 итерации при deg = 2, и посмотретьпросто как расчеты не соответствуют вашим ожиданиям.

...