Метод Градиентного Спуска: Как Шаг за Шагом Уменьшать Значение Функции

Метод градиентного спуска — это один из базовых численных подходов для нахождения минимума функции нескольких переменных. Его часто используют тогда, когда нужно постепенно приближаться к точке, в которой значение функции становится меньше. В этой статье рассмотрим основную идею метода, запишем итерационную формулу, объясним роль длины шага и покажем, как можно вычислять градиент, если частные производные не заданы явно.

Метод Градиентного Спуска: Основная Идея Минимизации

Рассмотрим функцию нескольких переменных

\[ f(\bar{x})=f(x_1,x_2,\dots,x_n), \]

где \( \bar{x} \) — это вектор переменных.

Минимизировать такую функцию означает найти такую точку \( \bar{x} \), в которой значение \( f(\bar{x}) \) будет наименьшим или хотя бы локально наименьшим в некоторой области. Само слово «локально» здесь важно. Ведь метод градиентного спуска в общем случае не всегда находит глобальный минимум. Обычно он приводит к локальному минимуму, который зависит от начальной точки и свойств функции.

Чтобы понять, куда двигаться, используют градиент функции. Для функции нескольких переменных он имеет вид

\[ \nabla f(\bar{x})= \left( \frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \dots, \frac{\partial f}{\partial x_n} \right). \]

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

Градиент указывает направление самого быстрого возрастания функции. А нам нужно уменьшать значение функции, не так ли? Поэтому двигаться нужно в противоположном направлении: \( -\nabla f(\bar{x}) \). Это направление называют антиградиентным. Именно оно показывает, в какую сторону нужно сделать шаг, чтобы значение функции уменьшалось быстрее всего вблизи текущей точки.

Итак, на первом этапе важно запомнить простую идею: метод начинает работу с некоторой точки, находит в ней градиент и движется в направлении, противоположном ему.

Начальное Приближение: Как Строится Итерационный Процесс

Теперь перейдем от идеи к алгоритму. Сначала нужно выбрать начальное приближение:

\[ \bar{x}^{(0)}= \left( x_1^{(0)}, x_2^{(0)}, \dots, x_n^{(0)} \right). \]

Это стартовая точка, с которой начинаются вычисления. Выбор этой точки имеет значение. Если функция сложная и имеет несколько локальных минимумов, то разные начальные точки могут привести к разным результатам.

После выбора \( \bar{x}^{(0)} \) вычисляют градиент в этой точке: \( \nabla f(\bar{x}^{(0)}) \). Далее выполняют первый шаг в направлении антиградиента:

\[ \bar{x}^{(1)} = \bar{x}^{(0)}-\alpha\cdot \nabla f(\bar{x}^{(0)}), \qquad \alpha>0. \]

Здесь \( \alpha \) — текущая длина шага. Она показывает, насколько далеко мы переходим от начальной точки в направлении убывания функции.

После этого получаем новую точку

\[ \bar{x}^{(1)}= \left( x_1^{(1)}, x_2^{(1)}, \dots, x_n^{(1)} \right). \]

На следующей итерации уже работаем не с начальной точкой, а с новым приближением. Поэтому снова вычисляем градиент, но уже в точке \( \bar{x}^{(1)} \), и переходим к точке \( \bar{x}^{(2)} \):

\[ \bar{x}^{(2)} = \bar{x}^{(1)}-\alpha\cdot \nabla f(\bar{x}^{(1)}), \qquad \alpha>0. \]

Таким образом, шаг за шагом строится последовательность приближений. В общем виде ее можно записать так:

\[ \bar{x}^{(k+1)} = \bar{x}^{(k)}-\alpha\cdot \nabla f(\bar{x}^{(k)}), \qquad k=0,1,2,\dots \]

где \( \alpha \) — текущая длина шага, которая используется при переходе от \( \bar{x}^{(k)} \) к \( \bar{x}^{(k+1)} \).

Эта формула является основой метода. Она показывает, как из текущей точки \( \bar{x}^{(k)} \) перейти к следующей точке \( \bar{x}^{(k+1)} \). При этом каждый переход выполняется с учетом направления убывания функции.

Длина Шага: Как Избежать Неудачного Перехода

