Выпуклая оптимизация

Дифференцируемое программирование

Google в 2017 году обучил оптимизатор-нейросеть, которая обогнала вручную настроенный Adam на 80+ задачах. Airbus оптимизирует геометрию крыла A350 через градиент по уравнениям аэродинамики, экономя 4% топлива. **Дифференцируемое программирование** превращает любую программу - симулятор, рендер, физику - в функцию, по которой можно делать обратный проход и оптимизировать.

  • **MAML и мета-обучение**: Apple и Google используют похожие подходы для персонализации моделей - быстрая адаптация к пользователю за несколько шагов, без переобучения с нуля
  • **Дифференцируемые симуляторы**: Tesla FSD обучается частично через дифференцируемые модели дорожной среды - градиенты из симуляции заменяют дорогостоящие реальные испытания
  • **Neural ODE**: оборачивает ODE-solver в дифференцируемый слой - используется в моделировании молекулярной динамики и временных рядов

Дифференцируемое программирование: программы = вычислительные графы

**Дифференцируемое программирование (DP)** - это парадигма, в которой вся программа рассматривается как вычислительный граф с дифференцируемыми операциями. Если каждая операция имеет определённую производную, то через chain rule (autograd) мы можем взять градиент потерь по любому параметру программы - даже по структуре алгоритма, гиперпараметрам или шагам оптимизатора.

В классическом ML мы дифференцируем по весам нейросети. В DP мы идём дальше: дифференцируем по **гиперпараметрам** (скорость обучения, архитектура), по **алгоритмам** (шаги физической симуляции), по **программам** (итерации внутреннего оптимизатора). Это открывает возможность обучать не только «что», но и «как».

Любая операция, для которой определено правило обратного распространения (VJP - vector-Jacobian product), встраивается в дифференцируемый граф. JAX, PyTorch и TensorFlow поддерживают сотни операций «из коробки». Нестандартные решатели (LP, QP, оптимизация на многообразиях) оборачиваются через `custom_vjp` / `register_hook` с аналитически выведенными градиентами.

Что принципиально нового даёт дифференцируемое программирование по сравнению с обычным autograd нейросетей?

Неявное дифференцирование и bi-level оптимизация

Многие задачи имеют вид: **найти θ, минимизирующее внешнюю задачу, где внутренняя задача - оптимизация по x(θ)**. Это **bi-level оптимизация** (двухуровневая). Для вычисления градиента нужно дифференцировать через argmin - это непросто, потому что argmin не имеет явного выражения.

Неявное дифференцирование использует **теорему о неявной функции**: если условие первого порядка выполнено и гессиан невырожден, то x*(θ) - дифференцируемая функция θ. Ключевое вычислительное преимущество: не нужно хранить граф всех шагов внутреннего оптимизатора - достаточно решить одну линейную систему H⁻¹v в конце.

**higher** (PyTorch): разворачивает оптимизатор и сохраняет граф - для точного unrolling. **jaxopt**: реализует неявное дифференцирование через `implicit_diff=True` для iterative solvers. **cvxpylayers**: оборачивает CVXPY задачи (LP, QP, SDP) в дифференцируемый слой через KKT-условия - те же уравнения первого порядка, что и неявное дифференцирование.

Главное преимущество неявного дифференцирования перед развёртыванием (unrolling) оптимизатора:

Развёртывание оптимизатора vs неявное дифференцирование

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

Компромиссный подход: развернуть только последние K итераций вместо всех T. Это ограничивает память O(K) и уменьшает vanishing gradients, но вводит bias в градиент. Используется в MAML с небольшим числом inner steps (обычно 5-10) и в обучении score функций в диффузионных моделях.

При bi-level оптимизации, где внутренняя задача - это LP (линейное программирование) с тысячами итераций simplex-метода. Какой подход единственно применим?

Приложения: MAML, физика, NAS

Дифференцируемое программирование стало основой ряда прорывных направлений ML последних лет - от meta-learning до дифференцируемой физики и автоматического поиска архитектур.

Зачем в MAML используется `create_graph=True` при вычислении inner loop градиентов?

Ключевые идеи

  • **Дифференцируемое программирование** - парадигма, где весь pipeline (симулятор, оптимизатор, архитектура) рассматривается как дифференцируемый вычислительный граф
  • **Bi-level оптимизация**: внешняя задача оптимизирует по решению внутренней; требует дифференцирования через argmin
  • **Неявное дифференцирование**: градиент через оптимальность условий (KKT/стационарность) - O(1) памяти, точен в оптимуме
  • **Unrolling**: развёртывание T шагов оптимизатора в граф - просто, но O(T) памяти и проблема vanishing/exploding gradients

Связанные темы

Дифференцируемое программирование связывает классическую оптимизацию с современным ML:

  • Оптимизация на многообразиях — Riemannian Autodiff - частный случай DP, где граф включает операции на многообразиях
  • Федеративная оптимизация — Персонализованный FL использует MAML-подобные bi-level схемы для адаптации к клиентам
  • Оптимизация в задачах RL — Policy gradient - специальный случай DP: дифференцируем через стохастическое выполнение программы-политики

Вопросы для размышления

  • Какие задачи в данной области могут быть сформулированы как bi-level оптимизация?
  • В чём принципиальная разница между MAML (unrolling) и методами meta-learning через неявное дифференцирование?
  • Как дифференцируемое программирование меняет границу между «моделью» и «алгоритмом» в ML?

Связанные уроки

  • calc-18-partial
Дифференцируемое программирование

0

1

Войти