Nbdev: используйте Jupyter Notebook для решения любых задач

4601

Nbdev: используйте Jupyter Notebook для решения любых задач

Это адаптированный перевод статьи Джереми Ховарда (Jeremy Howard) nbdev: use Jupyter Notebooks for everything. Повествование ведётся от лица автора.

Крис Латтнер, создатель Swift, LLVM и Swift Playgrounds: «Я действительно считаю, что nbdev — огромный шаг вперёд для программного окружения».

Я и мой коллега по fast.ai Сильвен Гаггер (Sylvain Gugger) последние несколько лет работали над любимым проектом. Это программное окружение Python, которое называется nbdev. Это окружение позволяет создавать полноценные пакеты Python, включая тесты и систему документации, в Jupyter Notebook. Мы уже написали библиотеку fastai с помощью nbdev. Также сделали с помощью этого инструмента ещё несколько небольших проектов.

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

Nbdev: исследовательское программирование

Мы верим, что каждое исследование имеет ценность само по себе, и что результаты каждого исследования надо сохранять для других программистов, включая самого исследователя через полгода. Думайте об этом как о дневнике исследователя. Вы можете использовать его, чтобы показать, что вы попробовали, что сработало, а что нет, и что вы сделали, чтобы в конце концов понять систему, с которой работаете. В процессе исследования вы понимаете, что какие-то части понимания критически важны для работы системы. Поэтому исследование должно включать тесты и утверждения (assertions) для закрепления такого поведения.

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

Nbdev переносит ключевые преимущества IDE в систему ноутбуков. То есть вы можете работать в ноутбуке без ущерба для удобства и результата.

Чтобы достичь нужной интерактивности, nbdev использует Jupyter Notebook в качестве платформы. Это позволяет по максимуму раскрыть динамические свойства языка Python, но привносит и другие инструменты, жизненно необходимые разработчику ПО:

  • Автоматическое создание модулей Python, в которых учтены лучшие практики, например, автоматическое определение __all__ с экспортом функций, классов и переменных.
  • Навигация и редактирование кода в стандартном редакторе или IDE, и автоматический экспорт изменений в ноутбук.
  • Автоматическое создание индексируемой перелинкованной документации. Любое слово, обёрнутое в бэктики, автоматически линкуется с соответствующим разделом документации. В разделе документации создаётся сайдбар, в котором находятся ссылки на модули.
  • Установщики pip, загруженные в pypi.
  • Тесты, объявленные прямо в блокноте и запускаемые в фоне.
  • Continuous integration (CI).
  • Разрешение конфликтов при версионировании кода.

Вот сниппет из нашего актуального исходного кода nbdev, который, конечно же, написан в nbdev.

код в nbdev

Изучаем формат файлов в исходном коде nbdev


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

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

Инструменты для разработки программного обеспечения

Большинство инструментов для разработчиков создано без учёта особенностей исследовательского программирования. Когда я начинал программировать около 30 лет назад, практически повсеместно использовалась каскадная модель (на сленге её иногда называют «модель водопадов»). Мне казалось, что эта модель, предполагающая точную детализацию и максимально близкое следование документации, не соответствовала тому, как я на самом деле работаю.

В 90-х годах ситуация изменилась. Популярным стал подход agile. Люди стали понимать, что разработка — итеративный процесс. Появились подходы, которые учитывают это. Однако инструменты разработки существенно не поменялись. В нашем арсенале появились инструменты, которые подходят для TDD (разработка через тестирование). Однако такие инструменты внедрялись скорее как расширения для существующих редакторов, чем как полностью переработанные среды разработки.

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

Легендарный Дональд Кнут опередил своё время. В 1983 году он представил концепцию грамотного программирования. Кнут описал её как «методологию, которая сочетает использование языка программирования и языка документирования. Она делает программы более простыми и надёжными. Также методология упрощает разработку программ, написанных на высокоуровневых языках. Главная идея — рассматривать программы как произведения литературы, которые создаются для людей, а не для компьютеров». Я долго был очарован этой идеей, но она, к сожалению, не получила широкого распространения. Инструменты, созданные для такого подхода, замедляли разработку. Это подошло далеко не всем специалистам.

