Добро пожаловать в наш еженедельный блог с советами и рекомендациями FiftyOne, где мы резюмируем интересные вопросы и ответы, недавно появившиеся на Slack, GitHub, Stack Overflow и Reddit.
Подожди, а что такое FiftyOne?
FiftyOne — это набор инструментов машинного обучения с открытым исходным кодом, который позволяет группам специалистов по обработке и анализу данных повышать производительность своих моделей компьютерного зрения, помогая им выбирать высококачественные наборы данных, оценивать модели, находить ошибки, визуализировать встраивания и быстрее приступать к работе.
- Если вам нравится то, что вы видите на GitHub, поставьте звезду проекту.
- "Начать!" Мы упростили запуск и запуск за несколько минут.
- Присоединяйтесь к сообществу Slack FiftyOne, мы всегда рады помочь.
Хорошо, давайте погрузимся в советы и рекомендации этой недели!
Пропуск классов с несколькими экземплярами обнаружения
Член сообщества Slack Сильвия Шмитт спросила:
«При группировке выборок по значениям в определенном поле я хотел бы исключить выборки со значениями, которые редко встречаются в наборе данных. Как это можно сделать?»
Один из способов добиться этого — использовать count_values()
для подсчета количества вхождений каждого уникального значения в заданном поле по всему объекту Dataset
или DatasetView
, взять значения, которые встречаются чаще, чем желаемое отсечение, и использовать match()
для получения образцов, содержащих их.
Например, если вы хотите получить образцы из тестового разделения набора данных Семьи в дикой природе со значениями name
, которые встречаются в наборе данных более десяти раз, вы можете сделать это следующим образом:
import fiftyone as fo import fiftyone.zoo as foz from fiftyone import ViewField as F ## load the dataset dataset = foz.load_zoo_dataset("fiw", split="test") counts = dataset.count_values("name") keep_names = [name for name, count in counts.items() if count > 10] ## filter for samples with these names view = dataset.match(F("name").is_in(keep_names)) session = fo.launch_app(view)
Затем вы можете передать полученное представление в group_by()
для группировки по значениям в поле или любой другой агрегации, которую вы хотите.
Узнайте больше о count_values(), is_in() и использовании агрегаций в FiftyOne Docs.
Сохранение изменений в образцах полей
Член сообщества Slack Сильвия Шмитт спросила:
«При добавлении образцов полей и последующем изменении этих значений в представлении нужно ли сделать изменения постоянными, вызвав save()
для объекта «Набор данных», или эти изменения будут сохранены, если набор данных уже является постоянным?»
Отличный вопрос, Сильвия! Как правило, при внесении изменений в отдельный образец в Dataset
или DatasetView
изменения необходимо сохранить, вызвав save()
для образца, а не для набора данных. Это имеет место, даже если набор данных является постоянным, т.е. если
dataset.persistent = True
Например, вы можете изменить метку класса для первого обнаружения первой выборки в наборе данных Quickstart следующим образом:
import fiftyone as fo import fiftyone.zoo as foz ## load dataset dataset = foz.load_zoo_dataset("quickstart") ## get sample sample = dataset.first() ## change label sample.ground_truth.detections[0].label = "bear" ## save changes to dataset sample.save()
Использование метода save()
в наборе данных необходимо только при редактировании метаданных на уровне набора данных, таких как dataset.info
.
Однако есть несколько случаев, когда нет необходимости явно запускать sample.save()
для распространения изменений обратно в набор данных. К ним относятся метод view.set_values(field_name, field_vals)
, который принимает список значений field_vals
и записывает их в поле field_name
для образцов в представлении, а также метод view.tag_samples(tags)
, добавляющий теги tags
ко всем образцам в представлении.
Если вы знаете, что вам нужно перебирать Dataset
или DatasetView
и вносить изменения в каждую выборку, а не вызывать save()
для каждой выборки, более эффективно передать autosave=True
в iter_samples()
, который группирует операции. Например, чтобы установить поле random
со случайным числом для каждой выборки в нашем наборе данных, мы можем запустить:
import random import fiftyone as fo import fiftyone.zoo as foz ## load dataset dataset = foz.load_zoo_dataset("quickstart") ## Automatically saves sample edits in efficient batches for sample in dataset.select_fields().iter_samples(autosave=True): sample["random"] = random.random()
Узнайте больше о set_values() и пометке образцов в FiftyOne Docs.
Предсказание меток классов в однородных изображениях
Член сообщества Slack Джордж Пирс спросил:
«Как лучше поступить с приложением, в котором метка объекта сильно переплетена с метками других объектов в образце? Например, у меня могут быть изображения, которые обычно представляют собой толпы всех кошек или толпы всех собак, но не толпы, содержащие и кошек, и собак».
Отличный вопрос, Джордж! Есть много способов работать с такими данными. Один из подходов — собрать множество подобных примеров и обучить модель на этих данных. Учитывая достаточное количество высококачественных примеров, модель должна (теоретически) быть в состоянии изучить эти отношения.
В качестве альтернативного подхода, используя только ваши существующие данные, вы можете выполнить постобработку меток в ваших образцах на основе результатов прогнозов вашей модели. Например, если прогнозы вашей модели хранятся в поле model_raw
в ваших выборках, вы можете создать новое поле метки model_processed
и заполнить содержимое этого нового поля на основе содержимого model_raw
для этой выборки.
Для каждого образца проверьте, есть ли, скажем, три или более объектов с одной и той же меткой класса. Для простоты предположим, что dog
и есть этот класс. Если они есть, то для всех объектов, которые не помечены как dog
s в model_raw
, если их оценка достоверности класса ниже некоторого порога, установите для их метки класса значение dog
в model_processed
.
Вот как это может выглядеть:
import numpy as np import fiftyone as fo import fiftyone.zoo as foz from fiftyone import ViewField as F ## create or load your dataset dataset = fo.Dataset(..) ## clone predictions into new field dataset.clone_sample_field( "model_raw", "model_processed" ) ## set a class confidence threshold conf_thresh = 0.3 ## iterate through samples in dataset for sample in dataset.iter_samples(autosave=True): dets = sample.model_processed.detections labels = [det.label for det in dets] unique_labels, label_counts = np.unique(labels, return_counts=True) ## find samples with at least 3 labels of same class if max(label_counts) > 2: crowd_label = unique_labels[np.argmax(label_counts)] for det in dets: if (det.label != crowd_label) and (det.confidence < conf_thresh): det.label = crowd_label det.confidence = None ## tag samples to look at later sample.tags.append("possible homogeneous crowd")
Затем вы можете сравнить эти помеченные образцы, чьи обработанные прогнозы модели отличаются от необработанных прогнозов, и проверить их в FiftyOne App.
Узнайте больше о сохранении, хранении и клонировании образцов полей в FiftyOne Docs.
Совпадение результатов классификации
Член сообщества Slack Надав спросил:
«У меня есть набор данных с двумя видами классификации. Как лучше всего создать представление в коде или в приложении, содержащее только образцы, на которых согласуются две классификации?»
Один из способов сделать это в коде — использовать встроенные в FiftyOne возможности фильтрации и сопоставления. Метод dataset.match(my_condition)
вернет представление, состоящее из всех выборок, для которых выполняется условие my_condition
.
В вашем случае вы можете использовать ViewField для создания условия согласования между двумя классификациями. Вот как это может выглядеть:
import fiftyone as fo import fiftyone.zoo as foz from fiftyone import ViewField as F # create or load your dataset with # classifications in field1 and field2 dataset = fo.Dataset(...) view = dataset.match( F("field1.label") == F("field2.label") ) session = fo.launch_app(view)
Если вместо этого вам нужно представление, содержащее все выборки, в которых две классификации не совпадают, вы можете заменить оператор равенства ==
оператором неравенства !=
.
Узнайте больше о фильтрации в FiftyOne Docs.
Завершение сеанса
Скотт, член сообщества Slack, спросил:
"Как отключить запущенный сеанс?"
В FiftyOne Сеанс — это экземпляр Приложения FiftyOne, подключенный к определенному Dataset
или DatasetView
. Вы можете запустить сеанс для определенного набора данных или просмотра с помощью метода launch_app()
:
import fiftyone as fo import fiftyone.zoo as foz ## load dataset dataset = foz.load_zoo_dataset("quickstart") ## launch one session session1 = fo.launch_app(dataset) ## create a view view = dataset.take(20) ## launch another session session2 = fo.launch_app(view)
Вы также можете просмотреть все зарегистрированные сеансы с помощью fo.core.session.session._subscribed_sessions
:
defaultdict(set, {5151: {Dataset: quickstart Media type: image Num samples: 20 Selected samples: 0 Selected labels: 0 Session URL: http://localhost:5151/ View stages: 1. Take(size=20, seed=None), Dataset: quickstart Media type: image Num samples: 20 Selected samples: 0 Selected labels: 0 Session URL: http://localhost:5151/ View stages: 1. Take(size=20, seed=None)}})
Когда вы завершаете процесс Python, в котором работает FiftyOne, все сеансы закрываются, поэтому обычно вам не нужно закрывать сеансы явно.
Однако, если вы хотите завершить сеанс в любой момент, вы можете сделать это с помощью закрытого метода _unregister_session()
:
from fiftyone.core.session.session import _unregister_session _unregister_session(session1)
Узнайте больше о сеансах, в том числе о том, как запустить несколько экземпляров приложения на удаленном компьютере, в FiftyOne Docs.
Присоединяйтесь к сообществу FiftyOne!
Присоединяйтесь к тысячам инженеров и специалистов по данным, уже использующих FiftyOne для решения некоторых из самых сложных задач в области компьютерного зрения уже сегодня!
- 1350+ участников FiftyOne Slack
- 2550+ звезд на GitHub
- 3200+ Участников встречи
- Использовано 246+ репозиториев
- 56+ авторов
Что дальше?
- Если вам нравится то, что вы видите на GitHub, поставьте звезду проекту.
- "Начать!" Мы упростили запуск и запуск за несколько минут.
- Присоединяйтесь к сообществу Slack FiftyOne, мы всегда рады помочь.
Первоначально опубликовано на https://voxel51.com 24 февраля 2023 г.