После записи итерационной формулы возникает важный практический вопрос: как выбрать длину шага \( \alpha \)? Ведь именно она определяет, насколько сильно мы сместимся в антиградиентном направлении.

Если шаг слишком мал, метод может двигаться очень медленно. Если же шаг слишком большой, можно перейти слишком далеко и получить не меньшее, а большее значение функции. Поэтому после каждого перехода желательно проверять, действительно ли функция уменьшилась:

\[ f(\bar{x}^{(k+1)})<f(\bar{x}^{(k)}). \]

Если это условие выполняется, то новую точку можно принять. В таком случае текущее значение \( \alpha \) можно оставить для следующей итерации.

Если же значение функции не уменьшилось или даже увеличилось, тогда длину шага нужно уменьшить. Один из простых способов — разделить шаг пополам:

\[ \alpha \leftarrow \frac{\alpha}{2}. \]

После этого новую точку вычисляют еще раз, но уже с меньшим шагом:

\[ \bar{x}^{(k+1)} = \bar{x}^{(k)}-\alpha\cdot \nabla f(\bar{x}^{(k)}). \]

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

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

\[ \|\nabla f(\bar{x}^{(k)})\|<\varepsilon. \]

Также можно использовать условие близости двух соседних приближений:

\[ \|\bar{x}^{(k+1)}-\bar{x}^{(k)}\|<\varepsilon. \]

Или условие малого изменения значения функции:

\[ |f(\bar{x}^{(k+1)})-f(\bar{x}^{(k)})|<\varepsilon. \]

Здесь \( \varepsilon \) — заданная точность вычислений.

С теоретической точки зрения, если локальный минимум достигается внутри области, то в этой точке выполняется условие

\[ \nabla f(\bar{x})=0. \]

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

Вычисление Градиента: Что Делать Без Явных Производных

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

Но что делать, если частные производные найти сложно? Или если функция задана так, что ее значение можно вычислить, но явный вид производных неудобен? В таком случае элементы градиента можно приближенно вычислять численно.

Для переменной \( x_i \) можно использовать формулу односторонней разности:

\[ \frac{\partial f}{\partial x_i}\approx \frac{ f(x_1,\dots,x_i+\Delta x_i,\dots,x_n)- f(x_1,\dots,x_i,\dots,x_n) }{ \Delta x_i }, \qquad i=1,2,\dots,n. \]

Здесь \( \Delta x_i \) — малое приращение переменной \( x_i \). Идея простая: мы немного изменяем одну переменную, оставляем остальные без изменений и смотрим, как изменилось значение функции.

Для большей точности иногда используют центральную разность:

\[ \frac{\partial f}{\partial x_i}\approx \frac{ f(x_1,\dots,x_i+\Delta x_i,\dots,x_n)- f(x_1,\dots,x_i-\Delta x_i,\dots,x_n) }{ 2\Delta x_i }. \]

Эта формула обычно дает более точное приближение, но требует больше вычислений значений функции. Поэтому на практике выбор способа зависит от того, что важнее: скорость или точность.

Итак, метод градиентного спуска можно применять не только тогда, когда градиент задан явно. Его можно использовать и в численной форме, если мы умеем вычислять значение самой функции.

Практическая Часть: Метод Градиентного Спуска Для Функции Двух Переменных

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

Пример 1. Найти минимальное значение функции \( f(x_1,x_2)=(x_1-1)^2+(x_2+2)^2 \) с точностью \( \varepsilon=0.05 \) методом градиентного спуска

График функции \( f(x_1,x_2)=(x_1-1)^2+(x_2+2)^2 \)

Рассмотрим функцию:

\[ f(x_1,x_2)=(x_1-1)^2+(x_2+2)^2. \]

Это функция двух переменных \( x_1 \) и \( x_2 \). Она имеет простой аналитический вид, поэтому с ее помощью удобно показать, как шаг за шагом применяется метод градиентного спуска.

Возьмем начальное приближение

\[ \bar{x}^{(0)}=(3,2). \]

Также выберем текущую длину шага \( \alpha=0.25 \). Условие остановки будем проверять по правилу

\[ \|\bar{x}^{(k+1)}-\bar{x}^{(k)}\|<0.05. \]

Для метода градиентного спуска используем формулу

\[ \bar{x}^{(k+1)} = \bar{x}^{(k)} -\alpha\cdot \nabla f(\bar{x}^{(k)}). \]

