Короткий ответ:
- При настройке большого количества данных (скажем, нескольких миллионов точек данных) расчет стоимости или градиента занимает очень много времени, потому что нам необходимо суммировать по всем точкам данных.
- Нам НЕ нужно иметь точный градиент, чтобы уменьшить стоимость в данной итерации. Некоторое приближение градиента будет работать хорошо.
- Стохастический градиент достойного (SGD) аппроксимирует градиент, используя только одну точку данных. Таким образом, оценка градиента экономит много времени по сравнению с суммированием по всем данным.
- При «разумном» количестве итераций (это число может составлять пару тысяч и намного меньше, чем число точек данных, которые могут быть миллионами), приличный стохастический градиент может получить разумное хорошее решение.
Длинный ответ:
Мое обозначение следует за курсом обучения Эндрю Н.Г. Если вы не знакомы с ним, вы можете просмотреть серию лекций здесь .
Давайте предположим регрессию на квадрате потерь, функция стоимости
J( θ ) = 12 мΣя = 1м( чθ( х( я )) - у( я ))2
и градиент
dJ( θ )dθ= 1мΣя = 1м( чθ( х( я )) - у( я )) х( я )
для градиента достойного (GD), мы обновляем параметр
θn e w= θо л г- α 1мΣя = 1м( чθ( х( я )) - у( я )) х( я )
1 / мИкс( я ), у( я )
θн е wзнак равно θо л г- α ⋅ ( чθ( х( я)) - у( я)) х( я )
Вот почему мы экономим время:
Предположим, у нас есть 1 миллиард точек данных.
В GD, чтобы обновить параметры один раз, нам нужен (точный) градиент. Это требует суммирования этих 1 миллиарда точек данных для выполнения 1 обновления.
В SGD мы можем думать об этом как о попытке получить приближенный градиент вместо точного градиента . Аппроксимация исходит из одной точки данных (или нескольких точек данных, называемых мини-пакетами). Поэтому в SGD мы можем очень быстро обновить параметры. Кроме того, если мы «зациклим» все данные (называемые одной эпохой), у нас фактически будет 1 миллиард обновлений.
Хитрость в том, что в SGD вам не нужно иметь 1 миллиард итераций / обновлений, а гораздо меньше итераций / обновлений, скажем, 1 миллион, и у вас будет «достаточно хорошая» модель для использования.
Я пишу код для демонстрации идеи. Сначала мы решаем линейную систему с помощью нормального уравнения, а затем решаем ее с помощью SGD. Затем мы сравниваем результаты в терминах значений параметров и конечных значений целевой функции. Чтобы визуализировать это позже, у нас будет 2 параметра для настройки.
set.seed(0);n_data=1e3;n_feature=2;
A=matrix(runif(n_data*n_feature),ncol=n_feature)
b=runif(n_data)
res1=solve(t(A) %*% A, t(A) %*% b)
sq_loss<-function(A,b,x){
e=A %*% x -b
v=crossprod(e)
return(v[1])
}
sq_loss_gr_approx<-function(A,b,x){
# note, in GD, we need to sum over all data
# here i is just one random index sample
i=sample(1:n_data, 1)
gr=2*(crossprod(A[i,],x)-b[i])*A[i,]
return(gr)
}
x=runif(n_feature)
alpha=0.01
N_iter=300
loss=rep(0,N_iter)
for (i in 1:N_iter){
x=x-alpha*sq_loss_gr_approx(A,b,x)
loss[i]=sq_loss(A,b,x)
}
Результаты:
as.vector(res1)
[1] 0.4368427 0.3991028
x
[1] 0.3580121 0.4782659
124.1343123.0355
Вот значения функции стоимости за итерации, мы можем видеть, что она может эффективно уменьшить потери, что иллюстрирует идею: мы можем использовать подмножество данных для аппроксимации градиента и получения «достаточно хороших» результатов.
1000sq_loss_gr_approx
3001000