Перейти до змісту

Лекція 17. Вибір кроку, пошук довжини кроку і збіжність

Коротко про лекцію

Тут головне питання — як вибрати довжину кроку, щоб рух уздовж хорошого напряму справді зменшував функцію. Ви познайомитеся з line search, умовою Armijo та практичними ознаками занадто малого або великого кроку.

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

Постановка та базові поняття

1. Напрям і довжина кроку виконують різні ролі

Градієнтний спуск має форму:

\[ x_{k+1}= x_k- \alpha_k \nabla f(x_k) \]

Вектор \(-\nabla f(x_k)\) задає локальний напрям спадання. Число \(\alpha_k>0\) визначає, наскільки далеко алгоритм рухається цим напрямом.

Якщо \(\alpha_k\) дуже мале, кожен перехід змінює точку лише трохи. Процес може бути стабільним, але вимагати великої кількості ітерацій. Якщо \(\alpha_k\) завелике, нова точка може перескочити через долину, збільшити ціль або запустити коливання.

Тому аналіз кроку починається з розділення двох запитань. Перше: чи вибраний напрям є напрямом спадання? Друге: яка довжина руху вздовж цього напряму є безпечною та ефективною?

Процедуру вибору \(\alpha_k\) називають пошуком довжини кроку. У документації бібліотек трапляється технічний термін line search. Далі використовуємо українську назву, а англійську залишаємо для API.

У цій темі корисно розрізняти три часові масштаби. Зовнішня ітерація будує напрям. Усередині неї пошук довжини може перевірити кілька пробних значень \(\alpha\). Після прийняття одного кроку алгоритм переходить до наступної зовнішньої ітерації та обчислює новий градієнт.

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

2. Наскрізна квадратична функція

Розглянемо:

\[ f(x,y)= \frac{1}{2}x^2+ 5y^2 \]

Її градієнт:

\[ \nabla f(x,y)= \begin{pmatrix} x\\ 10y \end{pmatrix} \]

Глобальний мінімізатор:

\[ x^*= \begin{pmatrix} 0\\ 0 \end{pmatrix} \]

а мінімальне значення:

\[ f(x^*)=0 \]

За координатою \(y\) функція значно крутіша, ніж за \(x\). Це видно з коефіцієнта 10 у градієнті. Один і той самий коефіцієнт \(\alpha\) тому створює різні множники оновлення для двох координат.

Стартуватимемо з точки:

\[ x_0= \begin{pmatrix} 4\\ 1 \end{pmatrix} \]

У ній:

\[ f(x_0)=\frac{1}{2}\cdot16+5\cdot1=13 \]

Градієнт у старті:

\[ \nabla f(x_0)= \begin{pmatrix} 4\\ 10 \end{pmatrix} \]

Його норма:

\[ \|\nabla f(x_0)\|_2=\sqrt{4^2+10^2}=\sqrt{116} \]

Антиградієнт тому сильніше спрямований за координатою \(y\). Саме там локальний нахил більший. Така геометрія створює типову вузьку долину: безпечний крок для крутої координати водночас може бути занадто малим для пологої.

Цей дисбаланс пояснює повільний «зигзаг» багатьох градієнтних методів на витягнутих рівнях функції. Пошук довжини кроку може покращити поведінку, але він не усуває саму різницю кривизни між напрямами.

3. Чотири характерні значення кроку

Після одного градієнтного кроку координати оновлюються незалежно:

\[ x_{k+1}= (1-\alpha)x_k \]
\[ y_{k+1}= (1-10\alpha)y_k \]

Для \(\alpha=0.01\) маємо множники 0.99 та 0.9. Обидві координати стискаються до нуля, але \(x\) рухається повільно. Перша точка:

\[ x_1= \begin{pmatrix} 3.96\\ 0.9 \end{pmatrix} \]

Для \(\alpha=0.1\):

\[ x_{k+1}=0.9x_k \]

та:

\[ y_{k+1}=0 \]

Друга координата зануляється за один крок. Зі старту отримуємо:

\[ x_1= \begin{pmatrix} 3.6\\ 0 \end{pmatrix} \]

Для \(\alpha=0.2\) маємо:

\[ y_{k+1}=-y_k \]

Модуль другої координати не зменшується, тому виникають незгасаючі коливання. Для \(\alpha=0.22\):

