00:00:07 Дифференцируемое программирование как новый термин.
00:01:38 Основная идея оптимизации на основе градиентов в глубоком обучении.
00:03:48 Прорыв автоматического дифференцирования в вычислении градиентов.
00:06:00 Происхождение дифференцируемого программирования и его влияние на машинное обучение.
00:07:43 Сложность на первый взгляд простых задач и итеративный прогресс в ИИ.
00:09:33 Переход от нейронных сетей к глубокому обучению и дифференцируемому программированию.
00:11:22 Преимущества дифференцируемого программирования в оптимизации цепей поставок.
00:13:26 Связь между ценообразованием, прогнозированием спроса и распределением запасов в управлении цепями поставок.
00:15:00 Дифференцируемое программирование в машинном обучении и решение вопросов неопределённости.
00:16:00 Дифференцируемое программирование в цепях поставок и сравнение с крупными технологическими компаниями.
00:18:19 Применение методов ИИ из других областей к задачам управления цепями поставок.
00:20:15 Преимущества дифференцируемого программирования для прогнозного моделирования и оптимизации в цепях поставок.
00:22:01 Предстоящие проблемы для дифференцируемого программирования в управлении цепями поставок.
00:24:16 Заключительные мысли.

Резюме

Kieran Chandler взял интервью у Joannes Vermorel, основателя Lokad, о дифференцируемом программировании и его значимости в ИИ и оптимизации цепей поставок. Дифференцируемое программирование возникло благодаря прорывам в методах автоматического дифференцирования и эволюционировало от нейронных сетей и глубокого обучения. Модульность дифференцируемого программирования позволяет собирать модели более гибко и универсально, что делает его полезным для оптимизации цепей поставок. Хотя существуют опасения по поводу надежности, Vermorel подчеркивает эффективность методов машинного обучения. Lokad, несмотря на меньший бюджет, остается конкурентоспособным, адаптируя исследования крупных технологических гигантов для задач управления цепями поставок. Дифференцируемое программирование предлагает более экспрессивное решение для создания числовых рецептов, соответствующих бизнес-задачам, хотя достижение стабильных результатов без сбоев остается проблемой.

Расширенное резюме

Kieran Chandler, ведущий интервью, обсудил тему дифференцируемого программирования с Joannes Vermorel, основателем Lokad, компании, специализирующейся на оптимизации цепей поставок. Vermorel рассказал об истоках и значении дифференцируемого программирования как концепции и его связи с ИИ и глубоким обучением.

Янн ЛеКун, директор отдела исследований ИИ в Facebook, недавно предположил, что термин «глубокое обучение» утратил свою актуальность как модное словечко, и предложил использовать «дифференцируемое программирование» для отражения новых разработок в программном обеспечении. Vermorel прокомментировал постоянную эволюцию терминологии в области ИИ, отметив, что как только найдено решение проблемы, оно перестает считаться ИИ и получает новое название, причем дифференцируемое программирование является последним примером.

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

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

Обсуждение сосредоточено вокруг концепции дифференцируемого программирования и его развития, а также применения в оптимизации цепей поставок.

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

Развитие дифференцируемого программирования происходило итеративно, опираясь на более ранние концепции нейронных сетей и глубокого обучения. Прогресс в этой области был стабильным в течение последних 50-60 лет, хотя первоначально существовало заблуждение, что некоторые задачи, например, распознавание собаки, будут решаться легче, чем сложные вычисления, такие как нахождение логарифма. На самом деле, задачи, кажущиеся простыми, как распознавание объектов и поддержание равновесия, оказались более сложными, в то время как вычисления стали относительно легкими с современной вычислительной архитектурой.

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

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

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

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

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

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

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

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

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

Полная транскрипция

Kieran Chandler: Сегодня мы продолжим нашу мини-серию, рассмотрев её истоки. Итак, Joannes, дифференцируемое программирование — это еще одно модное словечко в мире технологий. Разве нам действительно нужно еще одно?

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

Kieran Chandler: Хорошо, а теперь перейдем к дифференцируемому программированию. В чем суть? Откуда появилось это название и как мы к нему пришли?

Joannes Vermorel: Название происходит от одного из компонентов, лежащих в основе глубокого обучения, а именно от идеи оптимизации на основе градиентов. Что это означает? Оптимизация на основе градиентов подразумевает, что у вас есть модель с потенциально миллионами параметров. Способ обучения этих параметров заключается в использовании целевой функции, уравнения, которое сообщает, хорошо работают ваши результаты или плохо. Идея в том, что при рассмотрении каждого нового примера данных через эту функцию возвращается информация, и можно вычислить градиент. Градиент показывает, что если немного откорректировать параметры в определённом направлении, целевая функция улучшится локально. Именно эта идея лежит в основе стохастического градиентного спуска, алгоритма, который используется для оптимизации современных алгоритмов машинного обучения и всего глубокого обучения, например.

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

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

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

Kieran Chandler: Ладно, многое усвоено. Давайте попробуем немного разобраться. Вы сказали, что некоторые из этих идей появились в 50-х и 60-х годах. Это не похоже на стремительное развитие, которое мы наблюдаем в ИИ и подобных областях. Значит, на самом деле путь к дифференцируемому программированию был довольно итеративным?