Сначала найдем градиент заданной функции. Для этого вычислим частные производные:

\[ \frac{\partial f}{\partial x_1}=2\cdot (x_1-1), \qquad \frac{\partial f}{\partial x_2}=2\cdot (x_2+2). \]

Следовательно,

\[ \nabla f(x_1,x_2)= \left( 2\cdot (x_1-1), 2\cdot (x_2+2) \right). \]

Начинаем первую итерацию. В начальной точке \( \bar{x}^{(0)}=(3,2) \) градиент равен

\[ \nabla f(3,2)= \left( 2\cdot (3-1), 2\cdot (2+2) \right) = (4,8). \]

Тогда новое приближение вычисляем так:

\[ \bar{x}^{(1)} = (3,2)-0.25\cdot(4,8). \]

Отсюда

\[ \bar{x}^{(1)} = (3,2)-(1,2)=(2,0). \]

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

\[ f(3,2)=(3-1)^2+(2+2)^2=20. \]

В новой точке имеем

\[ f(2,0)=(2-1)^2+(0+2)^2=5. \]

Поскольку

\[ 5<20, \]

переход выполнен успешно. Следовательно, текущее значение \( \alpha=0.25 \) можно оставить для следующей итерации.

Теперь проверим условие точности:

\[ \|\bar{x}^{(1)}-\bar{x}^{(0)}\| = \sqrt{(2-3)^2+(0-2)^2}. \]

Поэтому

\[ \|\bar{x}^{(1)}-\bar{x}^{(0)}\| =\sqrt{1+4} =\sqrt{5} \approx 2.236. \]

Поскольку

\[ 2.236>0.05, \]

вычисления продолжаем.

Переходим ко второй итерации. Берем точку

\[ \bar{x}^{(1)}=(2,0). \]

Вычисляем градиент в этой точке:

\[ \nabla f(2,0)= \left( 2\cdot (2-1), 2\cdot (0+2) \right) = (2,4). \]

Тогда

\[ \bar{x}^{(2)} = (2,0)-0.25\cdot(2,4). \]

Следовательно,

\[ \bar{x}^{(2)} = (2,0)-(0.5,1)=(1.5,-1). \]

Значение функции в этой точке равно

\[ f(1.5,-1)=(1.5-1)^2+(-1+2)^2. \]

Получаем

\[ f(1.5,-1)=0.5^2+1^2=1.25. \]

Поскольку

\[ 1.250<5, \]

второй шаг также является успешным. В этом примере после каждого выполненного перехода значение функции уменьшается, поэтому уменьшать шаг \( \alpha \) не нужно.

Проверим точность:

\[ \|\bar{x}^{(2)}-\bar{x}^{(1)}\| = \sqrt{(1.5-2)^2+(-1-0)^2} \approx 1.118. \]

Поскольку

\[ 1.118>0.05, \]

переходим к следующей итерации.

Продолжение итерационного процесса

Для третьей итерации имеем

\[ \bar{x}^{(2)}=(1.5,-1). \]

Вычисляем градиент:

\[ \nabla f(1.5,-1)= \left( 2\cdot (1.5-1), 2\cdot (-1+2) \right) = (1,2). \]

Тогда

\[ \bar{x}^{(3)} = (1.5,-1)-0.25\cdot(1,2). \]

Отсюда

\[ \bar{x}^{(3)} = (1.5,-1)-(0.25,0.5)=(1.25,-1.5). \]

Вычислим значение функции:

\[ f(1.25,-1.5)=(1.25-1)^2+(-1.5+2)^2. \]

Поэтому

\[ f(1.25,-1.5)=0.25^2+0.5^2=0.313. \]

Получаем

\[ 0.313<1.25. \]

Следовательно, значение функции снова уменьшилось.

Теперь проверим условие точности:

\[ \|\bar{x}^{(3)}-\bar{x}^{(2)}\| = \sqrt{(1.25-1.5)^2+(-1.5+1)^2} \approx 0.559. \]

Поскольку

\[ 0.559>0.05, \]

вычисления продолжаем.

Для четвертой итерации берем

\[ \bar{x}^{(3)}=(1.25,-1.5). \]

Находим градиент:

