ValueError: не удалось изменить размер массива размером 2233188 в форму (123,)

Вопрос или проблема

импортировать ос
импортировать matplotlib.pyplot как plt # для создания графиков
импортировать numpy как np # для математических операций
импортировать время # для расчета времени расхода
из sklearn.datasets импортировать load_svmlight_file # загрузка наборов данных a8a и a8a.t
из sklearn.preprocessing импортировать StandardScaler #
из sklearn.model_selection импортировать train_test_split # для разделения данных
из sklearn.metrics импортировать accuracy_score # для измерения точности
из sklearn.linear_model импортировать LogisticRegression
из scipy.sparse импортировать csr_matrix # модель scipy для обработки разреженной матрицы (обеспечивает, чтобы матрица была разреженной)

Укажите каталог данных

Проверьте, существует ли каталог ‘data’, если нет, создайте его

data_dir=”data”
если не os.path.exists(data_dir):
os.makedirs(data_dir)

Скачайте наборы данных, если они не существуют

Возможно, вам потребуется изменить URL в зависимости от того, где размещены наборы данных

a8a_url = “https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/a8a”
a8a_t_url = “https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/a8a.t”

a8a_path = os.path.join(data_dir, ‘a8a’)
a8a_t_path = os.path.join(data_dir, ‘a8a.t’)

импортировать urllib.request # Для загрузки файлов

если не os.path.exists(a8a_path):
urllib.request.urlretrieve(a8a_url, a8a_path)
print(f”Скачан набор данных ‘a8a’ в {a8a_path}”)

если не os.path.exists(a8a_t_path):
urllib.request.urlretrieve(a8a_t_url, a8a_t_path)
print(f”Скачан набор данных ‘a8a.t’ в {a8a_t_path}”)

Загрузите обучающие и тестовые наборы данных

X, y = load_svmlight_file(os.path.join(data_dir, ‘a8a’)) # Обучающий набор данных
X_test, y_test = load_svmlight_file(os.path.join(data_dir, ‘a8a.t’)) # Тестовый набор данных

Убедитесь, что y является вектором-столбцом

y = y.reshape(-1, 1)
y_test = y_test.reshape(-1, 1) # Обеспечьте согласованность для тестового набора

Разделите данные на обучающие и валидационные наборы

Используйте X и y, которые уже загружены и определены

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)

Получите размеры из обучающего набора

n, d = X.shape # Количество обучающих образцов (22696) и признаки (размерность) (123)
w0 = np.zeros(d) # начальное значение w0, имеет ту же размерность, что и d

Параметры алгоритма

lambda_ = 0.01 # параметр регуляризации
eta0 = 0.01 # скорость обучения, описанная в алгоритме 2
alpha = 0.1 # скорость обучения гиперградиента, описанная в алгоритме 2
m = 15 # Размер внутреннего цикла (итерация)
n_iters = 30 # Размер внешнего цикла (эпоха)
batch_sizes = [300, 400, 500, 600] # Размеры мини-партий для тестирования

Функция потерь, описанная Чжаном в разделе 5 “Численные результаты”

def loss(w, X, y, lambda_):
z = X.dot(w)
return np.log(1 + np.exp(-y*z)) + (lambda_ / 2) * np.linalg.norm(w)**2

Градиент функции потерь

def grad_loss(w, y, X, lambda_):
z = X @ w # матричное умножение
y = y.flatten() # Убедитесь, что y – это 1D
return -( X.T * y) @ (1 / (1 + np.exp(z * y))) + lambda_*w

Полный расчет градиента представлен в Алгоритме 2

def full_grad(w, y, X, lambda_):
n = X.shape[0]
z = X @ w # Это работает с разреженными матрицами
# Измените форму y, чтобы убедиться, что это вектор-столбец и избежать проблем с трансляцией
y = y.reshape(-1, 1)
exp_term = y / (1 + np.exp(y * z))
grad = (X.T @ exp_term) / n + lambda_ * w.reshape(-1, 1) # Измените форму w на (123, 1)
# Измените форму grad обратно в исходную форму w, если необходимо
grad = grad[:123] # Измените форму grad на форму w (123,)
return grad

def SFR_SARAH_HD(X_train, y_train, n_iters, eta0, batch_size):
n, d = X_train.shape # Используйте X_train здесь
w0 = np.zeros(d) # Инициализация весов
# Используйте y_train вместо y
z0 = full_grad(w0, y_train, X_train, lambda_) # Используйте X_train здесь
total_time = 0 # Время установлено в ноль