\[ y_{k+1}=-1.2y_k \]

і амплітуда зростає. Отже, невелика зміна кроку може перевести процес від стабільності до розбіжності.

Важливо одночасно враховувати знак множника та його модуль. Від’ємний множник означає зміну боку відносно мінімізатора. Якщо його модуль менший за 1, коливання згасають. Якщо дорівнює 1, амплітуда зберігається. Якщо перевищує 1, відхилення зростає.

Така проста координатна модель дає студенту спосіб перевірити чисельну траєкторію без бібліотеки. За першими кількома точками можна передбачити, чи процес стискається, коливається або розбігається. Траєкторії для різних довжин кроку

Математична логіка

4. Звідки береться межа стабільності

Для першої координати потрібна умова:

\[ |1-\alpha|<1 \]

Звідси:

\[ 0<\alpha<2 \]

Для другої координати:

\[ |1-10\alpha|<1 \]

Розкриваємо:

\[ -1< 1-10\alpha < 1 \]

З лівої нерівності:

\[ \alpha<0.2 \]

з правої:

\[ \alpha>0 \]

Отже, спільна умова:

\[ 0<\alpha<0.2 \]

Саме крутіша координата задає жорсткішу межу. Значення \(\alpha=0.2\) є граничним: модуль множника за \(y\) дорівнює 1, тому збіжності за цією координатою немає.

5. Матричний погляд і власні значення

Наскрізну функцію можна записати як квадратичну форму:

\[ f(z)= \frac{1}{2} z^T H z \]

де:

\[ H= \begin{pmatrix} 1 & 0\\ 0 & 10 \end{pmatrix} \]

Власні значення матриці:

\[ \lambda_1=1, \qquad \lambda_2=10 \]

Для симетричної додатно визначеної квадратичної функції з постійним кроком базова умова градієнтного спуску:

\[ 0<\alpha< \frac{2}{ \lambda_{\max} } \]

У нашій задачі:

\[ \lambda_{\max}=10 \]

тому знову отримуємо:

\[ 0<\alpha<0.2 \]

Ця формула пояснює зв’язок довжини кроку з кривизною. Чим більша максимальна кривизна, тим обережніший крок потрібен для стабільності.

Водночас сам факт \(\alpha<2/\lambda_{\max}\) не означає, що крок практично хороший. Значення дуже близьке до нуля формально стабільне, але дає повільний прогрес. Значення дуже близьке до верхньої межі може створювати сильні коливання та погану поведінку за числового шуму.

Для квадратичної функції оптимальний сталий крок можна аналізувати точніше через весь спектр власних значень. У межах цієї лекції достатньо розуміти головну залежність: найбільша кривизна обмежує безпечний масштаб, а найменша кривизна впливає на швидкість стискання вздовж пологих напрямів.

Співвідношення \(\lambda_{\max}/\lambda_{\min}\) пов’язане з обумовленістю. Велике співвідношення означає, що одному сталому \(\alpha\) важко бути одночасно швидким за всіма координатами.

6. Напрям спадання і напрямна похідна

Для загального напряму \(p_k\) розглянемо функцію однієї змінної:

\[ \phi(\alpha)= f(x_k+\alpha p_k) \]

Її похідна в нулі:

