- BrainTools - https://www.braintools.ru -
Привет, хабр! Это уже 3-я статья про ClearML. В этой статье [1] я рассказывал про базовый функционал ClearML, а в этой [2]– про то, как настраивать и запускать эксперименты обучения [3] и тестирования через веб-браузер. А теперь я бы хотел затронуть менее популярную тему — организацию датасетов.
В ML есть такой важный тезис: “Данные — это душа модели”. Действительно, объем, чистота и разнообразие данных играют ключевую роль. Но почему-то тот факт, что версий данных может быть много, каждая со своими особенностями, и каждая может по-разному повлиять на исход обучения, часто оставляют за кулисами.
Например, у вас есть большой датасет А сомнительного качества. Есть еще другой датасет В более чистый, но меньше. Можно обучиться на А и В. А какие еще есть варианты?
1) объединить А+В;
2) еще можно очистить А;
3) а также расширить В.
4) объединить новые версии из п. 2 и 3
Из 2-ух исходных версий можно получить еще как минимум 4 новых (и это не считая различных комбинаций). А какая версия обучит лучшую модель? Этого мы не знаем. Нам остается только предполагать и экспериментировать.
С развитием проекта вариативность версий растет и растет, и повышается риск запутаться во всех них. И тут возникает потребность [4] в использовании метода хранения, отслеживания и применения разных версий данных. Для таких целей существуют такие инструменты, как DVC [5] или Pachyderm [6]. Но, как вы поняли из названия статьи, речь пойдет о другом инструменте.
Версионирование
Установку ClearML мы пропустим, потому что она описана тут [7]. Понимание материала лучше на конкретном примере. Представив проект “Распознавание объектов на изображении”. Пусть имеется первая (исходная) версия датасета, скачанная из Kaggle. Я назову ее 1.0-kaggle. Работа в ClearML делается с помощью тасок, и датасеты не исключение. Здесь и указывается название проекта.
from clearml import Task
from clearml import Dataset
Task.init(project_name="Dataset/Object Detection",
task_name="obj-detect",
task_type=Task.TaskTypes.data_processing,
auto_connect_frameworks=False,
auto_resource_monitoring=False,
auto_connect_streams=False)
Далее создадим непосредственно датасет с указанием версии, описания, свойств (user_properties) в виде словаря. А поскольку это первая версия, которая не имеет предшественников, то parent_datasets=None. По итогу нужно зафиксировать изменения.
dataset = Dataset.create(parent_datasets=None,
dataset_version="1.0-kaggle",
description="http://kaggle.com/obj_detect",
use_current_task=True)
dataset._task.set_user_properties(data_path="/path/to/1.0-kaggle.json")
logger = dataset.get_logger()
dataset.finalize() # commit
Как это выглядит в ClearML
Аналогичным образом создадим еще одну исходную версию, в этот раз с YouTube – 1.0-youtube. Но это версия содержит много дубликатов, поэтому нужно их почистить. Очищенную версию назовем 1.1-youtube. ID исходной версии можно взять из поля, как на рисунке выше.
parent_id = "48b8d22437624e519f6a177eddcfcd36" # 1.0-youtube
dataset = Dataset.create(parent_datasets=[parent_id],
dataset_version="1.1-youtube",
description="drop duplicates",
use_current_task=True)
dataset._task.set_user_properties(data_path="/path/to/data-youtube.v1.1.json")
logger = dataset.get_logger()
dataset.finalize() # commit
Как это выглядит в ClearML
Обратите внимание [8], что в аргументе parent_datasets указывается список родителей, т.е. их может быть несколько. Например, мы сейчас объединим версии 1.0-kaggle и 1.1-youtube , обозначив результат просто 1.0.
parent1_id = "8ccc9f696ebb4ea1b1b5f79adf200851" # 1.1-youtube
parent2_id = "ada9f6d0fe0b4ee880b976988a09fdae" # 1.0-kaggle
dataset = Dataset.create(parent_datasets=[parent1_id, parent2_id],
dataset_version="1.0",
description="merged datasets from YouTube and Kaggle",
use_current_task=True)
dataset._task.set_user_properties(data_path="/path/to/1.0.json")
logger = dataset.get_logger()
dataset.finalize() # commit
Как это выглядит в ClearML
Как родительских версий может быть несколько, так и дочерних может быть множество. При создании новой версии вы можете указывать в parent_datasets один и тот же parent_id сколь угодно раз.
Хранение метаданных о версии
Помимо уже сказанного, еще полезно хранить такую информацию, как размер датасета (кол-во примеров), количество классов, путь к данным, скрипт получения той или иной версии и еще много всего, что можно назвать метаданными. Если у вас удалится какая-либо версия, вы должны суметь восстановить ее по этим метаданным.

Если вы читали прошлую статью [1], то наверняка заметили сходство. Как я говорил, работа в ClearML делается с помощью тасок. Это касается обучения, тестирования и создания версии датасета. Эти таски могут хранить множество разнообразной информации.
Графики
Часто полезно хранить графическую информацию для отображения статистик. Например, распределения по классам или гистограммы. Это делается через logger.
Dataset.create(parent_datasets=None,
dataset_version="1.0",
description="Add table",
use_current_task=True)
logger = dataset.get_logger()
logger.report_table(title="classes",
series="names",
csv=csv_path)
logger.report_histogram("Class balance",
"data",
values=hist,
xaxis="classes",
yaxis="count")
logger.report_matplotlib_figure(title="Figure",
series="data",
figure=figure,
report_image=False,
report_interactive=True)
dataset.finalize() # commit
Как это выглядит в ClearML

Примеры медиа
Вдобавок ко всему, мне нравится возможность сохранять в отдельном окне некоторое количество примеров (картинок или аудио). Это называется debug samples. Полезно, если вы хотите самостоятельно просмотреть или прослушать пару примеров из датасета. Вдруг найдутся какие-то ошибки [9].
logger.report_media(title="examples",
series="1",
local_path=fpath,
stream=None,
delete_after_upload=False)

Загрузка самих данных в ClearML
Если ваши данные уже хранятся в заданном хранилище (прям на или в S3), то дублировать их в ClearML вам, возможно, и не нужно. Мы, например, так не делаем. Но если вы хотите использовать ClearML в качестве непосредственно хранилища и готовы отдать ему достаточно пространства на диске, то такая возможность тоже есть.
dataset = Dataset.create(parent_datasets=None,
dataset_version="1.0",
use_current_task=True)
dataset.add_files(path=dataset_path)
dataset.upload()
dataset.finalize()
Организация датасетов действительно недооцененная возможность, которая может уберечь от потенциальной путаницей со всеми этими данными и их версиями. Подумайте, все ли у вас гладко в плане управления датасетами и посмотрите в сторону таких инструментов.
Автор: kochetkover
Источник [10]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/14461
URLs in this post:
[1] этой статье: https://habr.com/ru/articles/901072/
[2] этой : https://habr.com/ru/articles/902148/
[3] обучения: http://www.braintools.ru/article/5125
[4] потребность: http://www.braintools.ru/article/9534
[5] DVC: https://habr.com/ru/companies/raiffeisenbank/articles/461803/
[6] Pachyderm: https://docs.pachyderm.com/
[7] тут: https://habr.com/ru/articles/901072/#:~:text=ClearML.%20%D0%A0%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D1%8F
[8] внимание: http://www.braintools.ru/article/7595
[9] ошибки: http://www.braintools.ru/article/4192
[10] Источник: https://habr.com/ru/articles/902824/?utm_campaign=902824&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.