Градиентный спуск и метод нормальных уравнений для решения линейной регрессии дают различные решения
я работаю над проблемой машинного обучения и хотите использовать линейную регрессию в качестве алгоритма обучения. Я реализовал 2 разных метода поиска параметров theta
модели линейной регрессии: градиентный (самый крутой) спуск и нормальное уравнение. На одних и тех же данных они оба должны давать примерно равные theta
вектор. Однако они этого не делают.
и theta
векторы очень похожи на все элементы, кроме первого. Это тот, который используется для умножения вектора всех 1 добавленных данных.
вот как theta
S выглядит так (первый столбец-выход градиентного спуска, второй выход нормального уравнения):
Grad desc Norm eq
-237.7752 -4.6736
-5.8471 -5.8467
9.9174 9.9178
2.1135 2.1134
-1.5001 -1.5003
-37.8558 -37.8505
-1.1024 -1.1116
-19.2969 -19.2956
66.6423 66.6447
297.3666 296.7604
-741.9281 -744.1541
296.4649 296.3494
146.0304 144.4158
-2.9978 -2.9976
-0.8190 -0.8189
что может вызвать разницу в theta(1, 1)
возвращается градиентным спуском по сравнению с theta(1, 1)
возвращается нормальным уравнением? У меня есть ошибка в коде?
вот моя реализация нормального уравнения в Matlab:
function theta = normalEque(X, y)
[m, n] = size(X);
X = [ones(m, 1), X];
theta = pinv(X'*X)*X'*y;
end
вот код для градиентного спуска:
function theta = gradientDesc(X, y)
options = optimset('GradObj', 'on', 'MaxIter', 9999);
[theta, ~, ~] = fminunc(@(t)(cost(t, X, y)),...
zeros(size(X, 2), 1), options);
end
function [J, grad] = cost(theta, X, y)
m = size(X, 1);
X = [ones(m, 1), X];
J = sum((X * theta - y) .^ 2) ./ (2*m);
for i = 1:size(theta, 1)
grad(i, 1) = sum((X * theta - y) .* X(:, i)) ./ m;
end
end
I передайте точно такие же данные X
и y
для обеих функций (я не нормализую X
).
Edit 1:
на основе ответов и комментариев я проверил несколько мой код и запустить некоторые тесты.
сначала я хочу проверить, может ли проблема быть вызвана X beeing рядом с сингулярным, как предложено @user1489497 ответ. Поэтому я заменил pinv на inv-и при запуске я действительно получил предупреждение Matrix is close to singular or badly scaled.
. Чтобы быть уверенным, что это не проблема я получил гораздо больший набор данных и запуск тестов с этим новым набором данных. На этот раз inv(X)
не отображается предупреждение и использование pinv
и inv
дал такие же результаты. Так что я надеюсь, что X
больше не близок к сингулярному.
затем сменил normalEque
код, как предложил by щепы Итак, теперь это выглядит так:
function theta = normalEque(X, y)
X = [ones(size(X, 1), 1), X];
theta = pinv(X)*y;
end
однако проблема все еще существует. Новый normalEque
функция на новых данных, которые не близко к единственному дает разные theta
as gradientDesc
.
чтобы узнать, какой алгоритм глючит, я запустил алгоритм линейной регрессии программного обеспечения для интеллектуального анализа данных Weka на тех же данных. Weka вычисленная тета очень похожа на выход normalEque
но отличается от выхода gradientDesc
. Так что я думаю, что normalEque
правильная и в gradientDesc
.
вот это theta
s вычисляется Weka,normalEque
и GradientDesc
:
Weka(correct) normalEque gradientDesc
779.8229 779.8163 302.7994
1.6571 1.6571 1.7064
1.8430 1.8431 2.3809
-1.5945 -1.5945 -1.5964
3.8190 3.8195 5.7486
-4.8265 -4.8284 -11.1071
-6.9000 -6.9006 -11.8924
-15.6956 -15.6958 -13.5411
43.5561 43.5571 31.5036
-44.5380 -44.5386 -26.5137
0.9935 0.9926 1.2153
-3.1556 -3.1576 -1.8517
-0.1927 -0.1919 -0.6583
2.9207 2.9227 1.5632
1.1713 1.1710 1.1622
0.1091 0.1093 0.0084
1.5768 1.5762 1.6318
-1.3968 -1.3958 -2.1131
0.6966 0.6963 0.5630
0.1990 0.1990 -0.2521
0.4624 0.4624 0.2921
-12.6013 -12.6014 -12.2014
-0.1328 -0.1328 -0.1359
я также вычислял ошибки, как предложено ответ Джастина пила. Выход normalEque
дает немного меньшую квадратную ошибку, но разница незначительна. Более того когда я вычисляю градиент стоимости theta
С помощью функции cost
(такой же, как тот, который используется gradientDesc
) у меня градиент около нуля. То же самое сделано на выходе gradientDesc
не дает градиента вблизи нуля. Вот что я имею в виду:
>> [J_gd, grad_gd] = cost(theta_gd, X, y, size(X, 1));
>> [J_ne, grad_ne] = cost(theta_ne, X, y, size(X, 1));
>> disp([J_gd, J_ne])
120.9932 119.1469
>> disp([grad_gd, grad_ne])
-0.005172856743846 -0.000000000908598
-0.026126463200876 -0.000000135414602
-0.008365136595272 -0.000000140327001
-0.094516503056041 -0.000000169627717
-0.028805977931093 -0.000000045136985
-0.004761477661464 -0.000000005065103
-0.007389474786628 -0.000000005010731
0.065544198835505 -0.000000046847073
0.044205371015018 -0.000000046169012
0.089237705611538 -0.000000046081288
-0.042549228192766 -0.000000051458654
0.016339232547159 -0.000000037654965
-0.043200042729041 -0.000000051748545
0.013669010209370 -0.000000037399261
-0.036586854750176 -0.000000027931617
-0.004761447097231 -0.000000027168798
0.017311225027280 -0.000000039099380
0.005650124339593 -0.000000037005759
0.016225097484138 -0.000000039060168
-0.009176443862037 -0.000000012831350
0.055653840638386 -0.000000020855391
-0.002834810081935 -0.000000006540702
0.002794661393905 -0.000000032878097
этот предполагают, что градиентный спуск просто не сходится к глобальному минимуму... Но это вряд ли так, поскольку я запускаю его для тысяч итераций. так где же ошибка?
4 ответов
у меня наконец-то было время вернуться к этому. Нет никакого "жука".
если матрица вырождена, то существует бесконечно много решений. Вы можете выбрать любое решение из этого набора и получить одинаково хороший ответ. Решение pinv (X)*y является хорошим, что многим нравится, потому что это решение минимальной нормы.
никогда нет веской причины использовать inv (X)*y. Хуже того, использовать обратное для нормальных уравнений, таким образом, inv(X'*X)*X'*y-это просто числовое дерьмо. Я не заботьтесь, кто сказал вам использовать его, они ведут вас в неправильное место. (Да, это будет приемлемо для проблем, которые хорошо обусловлены, но большую часть времени вы не знаете, когда он собирается дать вам дерьмо. Так зачем им пользоваться?)
нормальные уравнения, как правило, плохо делать, даже если вы решаете регуляризованную проблему. Есть способы сделать это, чтобы избежать возведения в квадрат номера условия системы, хотя я не буду объяснять их, если их не спросят, поскольку этот ответ получил достаточно долго.
X\y также даст результат, который является разумным.
нет абсолютно никаких оснований бросать неограниченный оптимизатор на проблему, так как это даст результаты, которые нестабильны, полностью зависят от ваших начальных значений.
в качестве примера я начну с особой проблемы.
X = repmat([1 2],5,1);
y = rand(5,1);
>> X\y
Warning: Rank deficient, rank = 1, tol = 2.220446e-15.
ans =
0
0.258777984694222
>> pinv(X)*y
ans =
0.103511193877689
0.207022387755377
pinv и обратная косая черта возвращают немного разные решения. Как оказалось, есть базовое решение, к которому можно добавить любое сумма вектора nullspace для пространства строк X.
null(X)
ans =
0.894427190999916
-0.447213595499958
pinv генерирует решение минимальной нормы. Из всех решений, которые могли бы привести к этому, у этого есть минимум 2-норма.
напротив, обратная косая черта генерирует решение, в котором одна или несколько переменных будут равны нулю.
но если вы используете неограниченный оптимизатор, он будет генерировать решение, которое полностью зависит от ваших начальных значений. Опять же, ANLY количество этого нулевого вектора может добавьте к вашему решению, и у вас все еще есть полностью действительное решение с тем же значением суммы квадратов ошибок.
обратите внимание, что, хотя сингулярность waring не возвращается, это не означает, что ваша матрица не близка к сингулярной. Вы мало изменились в проблеме, поэтому она все еще близка, просто недостаточно, чтобы вызвать предупреждение.
Как уже говорили, плохо обусловленной матрицы гессиана, скорее всего, причиной вашей проблемы.
число шагов, которые стандартные алгоритмы градиентного спуска выполняют для достижения локального оптимума, является функцией наибольшего собственного значения гессиана, деленного на наименьшее (это известно как номер условия Гессиана). Таким образом, если ваша матрица плохо обусловлена, то для сходимости градиентного спуска к оптимуму может потребоваться чрезвычайно большое количество итераций. (Для единичный случай, он может сходиться ко многим пунктам, конечно.)
Я бы предложил попробовать три разные вещи, чтобы убедиться, что неограниченный алгоритм оптимизации работает для вашей проблемы (которая должна): 1) генерировать некоторые синтетические данные, вычисляя результат известной линейной функции для случайных входов и добавляя небольшое количество гауссовского шума. Убедитесь, что у вас гораздо больше точек данных, чем измерений. Это должно породить не-сингулярный гессиан. 2) Добавить условия регуляризации к вашей функции ошибки, чтобы увеличить номер условия гессиана. 3) Используйте метод второго порядка, такой как сопряженный градиент или L-BFGS, а не градиентный спуск, чтобы уменьшить количество шагов, необходимых для сходимости алгоритма. (Вы, вероятно, нужно сделать это в сочетании с #2).
не могли бы вы опубликовать немного больше о том, как вы X выглядит? Вы используете pinv (), который является псевдо-инверсией Мура-Пенроуза. Если матрица плохо обусловлена, это может вызвать проблемы с получением обратной. Я бы поспорил, что метод градиентного спуска ближе к отметке.
вы должны определить, какой метод на самом деле дает вам наименьшую ошибку. Это покажет, какой метод борется. Я подозреваю, что метод нормального уравнения является проблемным решением, потому что если X плохо обусловлен, тогда у вас могут быть некоторые проблемы.
вы, вероятно, должны заменить свое нормальное решение уравнения на theta = X\y
который будет использовать метод QR-декомпозиции для его решения.