Метод градиентного спуска и нормального уравнения для решения линейной регрессии дает разные решения
Я работаю над проблемой машинного обучения и хочу использовать линейную регрессию в качестве алгоритма обучения. Я реализовал 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
Я передаю точно такие же данныеX
а такжеy
к обеим функциям (я не нормализуюX
).
Основываясь на ответах и комментариях, я немного проверил свой код и провел несколько тестов.
Сначала я хочу проверить, может ли проблема быть вызвана тем, что X находится вблизи единственного числа, как это было предложено@ user1489497 ответ, Поэтому я заменил pinv на inv - и когда я его запустил, я действительно получил предупреждениеMatrix is close to singular or badly scaled.
, Чтобы убедиться, что это не проблема, я получил гораздо больший набор данных и провел тесты с этим новым набором данных. Этот разinv(X)
не отображать предупреждение и использованиеpinv
а такжеinv
дал те же результаты. Так что я надеюсь чтоX
is not close to singular any more.
затемI changed normalEque
code as suggested отщепки так что теперь это выглядит так:
function theta = normalEque(X, y)
X = [ones(size(X, 1), 1), X];
theta = pinv(X)*y;
end
However the problem is still there, новыйnormalEque
Функция на новых данных, которые не близки к единственному, дает разныеtheta
какgradientDesc
.
Чтобы выяснить, какой алгоритм содержит ошибки, я запустил алгоритм линейной регрессии программного обеспечения для интеллектуального анализа данных Weka на тех же данных. Weka вычислил тета очень похожий на выводnormalEque
но отличается от выводаgradientDesc
, Так что я думаю, чтоnormalEque
правильно иthere is a bug in 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
дает немного меньшую квадратичную ошибку, но разница незначительна. Что большеwhen I compute gradient of cost of theta
using function cost
(the same as the one used by gradientDesc
) I got gradient near zero, То же самое сделано на выходе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
Это предполагает, что градиентный спуск просто не сходится к глобальному минимуму ... Но это вряд ли так, поскольку я запускаю его тысячи итераций.So where is the bug?