for outer_iter in range(n_iters):
    start = time.perf_counter()
    indices = np.random.permutation(n)
    X_shuffled = X_train[indices]  # Создайте перемешанную копию X_train
    v0 = z0
    d0 = -v0
    grad_eta_delta = 0

    for k in range(m):
        # Измените форму d0, чтобы соответствовать w0 перед выполнением операции
        # Убедитесь, что d0 имеет правильное количество элементов для изменения формы
        d0_reshaped = d0.reshape(w0.shape) если d0.shape != w0.shape иначе d0
        w = w0 + eta0 * d0_reshaped
        mini_batch = np.random.choice(n, size=batch_size, replace=False)

        # Предполагается, что mini_batch_grad определен где-то еще и ожидает одномерный массив для w
        grad_w = mini_batch_grad(w, X_shuffled, y_train[indices], mini_batch) # используйте X_shuffled и y_train[indices]
        grad_w0 = mini_batch_grad(w0, X_shuffled, y_train[indices], mini_batch) # используйте X_shuffled и y_train[indices]

        h = grad_w * grad_eta_delta
        eta = abs(eta0 - alpha * h)
        v = grad_w - grad_w0 + v0
        beta = np.linalg.norm(v) ** 2 / np.linalg.norm(v0) ** 2
        d = -v + beta * d0
        v0 = v

    z0 = v0
    w0 = w

    end = time.perf_counter()
    total_time += (end - start)

return total_time

Тестирование для различных размеров мини-партий

time_consume=[]
results = {}
для batch_size в batch_sizes: # эта итерация по мини-партиям
print(f”Запуск SFR-SARAH-HD с размером мини-партий: {batch_size}”)
time_consumed = SFR_SARAH_HD(X_train, y_train, n_iters, eta0, batch_size)
results[batch_size] = time_consumed
print(f”Размер мини-партий {batch_size}: Общее время {time_consumed:.4f} секунд”)

для outer_iter в range(n_iters): # эта итерация по epoch()
start_time=time.time()
time.sleep(1)
end_time = time.time()
time_taken = end_time-start_time

time_consume.append(time_taken)

Ответ или решение

Ошибка ValueError: cannot reshape array of size 2233188 into shape (123,) возникает, когда вы пытаетесь изменить размер массива numpy, чтобы он соответствовал неправильным значениям. Давайте разберемся с этой проблемой более детально.

Контекст проблемы

Исходя из предоставленного вами фрагмента кода, вы загружаете и обрабатываете наборы данных с использованием методов из библиотеки scikit-learn. Как видно, вы работаете с разреженными матрицами и разделяете данные на обучающую и тестовую выборки.

Когда вы вызываете функцию reshape, чтобы превратить массив y в столбец, это предполагает, что количество элементов в массиве соответствует количеству строк, которые вы хотите получить. В вашем случае, в коде вы работаете с массивом y размерностью 2233188, а после этого пытаетесь изменить его размер на (123,), что абсолютно не соответствует количеству элементов.

Основные детали проблемы

  1. Размерность массива: Если y имеет размер 2233188, это означает, что у вас есть 2233188 примеров. Вы не можете преобразовать его в массив размерности (123,), так как это требует только 123 элемента. Ошибка возникает из-за несоответствия между количеством элементов массива и желаемой размерностью.

  2. Место возникновения ошибки: Ошибка, скорее всего, возникает в функции full_grad, где вы используете y = y.reshape(-1, 1). Если y уже имеет размер (n,), функции reshape применяются некорректно, так как это размер 1D массива, который не соответствует тому, что вы ожидаете.

Решение проблемы

Чтобы избежать подобной ошибки, выполните следующие шаги:

  • Проверьте размерность массива: Изучите, где и как вы применяете reshape. Например, вместо жесткого задания размерности, проверьте фактическое количество элементов:

    print(y.shape)
  • Измените подход к reshape: Вместо того чтобы задавать фиксированное значение, используйте y.reshape(-1, 1), если вы хотите, чтобы y всегда воспринимался как столбцовый вектор, тогда как .flatten() будет меняться в зависимости от размера:

    y = y.reshape(-1, 1)  # Позволит избежать ValueError для y любой размерности
  • Измените функции, которые зависят от длины: Убедитесь, что все функции, где вы используете y, ожидают соответствующий формат. Ваша функция full_grad должна также корректно обрабатывать входы, проверяя фактическую длину перед любыми операциями reshape или среза.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...