<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=188.243.200.30&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=188.243.200.30&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/188.243.200.30"/>
		<updated>2026-06-10T19:26:49Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%BE%D1%85%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D1%83%D1%81%D0%BA&amp;diff=75094</id>
		<title>Стохастический градиентный спуск</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%BE%D1%85%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B3%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D1%83%D1%81%D0%BA&amp;diff=75094"/>
				<updated>2020-10-18T14:40:17Z</updated>
		
		<summary type="html">&lt;p&gt;188.243.200.30: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Стохастический градиентный спуск''' (англ. ''stochastic gradient descent'') $-$ оптимизационный алгоритм, отличающийся от обычного [https://ru.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D0%B4%D0%B8%D0%B5%D0%BD%D1%82%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D1%83%D1%81%D0%BA градиентного спуска] тем, что градиент оптимизируемой функции считается на каждом шаге не как сумма градиентов от каждого элемента выборки, а как градиент от одного, случайно выбранного элемента.&lt;br /&gt;
&lt;br /&gt;
== Обычный градиентный спуск ==&lt;br /&gt;
Для начала вспомним, как работает обычный градиентный спуск. Пусть объекты задаются $n$ числовыми признаками $f_j : X \to R, j = 1 ... n$ и пространство признаковых описаний в таком случае $X = R^n$. Пусть $Y$ $-$ конечное множество меток классов и задана обучающая выборка пар «объект-ответ» &amp;lt;tex&amp;gt;\{(x_1,y_1),\dots,(x_l,y_l)\}.&amp;lt;/tex&amp;gt; Пусть семейство алгоритмов $a(x, {\bf w})$ имеет параметр вектор весов $\bf w$. И пускай мы выбрали какую-нибудь функцию потерь. Для $i$-го объекта выборки для алгоритма с весами ${\bf w}$ обозначим ее &amp;lt;tex&amp;gt; \mathscr{L}_i({\bf w}) &amp;lt;/tex&amp;gt;. Необходимо минимизировать эмпирический риск, т.е. &amp;lt;tex&amp;gt;Q(w) = \sum\limits_{i=1}^l \mathscr{L}_i(w) \,\to\, \min\limits_{\bf w}&amp;lt;/tex&amp;gt;. Если функция потерь принадлежит классу $C_1(X)$, то можно применить метод градиентного спуска. Выберем ${\bf w}^{(0)}$ $-$ начальное приближение. Тогда каждый следующий вектор параметров будет вычисляться как ${\bf w}^{(t+1)}={\bf w}^{(t)} - h\sum\limits_{i=1}^{l}\nabla \mathscr{L}_i({\bf w}^{(t)})$, где $h$ - градиентный шаг, смысл которого заключается в том, насколько сильно менять вектор весов в направлении градиента. Остановка алгоритма будет определяться сходимостью $Q$ или $\bf w$.&lt;br /&gt;
&lt;br /&gt;
== Стохастический градиентный спуск ==&lt;br /&gt;
Проблема предыдущего алгоритма заключается в том, что чтобы определить новое приближение вектора весов необходимо вычислить градиент от каждого элемента выборки, что может сильно замедлять алгоритм. Идея ускорения алгоритма заключается в использовании только одного элемента, либо некоторой подвыборки для подсчета нового приближения весов. То есть теперь новое приближение будет вычисляться как ${\bf w}^{(t+1)}={\bf w}^{(t)} - h\nabla \mathscr{L}_i({\bf w}^{(t)})$, где $i$ $-$ случайно выбранный индекс. Так как теперь направление изменения $\bf w$ будет определяться за $O(1)$, подсчет $Q$ на каждом шаге будет слишком дорогостоящим. Для того, чтобы ускорить оценку $Q$, будем использовать приближенную рекуррентную формулу. Можно выбрать одну из следующих формул:&lt;br /&gt;
* среднее арифметическое: $\overline{Q}_m = \dfrac{1}{m}\varepsilon_m + \dfrac{1}{m}\varepsilon_{m - 1} + \dfrac{1}{m}\varepsilon_{m - 2} + \dots = \dfrac{1}{m}\varepsilon_m + (1 - \dfrac{1}{m})\overline{Q}_{m-1}$;&lt;br /&gt;
* экспоненциальное скользящее среднее: $\overline{Q}_m = \lambda\varepsilon_m + (1 - \lambda)\varepsilon_{m - 1} + (1 - \lambda)^2\varepsilon_{m - 2} + \dots = \lambda\varepsilon_m + (1-\lambda)\overline{Q}_{m - 1},$ где $\lambda$ $-$ темп забывания предыстории ряда.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
 '''def''' SGD(X, h, $\lambda$)''':''' &amp;lt;font color=green&amp;gt; # где X $-$ выборка, h $-$ градиентный шаг, а $\lambda$ $-$ темп забывания &amp;lt;/font&amp;gt;&lt;br /&gt;
    ${\bf w} =$ initialize_weights() &amp;lt;font color=green&amp;gt; # инициализировать веса &amp;lt;/font&amp;gt;&lt;br /&gt;
    $\overline{Q} = \frac{1}{l} \sum_{i=1}^{l}\mathscr{L}_i({\bf w})$ &amp;lt;font color=green&amp;gt;# инициализировать оценку функционала &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''while''' $Q$ not converges '''or''' ${\bf w}$ not converges''':'''&lt;br /&gt;
        $i =$ rand() % $l$ &amp;lt;font color=green&amp;gt; # случайно выбрать элемент, по которому будет считаться градиент &amp;lt;/font&amp;gt;&lt;br /&gt;
        $\varepsilon = \mathscr{L}_i({\bf w})$ &amp;lt;font color=green&amp;gt; # вычислить потерю &amp;lt;/font&amp;gt;&lt;br /&gt;
        ${\bf w} = {\bf w} - h \nabla \mathscr{L}_i({\bf w})$ &amp;lt;font color=green&amp;gt;# обновить вектор весов в направлении антиградиента&amp;lt;/font&amp;gt;&lt;br /&gt;
        $\overline{Q} = \lambda\varepsilon + (1 - \lambda)\overline{Q}$ &amp;lt;font color=green&amp;gt;# оценить функционал&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''return''' w&lt;br /&gt;
