Обзор Metaflow: шаги и артефакты ML-процесса — это разбор библиотеки, где программа описана как граф операций. Документация проекта называет flow графом, шаги — его узлами, а артефакты — сохранёнными переменными, которые переходят между шагами и остаются доступны после запуска.
Что описывает flow
Документация Metaflow описывает flow как направленный граф операций: программа разложена на узлы, между которыми заданы переходы. Такой граф удобен для конвейеров обработки данных и машинного обучения, где важен порядок вычислений и зависимость шагов друг от друга.
В графе есть жёсткие точки. Каждый flow обязан содержать шаг start и шаг end. Запуск, который документация называет run, начинается на start и считается успешным, когда завершился end. Всё, что находится между ними, проектирует автор: линейные переходы, ветвления, циклы по списку, условные развилки и рекурсию.
Структура графа задаётся декораторами @step и вызовами self.next. В линейном примере из документации шаг start создаёт переменную my_var, передаёт управление шагу a, тот печатает значение и вызывает end. Такой минимальный flow уже показывает главную идею: логика живёт внутри шагов, а связи между ними описаны явно.
Документация проекта перечисляет три базовых типа переходов: линейный, ветвление и foreach. Позже добавились условные ветки и рекурсия. Ветвление запускает несколько шагов параллельно, foreach создаёт отдельную задачу на каждый элемент списка, условная развилка выбирает ровно одну ветку по значению артефакта. Параллельные ветви и foreach завершаются шагом соединения с аргументом inputs. Условный переход выполняет только одну выбранную ветку, поэтому отдельный join для слияния нескольких наборов артефактов ему не требуется.
Для читателя это означает простую вещь: прежде чем писать код, полезно нарисовать граф. Если на рисунке появляется шаг, который делает слишком много, его стоит разделить. Документация советует держать шаг небольшим, но не дробить код до отдельной строки: каждый шаг добавляет накладные расходы на сохранение состояния.
Шаг и артефакт
Шаг — единица выполнения. Документация называет его неделимым: шаг либо завершается успешно целиком, либо падает. После успешного завершения Metaflow сохраняет все переменные экземпляра, созданные в коде шага. Поэтому шаг работает как контрольная точка: если следующий шаг упадёт, предыдущий повторно выполнять не нужно.
Артефакт — это переменная, присвоенная через self. В примере из документации строка self.my_var = 'hello world' создаёт артефакт my_var. Дальше его видно в последующих шагах как обычную переменную экземпляра. Исключение — ветки: там значение может оказаться неоднозначным, и его нужно разрешать явно.
Документация перечисляет назначение артефактов. Они управляют потоком данных внутри flow без ручной загрузки и сохранения. Они сохраняются, чтобы позже их можно было изучить через Client API, показать в Cards и использовать в других flow. Они одинаково работают в разных средах, поэтому часть шагов можно выполнить локально, а часть в облаке. Доступ к прошлым артефактам помогает отладке: можно посмотреть данные перед сбоем и возобновить выполнение после исправления.
Практический вывод: артефактом стоит делать то, что понадобится позже. Локальные переменные функции шага артефактами не становятся. Для переменных self сохраняется состояние на момент успешного окончания шага; промежуточные изменения одной переменной внутри шага отдельно не фиксируются.
Данные между шагами
При линейных переходах артефакты передаются просто: значение берётся на выходе предыдущего шага. Сложности начинаются на соединении веток. Если ветка a установила x = 1, а ветка b установила x = 2, значение x в шаге соединения неоднозначно.
Документация предлагает функцию merge_artifacts. Она помогает распространять однозначные значения и разрешать конфликты. В примере из документации артефакт pass_down проходит дальше, потому что в обеих ветках не менялся. Артефакт common тоже проходит: в обеих ветках ему присвоено одно и то же значение, а Metaflow сравнивает содержимое. Артефакт x обрабатывается кодом вручную до вызова merge_artifacts, поэтому функция его не трогает. Артефакт y исключён списком exclude. Артефакт from_a проходит, потому что задан только в одной ветке.
Есть и второй способ управления: параметр include. Он перечисляет артефакты, которые нужно рассмотреть при слиянии. Документация отмечает, что include и exclude в одном вызове не сочетаются. Если артефакт указан в include, но отсутствует в текущем шаге или во входных данных, возникает ошибка. Параметр доступен начиная с версии 2.2.1.
Функция merge_artifacts выбрасывает исключение, если артефакт, который она должна слить, имеет неоднозначное значение. Это защита от тихой ошибки: лучше остановиться на соединении, чем протащить дальше случайное значение из одной ветки.
Учебный фильтр и сумма
Соберём небольшой учебный процесс, чтобы увидеть артефакты в действии. Значения этого условного примера заданы заранее и служат проверкой логики. Измерения производительности здесь нет.
from metaflow import FlowSpec, step
class FilterFlow(FlowSpec):
@step
def start(self):
self.values = [10, 20, 30]
self.threshold = 15
self.next(self.filter)
@step
def filter(self):
self.selected = [v for v in self.values if v > self.threshold]
self.next(self.summarize)
@step
def summarize(self):
self.total = sum(self.selected)
self.next(self.end)
@step
def end(self):
print(self.selected, self.total)
if __name__ == '__main__':
FilterFlow()
Что здесь сохраняется как артефакт: values, threshold, selected, total. При пороге 15 шаг filter оставляет [20, 30], а summarize считает сумму 50. Для второго запуска замените присваивание self.threshold = 15 на self.threshold = 25 и запустите файл снова. Этот запуск даёт selected = [30] и total = 30. Оба результата — ожидаемые учебные значения, полученные вручную.
Проверка ошибок здесь простая. Первая: filter читает self.threshold, который создан в start. Если присвоить порог внутри filter, значение не станет артефактом предыдущего шага, и сравнение запусков усложнится. Вторая: summarize зависит от selected. Если filter упадёт, шаг summarize не получит список, и запуск остановится на сбое. Третья: при сравнении двух запусков нужно брать конкретный run ID и смотреть параметр. Слово latest без проверки успеха и конфигурации подходит плохо: последним может оказаться неудачный запуск с другим порогом.
Запуски и восстановление
Запуск flow создаёт run. Внутри run каждый шаг порождает задачу, у которой есть собственный идентификатор. Документация AWS-обзора показывает, как это выглядит в выводе: строка вида [40/start/413] содержит номер запуска, имя шага и номер задачи. Тот же материал показывает объектную модель: Flow оборачивает все выполнения, Run соответствует одному запуску, Step — узлу графа.
Восстановление опирается на контрольные точки. Документация описывает команду resume: если flow упал внутри рекурсивного шага, выполнение продолжается с последней успешной итерации, используя сохранённое состояние. Тот же механизм работает и для обычных шагов: сохранённые артефакты позволяют не пересчитывать завершённые части.
Здесь важно ограничение. Resume не гарантирует безопасный повтор произвольного внешнего действия. Если шаг отправлял письмо, списывал деньги или писал в чужую систему, повтор может создать дубль. Артефакты сохраняют состояние процесса, а внешние эффекты требуют отдельной защиты.
Для воспроизводимости нужны версии кода, данных и окружения. При сравнении артефактов проверяйте также сохранённую версию flow и его окружение: одних значений для воспроизводимости недостаточно. Документация проекта относит версионирование flow, экспериментов и артефактов к возможностям библиотеки, а окружение описывается отдельно.
Локально и в облаке
Документация проекта описывает три стадии проекта: прототип, масштабирование и продакшен. На стадии прототипа flow разрабатывается и тестируется локально без развёртывания инфраструктуры. На стадии масштабирования тот же код проверяется на больших данных. В продакшене включаются отказоустойчивые оркестраторы, а код при переходе не меняется.
Локальный старт простой: библиотека ставится как обычный Python-пакет, а flow запускается командой вида python myflow.py run. Документация AWS-обзора показывает, что при локальном запуске артефакт self.dataset создаётся в одном шаге и печатается в другом. Для облачного выполнения тот же материал описывает добавление флага --with batch к команде запуска и отдельную настройку через metaflow configure aws.
Разница сред проявляется в хранении. В облачной конфигурации артефакты сохраняются в объектное хранилище, и AWS-обзор называет Amazon S3. Там же описан сервис метаданных, который связывает запуски с созданными артефактами и позволяет читать их как объекты в памяти. Документация проекта перечисляет поддерживаемые облака: AWS, Azure и GCP, а также интеграции с AWS Batch, AWS Step Functions, Kubernetes, Argo Workflows и Apache Airflow.
Отдельный пример даёт публикация SAP о плагине Metaflow-Argo. Она описывает локальную разработку flow, а затем генерацию шаблона Argo для запуска на Kubernetes. Команды из этой публикации относятся к 2022 году и к конкретной платформе SAP AI Core, поэтому переносить их в другой проект стоит с оглядкой на текущую документацию.
Отличие от трекинга MLflow
Сравнение с MLflow tracking полезно начать с задачи читателя. В текущей документации Metaflow уже описано автоматическое отслеживание flow, экспериментов и артефактов. AWS-обзор также связывает прошлые запуски и их результаты через сервис метаданных. Наличие истории экспериментов само по себе не разделяет эти инструменты на непересекающиеся категории.
Разделите два требования. Первое — описать граф, передать значения между шагами и возобновить выполнение. Второе — договориться, какие параметры, метрики, версии и критерии сравнения относятся к каждому запуску. В учебном примере порог, отобранные значения и сумма сохраняются как артефакты; для сравнения выбирают нужные успешные run ID и проверяют конфигурацию.
| Вопрос процесса | Что показывает учебный Metaflow flow |
|---|---|
| Где выполняется преобразование | Именованный шаг графа |
| Что передано следующему шагу | Артефакты selected и total |
| Как различить варианты | Конкретный run ID и сохранённый threshold |
| Как сравнить результаты | Сопоставить selected и total для выбранных запусков |
| Что требует отдельного решения | Метрики качества и правила выбора лучшего результата |
При выборе между Metaflow и системой учёта экспериментов сопоставьте эти требования с интерфейсами своего проекта. Сохранённое состояние помогает восстановлению и анализу. Критерий качества модели определяет автор процесса и проверяет по подходящим данным.
Частые вопросы
Что такое metaflow python?
Это Python-библиотека с открытым исходным кодом под лицензией Apache 2.0, изначально созданная в Netflix. Она описывает программу как граф шагов и берёт на себя передачу данных между ними. Установка выполняется как у обычного Python-пакета, а запуск — командой python файл.py run. Документация проекта называет библиотеку дружелюбной к человеку и пригодной для задач с данными, ML и AI.
Чем шаг отличается от артефакта?
Шаг — узел графа и единица выполнения, которая завершается целиком. Артефакт — переменная, присвоенная через self и сохранённая после успешного завершения шага. Один шаг может создать несколько артефактов, а артефакт живёт дальше и доступен в последующих шагах. Документация называет артефакты ядром концепции Metaflow.
Как передать данные между шагами?
Присвоить значение переменной экземпляра: self.selected = [...]. В линейной цепочке следующее значение берётся с выхода предыдущего шага. На соединении веток используется merge_artifacts с параметрами include или exclude. Неоднозначное значение без разрешения приводит к исключению.
Что делает resume?
Продолжает выполнение с последней успешной точки вместо полного перезапуска. Документация показывает это на рекурсивном шаге: после прерывания команда resume продолжает с последней успешной итерации. Внешние действия при этом требуют отдельной защиты от повтора. Артефакты завершённых шагов сохраняются и повторно не считаются.
Можно ли запускать Metaflow локально без облака?
Да. Документация проекта описывает локальную разработку без развёртывания инфраструктуры: библиотека ставится как Python-пакет, flow запускается из командной строки. Облачные возможности подключаются отдельно, когда появляется потребность в масштабе. Публикация SAP описывает локальный запуск flow перед генерацией шаблона для Kubernetes.
