За годы разработки ML- и DL-проектов у студии Surf накопились и большая кодовая база, и много опыта, и интересные инсайты и выводы. При старте нового проекта эти полезные знания помогают увереннее начать исследование, переиспользовать полезные методы и получить первые результаты быстрее.  Очень важно, чтобы все эти материалы были не только в головах разработчиков, но и в читаемом виде на диске. Это позволит эффективнее обучить новых сотрудников, ввести их в курс дела и погрузить в проект. Конечно, так было не всегда. Мы столкнулись с множеством проблем на первых этапах Для того, чтобы эти проблемы решить раз и навсегда, мы решили, что нужно работать как над единой и правильной организаций проекта, так и над виртуализацией, абстракцией отдельных компонентов и переиспользуемостью полезного кода. Постепенно весь наш прогресс в этой области перерос в самостоятельный фреймворк — Ocean. Вишенка на торте — логи проекта, которые агрегируются и превращаются в красивый сайт, автоматически собранный с помощью выполнения одной команды. В статье мы расскажем на маленьком искусственном примере, из каких частей состоит Ocean и как его использовать. В мире ML существуют и другие варианты, которые мы рассматривали. Прежде всего нужно упомянуть cookiecutter-data-science (далее CDS) как идейного вдохновителя. Начнем с хорошего: CDS не только предлагает удобную структуру проекта, но и рассказывает, как вести проект, чтобы всё было хорошо, — поэтому здесь мы рекомендуем отвлечься и посмотреть в оригинальной статье CDS основные ключевые идеи этого подхода. Вооружившись CDS в рабочем проекте, мы сходу привнесли в него несколько улучшений: добавили удобный файловый логгер, класс-координатор, ответственный за навигацию по проекту и автоматический генератор Sphinx-документации. Кроме того, вынесли несколько команд в Makefile, чтобы даже непосвященному в детали проекта менеджеру было удобно их выполнять. Однако в процессе работы стали всплывать и минусы подхода CDS: Для решения вышеперечисленых проблем в Ocean представлена следующая сущность: эксперимент. Эксперимент — хранилище всех данных, участвовавших в проверке некоторой гипотезы. Сюда можно отнести: какие данные использовались, какие данные (артефакты) получились в результате, версия кода, время начала и завершения эксперимента, исполняемый файл, параметры, метрики и логи. Часть этих сведений можно трекать с помощью специальных утилит, например, MLFlow. Однако структура экспериментов, которая представлена в Ocean, богаче и гибче.  Модуль одного эксперимента выглядит следующим образом: Мы разделяем кодовую базу: переиспользуемый хороший код, актуальный во всем проекте, остается в src-модуле уровня проекта. Он обновляется редко, поэтому реже приходится собирать проект. А модуль scripts одного эксперимента должен содержать код, актуальный только для текущего эксперимента. Таким образом, его можно изменять часто: работу коллег в других экспериментах он никак не затрагивает. Рассмотрим возможности нашего фреймворка на примере абстрактного ML/DL-проекта. Итак, клиент — полиция Чикаго, — выгрузил нам данные и задачу: проанализировать преступления, совершенные в городе на протяжении 2011-2017 годов и сделать выводы. Начинаем! Заходим в терминал и выполняем команду: ocean project new -n Crimes Фреймворк создал соответствующую папку проекта crimes. Смотрим на её структуру: Выполнять навигацию по всем этим папкам помогает Coordinator из одноименного модуля, который уже написан и готов. Для его использования проект нужно собрать: make package Начинаем работу с того, что данные клиента, — в нашем случае файл crimes.csv, — мы помещаем в папку data/raw.  На сайте Чикаго есть карты с разделениями города на посты (“beats” — наименьшая по размеру локация, за которой закреплена одна патрульная машина), секторы (“sectors”, состоят из 3-5 постов), участки (“districts”, состоят из 3 секторов), административных районов (“wards”) и, наконец, общественные зоны (“community area”). Эти данные можно использовать для визуализации. В то же время json-файлы с координатами полигонов-участков каждого из типа не являются данными, присланными заказчиком, поэтому мы помещаем их в data/external. Далее нужно ввести понятие эксперимента. Все просто: рассматриваем отдельную задачу как отдельный эксперимент. Нужно распарсить/выкачать данные и подготовить их для использования в дальнейшем? Это стоит поместить в эксперимент. Подготовить много визуализации и отчетов? Отдельный эксперимент. Проверить гипотезу, подготовив модель? Ну, вы поняли. Для создание нашего первого эксперимента из папки проекта выполняем: ocean exp new -n Parsing -a ivanov Теперь в папке crimes/experiments появилась новая папка с именем exp-001-Parsing, её структура приведена выше.  После этого надо посмотреть на данные. Для этого создаем ноутбук в соответствующей папке notebooks. В Surf мы придерживаемся именования “номер ноутбука — название”, и созданный ноутбук будет называться 001-Parse-data.ipynb. Внутри мы подготовим данные для последующей работы. Чтобы ваши коллеги были в курсе, что вы сделали и могут ли ваши результаты быть ими использованы, нужно прокомментировать это в логе: файле log.md. Структура лога (по сути являющегося привычным markdown-файлом) выглядит следующим образом:  Цветом выделены части, которые заполнены от руки. Основная мета эксперимента (светло-сливовый цвет) — автор и объяснение своей задачи, результата, к которому эксперимент идет. Ссылки на данные, как взятые, так и порожденные в процессе (зеленый цвет), помогают следить за файлами данных и понимать, кто, в рамках чего и зачем их использует. В самом логе (желтый цвет) рассказывается итог работ, выводы и рассуждения. Все эти данные позже станут наполнением сайта проектного лога. Дальше— этап EDA (Exploratory Data Analysis — “разведывательный анализ данных”). Возможно, его будут проводить разные люди, и, конечно, нам понадобятся результаты в виде отчетов и графиков в последствии. Эти доводы повод создать новый эксперимент. Выполняем: ocean exp new -n Eda -a ivanov В папке notebooks эксперимента создаем тетрадь 001-EDA.ipynb. Полный код приводить не имеет смысла, но он и не нужен, например, вашим коллегам. Зато нужны графики и выводы. В тетради выходит много кода, и она сама по себе не то, что хочется показывать клиенту. Поэтому наши находки и инсайты запишем в файл log.md, а картинки графиков сохраним в references. Вот, например, карта безопасных районов Чикаго, если судьба вас занесет туда:  Она как раз была получена в тетради и перенесена в references. В логе добавлена следующая запись: Обратите внимание: график оформлен просто как вставка изображения в md-файл. А если оставить ссылку на тетрадь, то она будет конвертирована в html-формат и сохранена как отдельная страничка сайта. Чтобы его собрать из логов экспериментов, выполняем следующую команду на уровне проекта: ocean log new После этого создается папка crimes/project_log, и index.html в нём — лог проекта.  Посмотрим на формирование документации с помощью Sphinx. Создадим функцию в файле crimes/my_cool_module.py и задокументируем её. Обратите внимание, что в Sphinx используется reStructured Text-формат (RST): А дальше все очень просто: на уровне проекта выполняем команду формирования документации, и готово: ocean docs new Готовая html-документация ждет вас по пути crimes/docs/_build/html/index.html. И наш модуль с комментариями там уже появился:  Следующий шаг — построение модели. Выполняем:  ocean exp new -n Model -a ivanov И на этот раз взглянем на то, что лежит в папке scripts внутри эксперимента. Файл train.py — заготовка для будущего процесса обучения. В файле уже приведен boilerplate-код, который делает сразу несколько вещей. Зачем управлять нашим скриптом из консоли? Все организовано для того, чтобы процесс обучения или получения предсказаний любой модели был легко организован сторонним разработчиком, не знакомым с деталями реализации вашего эксперимента. Чтобы все кусочки паззла сошлись, после оформления train.py нужно оформить Makefile. В нем есть заготовка команды train, и вам остается только правильно расставить пути к перечисленным выше требуемым файлам конфигурации, а в значении параметра username перечислить всех желающих получать Telegram-оповещения. В частности, работает алиас all, который отправит оповещение всем членам команды. Как только все готово, наш эксперимент стартует с помощью команды make train, просто и изящно. На случай, если хочется применить чужие нейросети, вполне помогут виртуальные окружения (venv). Создавать и удалять их в рамках эксперимента очень легко:  Исходный код проекта лежит здесь. Если вы заинтересовались — здорово! Больше информации вы можете почерпнуть в README в репозитории Ocean. И как обычно говорят в таких случаях, contributions are welcome, мы будем только рады, если вы поучаствуете в улучшении проекта. Присоединиться >> Больше кейсов команды Surf ищите на сайте