Как выбрать метод оптимизации

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

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

Зачем об этом думать

За курс мы собрали целый арсенал: золотое сечение, градиентный спуск, Adam, Ньютон, BFGS, симплекс, ККТ, отжиг, ГА. Применить мощный молоток не к тому гвоздю — частая ошибка. Ньютон на нейросети с миллионом параметров захлебнётся; отжиг на выпуклой квадратичной — пустая трата времени; градиент на коммивояжёре бессмыслен. Хорошая новость: задача почти всегда сама подсказывает метод.

Четыре вопроса-маршрутизатора

  1. Переменные непрерывны или дискретны? Дискретны — ДП / ветви и границы / метаэвристики. Непрерывны — дальше.
  2. Задача линейна? Да (линейные цель и ограничения) — симплекс / внутренняя точка.
  3. Выпукла? Да — градиентные/Ньютон надёжно дают глобум; с ограничениями — ККТ / внутренняя точка.
  4. Есть ли градиент и какова размерность? Невыпукла, градиент есть, большое $n$ — SGD/Adam. Малое $n$, нужна скорость — Ньютон/BFGS. Градиента нет — золотое сечение (1D), отжиг/ГА.

Дерево решений в коде

def recommend(continuous, linear, convex, has_grad, big):
    if not continuous:
        return "ДП / ветви и границы / метаэвристики (отжиг, ГА)"
    if linear:
        return "симплекс или метод внутренней точки"
    if convex:
        if big:
            return "градиентный спуск / L-BFGS (глобум гарантирован)"
        return "Ньютон / BFGS (быстрая сходимость)"
    # невыпуклая непрерывная
    if not has_grad:
        return "производных нет -> отжиг / ГА / Нелдер-Мид"
    if big:
        return "SGD / Adam (только локальный оптимум)"
    return "BFGS с рестартами"

cases = [
    ("Линейная регрессия",   dict(continuous=True, linear=False, convex=True,  has_grad=True,  big=False)),
    ("Обучение нейросети",   dict(continuous=True, linear=False, convex=False, has_grad=True,  big=True)),
    ("План производства",    dict(continuous=True, linear=True,  convex=True,  has_grad=True,  big=False)),
    ("Коммивояжёр",          dict(continuous=False, linear=False, convex=False, has_grad=False, big=True)),
]
for name, kw in cases:
    print(f"{name:22s}-> {recommend(**kw)}")

Вывод:

Линейная регрессия    -> Ньютон / BFGS (быстрая сходимость)
Обучение нейросети    -> SGD / Adam (только локальный оптимум)
План производства     -> симплекс или метод внутренней точки
Коммивояжёр           -> ДП / ветви и границы / метаэвристики (отжиг, ГА)

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

Обусловленность и масштабирование

Отдельный практический совет, не зависящий от метода: нормируйте переменные. Признаки разного масштаба создают искусственные овраги (большое число обусловленности $\kappa$), от которых страдают все первопорядковые методы. Приведение к нулевому среднему и единичной дисперсии часто ускоряет сходимость в разы — дешевле любой смены алгоритма.

Как работает под капотом

За выбором стоит баланс трёх ресурсов: информация (есть ли градиент, гессиан), вычисления (можем ли позволить $O(n^2)$, $O(n^3)$), гарантии (нужен ли доказанный глобум). Второй порядок (Ньютон) тратит больше информации и вычислений, но сходится быстрее; нулевой порядок (отжиг) почти не требует информации, но медленный и без гарантий. Грамотный инженер выбирает точку на этом компромиссе под бюджет задачи, а не «самый модный» метод.

Частые ошибки

  • Сразу хвататься за нейросеть/метаэвристику. Если задача выпуклая или линейная, классический солвер быстрее и надёжнее.
  • Игнорировать масштаб данных. Без нормировки любой градиентный метод буксует в искусственном овраге.
  • Не проверять выпуклость. От неё зависит, гарантирован ли глобальный оптимум.

Итоги

  • Метод выбирают по структуре: дискретность → линейность → выпуклость → размерность/градиент.
  • Дискретно — ДП/ветви/метаэвристики; линейно — симплекс; выпукло — градиент/Ньютон; невыпукло+большое — SGD/Adam.
  • Нормировка переменных лечит обусловленность дешевле смены метода; помните о балансе информация/вычисления/гарантии.
Проверьте себя
1. Какой метод выбрать для линейной задачи планирования производства?
ASGD/Adam
BСимплекс или внутреннюю точку
CИмитацию отжига
DМетод Ньютона
2. Почему для обучения большой нейросети берут SGD/Adam, а не Ньютона?
AНьютон неточен
BНевыпуклость + огромная размерность делают гессиан недоступным, а SGD дёшев и масштабируем
CУ нейросети нет градиента
DSGD гарантирует глобум
3. Какой дешёвый приём ускоряет почти любой градиентный метод?
AУвеличить шаг
BНормировать переменные (убрать искусственные овраги)
CСменить язык
DДобавить ограничения
py
Курс по теме
Пройдите курс «Python с нуля» — по шагам, с проверкой
8 уроков · ~14 ч · теория, упражнения и экзамен с бейджем
Открыть курс →