Обучение объектного детектора AI с помощью Label Studio и MMDetection

Меткировка и обучение требуют некоторой интеграции

Содержимое страницы

Когда я обучал модель детектора объектов AI несколько лет назад - LabelImg был очень полезным инструментом, но экспорт из Label Studio в формат COCO не принимался фреймворком MMDetection..

Для этого требовались дополнительные инструменты и скрипты, чтобы всё заработало.

topimage

Перечислю здесь недостающие элементы и некоторые скрипты некоторые из которых я нашёл в интернете, а другие написал сам.

Основные шаги

Подготовка, обучение и использование AI включает в себя

  1. получение исходных данных (изображений для детекции объектов и классификации)
  2. аннотирование изображений и подготовка набора данных
  3. разработку новой модели или поиск подходящей существующей
  4. обучение модели, иногда с настройкой гиперпараметров
  5. использование модели для предсказания меток новых изображений (ингеринг)

Здесь я даю точные шаги, как аннотировать данные с помощью Label Studio (шаг 2) и обучить с помощью mmdetection и torchvision (шаг 4), а также касаюсь инференса (шаг 5)

Label Studio

У него есть некоторые открытые источники из программы LabelImg но сейчас он разрабатывается и поддерживается централизованно. И, конечно, есть корпоративная версия.

Все равно он доступен для саморазмещения, что очень приятно.

Настройка и запуск

Можно установить и запустить Label Studio несколькими способами, например, через пакет pip, или через контейнер docker compose. Здесь я использую одиночный docker-контейнер.

Подготовить исходную папку

mkdir ~/ls-data
sudo chown -R 1001:1001 ~/ls-data10

Настройка локального хранилища

mkdir ~/ai-local-store
mkdir ~/ai-local-labels

# настройка дополнительных разрешений

В ~/ai-local-store вы храните файлы изображений, ~/ai-local-labels - синхронизированные метки.

Запустить docker-контейнер

docker run -it -p 8080:8080 \
    -e LABEL_STUDIO_HOST=http://your_ip_address:8080/ \
    -e LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED=true \
    -e LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT=/ai-local-store \
    -e DATA_UPLOAD_MAX_NUMBER_FILES=10000000 \
    -v /home/somename/ls-data:/label-studio/data \
    -v /home/somename/ai-local-store:/ai-local-store \
    -v /home/somename/ai-local-labels:/ai-local-labels \
    heartexlabs/label-studio:latest \
    label-studio \
    --log-level DEBUG

LABEL_STUDIO_HOST - из-за перенаправлений веб-интерфейса LS. DATA_UPLOAD_MAX_NUMBER_FILES … Django ограничил количество загружаемых файлов до 100, что имело ужасные последствия для label studio, поэтому потребовалось указать это новое ограничение. Все остальные настройки хорошо документированы в документации Label Studio.

Импорт конфигурации. В настройках проекта в Облаке Хранения добавьте Источное Хранение типа Локальные Файлы, похожее на:

topimage

Не забудьте отметить “Рассматривать каждый объект ведра как исходный файл”, если вы планируете синхронизировать изображения (я думаю, да, вы это делаете), а не json. Если у вас уже есть некоторые метки для этих изображений в отдельном json - вы просто настраиваете это Облачное Хранение. Не нажимая Синхронизировать. А затем импортировать json.

Настройте то же самое для Целевого Облачного Хранения и ai-local-labels - если вы хотите синхронизировать их.

Импорт предварительно аннотированных данных в Label Studio

Люблю формат COCO json. Также Pascal VOC. Но они не совместимы напрямую с Label Studio, поэтому сначала нужно преобразовать в проприетарный формат LS.

Но сначала, возможно, потребуется отфильтровать набор данных. Возможно, вам нужны только некоторые метки, а не все. Мне нравится скрипт filter.py из coco-manager: https://github.com/immersive-limit/coco-manager/blob/master/filter.py

python filter.py --input_json instances_train2017.json --output_json filtered.json --categories person dog cat

Хорошо, теперь установите конвертер. Как рекомендует официальный сайт конвертера:

python -m venv env
source env/bin/activate
git clone https://github.com/heartexlabs/label-studio-converter.git
cd label-studio-converter
pip install -e . 

Конвертировать из coco и установить правильную папку

label-studio-converter import coco -i your-input-file.json -o output.json

Импортировать output.json, нажав кнопку Импорт в Label Studio.

Аннотирование

Здесь выполняется много очень творческой работы.

Экспорт

После нажатия кнопки Экспорта в Label Studio и выбора формата COC, посмотрите внутрь этого файла и восхищайтесь именами изображений. Они будут выглядеть так, если вы импортировали метки заранее, не перезаписывая базовый путь изображения

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "\/data\/local-files\/?d=\/iteration1001\/123.jpg"
    },

Или будут выглядеть так, если вы синхронизировали внешнее Облачное Хранение.

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "http:\/\/localhost:8080\/data\/local-files\/?d=iteration1001\/123.jpg"
    },

