Спикеры о вебинаре:
На вебинаре мы расскажем о так называемых нейродифференциальных уравнениях (Neural ODEs). Это архитектура нейронных сетей, основанная на системах обыкновенных дифференциальных уравнений и позволяющая моделировать непрерывную динамику скрытых представлений данных. Особое внимание уделим методам эффективного обучения подобных моделей и расскажем о нашей работе, опубликованной в материалах конференции NeurIPS 2020. Также мы расскажем об актуальных приложениях нейродифференциальных уравнений при решении задач машинного обучения. В заключение обсудим открытые проблемы обучения и использования нейросетей с подобными архитектурами.
Видео: https://youtu.be/76rN-dFBwr0
Презентация: https://drive.google.com/file/d/1NnP7lC68YYz9DLR3hO2Fcb8goRKEnFww/view?usp=sharing
(00:00:00) (Начало записи)
Николай Михайловский: Я Николай Михайловский, генеральный директор компании «НТР», и я вас всех приветствую на очередном вебинаре, который «НТР» проводит вместе с Высшей IT-школой Томского государственного университета. С нами сегодня Талгат Даулбаев и Александр Катруца из Skoltech, рассказывать они будут про свои работы в области нейронных обыкновенных дифференциальных уравнений.
Талгат Даулбаев: Да, в общем, сегодня мы с Александром… Меня зовут Талгат, я аспирант Skoltech, мы хотим рассказать про применение обыкновенных дифференциальных уравнений в не совсем обыкновенных нейронных сетях. Хотим мы, прежде всего, дать обзор области, но и сделать акцент на нашей работе, которая была представлена на конференции NeurIPS в 2020 году, она была в декабре.
Прежде чем переходить к не совсем обыкновенными нейронным сетям, давайте начнем с вполне обыкновенных и всем привычных. Это сеть ResNet, наверное, самая популярная архитектура нейронных сетей, все ее знают, и все знают, что ResNet состоит из так называемых ResNet-блоков. На картинке А как раз изображен ResNet-блок. Есть две параллельные ветви. Этот слайд про нашу статью с NeurIPS 2020 года, и здесь на слайде фото коллег из Сколковского института, в том числе двух моих научных руководителей, это Иван Оселедец и Анджей Чихотски. По ссылке можно найти ссылку на статью и код, чтобы повторить эксперименты.
Как я уже говорил, есть очень популярная и всем известная архитектура ResNet. На картиночке А находится ResNet-блок, который концептуально состоит из двух так называемых ветвей, бранчей, которые потом складываются в слой, который addition, и пропускаются через нелинейность, в данном случае это известная активация ReLu. Архитектуру ResNet все знают, также известна архитектура, которая называется Pre-ResNet, она тоже придумана Каймингом Хе, и тоже эту статью много раз цитировали, я смотрел, около 5 тысяч раз. В этой статье предложен другой вид ResNet-блока, когда параллельные ветки складываются, но дальше они не проходят через ReLu, но при этом в этой длинной ветке из нескольких слоев после нормализации идет сразу активация. Показано, что эта архитектура не хуже, чем ResNet, а иногда даже и лучше.
Что можно заметить? Если мы посмотрим на картинку Б, то можно понять, что это на самом деле очень похоже на метод Эйлера, самый простой метод решения систем дифференциальных уравнений, который выглядит следующим образом: где значение на следующем шаге, грубо говоря, на l+1 шаге, l+1 слое в данном случае, вычисляется как значение на предыдущем слое плюс hf, которое зависит от предыдущих значений. Мы видим, что есть прямая связь между архитектурой Pre-ResNet и методом Эйлера для решения дифференциальных уравнений, довольно очевидная и многим известная.
Также существует такая архитектура, которая называется DenseNet, она тоже очень известная и процитирована в статьях где-то около 10 тысяч раз. Слева на картиночке изображен так называемый Dense-блок, из которых состоит архитектура DenseNet. Она действует примерно следующим образом: каждая следующая группа слоев, которая выделена цветом, зависит от всех предыдущих групп слоев.
(00:05:04)
Зеленый слой получает на вход только Input, а фиолетовый слой получает на вход зеленый слой и Input, красный слой, желтый слой получает фиолетовый, зеленый и красный и так далее. Можно заметить, что это очень похоже на известные методы Runge-Kutta для решения тоже систем дифференциальных уравнений. Как они выглядят? Если метод S стадийный, то сначала вычисляется S коэффициентов k, где каждый коэффициент зависит от входа и от всех предыдущих коэффициентов, а затем значение на следующем шаге, на следующей итерации метода вычисляется следующим образом, это зависит от входа и от всех коэффициентов k. Есть прямая связь между DenseNet и методами Runge-Kutta.
На самом деле, существует довольно много архитектур, которые напоминают методы решения дифференциальных уравнений. Например, есть RevNet, PolyNet, FractalNet, но просто всех их я не стал упоминать и приводить на слайдах.
Но есть особенности, у этой связи есть особенности. Первая особенность в том, что эти нейросетевые архитектуры напоминают действительно методы для решения дифференциальных уравнений, но только с фиксированным шагом, хотя на практике многие специалисты по дифференциальным уравнениям предпочитают адаптивные солверы, которые умеют автоматически подбирать длину следующего шага, потому что так получается более точное решение.
Также есть особенность в том, что мы не можем рассчитывать, что эта динамика, то есть выходов соседних слоев, что она какая-то непрерывная, непрерывной зависимости здесь нет. Также аналогия с дифференциальными уравнениями не совсем прямая, в том смысле, что мы не можем добавить еще один блок, например, в ResNet, и недообучать сеть. Есть явная привязка к блокам, к количеству блоков.
Поэтому естественным продолжением, естественным использованием этой зависимости связей между дифференциальными уравнениями и известными нейросетевыми архитектурами была архитектура, которая называется Neural ODEs. Ее придумали в лаборатории Дэвида Дювено, была статья с NeurIPS 2018 года. Заключается примерно в следующем. Давайте вместо ResNet-блока или DenseNet-блока будем рассматривать просто систему дифференциальных уравнений, которая будет на вход принимать какой-то тензор z0, и этот z0 мы будем считать начальными условиями системы дифференциальных уравнений. А выходом этой системы дифференциальных уравнений, выходом этого блока, который на жаргоне часто называется PDE-блоком, мы будем считать значение z в точке t1, то есть на конце отрезка. При этом все параметры этого блока нейросетевого, они будут храниться в правой части, то есть в функции f, которая зависит от z и от θ, θ – это все параметры, которые задают поведение ODE-блока. Будем обучать этот блок так, как обычно это происходит в глубинном обучении, чтобы минимизировать какую-то лосс-функцию, которая в самом простом случае зависит от z(t1), то есть от конечного значения от выхода блока.
Последний пунктик здесь, я просто напоминаю, что есть зависимость между решением такой системы дифференциальных уравнений, и таким интегралом, таким интегральным выражением.
Здесь я привожу картинку из статьи про Neural ODEs, где слева построенная активации, то есть выходы каждых блоков ResNet, а справа построены выходы архитектуры Neural ODEs.
(00:10:01)
В архитектуре Neural ODEs можно использовать адаптивные солверы и солверы также с очень маленьким шагом. Если строить аналогию с дискретными нейросетевыми архитектурами, получается что это в некотором смысле сколько угодно глубокая нейронная сеть, где глубина задается шагом дифференциального уравнения.
Естественный вопрос, который здесь возникает, как решать эту оптимизационную задачу, то есть как минимизировать лосс-функцию, которая зависит от решения системы дифференциальных уравнений. Нам нужны градиенты лосс-функции по θ, где лосс-функция зависит от решения системы дифференциальных уравнений. Наверное, те люди, которые хорошо знают, как устроены библиотеки для автоматического дифференцирования, будь то Torch, TensorFlow, Jax, Autograd, они скажут, что никакой здесь проблемы нет, что мы просто можем написать численный метод, решить эту систему и дальше попросить эту библиотеку вычислить градиенты от решения, и она прекрасно справится с этой задачей. Эти люди будут правы. Мы можем взять, пройтись каким-нибудь методом вперед, от t0 до t1, и попросить библиотеку, чтобы она посчитала градиенты с помощью известного алгоритма обратного распространения ошибки, back propagation.
Но есть одна сложность, сложность заключается в том, что этому алгоритму back propagation необходимо хранить совершенно все вычисления для того чтобы дальше вычислить градиенты. Здесь жирными точками, не знаю, видно или нет, показаны промежуточные значения, и нам нужно хранить z от τ1, z от τ2, z от τ3 и так далее в памяти после прямого прохода. Несложно понять, что если сделать слишком маленький шаг, то мы не сможем хранить все это в памяти для довольно большой системы. Этот метод, он, конечно, предпочтителен, но если мы можем позволить себе делать довольно большой шаг и с довольно маленьким батчем.
Конечно, эту проблему можно частично обойти, если использовать так называемый чекпойнтинг, то есть если хранить не абсолютно все промежуточные значения, а лишь некоторые, а остальные пересчитывать заново. Здесь мы можем не хранить τ2 и τ4, но при этом τ2 мы будем пересчитывать через τ1. Нам придется дополнительно… Идем мы сначала с t1 до t0, нам придется сначала пересчитать τ4, потом пересчитать τ2, и потом вернуться. Так мы можем сэкономить память, но при этом нам придется проводить дополнительные вычисления. Этот метод довольно хорош, но, к сожалению, я не знаю ни одной библиотеки, которая бы хорошо его реализовала, то есть в теории он хорош, а на практике я не видел, чтобы люди так делали.
Все это, конечно, было придумано еще для нейронных сетей, для нейронных сетей тоже есть свои чекпойнтинг-алгоритмы, которые примерно так же устроены.
Есть еще третий классический подход, который называется Adjoint-методом, точнее, его в исходный статье о Neural ODEs его называли Adjoint-методом, хотя это название не очень хорошее, потому что Adjoint-метод, на самом деле, это немножко другое, и поэтому мы его называем Reverse Dynamic Method. или RDM. Дальше все сокращения RDM будут про этот метод.
Наш предложенный метод будет называться IRDM. В чем он заключается? Концептуально он заключается в следующем, что мы можем решать задачу вперед, начиная от времени t0 до t1, со сколько угодно мелким шагом, потому что ничего в памяти нам хранить не нужно, то есть мы ограничены только временем, но не памятью. Сохранить нам нужно будет только значение z в конечной точке, в t1, а градиенты обратно будут вычисляться с помощью решения еще одного дифференциального уравнения. Таким образом, мы можем делать сколько угодно мелкие шаги, и при этом мы можем использовать адаптивные методы, которые сами выбирают длину шага, потому что мы не боимся, что в какой-то момент метод сделает слишком много маленьких шагов, и все, программа перестанет работать из-за того, что кончилось место на графической карте.
(00:15:18)
В нашей работе, о которой я рассказывал в начале, мы развиваем и улучшаем этот метод, так, чтобы сделать его быстрее и устойчивее. Но об этом чуть позже.
Николай Михайловский: Талгат, а можно сразу вопросов парочку задать?
Талгат Даулбаев: Да, конечно.
Николай Михайловский: Вопрос первый. Это же у нас заменяет обычный ResNet примерно, плюс-минус, в котором у нас все равно хранятся данные на всех слоях, то есть у нас есть свертки на всех слоях.
Талгат Даулбаев: Да.
Николай Михайловский: Почему здесь идет борьба за память?
Талгат Даулбаев: Смотрите, здесь, хоть и есть аналогия с ResNet, но здесь этот набор параметров един для всех слоев. Еще можно… Здесь я не написал зависимость от времени, но на самом деле функция f может еще напрямую зависеть от времени, то есть будет такая хитрая нейронная… f – это такая хитрая нейронная сеть, она обычно последовательна, то есть безо всяких skip connections и так далее.
Николай Михайловский: То есть у нас один и тот же набор параметров, грубо говоря, для всех слоев.
Талгат Даулбаев: Да. Но только есть особенность в том, что обычно функция f еще зависит от времени, и время тоже подается, и поэтому в зависимости от времени мы можем получать разные значения f. Этот набор параметров θ обычно фиксирован для всех слоев, одинаковый. Но при этом еще функция f еще зависит от времени, поэтому выход разных блоков с одинаковыми параметрами и с одинаковыми начальными условиями с разными временами… точнее, выход каждого шага итерационного метода нашего в зависимости от времени будет разным. Не знаю, насколько это понятно.
Есть еще, я не стал приводить ссылки, но люди делают еще… Открытый вопрос, на самом деле, как правильно параметризовать такой Neural ODEs, люди делают еще θ, которые зависят от t, различными способами, например, строят аналогии с методами Галеркина или строят какие-то интерполяции для того чтобы θ было тоже зависимо от t, но при этом не требовала дополнительной памяти, как в ResNet, то есть чтобы θ в любой момент t можно было вычислить, но при этом не нужно было хранить много разных θ. Примерно вот такой ответ на этот вопрос.
Николай Михайловский: О’кей. Второй вопрос. Вы боретесь как бы с тем, что память потратиться, потому что делается много… решалка может сделать много коротких шагов и потратится память. С другой стороны, даже если у нас очень жесткие уравнения, то мы можем взять метод неявный, и неявным методом делать обычно довольно большие шаги, намного длиннее, чем мы бы делали явными методами. Или здесь уже делается слишком много шагов даже в случае неявных методов?
Талгат Даулбаев: Если говорить про неявные методы, я не видел ни в одной статье, чтобы напрямую неявные методы использовались, обычно используются явные методы. Мне сейчас сложно сказать, с чем это связано, но наверняка есть какие-то проблемы в использовании неявных методов. Но спасибо за вопрос, я подумаю после семинара над этим. Возможно, это тоже поможет как-то, может, для изучения нейронных дифференциальных уравнений. В основном все пользуются явными методами, да.
(00:19:50)
Николай Михайловский: Просто когда я был маленьким и занимался как раз жесткими… решалками для жестких систем дифференциальных уравнений. там обычно все уходило в то, что неявные методы помогают в этом все разобраться.
Виталий Безуглый спрашивает: «А что из себя представляют t в ResNet? Что такое длина шага?»
Талгат Даулбаев: В ResNet, на самом деле, мы можем считать, что все длины шагов одинаковые в рамках… Точнее, давайте так. Мы знаем, что в ResNet идет уменьшение размерности, давайте рассматривать ту последовательность ResNet-блоков, которые размерность не меняют. Их можно рассматривать как равномерные шаги на каком-то отрезке времени, вот такая аналогия. Напрямую t там не задано, но при этом можно рассматривать, если мы посмотрим на эту картиночку, можно считать, что эта h у всех одинаковая. Примерно такая аналогия.
Да, спасибо за вопросы, и особенно за вопрос про жесткие системы, идем дальше. Давайте я немножко повывожу различных формул, и покажу, как с математической точки зрения устроен этот последний метод, про который я говорил. Мы идем, сначала решаем задачи вперед, потом решаем задачи назад, при этом требуя только константное значение памяти.
В той статье, которая про Neural ODEs, находится какое-то современное доказательство, которое мне не очень нравится. Больше мне нравится доказательство через вариационное исчисление, мне кажется, так довольно естественно смотреть на эту задачу, когда мы хотим минимизировать функцию с такими ограничениями. Типичный researcher в машинном обучении или в прикладной математике обычно любит Каруша-Куна-Таккера либо вариационное исчисление и выписывает лагранжиан. Он довольно понятно выписывается, у нас есть функция, которую мы хотим минимизировать, вот много различных ограничений, которые… В дискретном случае у нас была бы здесь сумма, в непрерывном случае интеграл, где a(t) – это множитель Лагранжа. Но во всей этой теории нейродифференциальных уравнений a(t) называется ajoint-переменной. Эти ограничения мы тоже можем записать как какое-то число на (z(t0) – z0).
Дальше мы берем вариацию по разным переменным. Если мы посчитаем вариацию по θ, получится такое выражение, которое должно быть справедливо для любой допустимой вариации h. Отсюда мы можем понять вот что. Давайте посмотрим на это выражение, которое равно нулю. h, конечно, выносится, получается, что частная производная L по θ при z(t1) минус такой интеграл равны нулю. Эта частная производная, на самом деле, нас интересует, она нам нужна, и она равна вот такому интегралу.
Так как есть прямая зависимость между интегралом и дифференциальным уравнениям, давайте запишем дифференциальное уравнение в таком виде. На самом деле, мы можем записать дифференциальное уравнение и при t от t0 до t1, но будут проблемы, чуть позже объясню, почему. Поэтому эта система записывается как дифференциальное уравнение при времени, которое идет от t1 до t0, с нулевыми начальными условиями, потому что эта штука равна 0 плюс этот интеграл. Мы меняем интеграл от t1 до t0, меняется знак и получается такая система. В общем, математически кажется, что что-то сложное, на самом деле, концептуально очень просто, то есть много разных символов, но концептуально все очень понятно. Таким образом, мы получаем систему на то, что нам интересно, то есть если мы решим такую систему, мы получим частную производную по θ при z(t1),θ, что нам и нужно. Но эта система зависит от неизвестных переменных, нам еще a(t), и z(t), на самом деле, мы пока тоже не умеем вычислять.
Давайте пойдем дальше.
(00:24:59)
Николай Михайловский: У нас есть пара вопросов, их отложим чуть-чуть или ответим?
Талгат Даулбаев: Так, давайте… У меня, к сожалению, пропал блок вопросов…
Николай Михайловский: Ничего, я вам зачитаю.
Талгат Даулбаев: О неявных методах. Да, действительно, на Julia оказывается довольно хорошая…
Николай Михайловский: Давайте, чтобы у нас в памяти осталась я зачитаю то, что здесь Алексей написал: «О неявных методах, именно поэтому мне нравится играться с Julia, там не надо приписывать методы и решения дифуров (00:25:30) специально для использования в нейросетках, поэтому можно подставлять любые уже запрограммированные методы решения, в том числе и неявные».
Талгат Даулбаев: Да. К сожалению, про Julia, про то, что на Julia хорошая библиотека для тяг этих дифференциальных уравнений с нейросетями, что там есть, я это узнал после того, как мы написали эту работу, к сожалению. Но да, она там есть, и действительно хорошая.
«А не напоминает рекуррентные сети?» Да, напоминает, и я потом расскажу про связь, про то, как можно сделать непрерывные рекуррентные сети.
Давайте вернемся сюда. Мы показали, что на самом деле мы можем найти то, что нас интересует, этот градиент по θ, если мы будем решать такую систему. Но в этой системе есть неизвестные, которые нам нужно откуда-то взять. Продолжаем дальше считать вариации. Давайте посчитаем вариацию по z. Получается немножко более страшное выражение, которое… Это просто по определению, которое в сноске указано, то есть здесь что происходит? Довольно легко вариация этого члена, дальше то, что под интегралом, здесь никаких проблем, f мы можем расписать в ряд Тейлора, и последний член, когда мы его варьируем, там остается h(t0) h(t0=0), просто у меня на слайд не влезло. Поэтому здесь этот последний член тоже пропадет после этой вариации.
Дальше типичная техника, которая используется, интегрирование по частям, чтобы убрать производную с h(t) и все свести к такому выражению, в котором h фигурирует только как функция, без своих производных. Дальше можно воспользоваться основной леммой вариационного исчисления и сказать, что то что, в фигурных скобках, равно нулю, это, по сути, дифференциальное уравнение, и то, что здесь в больших круглых скобочках равно нулю, это начальное условие. Получается такое дифференциальное уравнение на а. Даны начальные условия в точке t1, то есть система будет решаться от обратного времени, от t1 до t0. Надеюсь, что более-менее понятно.
Как считать вариации по а, довольно понятно, просто получится то же самое дифференциальное уравнение, которое у на было, а по b получатся те же самые начальные условия.
Хорошо, идем дальше. Таким образом, получаются такие две системы, про эти две системы я рассказал, а та система, которая обведена в «коробочку», в ней есть особенность. Особенность заключается вот в чем. Нам бы хотелось решать эти две системы обратного времени, но если мы будем решать эту систему, которая у нас была изначально, от t0 до t1, то это будет очень сложно, нам придется в каждый момент времени, когда нам нужно z(t), а z(t) входит в каждую из этих систем, нам приходилось бы решать систему от t0 и дальше, то есть довольно сложно было бы. Поэтому Дювено в статье, которая про Neural ODEs, исходной, они предложили решать систему на z обратно во времени, то есть сохраняя z(t1), и потом на обратном проходе решать систему от t1 до t0. Итого, этот метод берет эти три системы вместе и решает их от времени t1 до t0. Надеюсь, что понятно.
(00:29:49)
Есть кое-какая проблема в этом допущении, когда мы вместо того чтобы решать dz по dt вперед, решаем ее назад, и она легко иллюстрируется таким примером из статьи. Просто возьмем картиночку из MNIST, и будем считать, что это начальное условие. Возьмем один ResNet-блок в качестве правой части дифференциального уравнения, и пропустим эту картинку через него. Получится какая-то такая картинка, то есть это просто взяли и посчитали, получится вот такая картинка. Теперь, если мы захотим посчитать эту систему обратно с помощью какого-нибудь метода явного, не очень точного, то получится такой шум на выходе, то есть получается, что эта система довольно жесткая, система на z, которая решается обратно. Кажется, что это довольно типичное поведение для систем, которые решаются обратно во времени, хотя я не очень большой специалист был в дифференциальных уравнениях раньше. Соответственно, этот метод может иметь проблемы с устойчивостью, потому что эта маленькая подсистема на z входит в большую систему и мешает этой системе быть решенной за какое-то разумное количество шагов.
Николай Михайловский: А можно какие-то оценки получить на собственное значение соответствующей матрицы, чтобы смотреть, оценивать жесткость этой системы?
Талгат Даулбаев: Вообще, мы пробовали что-то такое делать, но не довели до конца. Поэтому я не могу вам, наверное, на этот вопрос нормально ответить. Есть еще некоторые проблемы, что непонятно, как оценивать жесткость, на самом деле. Есть много разных методов, и ни один не идеален, кажется.
Николай Михайловский: Хорошо. Ни один не идеален, согласен.
Талгат Даулбаев: Да. Наше предложение примерно такое, но я немножко оговорюсь. Идея такая: давайте не решать эту систему обратно от t1 до t0, так, как делали раньше, а давайте во время прямого прохода возьмем и сохраним какие-то точки z(t) так, чтобы потом на обратном проходе при решении этих двух оставшихся систем получать z(t) с помощью интерполяции.
Как это выглядит? Мы во время прямого прохода… Эти красные жирные точки – это наши значения. Мы выбираем Barycentric Lagrange Interpolation, такой довольно известный и хороший метод интерполяции на Чебышевской сетке, сохраним это на Чебышевской сетке. Важно оговориться, что мы можем запускать адаптивный метод, который будет идти как зеленые стрелочки, и при этом интерполировать значение в необходимых нам точках красных. Мы никак не ограничиваем адаптивный метод, а интерполируем значения в красных точках. Таким образом, мы просто сохраняем эти значения во время прямого прохода. Во время обратного прохода при решении задачи мы просто интерполируем z(t) за O от числа наших чекпойнтов, этих красных точек. Собственно, эта вся идея. Важно сказать, что мы не знали о том, что такое интерполирование используется в дифференциальных уравнениях, но есть пакет CV ODEs, который уже использует похожие идеи, не конкретно такие же, но очень похожие, для нейродифференциальных уравнений, об этом тоже важно сказать. Но для нейронных сетей это, кажется, не было использовано раньше.
В чем плюсы? Плюсы в том, что у нас была система, которая… Мы не можем говорить, что она жесткая, потому что мы не проверяли, и никто, кажется, не может это нормально проверить, просто есть подсистема, которая была довольно нестабильна. Мы ее убираем из большой системы, и получаем что-то более устойчивое.
(00:35:04)
Так как мы убираем эти уравнения, то у нас просто уменьшается размерность системы, причем довольно сильно, на число элементов во входном тензоре. Мы можем использовать адаптивные солверы, то есть мы не теряем адаптивность и никак не ограничиваем эту решалку в выборе шага.
В деталях, как я уже говорил, мы используем Чебышевскую сетку, храним, дальше N будет обозначать количество чекпойнтов, которые мы используем. Мы храним N чекпойнтов, восстанавливаем z(t) всегда за O(N), там просто нужно посчитать линейную комбинацию. Как я уже говорил, адаптивные солверы могут быть использованы без каких-то проблем.
Давайте покажу какой-то простой пример классификация на CIFAR-10. Вы видите довольно небольшие числа, дело в том, что на CIFAR-10 и вообще для классификации Neural ODEs пока не достигают лучших результатов, таких, как у стандартных нейронных сетей, но мы просто взяли архитектуру, которая использовалась в Neural ODEs, и обучили ее с нашим методом. При этом использовали всего 8 из 16 чекпойнтов, то есть довольно мало.
Показано, что обучается быстрее и сходится примерно к такому же результату, только за более короткое время.
Но классификацией вообще не ограничивается применение Neural ODEs, и более интересный пример – это использование Neural ODEs для генеративного моделирования. Наверное, мне стоит сначала рассказать про такое семейство обычных дискретных моделей для генеративного моделирование, которое называется Normalizing Flows, «потоки», довольно известные, но все-таки используются, реже чем ганы, на мой взгляд. Принцип работы у всех потоков такой: давайте мы будем хотеть моделировать плотность, например, наших картинок, она очень сложная, и изображена справа на этом рисунке. Но при этом мы будем уметь сэмплировать из какого-то простого распределения, например, гауссовского. Оно, конечно, на картинке больше на ___ (00:37:44) похоже.
Что мы будем делать? Мы придумаем себе такое семейство функций fk, и будем требовать от них объективности и гладкости, чтобы существовала обратная функция каждой fk, и чтобы каждая fk функция была гладенькая. Построим такую архитектуру, которая будет отображать сэмпл из простого распределения в сэмпл из сложного распределения с помощью композиции этих функций. Каждая из этих функций, конечно, зависит от параметров, которые обучаются.
Для обучения этой модели нужно, чтобы существовали обратные функции k, то есть чтобы fk-1 тоже была, чтобы мы могли отображать эти наши картиночки из сложного распределения, необязательно картиночки, наши сложные данные, в простой шум.
Чем эти модели хороши? Тем, что кроме сэмплирования они могут еще оценивать плотность распределения через довольно простую форму, которая находится в курсе матанализа, о пересчете плотности распределения после каждого такого катого преобразования.
На самом деле, существует очень много моделей, и они отличаются выбором этих семейств функций. Какая есть проблема? Проблема, конечно, в определителе Якоби, функции f. Если функция f будет произвольной нейронной сетью в данном случае, то определитель Якоби будет считаться очень сложно.
(00:39:54)
Поэтому разные потоки отличаются друг от друга этим видом функции, чтобы получить каким-то хитрым образом якобиан, от которого будет легко вычислить определитель. Например, самый простой пример, это матрица, просто перемножать диагональные элементы. Здесь мы получаем какое-то ограничение, но при этом Normalizing Flows, все равно, самые продвинутые модели работают неплохо.
Оказывается, можно получить непрерывное обобщение этих Normalizing Flows, используя следующий факт. Оказывается, что при довольно мягких ограничениях на правую часть, липшицевость по z и непрерывность по t мы можем записать такое дифференциальное уравнение на логарифм плотности. Здесь вместо определителя от якобиана будет след от якобиана, что гораздо более простая функция, просто неимоверно простая функция, по сравнению с определителем. Что делают? Просто предлагают взять и дописать это уравнение к системе на z, это уравнение к тому же еще и одномерное, потому что плотность одномерная, и начальными условиями будет логарифм плотности z0, точнее, тут нужно было написать log p0, наверное, то есть во времени t0 мы просто рассматриваем, например, гауссовскую случайную величину, и плотность в любой точке от нее посчитать тоже очень удобно, очень легко. Таким образом, можно строить генеративные модели.
К тому же, пошли дальше, те же люди из лаборатории Дювено сделали статью, которая называется FFJORD, в ней он просто предлагают поменять этот trace, который от якобиана все равно довольно сложно считать, потому что нужно вычислять элементы якобиана, на такую известную оценку, которая еще называется Hutchinson’s Trick, можно заменить подсчет следа матрицы на матожидание по z, где z из гауссовской… гауссовская случайная величина либо радемахеровская, то есть она принимает значения +1 и -1 с равными вероятностями. Здесь нам нужно уметь всего лишь умножать матрицу на вектор. Умножение якобиана на вектор – это, в принципе, то, что умеют делать эти библиотеки для построения нейросетей.
Таким образом, можно не вычислять полностью якобиан, а просто уметь умножать его на вектор, сэмплировать сколько-то векторов, к сожалению, я не знаю, сколько они использовали для экспериментов, не помню, но получится быстрее, чем вычислять полный якобиан.
Таким образом, делается генеративное моделирование, и для такой задачи мы тоже применяли наш метод, и графики выглядят следующим образом. Видно, что метод ведет себя стабильнее, test loss для исходного метода здесь, на этом графике, ведет себя довольно странно, это усреднение по 9 разным сидам. Еще наш метод требует меньшего числа вычислений правой части, если складывать вычисления правой части на прямом проходе и на обратном, то у нас будет меньше вычислений правой части. Потенциально, в сложных нейросетях, мы полагаем, что правые части могут быть довольно вычислительно затратные, поэтому меньшее количество вычислений правых частей – это плюс метода.
Еще мы проводили эксперименты просто на тех данных, которые были в исходных статьях и сравнивались, и можно заметить, что в первом столбце – это исходный метод, время на итерации, а во втором столбце, в третьем и так далее – это наш метод с разным количеством Чебышевских узлов.
(00:44:51)
Можно заметить, что, в принципе, если взять 16 или 8 Чебышевских узлов, то мы получим в среднем более быстрое обучение этих моделек.
Я не буду детали объяснять, но в исходной статье еще были эксперименты с VAE и с Neural ODEs совмещенными. Мы тоже запустили наш метод, и получили меньшее количество вычислений правой части при 8 и 16 узлах и более быстрое падение лосса, что тоже хорошо.
Таким образом, это слайд с некоторым summary, есть такие модельки Neural ODEs, которые являются естественным обобщением дискретных известных архитектур. Есть метод Ajoint, который описан в статье и часто используется, но он не очень устойчив, и мы можем его поправить, просто используя интерполяции, при этом требуя какое-то константное значение памяти, и при этом уменьшится время вычисления, время обучения. Мы надеемся, что также улучшится стабильность.
На этом про нашу статью я закончу, и расскажу еще про две статьи из области, просто которое немножко про другие темы, чтобы у слушателей сложилось какое-то мнение и понимание, что происходит в области. Мне задавали вопрос, похоже ли это на рекуррентные сети. Да, похоже. Но вообще, можно делать даже непрерывные рекуррентные сети, есть такая работа, GRU-ODE-Bayes, она с NeurIPS позапрошлого года.
Предлагают авторы следующее. Есть обычная сеть GRU, довольно известная. В GRU рассматривается динамика для hidden state, для скрытых представлений. В чем особенность GRU? В том, что обычно с помощью GRU можно рассматривать только временные ряды с одинаковым шагом. Но многие временные ряды в жизни не являются равномерными. Например, представьте себе данные о пациентах больницы, у которых меряют давление, температуру, сахар в крови, например. в совершенно разное время. Поэтому для таких сетей приходится использовать непрерывные модели.
Непрерывную GRU можно получить довольно просто. Давайте возьмем, вычтем ht просто из первого уравнения, получится ht-1, и поделим все на дельта t, получится примерно вот такая закономерность, такая аналогия между дискретной моделью и непрерывной моделью. Авторы предложили просто взять и сделать непрерывную GRU. Будет рассматриваться такое дифференциальное уравнение, где r, z и g будут тоже непрерывные и вычисляться следующим образом.
Что они предложили? Концептуально они делают следующее. Пусть нам нужно предсказывать временной ряд, тогда эта модель GRU-ODE, она просто берет и может предсказать значение временного ряда в совершенно любой момент времени. Но если к нам в какой-то момент на tk поступят новые данные, авторы предлагают немножко корректировать hidden-слой, то есть проводить обновление. Делают они это с помощью такой сети, которую они называют GRU-Bayes, по сути, они просто обновляют статистики и подают это в сеть GRU и получает новую h. Они берут h, берут статистики, по-моему, берут новый объект, и подают это в GRU, получают обновление на h, оно такое дискретное, то есть они обновили h и предсказывают себе дальше временной ряд.
(00:49:57)
Как только появились новые данные, они опять делают какое-то обновление, и дальше предсказывают временной ряд. Они позволяют, эти модельки, делать в некотором смысле онлайновое обучение, приходят новые объекты, мы корректируем предсказание.
Есть еще непрерывные версии LSTM тоже. Но GRU-ODE-Bayes – довольно популярная статья. Это если говорить про рекуррентные сети и временные ряды, которые посэмплированы неравномерно.
Еще хотел бы упомянуть статью, которая с будущей конференции, с ICLR 2021, она уже признана outstanding paper, одной из лучших статей, и она тоже использует дифференциальные уравнения. Это еще одна генеративная модель с использованием дифференциальных уравнений.
На самом деле, есть уже довольно давно разрабатываемый подход, который называется Score-Based-подход для генеративного моделирования. Основан он примерно на следующем. Представьте, что мы можем выучивать, каким-то образом получать градиент логарифма плотности какого-то распределения. Оказывается, это довольно известно, в том числе в физике, что есть динамика Ланжевена, которая позволяет, зная градиент плотности распределения, делать сэмплирование из распределения по f(x). Это уже давно известно и было показано во многих предыдущих статьях, многие из которых были написаны тем же человеком, Янг Сонг.
В этих статьях в старых предлагался способ, как можно заставить нейросеть выучивать градиент логарифма p, при этом не зная p, то есть там были такие хитрые методы, как минимизировать матожидание MSE между градиентом логарифма p и выходом нейросети. Раньше все происходило так: нейросеть выучивала градиент логарифма p, и дальше сэмплировала с помощью динамики Ланжевена. Но в этой статье с будущего ICLR авторы предлагают следующее. Давайте считать, что у нас есть стохастическое дифференциальное уравнение, которое берет картинку какую-то, эту собачку, во времени t0, и превращает в шум во времени Т. Оказывается, это статья какого-то 80-го года, что обратное отображение выглядит следующим образом. Если прямое отображение выглядит вот так, то обратное отображение выглядит следующим образом, и прослеживается связь со Score-Based-моделированием. Значит, что это уравнение позволяет с помощью решения дифференциальных уравнений сэмплировать из шума данные. На правой картинке из шума получены лица, по-моему, это датасет CelebA, а NFE – это количество шагов, Number of Forward Estimations. Чем меньше шаг, тем лучше лицо получается на этой картинке из статьи.
Подход примерно заключается в следующем. Давайте выучим score-функцию, как умеем, потом выучим параметры этих f, и дальше от стохастического дифференциального уравнения просто перейдем к обычному, обыкновенному, уже без части, отвечающей за шум, и будем из шума сэмплировать картинки.
Почему мне эта статья очень нравится? Мало того, что там очень красивая математика, на мой взгляд, во всей этой теории про Score-Based-модели, еще получаются очень хорошие картинки. Картинки, на мой взгляд, ничем не хуже, чем то, что дают ганы, а на CIFAR-10, насколько мне известно, это вообще по метрикам лучший результат среди того, что существует. Поэтому есть какая-то надежда, что модели, основанные на дифференциальных уравнениях, будут давать лучшие результаты даже в тех областях, где давно есть ганы и прочие генеративные модели.
(00:55:12)
На этой позитивной ноте я, наверное, передам слово Александру. Он немножко расскажет…
Александр Катруца: Добрый день. Да, один слайд про то, что можно дальше делать в этом направлении. Тут есть несколько наиболее популярных и понятных для дальнейшего исследования тем. Первая – это то, как правильного выносить ODE-блоки, то есть слои которые моделируют некоторую скрытую динамику через обыкновенные дифференциальные уравнения, и смотреть, соответственно, как эта модификация архитектуры будет влиять на качество.
Например, была работа про то, как всяческие нормализации влияют на качество получаемых моделей, поскольку типичным условием на всякие там теоремы в дифурах, есть лип, (00:56:16) что с правой части, и введение различных способов нормализации там, Batch Norm, Layer Norm, Group Norm и прочие, они по-разному дают разные эффекты на качество получаемых моделей.
Помимо этого, есть отдельный трек, отдельная серия работ, которые тоже можно продолжать, про то, как дополнительно требовать некоторые свойства у обучаемой динамики, например, чтобы она была как можно более простой, в смысле, самая простая динамика, понятно, линейная, чтобы не было каких-либо сложных конфигураций, при сохранении качества, например. Или чтобы при фиксированном финальном времени, которое используется для обучения, при увеличении этого времени качество бы не ухудшалось, то есть мы могли бы смотреть, как бы себя вели скрытые представления на бесконечности.
Помимо этого, есть еще отдельные треки про то, как эти общие модели использовать для конкретных задач, из медицинских данных, из всяческих Data Driven моделирований, моделирований всяких физических явлений, в Object Detection для Point Cloud и тому подобных. Эта область, кажется, довольно сильно сейчас развивается, и она еще в стадии разработки находится, то есть не является какой-то законченной теорией, про которую все понятно. Поэтому, в общем, конечно, довольно перспективны исследования в этом направлении.
Талгат Даулбаев: Вот. На этом, наверное, все. Здесь на слайдах есть ссылки на статьи, которые были упомянуты. Эту презентацию можно найти по ссылке, либо, если вы с мобильного устройства, то QR-код, который ведет сюда. Спасибо большое. Есть ли какие-то вопросы?
Николай Михайловский: Спасибо, Талгат, спасибо, Александр. Коллеги, есть у вас к Александру и к Талгату еще какие-то вопросы, замечания, предложения? Можно писать в чат, можно писать в Q&A, можно поднимать руку, я вас тогда пущу разговаривать.
Талгат Даулбаев: Если вопросов нет, но они появятся, можно писать на почту, контакты можно найти на той страничке на GitHub, которую я оставлял на одном из своих слайдов.
Николай Михайловский: Леша Гольдин, я знаю, ты тоже эту тему немножечко крутил, ничего не хочешь сказать или спросить? Давайте, кто-то у нас руку поднимал. Кто-то руку поднял и опустил, все пропустил. Если кто-то поднимал руку, поднимите ее еще раз. Да, Леша, тебя не слышно, я тебя пущу. Теперь, если ты подключишь микрофон, тебя может быть слышно.
(00:59:59)
Но у тебя на вид микрофона нету вообще. Да, тебя совсем-совсем не слышно.
Талгат Даулбаев: Можно попробовать в чате.
Николай Михайловский: Да. Коллеги, еще у кого-то вопросы или соображения? Пока вы думаете, у меня есть в качестве накидывания тем, раз уж там был отдельный слайд с будущими работами, мне кажется, забавным было бы вспомнить, что те конволюции, которые есть в конволюционных сетках, это, по сути, вариации на тему операторов дифференцирования, то есть свертка (01:00:50) является некоей вариацией на тему оператора дифференцирования. Тогда у нас есть измерение, в котором оператор дифференцирования – это свертка, есть измерение как бы времени, и тогда мы получаем уравнение в частных производных вместо нейронной сети. Это уравнение в частных производных, вероятно, можно каким-то образом решать или исследовать. Возможно, там что-нибудь такое прикопано, в этом месте.
Талгат Даулбаев: Да, можно сразу отвечу тогда на это? Да, действительно, это очень, на мой взгляд, горячая тема. Из того, что есть, например, есть Иван Ящук, который написал библиотеку, в которой скрестил Phoenix и Firedrake, то есть программы для вычисления, для решения частных производных, и методы для вычисления градиентов решений. Он реализовал этот Ajoint-метод, который для обычных дифференциальных уравнений, я рассказывал, он также возможен для уравнений в частных производных, и уже есть библиотека, которая делает это все на Jax. Jax – это новый фреймворк от Google. Поэтому если кому-то интересно, библиотека в открытом доступе, можно в ней поковыряться.
Николай Михайловский: Хорошо. Вторая мысль, она чуть более сложная, наверное, мысль примерно следующая, что у нас… Появился третий Алексей Гольдин, который у нас появился, с микрофоном.
Алексей Гольдин: Меня сейчас слышно?
Николай Михайловский: Слышно, Леш, тебя.
Алексей Гольдин: На самом деле, я только играю с этой штукой, на самом деле, я еще на практике ее не использовал. У меня, на самом деле, был такое вопрос, что если, например, взять какие-то архитектуры типа Net какой-то, либо этот Perceiver, который недавно появился, когда мы все эти данные подаем снова и снова, и иногда те же самые слои используем, как в Perceiver, можно ли их как-то переделать на эти Neural ODEs, будут ли у нас какие-то преимущества с этим?
Талгат Даулбаев: Это похоже на какую-то идею для дальнейших исследований, но это мы не делали. Да, возможно…
Алексей Гольдин: Понятное дело, что у вас нет возможности делать все.
Талгат Даулбаев: Да-да-да.
Алексей Гольдин: Просто думали ли вы вообще хотя бы об этом?
Талгат Даулбаев: Нет, если честно, то не думали, но, наверно, идея хорошая. Спасибо.
Николай Михайловский: У нас есть вопрос в Q&A, Тимур спрашивает: «Расскажите про Julia, и как там все этой темой?» Если честно, я вопроса не понимаю, потому что я уже с этой вообще темой, с Neural ODE или с какой-то более частой темой, которую мы только что обсуждали.
Талгат Даулбаев: Да, к сожалению, на Julia я не пишу, и я знаю только поверхностно, что там тоже реализовали какую-то интерполяцию, но об этом мы уже узнали после того, как написали статью. Это все, о чем не могу сказать, потому что мы в последнее время перешли, также пишем на Python, но с PyTorch пытаемся перейти на Jax.
Николай Михайловский: Да, Тимур уточняет: «С ODE и автодифференцированием».
Алексей Гольдин: Я игрался немножко с Julia, опять же у меня нет ни одного проекта в production, только пока что экспериментируем с этим делом.
(01:04:59)
Но там, в общем-то, практически любая функция может дифференцироваться, там это на уровне компилятора сделано, и у нее очень хорошо с composability, то есть никто не писал первоначально эти методы решения для ODEs, например, для PyTorch, чтобы решать, там надо специально переписывать метод решения дифференциальных уравнений, чтобы использовать для этих Neural ODE, а для Julia просто используется тот, который уже есть. Они просто дописали дополнительный метод для того чтобы… этот Ajoint, чтобы считать производную, и там, в общем, практически очень мало что понадобилось извне, то есть в этом смысле довольно гибкая система. Но, насколько я знаю, там performance не такой хороший на graphical картах, как у PyTorch или у Jax какого-то, но в остальном язык очень привлекательный, то есть компилируемый и удобный, как Python. Так что я бы посмотрел, то есть я думаю использовать это для production где-то в будущем, но пока что у нас этого еще нет.
Николай Михайловский: Спасибо, Леш. Вторую мысль хотел сказать, она и у меня-то довольно смутная, но, может быть, чем-то будет забавно. Мысль следующая, что по одной из гипотез, рельеф решений у нейронных сетей связан с некоей фрустрацией, подобной геометрической фрустрации, которая в латентном пространстве, в котором существуют примеры, происходит за счет конкуренции обучающих примеров. Возможно, сама структура многообразий, которая там получается в связи с этими фрустрациями, она обусловлена пространством примеров. Возможно, эта штука лучше исследуется с помощью нейронных дифференциальных уравнений, нежели чем с помощью обыкновенных сетей, потому что подобные штуки вообще лучше исследуются с помощью каких-то непрерывных вещей. Немножко в других словах, переводя на слова, понятные нейросетевому сообществу: возможно, у нейронных ODE лучше исследуются adversarial samples, то есть возможно, проще исследовать устойчивость нейронных сетей к adversarial samples с помощью нейронных дифференциальных уравнений, чем на дискретном уровне.
Талгат Даулбаев: Да, возможно, то есть то, о чем вы говорите, над этим мы действительно думали, но пока не пока ни к чему… К чему-то пришли в лаборатории, но не к чему-то завершенному. А про adversarial-атаки если говорить, у нас недавно вышел препринт про то, как можно делать adversarial training, но это, конечно, только связано с… есть связь только с adversarial-атаками, что различная параметризация решателей помогает увеличивать устойчивость Neural ODEs к adversarial-атакам. Поэтому у нас есть новый препринт, но это просто в качестве рекламы, наверное, не очень относится именно к исследованию adversarial-атак для обычных нейронных сетей.
Николай Михайловский: Это тоже интересно, и интересно, что примерно в одну сторону у всех идет мышление.
Талгат Даулбаев: Да-да-да. Спасибо.
Николай Михайловский: Все, всем спасибо, до свидания.
Талгат Даулбаев: До свидания.
Александр Катруца: До свидания.
Талгат Даулбаев: Спасибо вам.
(01:09:18) (Конец записи)