Joannes Vermorel: Абсолютно, но дело в том, что даже глубокое обучение до этого было чрезвычайно итеративным, как и нейронные сети ещё раньше. То есть, темп прогресса на самом деле был довольно быстрым в последние 50–60 лет. Это было невероятно быстро. И что интригует, так это то, что в начале 60-х годов люди думали: «Если мы справимся с умножением, разложением или всеми этими сложными вычислениями, то определить, что перед нами собака, будет суперпростой задачей. В конце концов, любой прохожий может сказать: «Это собака», но для вычисления логарифма нужен суперподготовленный математик. Так что, очевидно, вычисление логарифма гораздо сложнее, чем определение, есть ли перед тобой собака».

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

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

Kieran Chandler: А как насчёт дифференцируемого программирования? Что было источником вдохновения для этого?

Joannes Vermorel: Ключевым, очень интересным открытием стал переход от нейронных сетей к глубокому обучению. Идея заключалась в полном отказе от всей биологической мотивации и осознании того, что если мы хотим двигаться вперёд, нам нужно отбросить биологическое вдохновение и сосредоточиться на том, что действительно работает на компьютерном железе. Одним из ключевых инсайтов, толкающих глубокое обучение, была его модульность. Вы можете строить модели машинного обучения таким образом, который является чрезвычайно модульным; вы можете комбинировать их, складывать, конкатенировать и смешивать множеством способов.

Kieran Chandler: И почему это имеет первостепенное значение для цепочек поставок?

Joannes Vermorel: Дело в том, что мы хотим объединять такие вещи, как цены, продукты, клиенты, локации, контейнеры и множество других разнородных объектов, которые необходимо скомбинировать для решения проблем цепочки поставок. Нужно учитывать всё это разнообразие. Когда у вас появляются модели, которые можно комбинировать множеством способов, вы фактически получаете язык программирования. Интересно, что люди начали создавать инструментарии для глубокого обучения, которые всё больше приближались к полноценным языкам программирования. Например, Microsoft выпустила свой набор инструментов для вычислительных сетей CNTK, который включал BrainScript – предметно-ориентированный язык программирования для глубокого обучения. Следующим этапом был переход к полноценному программированию.

Kieran Chandler: То есть, это своего рода подход, похожий на использование конструктора Лего, когда вы комбинируете разные блоки из разных мест и объединяете эти модели различными способами. Как это на практике? Как вы реализуете этот программный код за этим?

Joannes Vermorel: Лего были фактически архетипом того, что было в глубоком обучении. Речь шла о комбинировании блоков, но способами, которые были довольно ограниченными. Существует спектр между глубоким обучением и дифференцируемым программированием без чёткой границы. Разница заключалась в том, что люди перешли от Лего, где дело сводилось к сборке частей, к программированию, где можно делать то же самое, но с программной выразительностью. Для цепочек поставок это означает, что вы можете переосмыслить задачи и выразить своё решение гораздо более лаконично и точно в отношении проблемы, которую пытаетесь решить.

Kieran Chandler: Можете привести пример?

Joannes Vermorel: Конечно, давайте попробуем совместно оптимизировать ценообразование, прогнозирование спроса и распределение запасов. Если подумать, все эти аспекты полностью взаимосвязаны. Я прогнозирую спрос, но знаю, что если немного скорректирую стратегию ценообразования, спрос изменится. Если я изменю спрос, это повлияет на то, сколько мне нужно производить и хранить, ведь спрос станет другим. Всё это полностью взаимосвязано, и зависимости можно буквально записать.

Kieran Chandler: Это, так сказать, сложно. Если у меня больше спроса, мне нужно больше запасов для его удовлетворения. Это довольно очевидно, и если я установлю более высокую цену, то при сохранении того же спроса я получу большую маржу. Существует множество вещей, которые можно свести к приземлённым расчётам, но вопрос в том, как объединить все эти ингредиенты, чтобы создать нечто, что одновременно является и прогнозированием, и оптимизацией?

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

Kieran Chandler: То есть, вы говорите, что эти пустые места означают, что вы фактически пишете программу, в которой вы не знаете всех ответов?

Joannes Vermorel: Да, верно.

Kieran Chandler: Как можно быть уверенным, что, имея эти пустые места, вы всё-таки придёте к правильному ответу?

Joannes Vermorel: Действительно, это похоже на явления в машинном обучении. Вы учитесь, поэтому у вас нет гарантии, что получите хорошие результаты. Тем не менее, я не думаю, что сегодня это отличается от глубокого обучения и всех предыдущих техник машинного обучения. Например, программы машинного обучения уже превзошли всех человеческих игроков в таких играх, как Го и шахматы. Так что не то чтобы не было явных признаков того, что это действительно работает, даже сверх возможностей человека, для задач, которые всё ещё довольно узкие, в отличие от определения, где находится собака в захламлённой городской среде, что является гораздо более сложной задачей.