\[ \nabla f(1.25,-1.5)= \left( 2\cdot (1.25-1), 2\cdot (-1.5+2) \right) = (0.5,1). \]

Тогда

\[ \bar{x}^{(4)} = (1.25,-1.5)-0.25\cdot(0.5,1). \]

Получаем

\[ \bar{x}^{(4)} = (1.25,-1.5)-(0.125,0.25)=(1.125,-1.75). \]

Значение функции равно

\[ f(1.125,-1.75)=(1.125-1)^2+(-1.75+2)^2. \]

После вычисления имеем

\[ f(1.125,-1.75)=0.125^2+0.25^2=0.078. \]

Поскольку

\[ 0.078<0.313, \]

переход принимаем.

Проверяем точность:

\[ \|\bar{x}^{(4)}-\bar{x}^{(3)}\| = \sqrt{(1.125-1.25)^2+(-1.75+1.5)^2} \approx 0.280. \]

Поскольку

\[ 0.280>0.05, \]

нужно выполнить еще одну итерацию.

Для пятой итерации имеем

\[ \bar{x}^{(4)}=(1.125,-1.75). \]

Вычисляем градиент:

\[ \nabla f(1.125,-1.75)= \left( 2\cdot (1.125-1), 2\cdot (-1.75+2) \right) = (0.25,0.5). \]

Тогда

\[ \bar{x}^{(5)} = (1.125,-1.75)-0.25\cdot(0.25,0.5). \]

Отсюда

\[ \bar{x}^{(5)} = (1.125,-1.75)-(0.063,0.125)=(1.063,-1.875). \]

Значение функции в этой точке:

\[ f(1.063,-1.875)=(1.063-1)^2+(-1.875+2)^2. \]

Следовательно,

\[ f(1.063,-1.875) \approx 0.063^2+0.125^2 \approx 0.02. \]

Получаем

\[ 0.02<0.078, \]

поэтому точку \( \bar{x}^{(5)} \) принимаем.

Проверяем условие остановки:

\[ \|\bar{x}^{(5)}-\bar{x}^{(4)}\| = \sqrt{(1.063-1.125)^2+(-1.875+1.75)^2} \approx 0.14. \]

Поскольку

\[ 0.14>0.05, \]

итерационный процесс пока не завершаем.

Далее выполним еще две итерации в той же последовательности: вычисляем градиент, делаем шаг в направлении антиградиента, проверяем уменьшение функции и условие точности.

Для шестой итерации берем

\[ \bar{x}^{(5)}=(1.063,-1.875). \]

Градиент в этой точке равен

\[ \nabla f(1.063,-1.875) \approx \left( 2\cdot (1.063-1), 2\cdot (-1.875+2) \right) = (0.125,0.25). \]

Тогда

\[ \bar{x}^{(6)} = (1.063,-1.875)-0.25\cdot(0.125,0.25). \]

Получаем

\[ \bar{x}^{(6)} = (1.063,-1.875)-(0.031,0.063) = (1.031,-1.938). \]

Значение функции:

\[ f(1.031,-1.938) = (1.031-1)^2+(-1.938+2)^2 \approx 0.005. \]

Снова видим уменьшение значения функции:

\[ 0.005<0.02. \]

Теперь проверим точность:

\[ \|\bar{x}^{(6)}-\bar{x}^{(5)}\| = \sqrt{(1.031-1.063)^2+(-1.938+1.875)^2} \approx 0.07. \]

Поскольку

\[ 0.07>0.05, \]

выполняем еще одну итерацию.

Для седьмой итерации имеем

\[ \bar{x}^{(6)}=(1.031,-1.938). \]

Вычисляем градиент:

\[ \nabla f(1.031,-1.938) \approx \left( 2\cdot (1.031-1), 2\cdot (-1.938+2) \right) = (0.063,0.125). \]

Тогда

\[ \bar{x}^{(7)} = (1.031,-1.938)-0.25\cdot(0.063,0.125). \]

Отсюда

\[ \bar{x}^{(7)} = (1.031,-1.938)-(0.016,0.031) = (1.016,-1.969). \]

Вычислим значение функции:

\[ f(1.016,-1.969) = (1.016-1)^2+(-1.969+2)^2 \approx 0.001. \]

Поскольку

\[ 0.001<0.005, \]

последний переход также уменьшил значение функции.

