Обработка нескольких очень больших матриц - PullRequest
0 голосов
/ 30 марта 2020

Здравствуйте и спасибо за чтение этого вопроса.

Я заинтересован в решении линейных задач наименьших квадратов. Для этого я написал следующий код:

import numpy


def create_orthogonal_matrix(dimension):
    """
    :param dimension: The desired dimensions of the matrix.
    :return: Random dimension x dimension sized orthogonal matrix.
    """
    H = numpy.random.randn(dimension, dimension)
    return numpy.linalg.qr(H)[0]


def generate_benign_eigenvalues(beta=4):
    """
    :return: Sorted (descending) list of length number_of_parameters of eigenvalues which agrees with the required properties.
    """
    eigenvalues = [0] * number_of_parameters
    for k in range(1, number_of_parameters + 1):
        eigenvalues[k - 1] = (k ** (-1)) * (numpy.log(k + 1) ** (-beta))
    eigenvalues.sort(reverse=True)
    return eigenvalues


def generate_population_covariance(eigenvalues=[]):
    """
    :param eigenvalues: Sorted list (descending order) of number_of_parameters desired positive eigenvalues for covariance.
    :return: Square root of a  Random symmetric positive definite matrix dimensions number_of_parameters x number_of_parameters with the desired eigenvalues.
    """
    eigenvectors = create_orthogonal_matrix(len(eigenvalues))
    sqrt_of_cov = eigenvectors @ numpy.diag(numpy.sqrt(eigenvalues))
    return sqrt_of_cov


def generate_benign_data(sigma=0.1):
    """
    :param sigma: Standard deviation of noise
    :return: Data x shaped population_size x number_of_parameters of distributed N(0, cov) with required eigenvalues. y distributed N(0, 1) real.
    """
    eigenvalues = generate_benign_eigenvalues()
    sqrt_cov = generate_population_covariance(eigenvalues)
    x = numpy.zeros((population_size, number_of_parameters))
    for i in range(population_size):
        x[i] = sqrt_cov @ numpy.random.standard_normal(number_of_parameters)
    noise = numpy.random.normal(loc=0, scale=sigma, size=x.shape[0])
    noise = numpy.reshape(noise, (len(noise), 1))
    y = x @ actual_solution + noise
    y = numpy.reshape(y, (len(y), 1))
    return x, y


def train_test_split(x, y):
    """
    :param x: Entire population data
    :param y: Entire population targets
    :return: Split to train and test sets in the order x_train, y_train, x_test, y_test
    """
    x_train, y_train = x[:training_sample_size], y[:training_sample_size]
    x_test, y_test = x[training_sample_size:], y[training_sample_size:]
    return x_train, y_train, x_test, y_test


# Problem setup
population_size = 2000
training_sample_size = int(0.2 * population_size)
testing_sample_size = population_size - training_sample_size

number_of_parameters = training_sample_size * int(numpy.sqrt(training_sample_size))
actual_solution = numpy.random.uniform(-50, 50, number_of_parameters)
actual_solution = numpy.reshape(actual_solution, (number_of_parameters, 1))  # We want to find this.


x, y = generate_benign_data()
x_train, y_train, x_test, y_test = train_test_split(x, y)

# Find best fit and compare errors with random guess.
solution_for_training_set = numpy.linalg.lstsq(x_train, y_train, rcond=None)[0]
random_solution = numpy.random.uniform(-50, 50, number_of_parameters)
random_solution = numpy.reshape(random_solution, (number_of_parameters, 1))

train_mse_best_fit = (numpy.linalg.norm(x_train @ solution_for_training_set - y_train) ** 2) / training_sample_size
test_mse_best_fit = (numpy.linalg.norm(x_test @ solution_for_training_set - y_test) ** 2) / testing_sample_size
test_mse_random = (numpy.linalg.norm(x_test @ random_solution - y_test) ** 2) / testing_sample_size

print("Results on benign covariance:")
print("Training set error with best training solution = ", train_mse_best_fit)
print("Testing set error with best training solution = ", test_mse_best_fit)
print("Testing set error with random solution = ", test_mse_random)

Проще говоря, я рисую матрицу x из многомерного нормального распределения со средним нулем и некоторой специальной ковариационной матрицей (случайной, но с фиксированными собственными значениями) , создайте скрытый вектор решения actual_solution и вектор шума noise, и наш целевой вектор y = x @ actual_solution + noise

Меня интересует решение задачи линейной регрессии w_best = argmin |xw - y|^2

Код Я написал отлично работает и дает желаемый результат.

Проблема в том, что, когда параметр pop_size становится относительно большим (ничего лишнего), я получаю исключения из памяти. Например, если pop_size равен 10000, то матрица H в create_orthogonal_matrix равна 88000 x 88000.

Я знаю, что некоторые люди работают с гигантскими матрицами, поэтому это должно быть выполнимо. Я просто не знаю, как они это делают. Кто-нибудь может помочь, пожалуйста?

Для пояснения : Я понимаю, что тренировка только на 20% данных и с таким большим количеством параметров - верный способ переобучиться, но это нормально. Я заинтересован в переоснащении. Однако теория говорит, что если собственные значения ковариационной матрицы нормального распределения, из которого мы производим выборку, обладают определенным специальным свойством, то у нас будет хорошая тестовая ошибка, несмотря на нашу исходную позицию переоснащения, поэтому игнорируйте это.

...