Алгоритм градиентного спуска не будет сходиться
я пытаюсь написать немного кода для алгоритма градиентного спуска, объясненного в лекции по машинному обучению в Стэнфорде (лекция 2 около 25: 00). Ниже приведена реализация, которую я использовал сначала, и я думаю, что она правильно скопирована с лекции, но она не сходится, когда я добавляю большие числа (>8
) к тренировочному набору.
я ввожу число X
и point (X,X)
добавляется в тренировочный набор, поэтому на данный момент я только пытаюсь чтобы заставить его сходиться к y=ax+b
здесь a=1=theta[1]
и b=0=theta[0]
.
Обучающим набором является array x
и y
, где (x[i],y[i])
точка.
void train()
{
double delta;
for (int i = 0; i < x.size(); i++)
{
delta = y[i]-hypothesis(x[i]);
theta[1] += alpha*delta*x[i];
theta[0] += alpha*delta*1;
}
}
void C_Approx::display()
{
std::cout<<theta[1]<<"x + "<<theta[0]<<" t "<<"f(x)="<<hypothesis(1)<<std::endl;
}
некоторые из результатов, которые я получаю:
Я ввожу номер, он работает train()
несколько раз, потом display()
1
0.33616x + 0.33616 f(x)=0.67232
1
0.482408x + 0.482408 f(x)=0.964816
1
0.499381x + 0.499381 f(x)=0.998762
1
0.499993x + 0.499993 f(x)=0.999986
1
0.5x + 0.5 f(x)=1
пример того, как он расходится после того, как он прошел 8
:
1
0.33616x + 0.33616 f(x)=0.67232
2
0.705508x + 0.509914 f(x)=1.21542
3
0.850024x + 0.449928 f(x)=1.29995
4
0.936062x + 0.330346 f(x)=1.26641
5
0.951346x + 0.231295 f(x)=1.18264
6
0.992876x + 0.137739 f(x)=1.13062
7
0.932206x + 0.127372 f(x)=1.05958
8
1.00077x + 0.000493063 f(x)=1.00126
9
-0.689325x + -0.0714712 f(x)=-0.760797
10
4.10321e+08x + 4.365e+07 f(x)=4.53971e+08
11
1.79968e+22x + 1.61125e+21 f(x)=1.9608e+22
12
-3.9452e+41x + -3.26957e+40 f(x)=-4.27216e+41
я попробовал предложенное решение здесь масштабирования шага и в конечном итоге с аналогичными результатами. Что такое Я поступаю неправильно?
6 ответов
ваша реализация хороша. Как правило, стохастический градиентный спуск может расходиться, когда α слишком велик. Что бы вы сделали с большим набором данных, возьмите случайную выборку разумного размера, найдите α, которая даст вам лучшие результаты, а затем используйте ее для остальных.
Я испытал ту же проблему (хотя и на Java), потому что моя скорость обучения была слишком большой.
Короче говоря, я использовал α = 0.001
и мне пришлось подтолкнуть ее к 0.000001
чтобы увидеть реальное сближение.
Конечно, эти значения связаны с вашим набором данных.
когда ваша функция стоимости увеличивается или циклически вверх и вниз, у вас обычно слишком большое значение для alpha
. Что?!--0--> вы используете?
начинается с alpha = 0.001
и посмотреть, сходится ли это? Если не попробовать различные alphas
(0.003, 0.01, 0.03, 0.1, 0.3, 1)
и найти тот, который быстро сходится.
масштабирование данных (нормализация) не поможет вам только с 1 функцией (ваш theta[1]
) как нормализация применяется только к 2+
характеристики (множественная линейная регрессия).
также имейте в виду, что для небольшого количества функций, вы можете использовать нормальное уравнение, чтобы получить правильный ответ.
используйте поиск обратной линии, чтобы гарантировать конвергенцию. Это очень просто реализовать. См. Стивен Бойд, выпуклая оптимизация для справки. Вы можете выбрать некоторые стандартные альфа -, бета-значения для поиска обратной линии, например 0.3 и 0.8.
Если я правильно вас понимаю, ваш набор тренировок имеет ненулевой градиент только на краю линии? Если вы не начнете с линии (на самом деле начните точно с одной из ваших точек обучения), вы не найдете линию. Вы всегда на местном минимуме.
это не чисто из вашего описания, какую проблему вы решаете. Также очень опасно размещать ссылки на внешние ресурсы - вы можете быть заблокированы в stackoverflow.
в любом случае - метод градиентного спуска и (субградиентный спуск тоже) с фиксированным размером шага (сообщество ML называет его скоростью обучения) не должны обязательно сходиться.
п.С. Сообщество машинного обучения не интересует "условие конвергенции" и "конвергенция к чему" - их интересует создайте "что-то", которое пройдет перекрестную проверку с хорошим результатом.
Если вам интересно узнать об оптимизации-начните искать в выпуклой оптимизации. К сожалению, трудно найти работу на нем, но он добавляет чистое видение в то, что происходит в различных математических оптимизациях.
вот исходный код, который демонстрирует его для простой квадратичной цели:
#!/usr/bin/env python
# Gradiend descend method (without stepping) is not converged for convex
# objective
alpha = 0.1
#k = 10.0 # jumping around minimum
k = 20.0 # diverge
#k = 0.001 # algorithm converged but gap to the optimal is big
def f(x): return k*x*x
def g(x): return 2*k*x
x0 = 12
xNext = x0
i = 0
threshold = 0.01
while True:
i += 1
xNext = xNext + alpha*(-1)*(g(xNext))
obj = (xNext)
print "Iteration: %i, Iterate: %f, Objective: %f, Optimality Gap: %f" % (i, xNext, obj, obj - f(0.0))
if (abs(g(xNext)) < threshold):
break
if i > 50:
break
print "\nYou launched application with x0=%f,threshold=%f" % (x0, threshold)