Найти в Дзене
Георгий Багаев

Градиентный спуск на языке программирования Python.

Доброго времени суток, сегодня поговорим о градиентном спуске, что это, зачем он нужен и как его сделать в коде с помощью языка программирования Python.

Градиентный спуск, метод градиентного спуска — численный метод нахождения локального минимума или максимума функции с помощью движения вдоль градиента, один из основных численных методов современной оптимизации.

Активно используется в вычислительной математике не только для непосредственного решения задач оптимизации (минимизации), но и для задач, которые могут быть переписаны на языке оптимизации (решение нелинейных уравнений, поиск равновесий, обратные задачи и т. д.). Метод градиентного спуска можно использовать для задач оптимизации в бесконечномерных пространствах, например, для численного решения задач оптимального управления.

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

Алгоритм, как находить минимум функции с помощью градиентного спуска:

1) Выбрать начальную точку.

2) Сделать шаг спуска — сдвинуться из этой точки против направления градиента. Получить новую точку.

3) Повторять второй шаг, пока не подойдём к минимуму достаточно близко.

Сделаем шаг спуска для функции f(x, y)=0.5⋅x**2+0.2⋅y**2.

В уравнении функции два слагаемых, каждое из которых — квадратичная функция от одной переменной. Минимум каждой находится в её вершине, а значит, минимум данной функции f(x, y) достигается в точке (0, 0). В качестве начальной выберем точку недалеко от неё, например, (1, 2).

Вычислим градиент функции: ∇f(x, y)=(x, 0.4y).

Код вычисления:

import numpy as np

# Используем векторную запись точки.

x = np.array([1, 2])

def f(x):

# f(x) = 0.5x^2 + 0.2y^2

return 0.5*x[0]**2 + 0.2*x[1]**2

def grad(x):

# grad(x) = [x, 0.4y]

dx = x[0]

dy = 0.4 * x[1]

return np.array([dx, dy])

print("Точка 0:", x)

print("f(x) =", f(x))

print()

# Двигаем точку против градиента.

x = x - grad(x)

print("Точка 1:", x)

print("f(x) =", f(x))

Результат:

Точка 0: [1 2]

f(x) = 1.3

Точка 1: [0. 1.2]

f(x) = 0.288

Когда мы подходим к минимуму ближе, есть риск перешагнуть через него. Поэтому при подсчёте новой точки размер шага нужно изменять. Это можно сделать, просто домножая градиент на какое-то маленькое число k=xk−1−∇f(xk−1)⋅γ. Символ γ — это строчная греческая буква, читается как «гамма».Этот коэффициент имеет много названий: «коэффициент обучения», «скорость обучения» (по-английски — “learning rate”) и другие. Часто встречается название «размер шага» или «длина шага». Формально это не верно: фактический размер шага равен произведению этого коэффициента и градиента функции. Также можно встретить обозначения разными буквами, самые популярные:α,γ,η.

Мы будем называть этот множитель коэффициентом скорости градиентного спуска и обозначать как γ.

Градиентный спуск для функций не двух параметров

С помощью градиентного спуска можно находить точки минимума функции не только двух параметров.

В одномерном случае мы просто изменяем только одну переменную и вместо градиента используем производную: Xnew​=Xold​−f′(Xold​).

В случае, когда переменных больше двух, всё остаётся так же, как и в двумерном: Xnew​=Xold​−∇f(Xold​), только градиент и x содержат больше элементов.

Алгоритм и код совершенно такие же, как и для функции двух переменных.

Градиентный спуск для функции трёх переменных:

f(x, y, z) = x**2+2*y**2+z**4

Код нахождения минимума этой функции:

import numpy as np

def f(x):

return x[0]**2 + 2*x[1]**2 + x[2]**4

def grad(x):

return np.array([2*x[0], 4*x[1], 4*x[2]**3])

# Стартовая точка

x = np.array([1.5, 2, 3])

gamma = 1e-2

max_iter = 10

eps = 1e-4

f_old = f(x)

x = x - grad(x) * gamma

f_new = f(x)

i = 0

while abs(f_old - f_new) > eps and i < max_iter:

i = i + 1

f_old = f_new

print(f(x))

x = x - grad(x) * gamma

f_new = f(x)

print(f(x))

Результат

23.123244959999997

16.04923590375929

12.817007917327011

10.876852546622995

9.52954769703004

8.506928194534112

7.68482259419216

6.997967477278678

6.408685637343532

5.893557173839507

5.437115515211021

Пример решения задачи:

Известно, что функция имеет минимум недалеко от точки (1, 2, −3).Найдите точку, в которой функция f(x, y, z) = xln(x)+y**2+z**2 принимает значения меньше -0.36. Воспользуйтесь для этого градиентным спуском.Определите функции f и grad для вычисления значения f(x, y, z) и её градиента в коде.

Сохраните итоговую точку в переменной result и выведите значение функции f в этой точке.

Решение задачи методом градиентного спуска в коде на языке программирования Python.
Решение задачи методом градиентного спуска в коде на языке программирования Python.

Результат вычислений, минимум функции здесь последнее число в столбце.
Результат вычислений, минимум функции здесь последнее число в столбце.

Задача выполнена, значение в которой функция f(x, y, z) = xln(x)+y**2+z**2 принимает значения меньше -0.36, последнее число в столбце.

Кроме того, градиентный спуск может использоваться для оптимизации параметров управления космическими аппаратами, такими как направление или сила тяги двигателей, что может улучшить эффективность и точность при выполнении космических миссий. Такие задачи могут решаться с помощью методов оптимизации, включая градиентный спуск.

Здесь используется библиотека numpy. Она подключается оператором import -"import numpy as np".

Для того чтобы , библиотека numpy заработала необходимо установить ее сначала , командой pip install numpy и убедитесь , что используете последнюю версию Python. Команду необходимо вводить в cmd.exe.

В других ОС, существуют подобные командные строки, я работаю в операционной системе Windows.

В этом коде есть оператор def c помощью него мы создаем функцию grad(x).

«Житейский» пример функции: каждому человеку можно однозначно поставить в соответствие его биологического отца.

Аналогично, заранее заданный алгоритм по значению входного данного выдаёт значение выходного данного. В нашем примере кода присутствует оператор while, это цикл.

Цикл while в Python. Цикл while (“пока”) позволяет выполнять одну и ту же последовательность действий, пока проверяемое условие истинно. Условие записывается до тела цикла и проверяется до выполнения тела цикла. Как правило, цикл while используется, когда невозможно заранее определить точно количество шагов.

Ссылка на другую мою статью, про обратные матрицы и транспонирование матриц: https://dzen.ru/media/id/5f572502b7204709f04ab67c/primer-vychisleniia-obratnoi-matricy-v-kode-na-iazyke-programmirovaniia-python-640ae49697036f7610331184

Чтобы запустить этот код в среде разработки Python нужно в меню выбрать пункт File->New File, в появившемся окне набрать код или скопировать его туда, проверить ошибки, в меню появившегося окна выбрать Run->Run Module, программа выполнится.

Вот-так, относительно просто можно получить обратные матрицы и транспонировать матрицы в языке программирования Python.

Маленькая просьба, поставить лайк в Дзене, если Вам понравилась публикация и подписаться, это поможет развитию канала: https://dzen.ru/id/5f572502b7204709f04ab67c