Это не очень приятно. Мы хотим что-то вроде

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "iteration1001/123.jpg"
    },

Чтобы исправить имена файлов я использовал прекрасные скрипты. Они перезаписывают файл result.json, поэтому, если вам нужен резервный копии заранее - позаботьтесь об этом сами:

sed -i -e 's/\\\/data\\\/local-files\\\/?d=\\\///g' ~/tmp/result.json
sed -i "s%http:\\\/\\\/localhost:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json
sed -i "s%http:\\\/\\\/your_ip_address:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json

Резервное копирование данных и БД Label Studio

Внимательно остановите контейнер Label Studio docker и затем выполните что-то вроде

cp ~/ls-data ~/all-my-backups
cp ~/ai-local-store ~/all-my-backups
cp ~/ai-local-labels ~/all-my-backups

Объединение

Иногда нужно объединить несколько наборов данных в один, особенно если вы запускаете несколько итераций.

Я использовал COCO-merger инструмент. После установки и запуска с параметром -h:

python tools/COCO_merger/merge.py -h

COCO Files Merge Usage

python -m COCO_merger.merge --src Json1.json Json2.json --out OUTPUT_JSON.json

Argument parser

usage: merge.py [-h] --src SRC SRC --out OUT

Merge two annotation files to one file

optional arguments:
  -h, --help     show this help message and exit
  --src SRC SRC  Path of two annotation files to merge
  --out OUT      Path of the output annotation file

Да, можно объединить только два файла. Поэтому, если у вас 10 итераций - нужно приложить дополнительные усилия. Тем не менее, я его люблю.

MMDetection

topimage

Разделение набора данных

Для разделения набора данных на обучение и тестирование я использовал инструмент COCOSplit.

git clone https://github.com/akarazniewicz/cocosplit.git
cd cocosplit
pip install -r requirements

Тут не так много:

$ python cocosplit.py -h
usage: cocosplit.py [-h] -s SPLIT [--having-annotations]
                    coco_annotations train test

Splits COCO annotations file into training and test sets.

positional arguments:
  coco_annotations      Path to COCO annotations file.
  train                 Where to store COCO training annotations
  test                  Where to store COCO test annotations

optional arguments:
  -h, --help            show this help message and exit
  -s SPLIT              A percentage of a split; a number in (0, 1)
  --having-annotations  Ignore all images without annotations. Keep only these
                        with at least one annotation
  --multi-class         Split a multi-class dataset while preserving class
                        distributions in train and test sets

Чтобы запустить разделение coco:

python cocosplit.py --having-annotations \
  --multi-class \
  -s 0.8 \
  source_coco_annotations.json \
  train.json \
  test.json

Напомним, чтобы добавить свойства лицензий в начало файла json набора данных, где-то после первого “{”: Этот инструмент разделения действительно хочет это.

  "licenses": [],

Настройка

Да, конфигурации моделей сложны.

Но mask-rcnn довольно быстр и имеет разумную скорость детекции. См. здесь для деталей конфигурации: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets

# Новая конфигурация наследует базовую конфигурацию, чтобы подчеркнуть необходимые изменения
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'

# Нам также нужно изменить num_classes в голове, чтобы соответствовать аннотациям набора данных
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=3),
        mask_head=dict(num_classes=3)))

# Изменить настройки, связанные с набором данных
data_root = '/home/someusername/'
metainfo = {
    'classes': ('MyClass1', 'AnotherClass2', 'AndTheLastOne3'),
    'palette': [
        (220, 20, 60),
        (20, 60, 220),
        (60, 220, 20),
    ]
}
train_dataloader = dict(
    batch_size=1,
    dataset=dict(
        data_root=data_root,
        metainfo=metainfo,
        ann_file='train.json',
        data_prefix=dict(img='')))
val_dataloader = dict(
    dataset=dict(
        data_root=data_root,
        metainfo=metainfo,
        ann_file='test.json',
        data_prefix=dict(img='')))
test_dataloader = val_dataloader

# Изменить настройки, связанные с метриками
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator

# Мы можем использовать предварительно обученную модель Mask RCNN для получения более высокой производительности
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth'

# если вам нравятся длинные фильмы
# по умолчанию здесь, если я правильно помню, 12
train_cfg = dict(max_epochs=24) 

Что-то, на что стоит посмотреть, если маски не нужны: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html

Обучение

Предположим, у вас есть ваша конфигурация модели в /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py . Скрипт обучения - стандартный вызов инструмента mmdetection:

cd ~/mmdetection
python tools/train.py \
    /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py \
    --work-dir /home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x

Инференс

Некоторые документы здесь: https://mmdetection.readthedocs.io/en/latest/user_guides/inference.html

from mmdet.apis import DetInferencer

inferencer = DetInferencer(
    model='/home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py',
    weights='/home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x/epoch_12.pth')

# запустить для одного файла:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)

# или для целой папки
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)

Полезные ссылки

Надеюсь, это поможет вам как-то.

Другие полезные материалы см. на