&lt;br /&gt;
== Эвристики ==&lt;br /&gt;
Существует несколько способов инициализировать веса:&lt;br /&gt;
* ${\bf w} = {\bf 0}$;&lt;br /&gt;
* $w_j = random(-\dfrac{1}{2n}, \dfrac{1}{2n})$. Стоит брать небольшие случайные веса, так как если выбрать их слишком большими, в некоторых случаях (к примеру в случае нейрона с [[Нейронные_сети,_перцептрон|функцией активациии]] равной арктангенсу) большие начальные значения веса могут привести в область с малыми по модулю производными, в связи с чем из такой области будет трудно выбраться;&lt;br /&gt;
* $w_j = \dfrac{\langle y, f_j \rangle}{\langle f_j, f_j \rangle}$, где $f_j = (f_j(x_i))_{i=1}^l$. Оценка оптимальная в случае, если функция потерь квадратична и признаки нескоррелированы, то есть $\langle f_j, f_k \rangle = 0, j \neq k$.&lt;br /&gt;
Так же можно запустить спуск несколько раз с разными начальными приближениями и выбрать лучшее решение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При выборе случайного элемента можно использовать следующие эвристики:&lt;br /&gt;
* брать объекты из разных классов;&lt;br /&gt;
* брать объекты, на которых ошибка больше, то есть чем меньше отступ (в метрических классификаторах расстояние от разделяющей поверхности до объекта) i-го объекта $M_i$, тем больше вероятность взять этот объект;&lt;br /&gt;
* брать объекты, на которых уверенность меньше, то есть чем меньше $|M_i|$, тем больше вероятность взять этот объект;&lt;br /&gt;
* не брать объекты, на которых уже высокая уверенность ($M_i &amp;gt; \mu_+$) либо не брать объекты-выбросы ($M_i&amp;lt;\mu_i$);&lt;br /&gt;
&lt;br /&gt;
Выбирать величину градиентного шага можно следующими способами:&lt;br /&gt;
* $h_t = \dfrac{1}{t}$;&lt;br /&gt;
* метод скорейшего градиентного спуска: $\mathscr{L}_i({\bf w} - h\nabla \mathscr{L}_i({\bf w})) \rightarrow \min\limits_h$;&lt;br /&gt;
* при квадратичной функции потерь можно использовать $h = ||x_i||^2$;&lt;br /&gt;
* иногда можно выполнять пробные шаги, а именно увеличивать $h$ для выбивания процесса из локальных минимумов;&lt;br /&gt;
* [https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9B%D0%B5%D0%B2%D0%B5%D0%BD%D0%B1%D0%B5%D1%80%D0%B3%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%80%D0%BA%D0%B2%D0%B0%D1%80%D0%B4%D1%82%D0%B0 метод Левенберга-Марквардта];&lt;br /&gt;
&lt;br /&gt;
== Регуляризация ==&lt;br /&gt;
Основным способом уменьшить переобучение является [[Регуляризация|регуляризация]], т.е. сокращение весов. Будем штрафовать за увеличение нормы вектора весов, для этого перепишем функцию потерь $\tilde{\mathscr{L}}_i({\bf w}) = \mathscr{L}_i({\bf w}) + \dfrac{\tau}{2}||w||^2 = \mathscr{L}_i({\bf w}) + \dfrac{\tau}{2} \sum\limits_{j=1}^nw_j^2 \rightarrow \min\limits_w$, где $\tau$ $-$ коэффициент регуляризации.&lt;br /&gt;
&lt;br /&gt;
Тогда градиент будет следующим: $\nabla \tilde{\mathscr{L}}_i({\bf w}) = \nabla \mathscr{L}_i({\bf w}) + \tau {\bf w}$, а градиентный шаг будет выглядеть так: ${\bf w} = {\bf w}(1 - h\tau) - h\nabla \mathscr{L}_i({\bf w})$.&lt;br /&gt;
&lt;br /&gt;
== Достоинства и недостатки ==&lt;br /&gt;
'''Достониства:'''&lt;br /&gt;
* легко реализуется;&lt;br /&gt;
* функция потерь и семейство алгоритмов могут быть любыми (если функция потерь не дифференцируема, ее можно аппроксимировать дифференцируемой);&lt;br /&gt;
* легко добавить регуляризацию;&lt;br /&gt;
* возможно потоковое обучение;&lt;br /&gt;
* подходит для задач с большими данными, иногда можно получить решение даже не обработав всю выборку;&lt;br /&gt;
'''Недостатки'''&lt;br /&gt;
* нет универсального набора эвристик, их нужно выбирать для конкретной задачи отдельно;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Пример кода scikit-learn == &lt;br /&gt;
Классификатор [https://scikit-learn.org/stable/modules/sgd.html sklearn.linear_model.'''SGDClassifier'''] имеет несколько параметров, например: &lt;br /&gt;
&lt;br /&gt;
'''loss''' $-$ функция потерь. По умолчанию используется &amp;quot;hinge&amp;quot;, дающая алгоритм линейного SVM;&lt;br /&gt;
&lt;br /&gt;
'''penalty''' $-$ метод регуляризации. По умолчанию &amp;quot;l2&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
'''alpha''' $-$ $\tau$, коэффициент регуляризации;&lt;br /&gt;
&lt;br /&gt;
'''learning_rate''' $-$ алгоритм изменения градиентного шага;&lt;br /&gt;
&lt;br /&gt;
'''eta0''' $-$ начальный градиентный шаг;&lt;br /&gt;
&lt;br /&gt;
'''shuffle''' перемешивать тренировочную выборку после каждой итерации;&lt;br /&gt;
&lt;br /&gt;
* Импортируем нужные библиотеки:&lt;br /&gt;
 '''from''' sklearn.linear_model '''import''' SGDClassifier&lt;br /&gt;
 '''from''' sklearn '''import''' datasets&lt;br /&gt;
 '''from''' sklearn.model_selection '''import''' train_test_split&lt;br /&gt;
&lt;br /&gt;
* Выберем тренировочное и тестовое множества:&lt;br /&gt;
 iris = datasets.'''load_iris()'''&lt;br /&gt;
 &lt;br /&gt;
 X = iris.data&lt;br /&gt;
 y = iris.target&lt;br /&gt;
 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size='''0.3''')&lt;br /&gt;
