- Вопрос или проблема
- Укажите каталог данных
- Проверьте, существует ли каталог ‘data’, если нет, создайте его
- Скачайте наборы данных, если они не существуют
- Возможно, вам потребуется изменить URL в зависимости от того, где размещены наборы данных
- Загрузите обучающие и тестовые наборы данных
- Убедитесь, что y является вектором-столбцом
- Разделите данные на обучающие и валидационные наборы
- Используйте X и y, которые уже загружены и определены
- Получите размеры из обучающего набора
- Параметры алгоритма
- Функция потерь, описанная Чжаном в разделе 5 “Численные результаты”
- Градиент функции потерь
- Полный расчет градиента представлен в Алгоритме 2
- Тестирование для различных размеров мини-партий
- Ответ или решение
- Контекст проблемы
- Основные детали проблемы
- Решение проблемы
- Заключение
Вопрос или проблема
импортировать ос
импортировать 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,)
, что абсолютно не соответствует количеству элементов.
Основные детали проблемы
-
Размерность массива: Если
y
имеет размер 2233188, это означает, что у вас есть 2233188 примеров. Вы не можете преобразовать его в массив размерности (123,), так как это требует только 123 элемента. Ошибка возникает из-за несоответствия между количеством элементов массива и желаемой размерностью. -
Место возникновения ошибки: Ошибка, скорее всего, возникает в функции
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 или среза.
Заключение
Ошибки при попытке изменить размер массивов часто возникают из-за несоответствия между количеством элементов и ожидаемой размерностью. Применяйте проверки и используйте динамические подходы к изменению размерности, чтобы адаптироваться к различным входным данным. Это обеспечит большую устойчивость вашего кода и предотвратит неожиданное поведение в будущем.