Training van een objectdetectie AI met Label Studio & MMDetection

Labelen en training vereist wat lijmwerk

Inhoud

Toen ik object detectie AI optraaide enige tijd geleden - was LabelImg een zeer nuttig hulpmiddel, maar de export van Label Studio naar COCO formaat werd niet geaccepteerd door de MMDetection framework…

Het had enige tooling en scripting nodig om alles te laten werken.

topimage

Lijst hieronder de ontbrekende onderdelen en enkele scripts waarvan sommige ik op het internet vond en andere zelf schreef.

Basisstappen

Het voorbereiden, trainen en gebruiken van AI omvat

  1. het verkrijgen van brondata (afbeeldingen voor objectdetectie en classificatie)
  2. het labelen van afbeeldingen en het voorbereiden van het dataset
  3. het ontwikkelen van een nieuw model of het vinden van een geschikt bestaand model
  4. het trainen van het model, soms met het afstemmen van hyperparameters
  5. het gebruiken van het model om labels te voorspellen voor nieuwe afbeeldingen (ingerring)

Hier geef ik exacte stappen hoe je data kunt labelen met Label Studio (stap 2) en trainen met mmdetection en torchvision (stap 4), en raak iets aan met de voorspelling (stap 5)

Label Studio

Het heeft enige open source wortels in het LabelImg programma maar wordt nu centraal ontwikkeld en onderhouden. En heeft natuurlijk ook een enterpriseversie.

Toch is het beschikbaar voor zelf-hosting, wat zeer handig is.

Configureren en uitvoeren

Je kunt Label Studio op meerdere manieren installeren en uitvoeren, zoals bijvoorbeeld via een pip-pakket, of via een docker compose containergroep. Hier gebruik ik een enkele docker container.

Voorbereiden van de bronmap

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

Lokale opslagconfiguratie

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

# stel enkele extra permissies in

In ~/ai-local-store bewaar je de afbeeldingsbestanden, ~/ai-local-labels - uitgesynchroniseerde labels.

Start de docker container

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 - vanwege de LS webui-omleidingen. DATA_UPLOAD_MAX_NUMBER_FILES … Django beperkte het aantal te uploaden bestanden tot 100 en had een verschrikkelijke invloed op Label Studio, dus moesten we deze nieuwe limiet opgeven. Alle andere configuraties zijn zeer goed gedocumenteerd in de Label Studio docs.

Importeer configuratie. In de projectinstellingen in Cloud Storage voeg je een bronopslag van het type Lokale bestanden toe, zoals:

topimage

Vergeet niet om het vakje “Behandel elk bucketobject als een bronbestand” aan te vinken als je van plan bent om afbeeldingen te synchroniseren (ik denk dat je dat wel doet), niet de jsons. Als je al enkele labels hebt voor deze afbeeldingen in een aparte json - configureer je dan gewoon deze Cloud Storage. Niet klikken op Sync. En dan Importeren van de json.

Configureer hetzelfde voor de doel Cloud Storage en ai-local-labels - als je ze uit wilt synchroniseren.

Importeer vooraf gelabelde data in Label Studio

Ik hou van het COCO json formaat. Ook van Pascal VOC. Maar deze zijn niet direct compatibel met Label Studio, dus moet je ze eerst converteren naar het eigenaardige formaat van LS.

Maar vooraf - waarschijnlijk zul je de dataset moeten filteren. Je hebt mogelijk alleen enkele labels nodig, niet alle. Ik hou van het filter.py script van 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

Goed, nu installeer je de converter. Zoals de converter officiële site aanbeveelt:

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 . 

Converteren van COCO en instellen van de juiste map

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

Importeer het output.json bestand door in Label Studio op de Import-knop te klikken.

Labelen

Er wordt veel creatieve werk verricht hier.

Exporteren

Na op de Export-knop in Label Studio te klikken en het COCO export formaat te selecteren - kijk dan eens in dit bestand en bewonder de afbeeldingsnamen. Ze zouden er zo uitzien als je labels al had geïmporteerd zonder het basispad van de afbeelding te overschrijven

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

Of zouden er zo uitzien als je externe Cloud Storage hebt gesynchroniseerd.

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

Deze zijn niet erg mooi. We willen iets zoals

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

Om de bestandsnamen te corrigeren heb ik mooie scripts gebruikt. Ze overschrijven het result.json bestand, dus als je een back-up nodig hebt - zorg er dan zelf voor:

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

Back-up van Label Studio data en db

Stop je Label Studio docker container zorgvuldig en voer dan iets zoals

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

Samenvoegen

Soms moet je meerdere datasets samenvoegen tot één, vooral als je meerdere iteraties uitvoert.

Ik gebruikte het COCO-merger hulpmiddel. Na installatie en uitvoering met de -h parameter:

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

Ja, je kunt alleen twee bestanden samenvoegen. Dus als je tien iteraties hebt - moet je extra moeite doen. Toch hou ik het graag.

MMDetection

topimage

Dataset splitsen

Om de dataset te splitsen in training en test gebruikte ik het COCOSplit hulpmiddel.

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

Er is niet veel aan te doen:

$ 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

Om de COCO split uit te voeren:

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

Herinner je er aan om de licenses eigenschap aan het begin van het dataset json te toe te voegen, ergens na de eerste “{”. Dit splitsingsprogramma wil het echt.

  "licenses": [],

Configuratie

Ja, model configuraties zijn moeilijk.

Maar mask-rcnn is vrij snel en heeft een redelijke detectierate. Zie hier voor de configuratie details: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets

# De nieuwe configuratie neemt een basisconfiguratie over om de benodigde wijzigingen te benadrukken
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'

# We moeten ook het aantal klassen in de kop aanpassen om overeen te komen met de datasetannotatie
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=3),
        mask_head=dict(num_classes=3)))

# Wijzig de datasetgerelateerde instellingen
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

# Wijzig de metriekgerelateerde instellingen
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator

# We kunnen het vooraf getrainde Mask RCNN model gebruiken om hogere prestaties te verkrijgen
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'

# als je de lange films leuk vindt
# de standaard hier is, zo herinner ik me, 12
train_cfg = dict(max_epochs=24) 

Iets om te bekijken als de masks niet nodig zijn: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html

Trainen

Stel dat je je modelconfiguratie hebt in /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py . Het trainingscript is een standaard aanroep naar het mmdetection-hulpmiddel:

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

Inference

Enkele documentatie is hier: 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')

# voer het uit voor een enkel bestand:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)

# of voor een hele map
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)

Hopelijk helpt dit je op enige manier.

Andere nuttige lezingen vind je op