Kieran Chandler: Вы упомянули некоторые аспекты цепочки поставок в контексте дифференцируемого программирования. С точки зрения исследований и разработок, насколько близко то, что мы делаем здесь в Lokad, к тому, что Facebook и другие крупные технологические компании реализуют в дифференцируемом программировании?

Joannes Vermorel: Я считаю, что у таких гигантов, как Google, Facebook и Microsoft, гораздо больше бюджетов на исследования и разработки. В Lokad мы делаем всё возможное, но, давайте будем реалистами: у нас даже не 1% от бюджета на ИИ Microsoft или Facebook. Это реальность для большинства B2B-компаний на данный момент. Эти рынки всё ещё довольно нишевые, и нет такой цепочки поставок, где можно было бы сказать: «У нас 2000 специалистов по ИИ». Однако хорошая новость в том, что такие гиганты, как Google, Amazon и Facebook, активно публикуют результаты своих исследований, так что большая часть их работы доступна. Это означает, что одной из ключевых задач, с которой мы сталкиваемся в Lokad, является постоянный мониторинг этих публикаций и черпание из них вдохновения. Мы переосмысливаем их разработки, адаптируя их к специфике цепочек поставок, ведь крупные команды работают над большими задачами ИИ, такими как компьютерное зрение, распознавание речи, синтез речи и обработка естественного языка, что совсем не то, что решается в цепочке поставок.

Kieran Chandler: Так как же можно перейти от больших задач ИИ, таких как распознавание изображений и речи, к цепочке поставок? Как они вообще могут быть связаны?

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

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

Joannes Vermorel: Да, вы правы. Иногда обнаруживают технику, которая хорошо работает для изображений, но не становится революционной. Тем не менее, её публикуют, так как она считается новой и вносит вклад в научный прогресс. Однако когда вы применяете её в другом контексте, например, в цепочке поставок, вы можете добиться значительных скачков вперёд. Так что это работает в обе стороны.

Kieran Chandler: В чём же заключается основное преимущество дифференцируемого программирования с точки зрения Lokad? Это идея о том, что можно ответить на все те неизвестные переменные в цепочке поставок и заполнить все те пустые места, где вы фактически не знаете, что произойдёт в будущем?

Joannes Vermorel: Главная задача, с которой мы сталкиваемся в цепочке поставок, заключается в том, чтобы обеспечить предиктивное моделирование и предиктивную оптимизацию, которая не подведёт бизнес. Это нетривиально, поскольку речь идёт не о получении универсальных ответов; речь идёт о наличии очень специфического набора решений, оптимизирующих бизнес в точном соответствии с определёнными вами бизнес-драйверами. Мы не пытаемся, чтобы методы ИИ определяли бизнес-цели; цели определяются человеческим интеллектом для установления стратегии и видения. Проблема обладает большой структурой, и самая сложная задача — убедиться, что разрабатываемые числовые рецепты соответствуют этим бизнес-драйверам. Обычно получается, что у вас оказывается круглое отверстие и квадратный колышек, которые просто не подходят друг к другу. Дифференцируемое программирование — один из способов решения этой проблемы.

Kieran Chandler: Быть гораздо более выразительными, и именно это является ключом к тому, чтобы сформулировать числовые рецепты, действительно подходящие для бизнес-проблемы, стоящей перед вами. Если у вас есть доступ к языку программирования, вы становитесь, можно сказать, гораздо более выразительными и универсальными. Внезапно становится намного проще добиться соответствия. Ладно, давайте подведём итоги. Вы упомянули в начале, что дифференцируемое программирование — это всего лишь начало долгого пути с множеством предстоящих вызовов.

Joannes Vermorel: Да, где мы находимся на этом пути и какие главные вызовы нам предстоят… Возможно, самая большая задача — установить, то есть определить, ряд конструкций и строительных блоков, то есть программных строительных блоков, которые действительно хорошо работают для цепочки поставок. Помните, автоматическое дифференцирование позволяет дифференцировать любую программу, это правда, но, как вы отметили, нельзя просто начать запихивать параметры в программу и говорить: «Всё сработает, потому что я могу оптимизировать свои параметры». Нет, реальность такова, что не любая программа подходит. Да, вы можете дифференцировать любую программу с параметрами, но если вы напишете случайную программу с параметрами посреди, то при запуске оптимизации методом автоматического дифференцирования результаты будут полным беспорядком. Поэтому необходимо определить конкретные способы построения таких задач, которые дадут не только хорошие, но и очень стабильные и надёжные результаты. Ведь мы хотим получить решения, готовые для внедрения в производство, а немного лучшего в среднем недостаточно. Нужно, чтобы решение было не только лучше, но и чрезвычайно надёжным, чтобы не возникали разовые чудеса или критические провалы. Нам нужны результаты, которые будут стабильными и надёжными и не будут, скажем, катастрофически проваливаться раз в год. И это, вероятно, отчасти ещё впереди.

Kieran Chandler: Блестяще. Ладно, на сегодня на этом всё. Спасибо за ваше время, Joannes.

Joannes Vermorel: Спасибо.

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