\[ \phi'(0)= \nabla f(x_k)^T p_k \]

Якщо:

\[ \nabla f(x_k)^T p_k<0 \]

то напрям \(p_k\) є напрямом спадання. Для градієнтного спуску:

\[ p_k= -\nabla f(x_k) \]

тому:

\[ \nabla f(x_k)^T p_k=-\|\nabla f(x_k)\|_2^2<0 \]

для ненульового градієнта.

Ця перевірка важлива перед пошуком довжини кроку. Якщо напрям не веде вниз локально, зменшення \(\alpha\) саме по собі не виправляє математичну проблему вибору напряму.

Скаляр \(\nabla f(x_k)^Tp_k\) має ще одну корисну роль: він входить у праву частину умови Арміхо. Чим сильніше від’ємна напрямна похідна, тим більше локальне спадання прогнозує лінійна модель.

Для антиградієнта цей скаляр обчислюється без додаткових похідних. Для методу Ньютона, BFGS або іншого напряму треба перевірити його знак окремо. Така перевірка допомагає локалізувати помилку: проблема може бути в напрямі ще до вибору \(\alpha\).

Якщо градієнт уже майже нульовий, значення напрямної похідної теж стає малим. Тоді критерій зупинки зовнішнього алгоритму може бути важливішим за запуск нового пошуку довжини.

Алгоритм і покроковий розбір

7. Пошук довжини кроку як одновимірна задача

Після вибору \(p_k\) багатовимірна задача тимчасово перетворюється на одновимірну:

\[ \min_{\alpha>0} \phi(\alpha) \]

де:

\[ \phi(\alpha)= f(x_k+\alpha p_k) \]

Тобто змінюється лише одне число \(\alpha\). Сам векторний напрям уже зафіксований.

Теоретично можна шукати точний мінімум \(\phi(\alpha)\). Такий підхід називають точним пошуком довжини кроку. На практиці повне розв’язання внутрішньої одновимірної задачі на кожній зовнішній ітерації часто коштує занадто дорого.

Тому поширені неточні правила. Вони шукають достатньо добрий \(\alpha\), який забезпечує контрольоване зменшення цілі без дорогого внутрішнього мінімуму.

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

Пошук довжини тому є компромісом між якістю одного переходу та загальною вартістю алгоритму. Хороше правило приймає достатній прогрес без надмірної кількості пробних точок.

Цей погляд пов’язує лекцію з попередньою темою одновимірної оптимізації. Там \(x\) був основною змінною задачі. Тут одновимірною змінною тимчасово стає \(\alpha\) вздовж зафіксованого напряму.

8. Умова Арміхо

Умова Арміхо має вигляд:

\[ f(x_k+\alpha p_k)\le f(x_k)+c_1\alpha\nabla f(x_k)^T p_k \]

де зазвичай:

\[ 0<c_1<1 \]

Оскільки для напряму спадання:

\[ \nabla f(x_k)^T p_k<0 \]

права частина менша за \(f(x_k)\). Отже, умова вимагає реального зменшення цільової функції.

Коефіцієнт \(c_1\) задає, яку частину локально прогнозованого спадання ми вважаємо достатньою. Дуже мале значення робить умову м’якою. Проте сам параметр не варто трактувати ізольовано: результат залежить також від напряму, стартового кроку та коефіцієнта скорочення.

Умова Арміхо не шукає точний мінімум уздовж прямої. Вона відповідає на практичніше запитання: «чи цей пробний крок уже достатньо добрий, щоб його прийняти?».

Праву частину можна читати як лінійний прогноз. Вираз:

\[ f(x_k)+ \alpha \nabla f(x_k)^Tp_k \]

є наближенням цілі для малого руху. Множник \(c_1\) послаблює вимогу та дозволяє прийняти крок, який реалізує лише частину прогнозованого спадання.

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

Умова має сенс лише для напряму спадання. Саме тому перевірка slope < 0 повинна бути окремим явним етапом реалізації.

9. Пошук із послідовним зменшенням

Простий алгоритм починається зі стартового кроку:

\[ \alpha=\alpha_0 \]

Наприклад:

\[ \alpha_0=1 \]

Якщо умова Арміхо не виконується, крок множиться на коефіцієнт:

\[ 0<\rho<1 \]

тобто:

\[ \alpha\leftarrow \rho\alpha \]

Для \(\rho=0.5\) послідовність проб може бути:

\[ 1,\ 0.5,\ 0.25,\ 0.125,\ldots \]

Алгоритм зупиняє внутрішній пошук на першому кроці, який задовольняє умову достатнього спадання. Через це процедура є простою для реалізації та легкою для аудиту.

Початковий крок \(\alpha_0\) впливає на кількість проб. Якщо він систематично завеликий, кожна ітерація витрачає час на багато скорочень. Якщо надто малий, умова Арміхо може виконуватися відразу, але зовнішній прогрес буде слабким.

Коефіцієнт \(\rho\) визначає грубість пошуку. При \(\rho=0.5\) крок зменшується вдвічі. Значення ближче до 1 дає тонше регулювання, але може збільшити кількість перевірок.

У практичній реалізації корисно повертати разом із step число проб. Тоді журнал показує, чи алгоритм постійно приймає першу пропозицію, чи майже на кожній ітерації виконує довгий внутрішній пошук. Потрібно також встановити мінімальний крок або максимальну кількість скорочень. Це захищає програму від нескінченного циклу, якщо напрям неправильний або функція поводиться не так, як очікує алгоритм.

10. Один крок Арміхо вручну

У стартовій точці:

\[ x_0= \begin{pmatrix} 4\\ 1 \end{pmatrix} \]

маємо градієнт:

\[ g_0= \begin{pmatrix} 4\\ 10 \end{pmatrix} \]

та напрям:

\[ p_0= -g_0= \begin{pmatrix} -4\\ -10 \end{pmatrix} \]

Напрямна похідна:

\[ g_0^T p_0=-4^2-10^2=-116 \]

Візьмемо:

\[ c_1=10^{-4} \]

і пробний крок \(\alpha=1\). Кандидат:

\[ x_0+\alpha p_0= \begin{pmatrix} 0\\ -9 \end{pmatrix} \]

Його ціль дуже велика:

\[ f(0,-9)=405 \]

Права частина умови Арміхо близька до 13, тому крок 1 відхиляється.

Після кількох скорочень крок \(\alpha=0.125\) дає кандидат:

\[ \begin{pmatrix} 3.5\\ -0.25 \end{pmatrix} \]

і:

\[ f(3.5,-0.25)= 6.4375 \]

Це значно менше за 13. Умова Арміхо виконується, тому такий крок можна прийняти.

Перевіримо праву частину чисельно. Маємо:

\[ 13+10^{-4}\cdot0.125\cdot(-116)=12.99855 \]

Фактичне значення 6.4375 істотно менше за цю межу. Отже, крок зменшує функцію та задовольняє заявлену умову достатнього спадання.

Після прийняття кроку внутрішній пошук завершується. Новий градієнт потрібно обчислювати вже в точці \((3.5,-0.25)\). Старий напрям не слід автоматично продовжувати без нової зовнішньої ітерації.

Програмна реалізація та перевірка

11. Порівняння фіксованих кроків у Python

Спочатку відтворимо чотири характерні режими:

import numpy as np


# Цільова функція відповідає f(x,y)=0.5*x^2+5*y^2.
def objective(point):
    x, y = point
    return 0.5 * x ** 2 + 5.0 * y ** 2


# Градієнт має порядок компонентів [x, y].
def gradient(point):
    x, y = point
    return np.array([
        x,
        10.0 * y,
    ])


def gradient_step(point, step):
    # Для мінімізації рухаємося в напрямі -grad(f).
    return point - step * gradient(point)


start = np.array([
    4.0,
    1.0,
])

for step in [
    0.01,
    0.10,
    0.20,
    0.22,
]:
    # Виконуємо кілька однакових кроків і спостерігаємо стабільність.
    point = start.copy()

    for _ in range(12):
        point = gradient_step(
            point,
            step,
        )

    print(
        step,
        point,
        objective(point),
    )

Для \(\alpha=0.01\) ціль зменшується повільно. Для \(\alpha=0.1\) процес швидко рухається до нуля. Значення 0.2 залишає незгасаючий компонент за \(y\), а 0.22 створює розбіжність.

Корисно не обмежуватися фінальною точкою. Історія objective(point) по ітераціях показує характер процесу. Для стабільного кроку значення повинні систематично наближатися до нуля. Для граничного режиму крива може застрягнути на ненульовому рівні, а для завеликого — почати зростати.

Ще один аудит — перевірка теоретичних множників. Якщо код для \(\alpha=0.1\) не зануляє \(y\) після першого кроку, реалізація не відповідає формулі \(y_{k+1}=(1-10\alpha)y_k\). Такий простий тест добре виявляє переплутаний знак або коефіцієнт. Значення цілі за ітераціями

12. Реалізація пошуку з послідовним зменшенням

Відповідність формули та коду:

Математика Python Зміст
\(x_k\) point поточна точка
\(p_k\) direction напрям руху
\(\alpha\) step пробна довжина
\(\nabla f(x_k)^Tp_k\) slope напрямна похідна
\(c_1\) armijo коефіцієнт достатнього спадання
\(\rho\) reduction коефіцієнт скорочення

Сам алгоритм:

def backtracking_step(
    objective,
    gradient,
    point,
    direction,
    initial_step=1.0,
    reduction=0.5,
    armijo=1e-4,
    min_step=1e-12,
):
    # Значення f(x_k) не змінюється всередині внутрішнього пошуку.
    current_value = objective(point)

    # slope = grad(f)^T p має бути від'ємним для напряму спадання.
    slope = gradient(point) @ direction

    if slope >= 0.0:
        raise ValueError(
            "direction is not a descent direction"
        )

    step = initial_step

    while step >= min_step:
        # Будуємо пробну точку для поточної довжини кроку.
        candidate = (
            point
            + step * direction
        )

        # Права частина — межа достатнього спадання за Арміхо.
        armijo_bound = (
            current_value
            + armijo * step * slope
        )

        if objective(candidate) <= armijo_bound:
            # Повертаємо перший прийнятний крок.
            return step

        # Якщо умова не виконана, скорочуємо довжину.
        step *= reduction

    raise RuntimeError(
        "step became smaller than min_step"
    )

Тут помилки напряму та надмірне скорочення не приховуються. Вони мають окремі винятки, тому причина невдачі залишається видимою.

Параметр min_step є захисним, а не критерієм оптимальності. Якщо алгоритм доходить до нього, це сигнал діагностики. Можливо, напрям перестав бути напрямом спадання, значення функції містять шум або стартовий масштаб задачі потребує іншого налаштування.

У виробничому коді до функції варто додати лічильник кількості скорочень. Повернення (step, trials) дає змогу записати BACKTRACKING_TRIALS у журнал і побачити реальну вартість внутрішнього пошуку.

Також корисно перевірити параметри на вході: \(0<\rho<1\), \(0<c_1<1\), initial_step > 0. Явні перевірки роблять помилку конфігурації видимою до початку чисельних ітерацій.

13. Повна перевірка прийнятого кроку

Для стартової точки можна виконати:

import numpy as np


# Повторюємо ту саму математичну ціль для самодостатнього прикладу перевірки.
def objective(point):
    x, y = point
    return 0.5 * x ** 2 + 5.0 * y ** 2


# Порядок компонентів градієнта відповідає порядку координат [x, y].
def gradient(point):
    x, y = point
    return np.array([
        x,
        10.0 * y,
    ])


# Стартова точка збігається з наскрізним ручним прикладом лекції.
point = np.array([
    4.0,
    1.0,
])

current_gradient = gradient(point)
direction = -current_gradient

# Для антиградієнта slope точно від'ємний, поки градієнт ненульовий.
slope = current_gradient @ direction

# Підбираємо перший крок, який проходить перевірку Арміхо.
step = backtracking_step(
    objective,
    gradient,
    point,
    direction,
)

# Після прийняття кроку окремо будуємо фактичну нову точку.
candidate = point + step * direction

print("STEP_SIZE:", step)
print("SLOPE:", slope)
print("OBJECTIVE_BEFORE:", objective(point))
print("OBJECTIVE_AFTER:", objective(candidate))
print("GRAD_NORM_AFTER:", np.linalg.norm(gradient(candidate)))

Потрібно перевірити кілька фактів. SLOPE має бути від’ємним. OBJECTIVE_AFTER повинно бути меншим за OBJECTIVE_BEFORE. Додатково можна власною формулою повторно перевірити умову Арміхо для фактично прийнятого STEP_SIZE.

Під час повного градієнтного спуску корисно зберігати історію:

ITERATION
OBJECTIVE
GRAD_NORM
STEP_SIZE
BACKTRACKING_TRIALS

Тоді можна побачити, чи метод сповільнюється через малий градієнт, через скорочення довжини кроку або через складну локальну геометрію.

Фінальний GRAD_NORM потрібно читати разом із масштабом задачі. Значення \(10^{-6}\) може бути дуже малим для однієї моделі й недостатнім для іншої. Критерій зупинки повинен бути встановлений до аналізу результату.

Якщо OBJECTIVE_AFTER не менше за OBJECTIVE_BEFORE, прийнятий крок суперечить базовому очікуванню цієї реалізації. Якщо ціль зменшилась, але нерівність Арміхо не виконується, код приймає крок за іншим правилом, ніж заявлено в теорії.

Такий аудит особливо важливий перед переходом до BFGS та Ньютона. Там напрям буде складнішим, тому окреме тестування пошуку довжини кроку допомагає не змішувати помилку напряму з помилкою прийняття кроку.

Інтерпретація, межі та підсумок

14. Межі формули та типові помилки

Межа:

\[ 0<\alpha< \frac{2}{ \lambda_{\max} } \]

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

Ще одна типова помилка — переносити відповідальність за все на \(\alpha\). Якщо градієнт обчислений неправильно, навіть дуже малий крок рухатиметься за хибною геометрією. Тому перед налаштуванням пошуку довжини кроку варто незалежно перевірити сам градієнт.

Малий крок також не гарантує практичної якості. Процес може формально збігатися, але потребувати тисячі ітерацій. Тому потрібно дивитися на історію цілі, норму градієнта та кількість скорочень.

Умова Арміхо перевіряє достатнє спадання, але не визначає єдиний правильний крок. Різні параметри \(\alpha_0\), \(\rho\) і \(c_1\) можуть приводити до різних прийнятних довжин. Це алгоритмічні налаштування, які треба зберігати для відтворюваності.

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

У задачах із дуже різними масштабами координат причиною нестабільної поведінки може бути сама параметризація. Масштабування змінних часто робить геометрію рівнішою та зменшує потребу в крайніх довжинах кроку. Ця ідея повернеться в лекції про чисельну надійність.

Пошук довжини кроку також не скасовує критерій зупинки зовнішнього методу. Якщо норма градієнта вже мала, запуск довгого внутрішнього пошуку може бути зайвою роботою. Спочатку перевіряють умови завершення зовнішньої ітерації, далі за потреби будують новий напрям і підбирають його довжину.

Інтерактивна самоперевірка лекції

Пройдіть 10 коротких питань. Після кожної відповіді ви побачите пояснення, а за потреби — підказку й повний розбір.

15. Підсумок

Довжина кроку визначає масштаб руху вздовж уже вибраного напряму. Для функції \(\frac{1}{2}x^2+5y^2\) координатні множники показують чотири режими: повільну стабільність при \(\alpha=0.01\), ефективний рух при \(\alpha=0.1\), граничні коливання при \(\alpha=0.2\) і розбіжність при \(\alpha=0.22\). Цей приклад дозволяє побачити стабільність без бібліотеки через просте координатне оновлення.

Кривизна пояснює межу безпечного сталого кроку. Найбільше власне значення дорівнює 10, тому для квадратичної задачі потрібне \(0<\alpha<0.2\). У загальній нелінійній функції кривизна змінюється разом із точкою, тому практичний алгоритм часто підбирає довжину на кожній ітерації. Велика різниця кривизни між координатами також пояснює, чому один сталий крок може бути незручним для всієї задачі.

Пошук із послідовним зменшенням починається з пробного кроку та перевіряє його через умову Арміхо. Перед внутрішнім пошуком потрібно підтвердити \(\nabla f(x_k)^Tp_k<0\), а після прийняття кроку — повторно обчислити ціль і перевірити саму нерівність достатнього спадання. Крок, який пройшов Арміхо, є прийнятним для поточної ітерації, після чого градієнт обчислюють у новій точці.

Практичний журнал повинен зберігати OBJECTIVE, GRAD_NORM, STEP_SIZE і кількість внутрішніх скорочень. За цими полями можна відрізнити слабкий напрям, надто обережний рух і дорогий внутрішній пошук. Для чесного порівняння конфігурацій потрібно фіксувати однаковий старт, однакові критерії зупинки та максимальну кількість зовнішніх ітерацій. Раптово дуже малі кроки є окремим діагностичним сигналом і можуть вказувати на сильну кривизну або проблемне масштабування.

Логіка цієї лекції має послідовність «напрям → довжина → прийняття → перевірка». Вона зберігається і в складніших методах: Ньютон та квазіньютонівські алгоритми будують інші напрями, але все одно потребують надійного способу визначити безпечну довжину руху. Тому пошук довжини кроку є окремим компонентом оптимізатора, який варто тестувати та журналювати незалежно від формули напряму. Це суттєво спрощує діагностику чисельної поведінки. У повторних експериментах такий журнал дозволяє порівнювати траєкторії без здогадок і швидко знаходити момент, де алгоритм почав втрачати темп.