Спустя примерно 30 лет после появления концепции грамотного программирования ещё один яркий разработчик — Брет Виктор — сформулировал претензии к существующим инструментам для программистов. Он рассказал, как создавать системы программирования для понимания программ. В знаменитой речи «Принципы изобретательства» Брет Виктор отметил: «В рамках существующей концепции компьютерные программы рассматриваются как список текстовых определений, которые мы передаём в компилятор. Этот подход родом из 50-х годов прошлого века. Тогда в ходу были Fortran и ALGOL — языки, созданные для работы с перфокартами».

Брет Виктор сформулировал и проиллюстрировал примеры и принципы нового подхода к созданию систем для программирования. Пока никто не реализовал все идеи Виктора. Но попытки частичной имплементации были. Одна из самых известных — Swift Playgrounds Криса Латтнера.

Playgrounds в Xcode

Демонстрация Playgrounds в Xcode


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

Интерактивные среды программирования

Ещё одно направление развития систем программирования — интерактивные среды разработки. Они появились несколько десятилетий назад вместе с LISP и REPL, которые позволили разработчикам интерактивно редактировать код в работающем приложении. Smalltalk пошёл ещё дальше, создав интерактивное визуальное рабочее пространство. Во всех этих случаях языки программирования подходили для интерактивной работы. Например, LISP с его макросистемой и кодом как данными вписался в эту модель.

Smalltalk

Интерактивное программирование в Smalltalk


Хотя этот подход нельзя назвать общепринятым, он стал популярным в научной сфере, статистике и других областях Data Driven Development ( программирования, управляемого данными). Фронтенд-программирование на JavaScript тоже позаимствовало важные концепции из этого подхода, например, горячую перезагрузку или интерактивное редактирование кода в браузере.

MATLAB тоже создавался как полностью интерактивный инструмент в 70-е годы. Он и сейчас используется в инженерии, биологии и других отраслях. Похожие принципы используются в SPLUS и R, которые широко используются в области статистики и визуализации данных.

Я был приятно удивлён, когда впервые использовал систему Mathematica около 25 лет назад. Эта система показалась мне наиболее приближенной к грамотному программированию. Её применение не влияло на продуктивность. В Mathematica используется интерфейс ноутбуков, который ведёт себя практически как REPL. Также система позволяет использовать графики, изображения, форматированный текст и так далее. Эта система позволила мне делать то, что раньше было недоступным. Например, она позволяет тестировать алгоритмы и получать визуальную обратную связь.

Но Mathematica не позволила мне сделать что-то полезное, так как с её помощью невозможно поделиться кодом или приложениями с коллегами, пока вы не оплатите дорогую лицензию. Также Mathematica не позволяет делать приложения, которые можно использовать в браузере. Кроме того, мне показалось, что код Mathematica более медленный и требовательный к памяти, чем код, написанный на других языках.

Можете представить мою радость, когда я узнал о выходе Jupyter Notebook. В нём используется такой же простой интерфейс ноутбуков, как в Mathematica. Но это продукт с открытым исходным кодом, что позволило мне писать на доступных языках с широкой поддержкой. Я использовал Jupyter Notebook не только для изучения алгоритмов, API и проверки новых идей. Этот инструмент стал средством обучения в fast.ai. Многие студенты убедились, что возможность экспериментировать с входящими данными и сразу же видеть результат позволяет лучше усваивать учебный материал.

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

Одним словом, нам и нашим студентам понравился Jupyter Notebook. Оставалось использовать его для разработки нашего программного обеспечения.

Чего не хватает в Jupyter Notebook