&lt;br /&gt;
* Обучение:&lt;br /&gt;
 clf = SGDClassifier(shuffle = True)&lt;br /&gt;
 model = clf.'''fit'''(X_train, y_train)&lt;br /&gt;
&lt;br /&gt;
* Предсказание:&lt;br /&gt;
 y_pred = model.'''predict'''(X_test)&lt;br /&gt;
 model.'''score'''(X_test, y_test)&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Общие понятия]]&lt;br /&gt;
* [[Обзор библиотек для машинного обучения на Python]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://www.machinelearning.ru/wiki/images/5/53/Voron-ML-Lin-SG.pdf К.В. Воронцов {{---}} Линейные методы классификации и регрессии: метод стохастического градиента]&lt;br /&gt;
*[https://www.youtube.com/watch?v=4BKQ3GZR32w&amp;amp;list=PLJOzdkh8T5kp99tGTEFjH_b9zqEQiiBtC&amp;amp;index=4 Курс &amp;quot;Машинное обучение&amp;quot; {{---}} Линейные методы классификации: метод стохастического градиента {{---}} К.В. Воронцов]&lt;br /&gt;
*[https://en.wikipedia.org/wiki/Logistic_regression Wikipedia {{---}} Logistic regression]&lt;br /&gt;
*[https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier.decision_function sklearn.linear_model.SGDClassifier {{---}} описание алгоритма]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Машинное обучение]]&lt;/div&gt;</summary>
		<author><name>188.243.200.30</name></author>	</entry>

	</feed>