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


    С четырьмя параметрами я могу задать слона, а с пятью я могу заставить его шевелить хоботом.
    – John Von Neumann

    Идея «дифференцируемого программирования» очень популярна в мире машинного обучения. Для многих не ясно, отражает ли этот термин реальный сдвиг в том, как исследователи понимают машинное обучение, или это просто (еще один) ребрендинг «глубокого обучения». В этом посте разъясняется, что нового дает дифференцируемое программирование (или ∂P) в таблице машинного обучения.


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


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


    Brute Force with Benefits


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


    А как насчет биологических нейронов и $y = σ (W \times x + b)$? В этой формуле нет ничего особенного; это простой и гибкий пример высокопараметрической нелинейной функции. На самом деле, это, вероятно, худшая функция в большинстве случаев. Один слой нейронной сети, в принципе, может классифицировать изображения кошек, но только используя относительно неинтересную уловку. Работает безотказно! — но мелкий шрифт предупреждает, что вам может понадобиться больше параметров, чем атомов во вселенной. Чтобы на самом деле заставить это дело работать, вам нужно закодировать проблемную структуру в модели — именно здесь она начинает больше походить на традиционное программирование.


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


    Encoding Structure, Redux


    Наборы инструментов ML все больше поддерживают алгоритмическое дифференцирование (AD), что позволяет нам дифференцировать модели с помощью циклов, ветвлений и рекурсии — или любой программы, построенной на наборе дифференцируемых математических примитивов. Это привело к более сложной архитектуре: модели НЛП все больше похожи на классические грамматические парсеры со stack-augmented моделями, и можно даже дифференцировать аналог машины Тьюринга или интерпретатор языка программирования.


    Последний шаг, предпринятый дифференцируемым программированием, состоит в том, чтобы больше не рассматривать умножение матриц, свертки и RNN как фундаментальные строительные блоки глубокого обучения, а лишь как частные случаи. Мы можем применить методы глубокого обучения к любой параметризованной дифференцируемой функции $f (x)$. Функции, столь же сложные, как физические симуляторы или трассировщики лучей, также могут быть дифференцированы и оптимизированы. Даже квантовые вычисления могут вписаться в эту структуру.



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


    Действительно мощный прогресс заключается в следующем: всепроникающая дифференцируемость означает, что все эти методы соединяются вместе, как кирпичи lego.
    Вместо того, чтобы всегда писать новые программы для ML, мы можем переиспользовать существующие программы, применяя физические движки внутри моделей робототехники, основанных на глубоком обучении. Там, где современные алгоритмы обучения с подкреплением должны строить детальную модель внешнего мира основываясь только на том, за что дадут вознаграждение (звучит как грубая сила), мы можем вместо этого просто применить детальное, точное знание физических систем, прежде чем обучение даже начинается.


    Даже самые зрелые области глубокого обучения не остаются в стороне; после ядра свертки естественным следующим шагом для моделей изображений является дифференцируемый трассировщик лучей. 3D рендеринг содержит много структурных знаний о том, как сцены отображаются в пикселях, что еще сыграет свою роль на нашей кухне. Скажем, модель принимает решения в моделируемой среде, отображаемой в виде пикселей, которые модель использует в качестве входных данных. В принципе, теперь мы можем сделать весь цикл дифференцируемым, что позволит нам непосредственно увидеть влияние среды на решения модели и наоборот. Это может значительно увеличить мощность реалистичной моделируемой среды для тренировочных моделей, таких как автомобили с автоматическим вождением.


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


    Если это все так замечательно, почему же все всё не побросали и не кинулись учиться дифференцировать? К сожалению, ограничения существующих фреймворков затрудняют построение моделей такой сложности, и невозможно повторно использовать богатство знаний, встроенных в существующий научный код. Необходимость заново реализовать физические движки с нуля на весьма ограниченном языке моделирования превращает сценарий из десяти строк в многолетний исследовательский проект. Но достижения в области языка и технологии компиляции, особенно автоматическое дифференцирование, приближают нас к святому Граалю: «просто дифференцируйте мой игровой движок, пожалуйста».


    Итак, что такое дифференцируемое программирование?


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


    Дифференцируемые проблемы управления


    Далее покажем, что дифференцируемость может привнести в некоторые простые, но классические задачи управления, в которых мы обычно используем как «черный ящик» обучение с подкреплением (Reinforcement Learning, RL). Диффиренцируемые модели (∂P-модели) не только выявляют гораздо более эффективные стратегии управления, но и обучаются на несколько порядков быстрее. Код доступен для изучения — в большинстве случаев он обучается за несколько секунд на любом ноутбуке.


    Следуйте за Градиентом


    Дифференцирование — это то, что является движущей силой практически на каждом шаге глубокого обучения; для данной функции $y = f (x)$ мы используем градиент $\frac{dy}{dx}$, чтобы выяснить, как изменение x повлияет на y. Несмотря на математическую сущность, градиенты на самом деле являются очень общей и интуитивной концепцией. Забудьте формулы, на которые вам приходилось смотреть в школе; давайте делать что-то более веселое, например, швырять что-нибудь по параболической траектории.



    Когда мы бросаем снаряды с помощью требушета, наш x (входные данные) представляет собой настройку (скажем, размер противовеса или угол выброса), а y — это расстояние, которое снаряд проходит до приземления. Если вы пытаетесь прицелиться, градиент говорит вам кое-что очень полезное — увеличить или уменьшить определенный параметр. Чтобы максимизировать расстояние, просто следуйте градиенту.


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


    # what you did in school
    gradient(x -> 3x^2 + 2x + 1, 5) # (32,)
    # something a little more advanced
    gradient((wind, angle, weight) -> Trebuchet.shoot(wind, angle, weight),
             -2, 45, 200) # (4.02, -0.99, 0.051)

    Throwing Stuff


    Нам нужно нацелить требушет на цель, используя градиенты для точной настройки угла выброса; Это называется оценкой параметров, и мы уже рассматривали подобные примеры. Мы можем сделать задачу интересней, перейдя к мета-методу: вместо того, чтобы нацеливать trebuchet на одну цель, мы оптимизируем нейронную сеть, которая может нацеливать его на любую цель. Вот как это работает: нейронная сеть принимает два входа, целевое расстояние в метрах и текущую скорость ветра. В сети выкладываются настройки требушета (масса противовеса и угол расцепления), которые подаются в симулятор, который рассчитывает пройденное расстояние. Затем мы сравниваем с нашей целью и продвигаемся по всей цепочке, чтобы скорректировать вес сети. Наш «набор данных» — это случайно выбранный набор целей и скоростей ветра.



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



    Примерно после пяти минут обучения (на одном ядре процессора моего ноутбука) это выглядит так:



    Если вы хотите повлиять на траекторию, увеличьте скорость ветра:



    Отклонилось на 16 см, или около 0,3%. А как насчет того, чтобы нацелиться требушетом напрямую? Это легко сделать градиентным спуском, учитывая, что у нас есть градиенты. Однако это медленный итеративный процесс, который каждый раз занимает около 100 мс. Напротив, работа нейронной сети занимает 5 мкс (в двадцать тысяч раз быстрее) с небольшой потерей точности. Этот трюк, называемый «приблизительной инверсией функций через градиенты» является очень общим, и его можно использовать не только с динамическими системами, но и с алгоритмом быстрой передачи стиля.


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


    Cart, meet Pole


    Более узнаваемой проблемой управления является CartPole, «Hello world» для обучения с подкреплением. Задача состоит в том, чтобы научиться балансировать вертикальный столб, подталкивая его основание влево или вправо. Наша установка в целом похожа на случай с Trebuchet: реализация Julia позволяет напрямую рассматривать вознаграждение, полученное средой, как потери. ∂P даёт нам возможность беспрепятственно переключаться с простой модели на RL-модель.



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


    $ f(x) = \left\{\begin{matrix} \,1,\, x\geqslant0\\ -1,\, x<0 \end{matrix}\right. $


    $ \frac{df}{dx} = 1 $


    Другими словами, мы заставляем градиент вести себя так, как если бы $f$ была тождественной функцией. Учитывая, насколько математическая идея дифференцируемости уже используется в ML, возможно, не удивительно, что мы можем просто здесь схитрить; для обучения все, что нам нужно, это сигнал для информирования нашего псевдослучайного обхода пространства параметров, а остальное — детали. Результаты говорят сами за себя. В тех случаях, когда методам RL необходимо обучаться сотнями эпизодов, прежде чем решать проблему, модели ∂P нужно всего лишь около 5 эпизодов, чтобы окончательно победить.



    The Pendulum & Backprop through Time


    Важной целью для RL (обучение с подкреплением) является обработка отсроченного вознаграждения, когда действие не помогает нам улучшать результаты несколько шагов подряд. Когда среда дифференцируема, ∂P позволяет обучать агента обратным распространением во времени, как в рекурентной сети! В этом случае состояние окружающей среды становится «скрытым состоянием», которое изменяется между временными шагами.



    Чтобы продемонстрировать эту технику, рассмотрим модель маятника, где задача состоит в том, чтобы качать маятник до тех пор, пока он не встанет вертикально, и удерживать его в неустойчивом равновесии. Это сложно для моделей RL; после примерно 20 эпизодов обучения проблема решается, но зачастую путь к решению является явно неоптимальным. В отличие от этого, BPTT может побить рейтинг лидеров RL в одном эпизоде обучения. Поучительно наблюдать, как разворачивается этот эпизод; в начале записи стратегия является случайной, и модель со временем улучшается. Темпы обучения почти тревожны.



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



    Это только начало; мы добьемся реальных успехов, применяя DP к средам, с которыми RL вообще слишком сложно работать, где уже существуют богатые симуляции и модели (как в большинстве инженерных и естественных наук), и где интерпретируемость является важным фактором (как в медицине).


    The Map Is Not The Territory


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


    Coda


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


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


    Ссылки



    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 8

      +3

      Во всех этих текстах (про дифференциальное программирование) ощущается что-то странное. Я прочитал текст, два, три, и, кажется, я начал понимать о чём идёт речь.


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


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


      • Сайд-эффекты полностью исключены (программа без сайд-эффектов эквивалентна GLUT'у)
      • область определения упорядочена (т.е. мы исключаем большинство бизнес- и индустриальных задач, интерфейсы и т.д.).

      Уф, как-то так.

        0

        Да, это всё нацелено в computer-science (machine learning, высокопроизводительные вычисления для естественных наук, статистика и т.д.), то есть туда, где всё удобней представимо в функциональном виде, и где большинство проблем можно свести к минимизации функционала.


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

        +1
        Признаюсь, прочитал статью и перечитал отдельные части несколько раз.
        Но так и не понял, чем отличается Differential Programming от обычного Reinforcement Learning.

        Конечно, понятно, что нейросети — лишь один из множества способов описать функцию f(x), необходимую для решения некой задачи.
        И сама идея применить производную f(x) для поиска решения — как раз понятна.

        Но это давно используется при обучении нейросетей.
        Что же нового предлагает DP в сравнении с Reinforcement Learning?
        Использовать другую, более простую Loss function?

        Если да, то можно ли применить это подход для решения задачи MountainCar?
        Там не получится определить Loss function столь же просто, как, например, угол наклона маятника в задаче CartPole.
        Ведь чтобы решить эту проблему, нужно машинку разгонять влево-вправо, набирая инерцию. Как раз с этой задачей Reinforcement Learning справляется хорошо.
          0

          Я думал, дескать, торможу слегка — никак не пойму в чем здесь новшество, а нет, вот люди тоже в недоумении. Ребята из MIT как всегда лукавят и приукрашивают: за сенсационные и непонятные изобретения будет больше грантов, а чтоб была сенсация, достаточно сказать, де у нас новая веха в машинном обучении, прям как рекуррентные сети.


          Основная фича DP это автодифференцирование, позволяющее находить производную функции не приближенном численным методом, а прям как в Mathcad или Mathematica, символьно, и хотя у вас не прописывается явный вид вашей производной, все равно генерируется "эффективный машинный код". Вот и получается, что всё волшебство как и у нейронных сетей состоит в решении задачи многомерной оптимизации с множеством переменных.
          Пример The Pendulum больше соответствует горной машинке, но можно кстати и на ней MountainCar попробовать

          +1
          Я правильно понимаю, что в данном методе используется явная, рукописная модель среды, и по этой модели с помощью градиентного спуска ищется оптимальный план действий?
          А концепция будет работать, если модель среды — это нейросеть от Model-Based алгоритма? Она точно дифференцируема. Ну и если рельеф подкреплений хоть немного сложный, то локальные оптимумы будут с гарантией (если медленно прыгнуть с обрыва, то убьёшься, а если с разбегу — то перепрыгнешь и получишь профит. Локальный оптимум).
            +1

            Советую пройтись по предоставленным ссылкам (например https://arxiv.org/abs/1810.07951) чтоб самостоятельно разобраться в теме, а также поискать бложики и дискуссии тех, кто варится в этой области — их объяснения не будут поверхностными

              +1
              Спасибо!
            +1

            Очень интересная статья! Помогла немного разобраться, что такое дифференцируемое программирование. Наткнулся на тему, когда начал ознакамливаться с https://arxiv.org/abs/2007.08017 "λS: Computable semantics for differentiable programming with higher-order functions and datatypes".

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

            Самое читаемое