Теперь снова проверяем условие точности:

\[ \|\bar{x}^{(7)}-\bar{x}^{(6)}\| = \sqrt{(1.016-1.031)^2+(-1.969+1.938)^2} \approx 0.035. \]

Поскольку

\[ 0.035<0.05, \]

итерационный процесс можно завершить.

Последним найденным приближением является

\[ \bar{x}^{(7)}=(1.016,-1.969). \]

Поэтому приближенно точку минимума можно записать так:

\[ \bar{x}^{*}\approx(1.016,-1.969). \]

Теперь найдем приближенное минимальное значение функции:

\[ f_{\min}\approx f(1.016,-1.969). \]

Подставляем найденное приближение:

\[ f(1.016,-1.969) = (1.016-1)^2+(-1.969+2)^2. \]

Следовательно,

\[ f(1.016,-1.969) = 0.016^2+0.031^2 \approx 0.001. \]

Таким образом, методом градиентного спуска получаем

\[ \bar{x}^{*}\approx(1.016,-1.969), \qquad f_{\min}\approx 0.001. \]

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

\( k \) \( \bar{x}^{(k)} \) \( f(\bar{x}^{(k)}) \) \( \|\bar{x}^{(k)}-\bar{x}^{(k-1)}\| \)
\( 0 \) \( (3,2) \) \( 20 \) —
\( 1 \) \( (2,0) \) \( 5 \) \( 2.236 \)
\( 2 \) \( (1.5,-1) \) \( 1.25 \) \( 1.118 \)
\( 3 \) \( (1.25,-1.5) \) \( 0.313 \) \( 0.559 \)
\( 4 \) \( (1.125,-1.75) \) \( 0.078 \) \( 0.28 \)
\( 5 \) \( (1.063,-1.875) \) \( 0.02 \) \( 0.14 \)
\( 6 \) \( (1.031,-1.938) \) \( 0.005 \) \( 0.07 \)
\( 7 \) \( (1.016,-1.969) \) \( 0.001 \) \( 0.035 \)

Сравнение с точным ответом

Проверим, как найденный результат согласуется с точным ответом. Для этого вернемся к самой функции:

\[ f(x_1,x_2)=(x_1-1)^2+(x_2+2)^2. \]

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

\[ x_1-1=0, \qquad x_2+2=0. \]

Отсюда получаем

\[ x_1=1, \qquad x_2=-2. \]

Следовательно, точная точка минимума имеет вид

\[ \bar{x}^{*}=(1,-2). \]

Соответствующее минимальное значение функции равно

\[ f_{\min}=f(1,-2). \]

Подставляем точные значения:

\[ f(1,-2)=(1-1)^2+(-2+2)^2=0. \]

Следовательно,

\[ \bar{x}^{*}=(1,-2), \qquad f_{\min}=0. \]

Полученное методом градиентного спуска приближение

\[ \bar{x}^{*}\approx(1.016,-1.969) \]

близко к точной точке \( (1,-2) \). Поэтому результат вычислений хорошо согласуется с точным ответом. Вычисления начались с точки \( (3,2) \), затем значение функции последовательно уменьшалось, а процесс завершился тогда, когда расстояние между двумя соседними приближениями стало меньше заданной точности.

Что Рассмотреть Дальше: Полезные Темы для Продолжения

Метод градиентного спуска хорошо показывает базовую идею движения к минимуму с помощью градиента. Но в численной оптимизации есть и другие подходы. Именно они помогают лучше сравнить разные способы минимизации функций нескольких переменных.

  1. Метод покоординатного спуска: Минимизация шаг за шагом — В этой статье речь пойдет о поиске минимума через последовательное изменение отдельных координат функции нескольких переменных.
  2. Метод Ньютона: Минимизация функции многих переменных — Материал покажет, как в минимизации используют не только градиент, но и информацию о кривизне функции.
  3. Метод Ньютона с параметром: Управляемое движение к минимуму — В статье будет рассмотрено, как параметр шага помогает сделать метод Ньютона более управляемым во время минимизации.

Метод Градиентного Спуска в Коде: От Схемы до Собственной Программы

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

Блок-схема алгоритма, которая шаг за шагом показывает, как находят минимальное значение функции нескольких переменных, используя метод градиентного спуска