model_path: /mnt/data/models/final_model_v3_new_best.pth
data_path: /mnt/data/train_data_final_cleaned.csv
epochs: 100
learning_rate: 0.001 # подкрутили руками перед деплоем
Этот конфигурационный файл — эпитафия вашей инженерной культуре. Вы смотрите на него и понимаете: если сервер сгорит прямо сейчас, вы никогда в жизни не получите эту же самую модель. Файл final_model_v3_new_best.pth — это не артефакт, это крик о помощи. Данные были изменены по месту, код обучения остался в локальной ветке на ноутбуке уволившегося сотрудника, а гиперпараметры меняли на лету, чтобы успеть к релизу. Когда бизнес спросит, почему новая версия нейросети галлюцинирует под нагрузкой, вы будете мямлить про сдвиг распределения, хотя на самом деле вы просто потеряли исходник. Строить пайплайны и наводить порядок нужно до того, как вы упретесь в потолок деградации метрик. И это не про покупку модных облачных платформ.
Ноутбуки, ручное управление и смерть воспроизводимости
Переход от ноутбука к автоматизированному пайплайну обучения — это первый фильтр профпригодности для любой команды машинного обучения. Jupyter notebooks великолепны для быстрого ресёрча, визуализации и проверки гипотез, но тащить их в прод или использовать как финальную точку сборки весов — чистое преступление против здравого смысла. В них живет скрытое состояние. Вы выполнили ячейку четыре, затем ячейку два, потом десять. В оперативной памяти висит объект, которого формально по линейному коду просто не существует. Потом вы скидываете этот файл коллеге, он нажимает Run All и закономерно получает ошибку или, что гораздо хуже, совершенно другие метрики. Воспроизводимость умерла прямо на этапе запуска скрипта.
Воспроизводимая сборка означает, что весь процесс запускается одной командой в чистом, изолированном окружении. Без ручного скачивания CSV-файлов из корпоративного мессенджера, без закомментированных кусков кода, без зависимости от того, что установлено в глобальном окружении питона на сервере. Вы либо можете выполнить сборку с нуля и получить бит-в-бит те же самые веса при фиксированном сиде, либо вы не контролируете свой продукт. Фиксация сидов — это вообще отдельная боль. Инженеры часто забывают, что зафиксировать нужно не только генератор случайных чисел в numpy или torch, но и хеширование самого Python, а также отключить недетерминированные операции в CUDA, если вы учитесь на GPU. Иначе на разных видеокартах или даже при разных запусках на одной и той же карточке математика поплывет из-за особенностей параллельных вычислений с плавающей точкой.
Инженерия начинается там, где заканчивается ручной труд. Если для получения модели нужно выполнить инструкцию из текстового документа, где написано «тут запусти скрипт, потом скопируй папку, потом поменяй пути» — у вас нет MLOps. У вас есть карго-культ, который развалится при первой же ротации кадров.
MLOps с нуля: как версионировать данные и модели и не потерять воспроизводимость
Модель машинного обучения — это не просто файл с весами. Это точка пересечения трех жестких координат: конкретного коммита программного кода, конкретного слепка обучающих данных и конкретной конфигурации гиперпараметров. Если вы потеряли или изменили хотя бы одну координату, этой модели больше не существует. Версионировать данные, код и веса нужно исключительно вместе, связывая их непробиваемыми криптографическими хешами. Обычные разработчики настраивают Git, радуются зеленой галочке в CI/CD и идут дальше. Но классический Git физически не способен переварить терабайтный датасет с изображениями или аудио. В итоге код лежит в репозитории, а данные болтаются на каком-то S3 бакете, где кто-то периодически перезаписывает архивы с обучающей выборкой без изменения имени файла.
Когда мы в Morana Labs отлаживали инференс тяжелых CV-моделей на edge-устройствах для промышленной дефектоскопии на заводе, мы быстро уяснили одно правило: если не связать хеш датасета с хешем коммита, ты будешь неделями искать причину внезапного падения пропускной способности или точности на железе клиента, тестируя правильный код на неправильных картинках. Данные мутируют. Разметчики исправляют ошибки, добавляются новые классы, удаляются битые файлы. Если в момент переобучения вы не сделали снапшот состояния данных, вы не сможете доказать, что деградация модели вызвана алгоритмом, а не мусором, который залили в базу час назад.
Здесь на сцену выходит реестр моделей и трекинг экспериментов. Это не какая-то корпоративная блажь, это базовая гигиена разработки. Кто-то должен записать, что конкретный коммит с конкретной версией датасета при скорости обучения в одну тысячную выдал точность в 98 процентов на валидации. И этот кто-то — не эксель-табличка на рабочем столе дата-саентиста. Трекер экспериментов автоматически логирует каждую попытку, сохраняя параметры, метрики и потребление ресурсов. Реестр моделей — это следующий шаг, где из сотен мусорных запусков отбираются те, которые прошли все тесты и готовы к деплою. В реестре модель получает статус продакшена, и микросервис, отвечающий за инференс, забирает не файл по захардкоженному пути, а абстрактную сущность нужной версии через API. Это разделяет зону ответственности ресёрча и эксплуатации.
Вам нужен минимальный жизнеспособный MLOps без оверинжиниринга. Не нужно тащить в проект монструозные оркестраторы вроде Kubeflow, если у вас два инженера и один сервер с несколькими ускорителями. Вам не нужен Airflow для запуска одного скрипта переобучения раз в неделю. Оверинжиниринг убивает инициативу и скорость поставки быстрее, чем полнейший хаос. Команды часто путают инструмент с процессом: покупают дорогую подписку на облачный MLOps-сервис и свято верят, что теперь у них всё отлично, продолжая заливать в него модели с названиями вроде test_final_2.
Стартовый стек и порядок внедрения
Порядок внедрения инструментов диктуется исключительно болью, которую испытывает команда. Сначала мы забираем у всех право менять данные руками в обход системы контроля версий. Для этого идеально подходит DVC. Он работает по принципу симлинков: сами тяжелые файлы уезжают в ваше удаленное хранилище, а в Git коммитятся только легковесные текстовые файлы с MD5-хешами этих данных. Вы меняете датасет, DVC пересчитывает хеши, вы делаете git commit. Теперь обычный git checkout откатывает не только логику обработки признаков, но и физическое состояние датасета на диске. Это решает половину проблем с воспроизводимостью одним ударом.
Следом внедряется трекинг экспериментов. MLflow разворачивается локально или на виртуальной машине за тридцать минут. В код обучения добавляются три строчки инициализации логирования. Теперь каждый запуск скрипта оставляет несмываемый след: кто запускал, на каком железе, какие метрики получил в эпохах, какие артефакты сгенерировал. Никаких больше споров на дейликах о том, чья архитектура показала лучшую сходимость.
Реестр моделей становится финальным аккордом этого стартового стека. Из MLflow лучшие запуски промоутируются в Model Registry. Продакшен-система при старте опрашивает реестр, скачивает утвержденные веса и поднимает сервер. Всё. Этот лаконичный стек из Git, DVC и MLflow покроет подавляющее большинство потребностей до тех пор, пока вы не вырастете в огромную корпорацию с десятками команд. Никакой магии, никаких сложных абстракций ради красивых архитектурных схем. Только железобетонная уверенность в том, что вчерашний успешный результат можно повторить сегодня, завтра и через год.