Всем привет! Пара анонсов/записей.
1. На прошлой неделе выступил для школьников в рамках программы Академии Яндекса с рассказом про DL.
Запись тут:
https://www.youtube.com/watch?v=J7uWN0-_A2A
Может быть интересно не только школьникам, но и тем, кто хочет простыми словами про область в целом за час времени. Ну насколько это можно в таком режиме :) Надеюсь, что худо-бедно получилось.
"Нынешняя революция Deep Learning началась уже примерно десять лет назад. За это время много всего произошло. Мы научились решать множество ранее нерешённых задач: распознавать изображения на уровне лучше человека, играть в го, предсказывать структуру белков, генерировать картинки фотографического качества и неотличимые от человеческих тексты. Появились новые архитектуры нейросетей, высокоэффективные и мощные фреймворки и библиотеки, высокопроизводительное железо. Мы продвинулись в научном понимании того, что происходит. Но вопросов ещё множество.
В лекции я сделаю краткий обзор важных вех на этом пути, расскажу про перспективы области и открытые вопросы. Возможно, кто-то из вас поможет продвинуться по этому пути дальше."
2. На этой неделе в пятницу 18 февраля выступаю на конференции OpenTalks.ai с рассказом про достижения в NLP в 2021 году.
https://opentalks.ai/ru/timetable#!/tab/404591939-3
Постарался собрать вместе всё интересное и важное, что можно уместить в 40 минут :)
1. На прошлой неделе выступил для школьников в рамках программы Академии Яндекса с рассказом про DL.
Запись тут:
https://www.youtube.com/watch?v=J7uWN0-_A2A
Может быть интересно не только школьникам, но и тем, кто хочет простыми словами про область в целом за час времени. Ну насколько это можно в таком режиме :) Надеюсь, что худо-бедно получилось.
"Нынешняя революция Deep Learning началась уже примерно десять лет назад. За это время много всего произошло. Мы научились решать множество ранее нерешённых задач: распознавать изображения на уровне лучше человека, играть в го, предсказывать структуру белков, генерировать картинки фотографического качества и неотличимые от человеческих тексты. Появились новые архитектуры нейросетей, высокоэффективные и мощные фреймворки и библиотеки, высокопроизводительное железо. Мы продвинулись в научном понимании того, что происходит. Но вопросов ещё множество.
В лекции я сделаю краткий обзор важных вех на этом пути, расскажу про перспективы области и открытые вопросы. Возможно, кто-то из вас поможет продвинуться по этому пути дальше."
2. На этой неделе в пятницу 18 февраля выступаю на конференции OpenTalks.ai с рассказом про достижения в NLP в 2021 году.
https://opentalks.ai/ru/timetable#!/tab/404591939-3
Постарался собрать вместе всё интересное и важное, что можно уместить в 40 минут :)
YouTube
Введение в Deep Learning. Григорий Сапунов
Нынешняя революция Deep Learning началась примерно десять лет назад. Мы научились решать множество ранее нерешаемых задач: распознавать изображения иногда даже лучше человека, играть в го, предсказывать структуру белков, генерировать картинки фотографического…
👍26
Supermasks in Superposition
Mitchell Wortsman, Vivek Ramanujan, Rosanne Liu, Aniruddha Kembhavi, Mohammad Rastegari, Jason Yosinski, Ali Farhadi
Статья: https://arxiv.org/abs/2006.14769
Пост: https://mitchellnw.github.io/blog/2020/supsup/
Код: https://github.com/RAIVNLab/supsup
Ещё про суперпозицию, но другого рода. И снова в контексте борьбы с catastrophic forgetting.
Начать стоит издалека. Уже давно в работе про Lottery Ticket Hypothesis (https://arxiv.org/abs/1803.03635) было показано, что в обученной сети есть подсети, которые дают такое же (или даже более высокое) качество, будучи натренированы с нуля с той же инициализации, что и большая сеть, в которой их нашли. Потом много чего было, например, работа про супермаски (и не только, https://arxiv.org/abs/1905.01067), где показали, что в рандомно инициализированной сети уже есть подсети с высоким качеством (и маска задаёт такую подсеть). Потом была работа “What's Hidden in a Randomly Weighted Neural Network?” (https://t.me/gonzo_ML/196), где авторы предложили алгоритм Edge-Popup для нахождения таких подсетей. Коллектив (почти) этих же авторов написал через год другую интересную работу (была принята на NeurIPS 2020).
Здесь также стоит отвлечься и вспомнить интересную работу про альтернативу файнтюнингу под названием “Piggyback: Adapting a Single Network to Multiple Tasks by Learning to Mask Weights” (https://arxiv.org/abs/1801.06519), где с помощью маскирования весов обученной сети добивались адаптации сети к новым задачам. У этого метода было преимущество в том, что оригинальные веса не трогались, соответственно не происходило забывания, свойственного файнтюнингу при обучении сети новым задачам.
Авторы текущей работы в каком-то смысле сочетают эти две. Они предложили метод под названием SupSup (Supermasks in Superposition), позволяющий в базовой рандомно инициализированной сети находить маски под разные задачи. Причём в том числе и для кейсов, когда конкретная задача в данный момент неизвестна и сеть должна догадаться, какая это задача была.
Первым делом авторы предложили таксономию сценариев continual learning и специальный трёхбуквенный код для описания. Используя буквы G (Given) и N (Not given) они описывают, известны ли id задач во время обучения (первая буква кода) и тестирования (вторая буква). И ещё есть третья буква, которая говорит, расшарены ли метки классов между задачами (s) или нет (u). Получаются разные варианты, но практически полезные среди них следующие: GG (самый лёгкий, id задач известны в трейне и тесте, а GGs и GGu эквивалентны, поэтому просто GG), GNs (id задачи известен в трейне и неизвестен в тесте, метки классов общие), GNu (то же, но метки раздельные, что оказывается более сложным, потому что эффективно надо предсказывать классов больше в число раз равное числу задач), и наконец NNs (потому что сценарий NNu невалиден).
Во всех сценариях мы работаем со случайно инициализированной сетью. Веса её заморожены и вообще не обучаются. Все bias термы установлены в 0, в параметры весов в ±c с равной вероятностью, где c — это стандартное отклонение соответствующего Kaiming normal distribution (про важность выбора распределения инициализации было в предыдущей их работе).
Для сценария GG всё просто — информация о задаче есть и в режиме обучения, и в режиме тестирования. Здесь для каждой новой задачи можно выучить новую бинарную маску (тем же Edge-Popup), при вычислении сети веса маски {0,1} перемножаются с соответствующими весами модели. Маску, кстати, можно хранить в разреженном формате, а веса сети можно вообще не хранить, а зная seed просто генерировать. Получается весьма мало места. И разреженность можно также регулировать, находя баланс между качеством и занимаемым местом.
Mitchell Wortsman, Vivek Ramanujan, Rosanne Liu, Aniruddha Kembhavi, Mohammad Rastegari, Jason Yosinski, Ali Farhadi
Статья: https://arxiv.org/abs/2006.14769
Пост: https://mitchellnw.github.io/blog/2020/supsup/
Код: https://github.com/RAIVNLab/supsup
Ещё про суперпозицию, но другого рода. И снова в контексте борьбы с catastrophic forgetting.
Начать стоит издалека. Уже давно в работе про Lottery Ticket Hypothesis (https://arxiv.org/abs/1803.03635) было показано, что в обученной сети есть подсети, которые дают такое же (или даже более высокое) качество, будучи натренированы с нуля с той же инициализации, что и большая сеть, в которой их нашли. Потом много чего было, например, работа про супермаски (и не только, https://arxiv.org/abs/1905.01067), где показали, что в рандомно инициализированной сети уже есть подсети с высоким качеством (и маска задаёт такую подсеть). Потом была работа “What's Hidden in a Randomly Weighted Neural Network?” (https://t.me/gonzo_ML/196), где авторы предложили алгоритм Edge-Popup для нахождения таких подсетей. Коллектив (почти) этих же авторов написал через год другую интересную работу (была принята на NeurIPS 2020).
Здесь также стоит отвлечься и вспомнить интересную работу про альтернативу файнтюнингу под названием “Piggyback: Adapting a Single Network to Multiple Tasks by Learning to Mask Weights” (https://arxiv.org/abs/1801.06519), где с помощью маскирования весов обученной сети добивались адаптации сети к новым задачам. У этого метода было преимущество в том, что оригинальные веса не трогались, соответственно не происходило забывания, свойственного файнтюнингу при обучении сети новым задачам.
Авторы текущей работы в каком-то смысле сочетают эти две. Они предложили метод под названием SupSup (Supermasks in Superposition), позволяющий в базовой рандомно инициализированной сети находить маски под разные задачи. Причём в том числе и для кейсов, когда конкретная задача в данный момент неизвестна и сеть должна догадаться, какая это задача была.
Первым делом авторы предложили таксономию сценариев continual learning и специальный трёхбуквенный код для описания. Используя буквы G (Given) и N (Not given) они описывают, известны ли id задач во время обучения (первая буква кода) и тестирования (вторая буква). И ещё есть третья буква, которая говорит, расшарены ли метки классов между задачами (s) или нет (u). Получаются разные варианты, но практически полезные среди них следующие: GG (самый лёгкий, id задач известны в трейне и тесте, а GGs и GGu эквивалентны, поэтому просто GG), GNs (id задачи известен в трейне и неизвестен в тесте, метки классов общие), GNu (то же, но метки раздельные, что оказывается более сложным, потому что эффективно надо предсказывать классов больше в число раз равное числу задач), и наконец NNs (потому что сценарий NNu невалиден).
Во всех сценариях мы работаем со случайно инициализированной сетью. Веса её заморожены и вообще не обучаются. Все bias термы установлены в 0, в параметры весов в ±c с равной вероятностью, где c — это стандартное отклонение соответствующего Kaiming normal distribution (про важность выбора распределения инициализации было в предыдущей их работе).
Для сценария GG всё просто — информация о задаче есть и в режиме обучения, и в режиме тестирования. Здесь для каждой новой задачи можно выучить новую бинарную маску (тем же Edge-Popup), при вычислении сети веса маски {0,1} перемножаются с соответствующими весами модели. Маску, кстати, можно хранить в разреженном формате, а веса сети можно вообще не хранить, а зная seed просто генерировать. Получается весьма мало места. И разреженность можно также регулировать, находя баланс между качеством и занимаемым местом.
👍7
Сценарии GNs и GNu хитрее — в обучении id задачи известен, но в режиме инференса этой информации нет и сеть должна сама что-то выбрать. Идея, как это можно сделать, основана на энтропии распределения выходных классов — мы считаем, что правильно выбранная маска должна генерировать распределение с низкой энтропией. Это, конечно, может быть проблемным местом, зная тенденцию к выдаче over-confident результатов.
Здесь в качестве маски берётся суперпозиция всех масок отдельных задач, взвешенных с коэффициентами alpha_i, а эти коэффициенты можно найти градиентным спуском, минимизируя энтропию (начинают с равномерного распределения). Альтернативно можно просто перебрать все маски и выбрать с наименьшей энтропией (но для этого надо k forward passes). Тут хочется иметь сублинейную сложность от количества масок и для этого предлагают два алгоритма One-Shot и Binary. В первом берётся задача, для координаты которой энтропия уменьшается сильнее всего и это можно посчитать по одному градиенту; во втором за log(k) шагов наподобие бинарного поиска отсеиваются задачи, где энтропия уменьшается минимально.
Для сценария NNs задача неизвестна даже при обучении и здесь, если алгоритм SupSup не уверен насчёт конкретной задачи (для этого в статье есть критерий, что распределение примерно равномерное), то вероятно это новая задача. В таком случае создаётся новая маска и их число k инкрементируется. Авторы сумели обучить сеть на 2500 задач (перестановки MNIST) без знания информации о задаче.
В процессе всех экспериментов авторы сравниваются с описанным в прошлый раз PSP (https://t.me/gonzo_ML/870) и с методом BatchEnsemble (https://arxiv.org/abs/2002.06715). SupSup рулит, обходя обоих конкурентов, а в сценарии NNs достигает сравнимого с GNu качества.
Есть отдельные интересные предложения про кодирование масок внутри сети Хопфилда (это называется методом HopSupSup). Получается резервуар фиксированного размера, где маски это аттракторы в сети.
Для сценария GNu HopSupSup нужно L*K выходных нейронов, в то время как SupSup обходится без такого количества и может использовать всего L. Что интересно, хотя в теории L обычному SupSup и достаточно, но добавление “излишних” (superfluous) нейронов (s-нейроны) на практике помогает.
В целом интересная работа. Я по-прежнему уверен, что тема со случайными большими сетями ещё недоисследована.
Здесь в качестве маски берётся суперпозиция всех масок отдельных задач, взвешенных с коэффициентами alpha_i, а эти коэффициенты можно найти градиентным спуском, минимизируя энтропию (начинают с равномерного распределения). Альтернативно можно просто перебрать все маски и выбрать с наименьшей энтропией (но для этого надо k forward passes). Тут хочется иметь сублинейную сложность от количества масок и для этого предлагают два алгоритма One-Shot и Binary. В первом берётся задача, для координаты которой энтропия уменьшается сильнее всего и это можно посчитать по одному градиенту; во втором за log(k) шагов наподобие бинарного поиска отсеиваются задачи, где энтропия уменьшается минимально.
Для сценария NNs задача неизвестна даже при обучении и здесь, если алгоритм SupSup не уверен насчёт конкретной задачи (для этого в статье есть критерий, что распределение примерно равномерное), то вероятно это новая задача. В таком случае создаётся новая маска и их число k инкрементируется. Авторы сумели обучить сеть на 2500 задач (перестановки MNIST) без знания информации о задаче.
В процессе всех экспериментов авторы сравниваются с описанным в прошлый раз PSP (https://t.me/gonzo_ML/870) и с методом BatchEnsemble (https://arxiv.org/abs/2002.06715). SupSup рулит, обходя обоих конкурентов, а в сценарии NNs достигает сравнимого с GNu качества.
Есть отдельные интересные предложения про кодирование масок внутри сети Хопфилда (это называется методом HopSupSup). Получается резервуар фиксированного размера, где маски это аттракторы в сети.
Для сценария GNu HopSupSup нужно L*K выходных нейронов, в то время как SupSup обходится без такого количества и может использовать всего L. Что интересно, хотя в теории L обычному SupSup и достаточно, но добавление “излишних” (superfluous) нейронов (s-нейроны) на практике помогает.
В целом интересная работа. Я по-прежнему уверен, что тема со случайными большими сетями ещё недоисследована.
Telegram
gonzo-обзоры ML статей
Superposition of many models into one
Brian Cheung, Alex Terekhov, Yubei Chen, Pulkit Agrawal, Bruno Olshausen
Статья: https://arxiv.org/abs/1902.05522
Прикольная и малоизвестная работа с NeurIPS 2019 года. Авторы заходят с проблемы катастрофического…
Brian Cheung, Alex Terekhov, Yubei Chen, Pulkit Agrawal, Bruno Olshausen
Статья: https://arxiv.org/abs/1902.05522
Прикольная и малоизвестная работа с NeurIPS 2019 года. Авторы заходят с проблемы катастрофического…
👍2
Gradients without Backpropagation
Atılım Güneş Baydin, Barak A. Pearlmutter, Don Syme, Frank Wood, Philip Torr
Статья: https://arxiv.org/abs/2202.08587
Код: обещают, но пока нет
Любопытная работа. По названию я ожидал, что будет что-то из серии про отказ от бэкпропа и/или про стремление к более биологически-адеквантым подходам, может быть что-то типа синтетических градиентов (крутая работа, кстати, если кто не знаком: https://deepmind.com/blog/article/decoupled-neural-networks-using-synthetic-gradients). Но неожиданно это оказалось про заход вообще с другой стороны, где первое и второе как бы даже верно, но используется при этом всё тот же autodiff, и градиент получается примерно тот же самый, но без бэкпропа. С форвардпропом.
В современных фреймворках практически везде сейчас используется автоматическое дифференцирование (autodiff, AD), которое позволяет писать код нейросетей (причём не только статическое перемножение матриц, но и произвольные математические операции и даже управление потоком выполнения с ветвлением и условиями) и не думать про производные. Это, конечно, существенное упрощение жизни. Кто помнит, что было лет 10 назад (или проходил курс Хинтона в 2012-м), не может не оценить. Тогда чтобы запрограммировать сеть и реализовать бэкпроп, надо было просчитать вручную производные ваших слоёв, что не всегда было тривиально и часто вело к ошибкам. Сейчас, благодаря AD, пиши что хочешь, компьютер сам посчитает.
Если вкратце про AD, то его важно различать с символьным дифференцированием и с численным дифференцированием. Второе в DL обычно не вариант (медленное и неточное), использовалось разве что для проверки, что вы правильно посчитали производные. Символьное вроде кое-где использовалось (я, кстати, думал, что Theano было на нём, но похоже, что оно всё же тоже на AD, хоть и называли его символьным), но сейчас я знаю разве что SymPy. Современные фреймворки, кажется, все на AD.
У AD есть два варианта: reverse-mode AD (в своём частном случае известный как backprop) и менее известный forward-mode AD.
Forward-mode позволяет получить частные производные каждого из выходов по конкретному входу за один проход и эффективен, когда входов меньше, чем выходов. В общем виде он позволяет посчитать произведение якобиана на вектор (JVP, Jacobian-vector product), где единичный вектор на какой-то оси даст частную производную по этой координате, а произвольный вектор даст производную по направлению этого вектора, directional derivative. Что круто, и значение самой функции, и jvp вычисляются за один проход.
Reverse-mode эффективен, когда входов больше, чем выходов. Этот вариант двухфазный, когда сначала надо сделать forward pass, то есть прогон значений через функцию, запомнить по ходу дела промежуточные вычисления, а затем на обратном проходе посчитать градиенты. Этот режим вычисляет произведение вектора на якобиан (VJP, vector-Jacobian product) и для единичного вектора это собственно полноценный градиент, то есть частные производные по всем входам.
Обе эти операции производятся без необходимости прямого вычисления всего якобиана.
Важно, что forward и reverse режимы вычисляют различные вещи, собственно производную по заданному вектором направлению или полный градиент. Reverse режим обычно более дорогостоящий, потому что, во-первых, два прохода, а во-вторых надо сохранять результаты операций по ходу дела (и для этого используются все эти gradient tape или что-то подобное, в pytorch вроде как это через граф делается, но пишут они про это своеобразно — то tape, то не tape: https://discuss.pytorch.org/t/is-pytorch-autograd-tape-based/13992). Но тут правда надо ещё сделать поправку на форму матрицы, чего там больше, строк или столбцов (соответственно входов или выходов).
Хорошее краткое интро в AD есть на ютубе (https://www.youtube.com/watch?v=wG_nF1awSSY). Более подробное и детальное есть в статье https://www.jmlr.org/papers/volume18/17-468/17-468.pdf (два первых автора там те же, что и в текущей статье, кстати).
Atılım Güneş Baydin, Barak A. Pearlmutter, Don Syme, Frank Wood, Philip Torr
Статья: https://arxiv.org/abs/2202.08587
Код: обещают, но пока нет
Любопытная работа. По названию я ожидал, что будет что-то из серии про отказ от бэкпропа и/или про стремление к более биологически-адеквантым подходам, может быть что-то типа синтетических градиентов (крутая работа, кстати, если кто не знаком: https://deepmind.com/blog/article/decoupled-neural-networks-using-synthetic-gradients). Но неожиданно это оказалось про заход вообще с другой стороны, где первое и второе как бы даже верно, но используется при этом всё тот же autodiff, и градиент получается примерно тот же самый, но без бэкпропа. С форвардпропом.
В современных фреймворках практически везде сейчас используется автоматическое дифференцирование (autodiff, AD), которое позволяет писать код нейросетей (причём не только статическое перемножение матриц, но и произвольные математические операции и даже управление потоком выполнения с ветвлением и условиями) и не думать про производные. Это, конечно, существенное упрощение жизни. Кто помнит, что было лет 10 назад (или проходил курс Хинтона в 2012-м), не может не оценить. Тогда чтобы запрограммировать сеть и реализовать бэкпроп, надо было просчитать вручную производные ваших слоёв, что не всегда было тривиально и часто вело к ошибкам. Сейчас, благодаря AD, пиши что хочешь, компьютер сам посчитает.
Если вкратце про AD, то его важно различать с символьным дифференцированием и с численным дифференцированием. Второе в DL обычно не вариант (медленное и неточное), использовалось разве что для проверки, что вы правильно посчитали производные. Символьное вроде кое-где использовалось (я, кстати, думал, что Theano было на нём, но похоже, что оно всё же тоже на AD, хоть и называли его символьным), но сейчас я знаю разве что SymPy. Современные фреймворки, кажется, все на AD.
У AD есть два варианта: reverse-mode AD (в своём частном случае известный как backprop) и менее известный forward-mode AD.
Forward-mode позволяет получить частные производные каждого из выходов по конкретному входу за один проход и эффективен, когда входов меньше, чем выходов. В общем виде он позволяет посчитать произведение якобиана на вектор (JVP, Jacobian-vector product), где единичный вектор на какой-то оси даст частную производную по этой координате, а произвольный вектор даст производную по направлению этого вектора, directional derivative. Что круто, и значение самой функции, и jvp вычисляются за один проход.
Reverse-mode эффективен, когда входов больше, чем выходов. Этот вариант двухфазный, когда сначала надо сделать forward pass, то есть прогон значений через функцию, запомнить по ходу дела промежуточные вычисления, а затем на обратном проходе посчитать градиенты. Этот режим вычисляет произведение вектора на якобиан (VJP, vector-Jacobian product) и для единичного вектора это собственно полноценный градиент, то есть частные производные по всем входам.
Обе эти операции производятся без необходимости прямого вычисления всего якобиана.
Важно, что forward и reverse режимы вычисляют различные вещи, собственно производную по заданному вектором направлению или полный градиент. Reverse режим обычно более дорогостоящий, потому что, во-первых, два прохода, а во-вторых надо сохранять результаты операций по ходу дела (и для этого используются все эти gradient tape или что-то подобное, в pytorch вроде как это через граф делается, но пишут они про это своеобразно — то tape, то не tape: https://discuss.pytorch.org/t/is-pytorch-autograd-tape-based/13992). Но тут правда надо ещё сделать поправку на форму матрицы, чего там больше, строк или столбцов (соответственно входов или выходов).
Хорошее краткое интро в AD есть на ютубе (https://www.youtube.com/watch?v=wG_nF1awSSY). Более подробное и детальное есть в статье https://www.jmlr.org/papers/volume18/17-468/17-468.pdf (два первых автора там те же, что и в текущей статье, кстати).
Deepmind
Decoupled Neural Interfaces Using Synthetic Gradients
Neural networks are the workhorse of many of the algorithms developed at DeepMind. For example, AlphaGo uses convolutional neural networks to evaluate board positions in the game of Go and DQN and Deep Reinforcement Learning algorithms use neural networks…
👍9❤1
В текущей работе авторы предлагают метод расчёта градиента на основе производных по направлению через forward-mode AD и называют такую постановку forward gradient. Forward-prop’ом его специально не стали называть, потому что под этим часто подразумевается обычный forward pass как первый этап бэкпропа.
Авторы понятно доказывают, что если брать случайный вектор (той же размерности что и вход) так, что его компоненты не зависят друг от друга и имеют среднее и дисперсию соответственно 0 и 1, то forward gradient является несмещённой оценкой обычного градиента (то есть распределение, из которого сэмплятся эти вектора, многомерное нормальное с нулевым средним и единичной матрицей ковариации). Исследование других распределений оставляют на будущее.
Сам алгоритм спуска по “прямому градиенту” работает аналогично SGD, только лишь вместо настоящих градиентов берутся forward gradients. Назвали FGD (Forward Gradient Descent). Более продвинутые алгоритмы оптимизации типа момента или Adam также оставляют на будущее.
Реализовали это в PyTorch’е с нуля, отключив всю его собственную механику autodiff’а, то есть все тензоры это обычные тензоры с requires_grad=False, и также перегружены операции над тензорами. Сравниваются с обычным торчовым автоматическим дифференцированием (requires_grad=True и backward()). Дополнительными оптимизациями не занимались, так что на будущее задел ещё есть (хотя зачем, если есть JAX :) ).
Дальше собственно эксперименты.
Сначала на двух модельных функциях — Била и Розенброка. Кстати, в Википедии красивая коллекция тестовых функций, почему-то в русской версии с объёмными картинками (https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8_%D0%B4%D0%BB%D1%8F_%D0%BE%D0%BF%D1%82%D0%B8%D0%BC%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8), а в английской с контурными (https://en.wikipedia.org/wiki/Test_functions_for_optimization). И SGD, и FGD сходятся одинаково хорошо по итерациям, но FGD по времени чуть быстрее.
Интересно выглядят оптимизационные траектории, для FGD они как будто более шумные (хотя я не совсем понимаю, почему они для SGD такие гладкие). Если траектории FGD действительно шумнее (им есть откуда), то это тоже интересно, и может оно даст какую-то дополнительную регуляризацию по аналогии как и сам SGD это делает, и может быть какие-то иные свойства ландшафта проявятся, если подробнее всё поисследовать.
На логрегрессии на MNIST также примерно одинаковое качество, но FGD быстрее. Относительно базового случая (просто вычисление функции, а-ля чистый forward pass без всяких градиентов), FGD медленнее в ~2.4 раза, а SGD медленнее в ~4.4 раза. То есть forward gradient быстрее классического бэкпропа и занимает примерно 55% времени последнего.
Дальше собирают MLP (1024-1024-10 + ReLU) для MNIST. Тут интересно. На низком learning rate всё примерно так же, а на более высоком FGD ещё и по итерациям начинает сходиться быстрее, чем SGD.
На простой CNN для MNIST тоже примерно всё так же.
Отдельно проверили, как эта штука скейлится с увеличением числа слоёв от 1 до 100. В целом скейлится. Относительно бэкпропа время нового алгоритма с увеличением слоёв поднимается от примерно чуть меньше 0.6 до чуть больше 0.8. Интересно, как дальше будет. Но в любом случае на всех этих примерах forward gradients быстрее и не хуже (а кое-где и лучше). При этом есть ещё и куда ускорять.
Следующими шагами, конечно, ожидаются реальные большие сети. Ждём в следующих работах. Можно не дожидаться статьи и провести самостоятельно. Никто не хочет? :)
В целом интересно, как оно себя будет вести в более реальных сложных кейсах с современными архитектурами и оптимизаторами, и особенно интересно с другими распределениями случайных векторов.
Ну и с точки зрения biological plausibility (https://arxiv.org/abs/1807.04587) тоже может оказаться более реальным, чем бэкпроп.
Прикольная тема. Ждём, да и чего ждать, пробуем!
Авторы понятно доказывают, что если брать случайный вектор (той же размерности что и вход) так, что его компоненты не зависят друг от друга и имеют среднее и дисперсию соответственно 0 и 1, то forward gradient является несмещённой оценкой обычного градиента (то есть распределение, из которого сэмплятся эти вектора, многомерное нормальное с нулевым средним и единичной матрицей ковариации). Исследование других распределений оставляют на будущее.
Сам алгоритм спуска по “прямому градиенту” работает аналогично SGD, только лишь вместо настоящих градиентов берутся forward gradients. Назвали FGD (Forward Gradient Descent). Более продвинутые алгоритмы оптимизации типа момента или Adam также оставляют на будущее.
Реализовали это в PyTorch’е с нуля, отключив всю его собственную механику autodiff’а, то есть все тензоры это обычные тензоры с requires_grad=False, и также перегружены операции над тензорами. Сравниваются с обычным торчовым автоматическим дифференцированием (requires_grad=True и backward()). Дополнительными оптимизациями не занимались, так что на будущее задел ещё есть (хотя зачем, если есть JAX :) ).
Дальше собственно эксперименты.
Сначала на двух модельных функциях — Била и Розенброка. Кстати, в Википедии красивая коллекция тестовых функций, почему-то в русской версии с объёмными картинками (https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8_%D0%B4%D0%BB%D1%8F_%D0%BE%D0%BF%D1%82%D0%B8%D0%BC%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8), а в английской с контурными (https://en.wikipedia.org/wiki/Test_functions_for_optimization). И SGD, и FGD сходятся одинаково хорошо по итерациям, но FGD по времени чуть быстрее.
Интересно выглядят оптимизационные траектории, для FGD они как будто более шумные (хотя я не совсем понимаю, почему они для SGD такие гладкие). Если траектории FGD действительно шумнее (им есть откуда), то это тоже интересно, и может оно даст какую-то дополнительную регуляризацию по аналогии как и сам SGD это делает, и может быть какие-то иные свойства ландшафта проявятся, если подробнее всё поисследовать.
На логрегрессии на MNIST также примерно одинаковое качество, но FGD быстрее. Относительно базового случая (просто вычисление функции, а-ля чистый forward pass без всяких градиентов), FGD медленнее в ~2.4 раза, а SGD медленнее в ~4.4 раза. То есть forward gradient быстрее классического бэкпропа и занимает примерно 55% времени последнего.
Дальше собирают MLP (1024-1024-10 + ReLU) для MNIST. Тут интересно. На низком learning rate всё примерно так же, а на более высоком FGD ещё и по итерациям начинает сходиться быстрее, чем SGD.
На простой CNN для MNIST тоже примерно всё так же.
Отдельно проверили, как эта штука скейлится с увеличением числа слоёв от 1 до 100. В целом скейлится. Относительно бэкпропа время нового алгоритма с увеличением слоёв поднимается от примерно чуть меньше 0.6 до чуть больше 0.8. Интересно, как дальше будет. Но в любом случае на всех этих примерах forward gradients быстрее и не хуже (а кое-где и лучше). При этом есть ещё и куда ускорять.
Следующими шагами, конечно, ожидаются реальные большие сети. Ждём в следующих работах. Можно не дожидаться статьи и провести самостоятельно. Никто не хочет? :)
В целом интересно, как оно себя будет вести в более реальных сложных кейсах с современными архитектурами и оптимизаторами, и особенно интересно с другими распределениями случайных векторов.
Ну и с точки зрения biological plausibility (https://arxiv.org/abs/1807.04587) тоже может оказаться более реальным, чем бэкпроп.
Прикольная тема. Ждём, да и чего ждать, пробуем!
👍7