Консенсусное агрегирование голосов, точек и рамок от многих разметчиков
Сводит ответы нескольких разметчиков на каждый объект в один консенсус с долями голосов, кластерами точек DBSCAN и медианными рамками, как это делают редьюсеры Zooniverse.
Новое в v2.13.0
Экспорт consensus объединяет ответы нескольких разметчиков на каждый объект в один консенсусный ответ на объект, так же как проекты гражданской науки, например Zooniverse, объединяют классификации волонтёров. В проекте с волонтёрами каждый объект (subject) получают несколько волонтёров, например чтобы сосчитать пингвинов на фотографии колонии или отметить животных на кадре фотоловушки. Для вопроса с выбором экспорт сообщает, сколько разметчиков дали каждый ответ, и помечает каждый объект как retired или needs_review. Точечные отметки разметчиков экспорт объединяет в кластеры, по одной точке на каждый объект изображения, а для ограничивающих рамок выдаёт одну медианную рамку на каждый объект изображения. Команды краудсорсинга вне гражданской науки используют тот же экспорт, чтобы свести несколько меток на объект к одной метке на объект. Вслед за Zooniverse Potato называет разметчиков, ответивших на вопрос по объекту, классификаторами этого объекта.
- Вопросы с выбором: схемы
radio,select,likertиmultiselectполучают число голосов и долю голосов для каждого ответа, лучший ответ, ничью, если она есть, и статус. - Числовые вопросы: схемы
sliderиnumberполучают число ответов, среднее, медиану, стандартное отклонение, минимум и максимум. - Точки: отметки
landmarkв схемеimage_annotationкластеризуются методом DBSCAN с радиусом в пикселях или в долях изображения. - Рамки: отметки
bboxв схемеimage_annotationгруппируются по перекрытию, и каждая группа получает медианную рамку. - Установка: экспорту не нужно ничего, кроме Potato. Кластеризация использует numpy, а Potato устанавливает numpy как основную зависимость.
Консенсус и согласованность
Potato измеряет, насколько согласны между собой разметчики, а экспорт консенсуса выдаёт один ответ на объект. Экспорт reliability и страница /admin/iaa сообщают альфу Криппендорфа по каждому вопросу для всего исследования, и команда с низкой альфой сначала проверяет инструкции или обучение разметчиков. Экспорт консенсуса работает с каждым объектом отдельно. Каждый объект получает статус, который показывает, достаточно ли согласны разметчики этого объекта, чтобы сохранить ответ. Проверьте согласованность, прежде чем полагаться на консенсус, потому что экспорт консенсуса даёт каждому разметчику один голос независимо от точности этого разметчика. Согласованность с поправкой на случайность для пространственных меток описана в руководстве Измерение согласованности по ограничивающим рамкам.
MACE взвешивает голоса каждого разметчика, а не считает все голоса одинаково. MACE оценивает компетентность каждого разметчика на схемах radio, likert, select и multiselect и выводит метку каждого объекта из взвешенных голосов. Руководство Агрегирование меток краудсорсинга объясняет, когда модель компетентности лучше невзвешенного голосования и когда стоит сохранить разброс ответов. MACE не читает точки и рамки. Для отметок на изображениях используйте экспорт консенсуса.
Конфигурация
Конфигурация ниже задаёт подсчёт пингвинов с вопросом из трёх вариантов, вопросом с множественным выбором и схемой изображения, в которой разметчики отмечают точкой каждого взрослого пингвина и обводят рамкой каждое гнездо:
annotation_task_name: "Penguin colony counts"
task_dir: .
data_files: [data/colonies.jsonl]
item_properties: {id_key: id, text_key: image}
output_annotation_dir: annotation_output
num_annotators_per_item: 5
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: radio
name: T0
description: "Are there penguins in the image?"
labels: ["Yes", "No", "Unsure"]
- annotation_type: multiselect
name: T1
description: "What else is in the image?"
labels: [Ice, Water, Rock]
- annotation_type: image_annotation
name: T2
description: "Mark each adult penguin and draw a box round each nest"
source_field: image
tools: [landmark, bbox]
labels:
- {name: Adult, color: "#00ff00"}
- {name: Nest, color: "#ff0000"}
consensus_aggregation:
agreement_threshold: 0.8
min_classifiers: 2
points:
eps: 10
eps_unit: pixels
min_samples: 2
boxes:
iou_threshold: 0.5Имена схем T0, T1 и T2 — это идентификаторы задач Zooniverse. Когда проект приходит из Zooniverse, potato import сохраняет идентификаторы задач как имена схем, а в исследовании, созданном в Potato, имена могут быть любыми. Potato отправляет каждое изображение пяти разметчикам (num_annotators_per_item: 5). При agreement_threshold: 0.8 четверо из пяти разметчиков должны дать один и тот же ответ, чтобы объект получил статус retired. При min_classifiers: 2 ответ одного разметчика никогда не считается консенсусом. Две точки на расстоянии не больше 10 пикселей друг от друга могут образовать кластер, а две рамки относятся к одному гнезду, только если их пересечение по объединению (IoU) не меньше 0,5.
Чтобы кластеризовать точки с радиусом в пикселях, экспорту нужен размер каждого изображения. Каждый объект указывает изображение, а также его ширину и высоту в пикселях:
{"id": "9001", "image": "/media/colony_9001.png", "image_width": 1000, "image_height": 500}Все ключи блока необязательны:
| Ключ | По умолчанию | Имя для --option | Значение |
|---|---|---|---|
agreement_threshold | 0.8 | agreement_threshold или threshold | Доля классификаторов, которую должен набрать лучший ответ, чтобы объект получил статус retired. Больше 0 и не больше 1 |
min_classifiers | 2 | min_classifiers | Наименьшее число классификаторов для любого статуса, кроме needs_review. Целое число, не меньше 1 |
schemes | все поддерживаемые схемы | schemes (через запятую) | Имена схем для агрегирования. Каждое имя должно быть схемой, объявленной в конфигурации |
points.eps | 0.02 | eps | Радиус кластера. Больше 0 и не больше 1, когда eps_unit равен fraction |
points.eps_unit | fraction | eps_unit | fraction измеряет x как долю ширины изображения, а y как долю высоты, а pixels измеряет в пикселях изображения |
points.min_samples | 2 | min_samples | Наименьшее число точек в пределах eps от точки, при котором точка становится основной (core point). Сама точка входит в это число. Целое число, не меньше 1 |
boxes.iou_threshold | 0.5 | iou_threshold | Наименьший IoU между любыми двумя рамками группы. Больше 0 и не больше 1 |
Сервер останавливается при запуске и выводит сообщение с именем ключа, если значение выходит за допустимый диапазон, ключа нет в списке ключей блока или элемент schemes называет схему, которую конфигурация не объявляет. python -m potato.validate_cli config.yaml сообщает о тех же ошибках до начала исследования.
Команда экспорта
Экспорт читает конфигурацию и разметку, сохранённую в output_annotation_dir:
python -m potato.export -c config.yaml -f consensus -o consensus_outКоманда записывает в consensus_out/ файл consensus.json и CSV-файлы для типов схем из конфигурации. Передайте --option, чтобы переопределить одну настройку блока на один запуск, не меняя конфигурацию:
python -m potato.export -c config.yaml -f consensus -o consensus_out \
--option agreement_threshold=0.9 --option eps=8 --option eps_unit=pixelsНа неизвестном имени параметра экспорт останавливается и выводит список известных имён. Экспорт также останавливается и выводит причину, если в конфигурации нет схемы поддерживаемого типа или не сохранено ни одной разметки. API экспорта для администратора по адресу /admin/api/export предлагает тот же экспорт под именем формата consensus командам без доступа к командной оболочке сервера.
Вопросы с выбором
Для каждого объекта и вопроса экспорт считает классификаторов и разметчиков, давших каждый ответ. Доля ответа — это число голосов за ответ, делённое на число классификаторов. Для вопроса с одним ответом доли в сумме дают 1. Для multiselect каждая доля — это часть классификаторов, отметивших этот вариант, и в сумме доли могут превышать 1. В consensus_questions.csv одна строка на каждую пару объекта и вопроса. Строки ниже взяты из примера проекта, описанного в конце страницы:
instance_id,schema,type,n_classifiers,top_answer,top_count,top_fraction,tied,status,reason
9001,T0,radio,5,Yes,4,0.8,,retired,
9001,T1,multiselect,5,Ice,4,0.8,,needs_review,no agreement on Water (ticked by more than 20% and fewer than 80% of classifiers)
9002,T0,radio,4,Yes,2,0.5,Yes;No,needs_review,"tie between Yes, No"
9002,T1,multiselect,4,Rock,4,1.0,,retired,
9003,T0,radio,1,Yes,1,1.0,,needs_review,"1 classifier, fewer than min_classifiers (2)"
9003,T1,multiselect,1,Ice,1,1.0,,needs_review,"1 classifier, fewer than min_classifiers (2)"Статус определяется тремя правилами:
- Слишком мало классификаторов: объект, у которого классификаторов меньше
min_classifiers, получает статусneeds_review. - Вопросы с одним ответом: объект в схеме
radio,selectилиlikertполучает статусretired, когда доля лучшего ответа не меньшеagreement_thresholdи никакой другой ответ не делит с ним первое место. - Вопросы с множественным выбором: объект получает статус
retired, когда решён каждый вариант. Вариант решён, когда его отметила доля классификаторов не меньшеagreement_thresholdили такая же доля оставила его неотмеченным.
На изображении 9001 вариант Water отметили двое из пяти разметчиков. Поэтому вариант Water остаётся нерешённым, ведь ни 40% отметивших Water, ни 60% оставивших его неотмеченным не достигают порога 0,8. При ничьей top_answer называет первый из равных ответов в том порядке, в котором схема объявляет метки, а tied перечисляет все равные ответы через точку с запятой. Столбец reason объясняет, почему объект требует проверки.
Статус консенсуса — это отчёт, и Potato никак на статус не реагирует. Zooniverse снимает объект с показа после заданного числа классификаций, а Potato продолжает назначать объекты по правилам назначения исследования, каким бы ни был статус консенсуса. По статусу выбирайте объекты, которые нужно отправить ещё нескольким разметчикам или на разрешение разногласий.
В consensus_votes.csv одна строка на каждое сочетание объекта, вопроса и ответа, со столбцами instance_id, schema, answer, count, fraction, n_classifiers. Строку получает каждый вариант, который объявляет схема, с числом голосов 0, если ни один разметчик этот вариант не выбрал:
instance_id,schema,answer,count,fraction,n_classifiers
9001,T0,Yes,4,0.8,5
9001,T0,No,1,0.2,5
9001,T0,Unsure,0,0.0,5
9001,T1,Ice,4,0.8,5
9001,T1,Water,2,0.4,5
9001,T1,Rock,1,0.2,5Сохранённая запись multiselect, в которой перечислены варианты, но ни один не отмечен, считается классификатором без голосов. Такая запись добавляет единицу к n_classifiers и ничего не добавляет к числу голосов за какой-либо ответ. Запись без данных по вопросу классификатором не считается.
Вопросы со слайдером и числом
В consensus_numeric.csv одна строка на каждую пару объекта и вопроса, со столбцами instance_id, schema, type, n, mean, median, sd, min, max. n — число разметчиков с числовым ответом. sd — выборочное стандартное отклонение со знаменателем n − 1. sd остаётся пустым, если ответил только один разметчик. Числовые вопросы статуса не получают.
Кластеры точек
DBSCAN (density-based spatial clustering of applications with noise, плотностная кластеризация с шумом) объединяет близко лежащие точки и оставляет изолированные точки вне кластеров как шум. Экспорт собирает точки одной метки на одном объекте от всех разметчиков и кластеризует собранные точки методом DBSCAN:
- Точка основная, когда сама точка вместе с другими точками в пределах
epsот неё насчитывает не меньшеmin_samplesточек. - Кластер — это связная группа основных точек вместе с другими точками в пределах
epsот одной из основных точек. Точка рядом с двумя кластерами присоединяется к кластеру, найденному первым, в порядке загрузки разметки. - Все остальные точки считаются шумом.
Это то же правило, которое реализует DBSCAN из scikit-learn и вызывает редьюсер point_reducer_dbscan из panoptes_aggregation. С eps_unit: pixels и теми же eps и min_samples экспорт даёт те же кластеры и центры, что и point_reducer_dbscan. По умолчанию panoptes_aggregation использует eps в 5 пикселей и min_samples, равный 3, а значения по умолчанию в Potato рассчитаны на несколько разметчиков на объект. Если волонтёров на изображение много, увеличьте min_samples.
В consensus_points.csv одна строка на каждое сочетание объекта, схемы, метки и кластера:
instance_id,schema,label,cluster,x,y,x_px,y_px,size,n_annotators,spread,spread_px,var_x,var_y,cov_xy,annotators,label_points,label_annotators,label_noise,n_classifiers,note
9001,T2,Adult,0,0.10025,0.201,100.25,100.5,4,4,0.003897,2.331845,2.916667,4.333333,-1.166667,vol1;vol2;vol3;vol4,8,4,1,4,
9001,T2,Adult,1,0.800667,0.8,800.666667,400.0,3,3,0.004643,3.681787,16.333333,4.0,8.0,vol1;vol2;vol4,8,4,1,4,
9002,T2,Adult,,,,,,,,,,,,,,1,1,1,1,no cluster (every point is noise)На изображении 9001 четыре разметчика поставили восемь точек Adult. Семь точек образуют два кластера, по одному взрослому пингвину в каждом, а восьмая точка — шум. Столбцы таблицы:
| Столбец | Значение |
|---|---|
cluster | Номер кластера внутри метки на объекте, начиная с 0 |
x, y | Центр кластера, то есть среднее точек кластера, в долях ширины и высоты изображения |
x_px, y_px | Тот же центр в пикселях, пусто, если размер изображения неизвестен |
size | Число точек в кластере |
n_annotators, annotators | Число разных разметчиков, поставивших точку в кластер, и имена этих разметчиков |
spread, spread_px | Среднеквадратичное расстояние точек кластера от центра, в долях и в пикселях |
var_x, var_y, cov_xy | Выборочные дисперсии x и y и ковариация x и y, в пикселях, если размер изображения известен. Значения совпадают со столбцами clusters_var_x, clusters_var_y и clusters_var_x_y редьюсера Zooniverse |
label_points, label_annotators, label_noise | Точки, разметчики и точки-шум для всей метки на объекте, повторяются в каждой строке метки |
n_classifiers | Разметчики, сохранившие схему изображения на объекте |
note | Почему у метки нет кластера |
Метка, все точки которой оказались шумом, всё равно получает одну строку с пустым cluster и заполненным note, как на изображении 9002. DBSCAN не мешает двум точкам одного разметчика попасть в один кластер. Чтобы найти такие кластеры, сравните size с n_annotators.
Размер изображения и импорт из Zooniverse
Potato хранит каждую отметку в долях ширины и высоты изображения. Поэтому с eps_unit: fraction экспорт кластеризует точки на любом объекте без размера изображения. На изображении 1000 на 500 пикселей eps, равный 0,02, соответствует 20 пикселям по горизонтали и 10 пикселям по вертикали.
Размер изображения нужен экспорту для вывода в пикселях и для eps_unit: pixels. Экспорт берёт размер из полей image_width и image_height объекта (или width и height). Если этих полей нет, экспорт читает размер из самого файла изображения, когда файл лежит в каталоге медиафайлов задачи. Удалённые изображения не загружаются. С eps_unit: pixels метка на объекте неизвестного размера получает строку с примечанием «image size unknown; pixel eps cannot be applied», и экспорт выводит предупреждение, в котором названы до пяти таких объектов.
Объекты Zooniverse — это изображения на серверах Zooniverse, и экспорт не может открыть изображения на этих серверах. Начиная с Potato 2.13.0, potato import записывает image_width и image_height в каждый объект проекта с задачами рисования. Размер берётся из размеров изображения, которые Zooniverse записал вместе с классификациями, или из ширины и высоты в метаданных объекта. Поэтому импортированные рисунки кластеризуются в пикселях с тем же eps, который команда использовала в panoptes_aggregation. Импортируйте с флагом --keep-annotators. С этим флагом импортёр записывает классификации каждого волонтёра как собственную сохранённую работу этого волонтёра, и экспорт консенсуса затем учитывает каждого волонтёра один раз:
potato import -i zooniverse-exports/ -o my-project --keep-annotators
python -m potato.export -c my-project/config.yaml -f consensus -o consensus_outВолонтёры, не вошедшие в систему, появляются как anon_<id>, и тогда один человек может считаться несколькими классификаторами. Отметки на объектах без записанного размера при импорте пропускаются, а импорт подсчитывает пропущенные отметки и выводит предупреждение. Типы задач, которые читает импортёр, перечислены в разделе об импорте из Zooniverse.
Консенсусные рамки
Пересечение по объединению (IoU) — это площадь, общая для двух рамок, делённая на площадь, которую две рамки покрывают вместе. Экспорт разбивает рамки одной метки на одном объекте на группы. В группе не больше одной рамки от каждого разметчика, и каждая пара рамок в группе перекрывается с IoU не меньше iou_threshold. Экспорт строит группы в три шага:
- Каждая оставшаяся рамка начинает группу-кандидат, и оставшиеся рамки других разметчиков перебираются в порядке убывания IoU с первой рамкой. Рамка входит в группу, когда её IoU с каждой рамкой, уже входящей в группу, достигает порога.
- Сохраняется самая большая группа-кандидат. При равенстве выбирается группа с большей суммой IoU с первой рамкой, а затем группа более ранней рамки.
- Рамки сохранённой группы удаляются из пула, и шаги повторяются на оставшихся рамках. Рамка, которая не перекрывается ни с одной другой рамкой, образует группу из одной рамки.
Две рамки, каждая из которых перекрывается с третьей, оказываются в разных группах, если эти две рамки не перекрываются друг с другом. Консенсусная рамка — это медиана левых, верхних, правых и нижних краёв рамок группы. IoU не меняется при растяжении изображения. Поэтому группировке не нужен размер изображения, а столбцы в пикселях заполняются, когда размер известен.
В consensus_boxes.csv одна строка на каждое сочетание объекта, схемы, метки и группы:
instance_id,schema,label,group,x,y,width,height,x_px,y_px,width_px,height_px,support,n_classifiers,support_fraction,mean_iou,min_iou,annotators
9001,T2,Nest,0,0.2,0.2,0.1,0.11,200.0,100.0,100.0,55.0,3,4,0.75,0.85617,0.826087,vol1;vol2;vol3
9001,T2,Nest,1,0.6,0.6,0.05,0.1,600.0,300.0,50.0,50.0,1,4,0.25,1.0,1.0,vol4
9003,T2,Nest,0,0.01,0.04,0.03,0.08,10.0,20.0,30.0,40.0,1,1,1.0,1.0,1.0,vol1x, y, width и height задают консенсусную рамку в долях изображения, а столбцы _px дают ту же рамку в пикселях. support — число разметчиков в группе, n_classifiers — число разметчиков, сохранивших схему изображения на объекте, а support_fraction — это support, делённое на n_classifiers. mean_iou и min_iou сравнивают каждую рамку группы с консенсусной рамкой. На изображении 9001 трое из четырёх разметчиков обвели первое гнездо со средним IoU 0,86 относительно медианной рамки, а рамка одного разметчика не перекрылась ни с одной другой рамкой с IoU не ниже порога и образует группу из одной рамки.
Группировка разработана в самом Potato и не перенесена из редьюсеров рамок Zooniverse. rectangle_reducer из panoptes_aggregation запускает DBSCAN по x, y, ширине и высоте каждой рамки в пикселях. shape_reducer_dbscan с metric_type: IoU запускает DBSCAN с расстоянием 1 − IoU, и цепочка перекрывающихся рамок может объединить две рамки, которые друг с другом не перекрываются. Поэтому консенсусные рамки Potato и Zooniverse по одним и тем же классификациям могут различаться.
Текст и другие типы ответов
Экспорт консенсуса читает семь типов схем: radio, select, likert, multiselect, slider, number и image_annotation. Свободный текст, фрагменты и все остальные типы схем исключаются из консенсуса без предупреждения. Чтобы сузить список ещё больше, задайте schemes. В текстовом ответе нет голоса, который можно подсчитать, а табличные экспорты сохраняют текст каждого разметчика, чтобы ответы можно было читать рядом или передать на разрешение разногласий.
Внутри схемы image_annotation экспорт агрегирует только точки и рамки. Полигоны, ломаные, эллипсы, фигуры произвольной формы, маски и наборы ключевых точек подсчитываются по типам, и экспорт приводит эти числа в предупреждении. consensus.json записывает те же числа в not_aggregated.
Выходные файлы
| Файл | Одна строка на | Записывается, когда |
|---|---|---|
consensus_questions.csv | объект и вопрос | в конфигурации есть схема radio, select, likert или multiselect |
consensus_votes.csv | объект, вопрос и ответ | то же условие |
consensus_numeric.csv | объект и вопрос | в конфигурации есть схема slider или number |
consensus_points.csv | объект, схему, метку и кластер точек | в конфигурации есть схема image_annotation |
consensus_boxes.csv | объект, схему, метку и группу рамок | то же условие |
consensus.json | все результаты выше во вложенном виде, с использованными настройками, числами not_aggregated и предупреждениями | всегда |
Значения в CSV-файлах округляются до шести знаков после запятой. Списки, такие как annotators и tied, соединяются через точку с запятой. consensus.json хранит полные значения и список классификаторов для каждого вопроса.
Пример
python potato/flask_server.py start examples/image/zooniverse-aggregation/config.yaml -p 8000Пример — вымышленный подсчёт пингвинов, импортированный из экспорта Zooniverse, с сохранёнными классификациями пяти волонтёров на четырёх изображениях колоний. Строки CSV на этой странице получены экспортом консенсуса этого примера, запущенным из клона репозитория Potato командой python -m potato.export -c examples/image/zooniverse-aggregation/config.yaml -f consensus -o consensus_out.
Что почитать дальше
- Агрегирование меток краудсорсинга - Dawid-Skene, MACE и когда стоит сохранить разброс ответов
- Оценка компетентности MACE - Метки, взвешенные по компетентности, для категориальных схем
- Измерение согласованности по ограничивающим рамкам - Согласованность с поправкой на случайность для пространственных меток
- Форматы экспорта - Форматы экспорта Potato и команда экспорта
- Экология - Potato для разметки снимков фотоловушек и биоакустических записей
Подробности реализации см. в исходной документации.