galchinsky.github.io

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

Мне обе этих крайности не нравятся. Если забить на управление воспроизводимостью, мозг вместо занятия полезными делами должен помнить какую-то чушь, а ошибки съедают иногда часы. При чем начинается это довольно быстро - вот у тебя простой очевидный пайплайн, а уже ты сидишь и думаешь, почему эта модель дала такой крутой результат и не воспроизводится. Если использовать вещи типа DVC или W&B, эти тулзы превращают простую в общем-то задачу в кровавый энтерпрайз с километровыми конфигурациями, где ты должен описать стадии, с md5 хэшами, справками и печатями.

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

Есть три сущности в виде файлов: скрипт, конфиг и данные.

Сами правила:

Основной друг здесь - дефолтные значения. Допустим, мы решили протестить модель, у которой в слое не 5 фильтров, а 10. Конфиг загружен в переменную params, которая доступна везде в коде. В коде пишем Conv(params.get(“kolvo_kanalov”, 5), …). Копируем конфиг, добавляем в него строчку “kolvo_kanalov” : 10. Старые конфиги работают, потому params.get не найдет новый ключ и вернет 5, новая модель тоже работает с числом фильтров 10.

Структура любого скрипта получается такой:

Базовые скрипты:

Соответственно, нужно три кофига: data.json, augmentation.json и model.json.

Каждый последующий конфиг содержит имя предыдущего как один из параметров, таким образом формируется направленный граф/пайплайн, в данном случае data->augmentation->model.

Помимо этого, есть еще predict.py, evaluate.py, export.py и тому подобные вещи, которые, читая model.json, генерируют что-то более приземленное.

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

Уровень паранойи регулируется согласно требованиям проекта. Например, если датасет меняется часто, можно считать чексумму директории и сохранять список файлов. А если редко, то достаточно пути, где этот датасет лежит, и забэкапить его на S3 вручную.

Что с распределенностью? Конфиги можно хранить в монге. Тогда скрипту-воркеру остается подгрузить данные из распределенной ФС, посчитать, что нужно, и сохранить данные в распределенную ФС, апдейтнув монгу, что конфиг посчитан и лежит там-то.

Применение этих правил позволило мне сократить время, затрачиваемое на ресерч, примерно на порядок.