- Вопрос или проблема
- Ответ или решение
- Почему градиентный спуск расходится: технический анализ проблемы
- 1. Характеристика ваших данных
- 2. Проблема с размером шага (Learning Rate)
- 3. Инициализация параметров
- 4. Масштабирование данных
- 5. Динамика чередования градиентного спуска
- Рассмотрим комбинацию рекомендаций
- Заключение
Вопрос или проблема
Я вручную создал случайный набор данных вокруг некоторого среднего значения и попытался использовать градиентный спуск для линейной регрессии, чтобы предсказать это простое среднее значение.
Я сделал точно так же, как в руководстве, и по какой-то причине коэффициенты моего предсказателя стремятся к бесконечности, хотя это работало в другом случае.
Почему в этом случае он не может предсказать простое значение 1.4?
clear all;
n=10000;
t=1.4;
sigma_R = t*0.001;
min_value_t = t-sigma_R;
max_value_t = t+sigma_R;
y_data = min_value_t + (max_value_t - min_value_t) * rand(n,1);
x_data=[1:10000]';
m=0
c=0
L=0.0001
epochs=1000 %итерации
for i=1:epochs
y_pred=m.*x_data+c;
D_m=(-2/n)*sum(x_data.*(y_data-y_pred));
D_c=(-2/n)*sum((y_data-y_pred));
m=m-L*D_m;
c=c-L*D_c;
end
plot(x_data,y_data,'.')
hold on;
grid;
plot(x_data,y_pred)
Обновление: Я попытался переписать ваш код на языке Matlab, который я лучше знаю. Мои матрицы признаков в виде NX2 [1,X_data] называются Xmat. Я следовал каждому шагу при преобразовании кода, и у меня в обоих Theta получаются NAN. Где я ошибся?
%%начало кода Matlab
n=1000;
t=1.4;
sigma_R = t*0.001;
min_value_t = t-sigma_R;
max_value_t = t+sigma_R;
y_data = min_value_t + (max_value_t - min_value_t) * rand(n,1);
x_data=[1:1000];
L=0.0001; %скорость обучения
%plot(x_data,y_data);
itter=1000;
theta_0=0;
theta_1=0;
theta=[theta_0;theta_1];
itter=1000;
for i=1:itter
onss=ones(1,1000);
x_mat=[onss;x_data]';
pred=x_mat*theta;
residuals = (pred-y_data);
for k=1:2 %начало цикла theta
partial=2*dot(residuals,x_mat(:,k));
theta(k)=theta(k)-L*partial;
end%конец цикла theta
end %конец цикла итераций
%%конец кода matlab
```
Хотя данный ответ показывает код на Python, теория остается точно такой же. Два совета при запуске линейной регрессии с использованием градиентного спуска с нуля:
- используйте матричную нотацию для ваших данных признаков (т.е. входных данных), чтобы вы могли применять это к n-мерным наборам данных (а не только 1-D, как в этом случае)
- нормализуйте данные вашей матрицы признаков (хотя в этом случае у вас на самом деле 1-D, это хорошая практика, которая всегда работает)
Ваши данные, построенные с помощью matplotlib:
import numpy as np
from numpy.random import randn, seed
x_data = 20 * randn(1000) + 100
y_data = x_data + (10 * randn(1000) + 50)
n=1000
t=1.4
sigma_R = t*0.001
min_value_t = t-sigma_R
max_value_t = t+sigma_R
y_data = min_value_t + (max_value_t - min_value_t) * np.random.rand(n,1)
x_data=np.array(range(1000))
pyplot.scatter(x_data, y_data)
pyplot.show()
Создание вашего набора данных для обучения модели:
final_df_DICT = {'X': x_data}
import pandas as pd
H = pd.DataFrame(final_df_DICT)
feature_matrix = np.zeros(n*2)
feature_matrix.shape = (n, 2)
feature_matrix[:,0] = 1
feature_matrix[:,1] = H['X']
#нормализация признаков
feature_matrix = (feature_matrix - feature_matrix.mean()) / feature_matrix.std()
target_data = y_data.reshape(len(y_data), )
Посмотрите на матрицу признаков, в которой первый столбец заполнен единицами, а второй столбец содержит реальные x_data:
Обучение модели с вашими гиперпараметрами:
w = [0, 0]
L=0.0001
epochs=1000
iteration = 0
cost=[]
while iteration < epochs:
pred = np.dot(feature_matrix, w)
residuals = pred-target_data
#мы вычисляем градиент для 2 коэффициентов при помощи скалярного произведения
for i in range(len(w)):
partial = 2*np.dot(residuals, feature_matrix[:, i])
w[i] = w[i] - L*partial
iteration += 1
computed_cost = np.sum(np.power((pred - target_data), 2)) / n
cost.append(computed_cost)
print('коэффициенты: {}'.format(w))
print('стоимость: {}'.format(cost[-1]))
Результат:
коэффициенты: [-1.80963253e+00 -6.15189807e-06] стоимость: 6.466287828899486e-07
Давайте нарисуем предсказания модели линейной регрессии на исходном наборе данных (мы обучались на всем наборе данных, не принимая во внимание никакой валидационный набор в этом случае…):
my_predictions = np.dot(feature_matrix, w)
pyplot.scatter(feature_matrix[:, 1], target_data)
pyplot.scatter(feature_matrix[:, 1], my_predictions, color="r")
pyplot.show()
Ответ или решение
Почему градиентный спуск расходится: технический анализ проблемы
Градиентный спуск — это мощный метод оптимизации, широко используемый в задачах регрессии и машинного обучения. Однако его основные параметры, такие как скорость обучения и начальные условия, значительно влияют на его производительность. В вашем случае результаты градиентного спуска divergируют, что требует более глубокого анализа.
1. Характеристика ваших данных
Вы создадите набор данных с использованием 1.4
как целевой средней величины, добавляя небольшие случайные колебания, что теоретически должно привести к концу меньшего стандартного отклонения. Однако, несмотря на это, результаты предсказания уходят к бесконечности. Рассмотрим несколько причин этого поведения.
2. Проблема с размером шага (Learning Rate)
Скорость обучения (L
) — один из критически важных параметров gradient descent. В вашем случае вы указали L=0.0001
. Эта скорость может быть слишком низкой, но также существует вероятность, что она слишком высока для входящих данных, что может привести к осциллированию и расходимости.
Рекомендации:
- Попробуйте использовать более высокие значения скорости обучения, например,
L=0.001
илиL=0.01
, и наблюдайте за поведением алгоритма. - Однако, если используете высокую скорость, внимательно следите за значениями
theta
; они могут нарастать слишком быстро и начать выдаватьNaN
.
3. Инициализация параметров
Инициализация коэффициентов также имеет значение. Если параметры инициализируются неправильно (например, затирание нулями слишком близко к вашему целевому значению), это может привести к проблемам при минимизации функции потерь.
Рекомендации:
- Попробуйте инициализировать параметры случайными значениями или небольшими ненулевыми числами.
4. Масштабирование данных
Большое значение входных переменных, таких как x_data
, может привести к значительному увеличению величины градиентов, что может вызвать нестабильность алгоритма. Стандартизация или нормализация фичей может помочь избежать этой проблемы.
Рекомендации:
- Примените стандартизацию ваших данных, чтобы нормализовать ваши признаки. Например, вы можете сместить и разделить данные, чтобы их среднее значение было равно 0 и стандартное отклонение — 1.
5. Динамика чередования градиентного спуска
В вашем примере используется for
-цикл для расчета вашего градиента для каждого коэффициента. Алгоритм в данном случае проходит через два цикла, что может дополнительно усложнить процесс. Попробуйте заменить это на матричные операции для оптимизации производительности.
Рекомендации:
- Рассмотрите возможность реализации матричных вычислений для обновления
theta
, что позволит избежать двух вложенных циклов и повысит скорость обучения.
Рассмотрим комбинацию рекомендаций
Применение рекомендаций выше вероятно решение проблемы расходимости. Пример изменения кода может выглядеть следующим образом:
L = 0.001; % Измененное значение скорости обучения
theta = rand(2, 1); % Случайная инициализация параметров
for i = 1:itter
pred = x_mat * theta;
residuals = (pred - y_data);
% Применение векторизованного расчета градиента
gradient = (2/n) * (x_mat' * residuals);
theta = theta - L * gradient;
end
Заключение
Оптимизация градиентного спуска требует тщательной настройки различных параметров. Правильный выбор скорости обучения, инициализация параметров, предварительная обработка данных и оптимизированный расчет градиента — все эти элементы могут значительно повлиять на результат. Следуя предложенным рекомендациям, вы сможете решить проблему расходимости вашей модели и достичь стабильных и предсказуемых результатов.