Jupyter Notebook хорош для исследовательской части исследовательского программирования, но не так хорош для собственно программирования. Например, в нём невозможно:

  • Создавать модульный код, который можно переиспользовать и запускать за пределами Jupyter Notebook.
  • Создавать гипертекстовую индексируемую документацию.
  • Тестировать код, включая автоматическое тестирование при непрерывной интеграции.
  • Удобно перемещаться по коду.
  • Контролировать версии.

Из-за таких проблем люди вынуждены переключаться между инструментами, например, использовать IDE или редакторы, REPL/shell, блокноты и так далее.

Мы решили, что лучший способ справиться с проблемой — использовать хорошие существующие инструменты, где это возможно, и создавать собственные инструменты, если это необходимо. Например, для управления пулреквестами и отслеживания диффов есть отличный инструмент — ReviewNB. Когда вы смотрите на визуальное представление диффов в ReviewNB, понимаете, насколько ограничены стандартные текстовые представления диффов. Например, как можно понять по тексту, что в коммите есть некачественное изображение? Или что в графиках не хватает меток? А благодаря визуальному представлению диффа вы знаете, что происходит.

дифф в визуальном представлении

Визуальное представление диффа в ReviewNB


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

конфликт при мёрже

Конфликт при слиянии отображён в nbdev


Чтобы получить модульный переиспользуемый код в nbdev, достаточно создать модули Python. Nbdev ищет в коде специальные комментарии, например, #export. Такие комментарии сигнализируют, что ячейку нужно экспортировать в модуль Python. Каждый блокнот связывается с конкретным модулем с помощью специального комментария. Сайт с документацией автоматически создаётся с помощью генератора статических сайтов Jekyll. Такие сайты можно размещать на GitHub Pages. Мы написали свою систему документации, так как существующие решения, например, Sphinx, не давали нам все необходимые возможности.

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

Для тестирования мы написали собственную простую библиотеку и утилиту командной строки. Тесты можно писать непосредственно в ноутбуках, это часть исследования и документирования. Естественная statefulness ноутбуков (наличие у них состояния) позволяет использовать как юнит-тесты, так и интеграционные тесты. Вместо изучения нового синтаксиса для создания тестов вы можете использовать коллекции и циклы Python. Созданные тесты можно запускать в среде Continuous Integration (CI), которую вы используете. При этом вы будете получать информацию об источниках ошибок. Nbdev интегрирован с GitHub Actions. Пулреквесты для интеграции с другими платформами приветствуются.

Динамический Python

Одна из проблем с поддержкой Python в IDE или редакторе связана с динамическими свойствами Python. Например, вы в любой момент можете добавить метод в класс, с помощью метаклассов изменить способы создания классов, а с помощью декораторов изменять поведение функций и методов. Microsoft создал Language Server Protocol, который может использоваться в средах разработки для получения информации о текущем файле. Использование этого протокола необходимо для важных функций, например, автодополнений, навигации по коду и так далее. Однако при работе с динамическими языками, такими, как Python, подобная информация всегда будет носить характер догадок, так как для получения актуальных данных надо запускать код. Это не всегда возможно по целому ряду причин.

С другой стороны, в ноутбуках есть интерпретатор Python, который вы полностью контролируете. Таким образом Jupyter поддерживает автодополнения, списки параметров, контекстную документацию, которая основана на актуальном состоянии кода.

Что дальше

Одновременно с разработкой nbdev мы писали вторую версию fastai полностью в nbdev. В fastai есть структурированное API для создания моделей глубинного обучения (deep learning). Релиз планируется в первой половине 2020 года. Этот продукт уже наполнен функциональностью, и первые пользователи уже создают классные проекты с помощью тестовой версии.

Мы заметили рост продуктивности в два или три раза при использовании nbdev по сравнению с другими инструментами. Я программирую около 30 лет практически каждый день, и такой рост продуктивности меня приятно удивил.

Спасибо за интерес к nbdev.

Адаптированный перевод статьи nbdev: use Jupyter Notebooks for everything by Jeremy Howard.

источник