Градиентный спуск (ч. 1)



😔 Всем привет! Сегодня я бы хотел вам рассказать про то, что такое градиентный спуск и вообще для чего он применяется, в каких направлениях и для чего. Градиент отражает направление скорейшего возрастания функции



💳 Начнем с линейной ргерессии, для тех кто не помнит / не знает, уравнение прямой задается yi = wi * xi, где yi - значение целевого признака. Это конечно замечательно, но истинные значения (если мы живем в непрерывном пространстве будут всегда различаться от предсказанных (какая-то ошибка возникнет).



🍦 Решение задачи - минимизировать ошибки, возникаемые при изучении модели. Но как мы это можем сделать, если у нас xi, yi заданы? Правильно, повлиять как-то на веса признаков. Для линейной регрессии обычно используется такая функция потерь, как MSE, которую мы хотим минимизировать. Градиентный спуск позволяет найти веса модели, при которых ошибка будет минимальна (осторожно, модель может найти локальный / глобальный минимум). Мы хотим понять, при каких значения wi наше значение ошибки будет минимально. Почему берется MSE, могу рассказать в следующих частях



👌 У градиентного спуска есть 3 параметра:

1) начальная точка, в нашем контексте - это вектор весов признаков (выбираются случайно)

2) количество итераций, мы определяем заранее сколько итеративно нам нужно пройтись, чтобы прийти к точке, близкой к минимуму

3) коэффициент скорости обучения (Learning Rate). Если мы будем выбирать слишком маленький шаг, то можем за ограниченное количество итераций не прийти в точку минимума (функции потерь в нашем случае), а если Learning Rate будет слишком большим, то мы можем перепрыгнуть точку минимума.

4*) количество эпох и размер батчей - это используется для стохастического градиентного спуска.



в общем виде:



start_point = i

iterations = n

learning_rate = t



for _ in range(iterations):

start_point -= t * gradient(x)



start_point, func(start_point)



Это позволит нам найти минимум функции итерационно, в нашем контексте - функции потерь.



Игрушечный пример с градиентным спуском.





import numpy as np



def loss_function(x):

return x ** 2 * np.sin(x)



def gradient(x):

return 2 * x * np.sin(x) + x**2 * np.cos(x)



def gradient_descent(starting_point, learning_rate, num_iterations):

x = starting_point

for _ in range(num_iterations):

x -= learning_rate * gradient(x)

return x



starting_point = 3 # Начальная точка, выбирается случайно

learning_rate = 0.01 # Скорость обучения

num_iterations = 100 # Количество итераций



minimum = gradient_descent(starting_point, learning_rate, num_iterations)



В этом примере minimum = argmin(x), т.е. точка в которой достигается минимум функции, а соответствующее значение можно найти, если подставить значения в loss_function(minimum).



Эта техника применяется в различных моделях машинного обучения, в нейронных сетях и др., о чем я более подробно хочу написать в следующих постах.



Где можно почитать подробней?



Учебник Яндекса (с формулками)

Статья на Хабр

Презентация от Александра Дьяконова



Если хотите больше постов, связанных с ML или около того, ставьте реакции, пишите комментарии!