Träna objektdetektorns AI med Label Studio & MMDetection

Etikettering och träning kräver lite limning

Sidinnehåll

När jag tränade objektdetektions-AI för några månader sedan - var LabelImg ett mycket användbart verktyg, men exporten från Label Studio till COCO-format accepterades inte av MMDetection-ramverket..

Det krävde lite verktyg och skript för att få allt att fungera.

topimage

Här listar jag saknade bitar och några skript varav några jag hittade på internet och skrev de andra själv.

Grundläggande steg

Förberedelse, träning och användning av AI involverar

  1. att få tag på källdata (bilder för objektdetektering och klassificering)
  2. att märka bilder och förbereda dataset
  3. att utveckla en ny modell eller hitta en lämplig befintlig
  4. att träna modellen, ibland med hyperparameterjustering
  5. att använda modellen för att förutspå etiketter för nya bilder (inferens)

Här ger jag exakta steg för hur man märker data med Label Studio (steg 2) och tränar med mmdetection och torchvision (steg 4), och berör inferens (steg 5)

Label Studio

Det har några öppna källkodrötter i LabelImg-programmet men utvecklas och underhålls nu på ett mycket centraliserat sätt. Och har naturligtvis en enterprise-version.

Det är fortfarande tillgängligt för självhosting, vilket är mycket trevligt.

Konfigurera och köra

Man kan installera och köra Label Studio på flera sätt, till exempel som pip-paket, eller som docker-compose-containergrupp. Här använder jag en enda docker-container.

Förbered källmapp

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

Lokal lagringskonfiguration

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

# ställ in några extra behörigheter

I ~/ai-local-store håller du bildfilerna, ~/ai-local-labels - outsynkade etiketter.

Starta docker-container

docker run -it -p 8080:8080 \
    -e LABEL_STUDIO_HOST=http://din_ip_adress: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 - på grund av LS-webbgränssnittets omdirigeringar. DATA_UPLOAD_MAX_NUMBER_FILES … Django begränsar standarduppdateringsfilräkningen till 100 och det hade en fruktansvärd effekt på Label Studio, så det behövdes att ge denna nya gräns. Alla andra konfigurationer är mycket väl dokumenterade i Label Studio-dokumentationen.

Importera konfiguration. I projektinställningarna i Cloud Storage lägger du till en källlagring av typen Lokala filer liknande:

topimage

Glöm inte att kryssa i “Behandla varje bucket-objekt som en källfil” om du planerar att synkronisera in bilder (jag tror att du gör det), inte json-filerna. Om du redan har några etiketter för dessa bilder i en separat json - så konfigurerar du bara denna Cloud Storage. Klickar inte på Synkronisera. Och importerar sedan json-filen.

Konfigurera detsamma för Target Cloud Storage och ai-local-labels - om du vill synkronisera ut dem.

Importera förmärkt data till Label Studio

Jag gillar COCO json-format. Pascal VOC också. Men de är inte direkt kompatibla med Label Studio så de måste först konverteras till LS:s proprietära format.

Men först - kommer du troligen behöva filtrera datasetet. Du kanske bara behöver vissa etiketter där, inte alla. Jag gillar filter.py-skriptet från 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

Okej, nu, installera konverteraren. Som den officiella konverterarens webbplats rekommenderar:

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 .

Konvertera från coco och ställ in rätt mapp

label-studio-converter import coco -i din-input-fil.json -o output.json

Importera output.json genom att klicka på Import-knappen i Label Studio.

Märkning

En hel del extremt kreativt arbete görs här.

Export

Efter att ha klickat på Export-knappen i Label Studio och valt COCO-exportformatet - titta in i denna fil och beundra bildnamnen. De skulle se ut så här om du importerade etiketter tidigare utan att ersätta bildens basväg

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

Eller skulle se ut så här om du synkroniserade extern Cloud Storage.

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

Dessa är inte särskilt trevliga. Vi vill ha något som

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

För att åtgärda filnamnen använde jag underbara skript. De skriver över result.json-filen, så om du behöver en säkerhetskopia i förväg - ta hand om det själva:

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:\\\/\\\/din_ip_adress:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json

Säkerhetskopiera Label Studio-data och databas

Stopp din Label Studio docker-container noggrant och kör sedan något som

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

Sammanfoga

Man behöver ibland sammanfoga flera dataset till ett, särskilt om man kör flera iterationer.

Jag använde COCO-mergerverktyget. Efter installation och körning med -h-parametern:

python tools/COCO_merger/merge.py -h

COCO Filer Sammanfogning Användning

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

Sammanfoga två annoteringar till en fil

valfria argument:
  -h, --help     visa hjälptexten och avsluta
  --src SRC SRC  Sökväg till två annoteringar att sammanfoga
  --out OUT      Sökväg till den utdatafil som ska skapas

Ja. Kan bara sammanfoga två filer. Så om du har 10 iterationer - behöver du göra extra ansträngningar. Gillar det fortfarande.

MMDetection

topimage

Dela upp datasetet

För att dela upp datasetet i tränings- och testdata använde jag COCOSplitverktyget.

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

Det finns inte så mycket att säga om det:

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

Delar upp COCO-annoteringar i tränings- och testuppsättningar.

positionella argument:
  coco_annotations      Sökväg till COCO-annoteringar.
  train                 Var ska COCO-träningsannoteringar sparas
  test                  Var ska COCO-testannoteringar sparas

valfria argument:
  -h, --help            visa hjälptexten och avsluta
  -s SPLIT              En procentsats för uppdelningen; ett tal i (0, 1)
  --having-annotations  Ignorera alla bilder utan annoteringar. Bevara bara de
                        med minst en annotering
  --multi-class         Dela upp ett flerklassdataset medan klassfördelningarna
                        bevaras i tränings- och testuppsättningar

För att köra coco-delningen:

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

Kom ihåg att lägga till licenses-egenskapen i början av dataset-json, någonstans efter första “{”. Den här delningsverktyget vill verkligen ha det.

  "licenses": [],

Konfiguration

Ja, modellkonfigurationer är trickiga.

Men mask-rcnn är ganska snabb och har en rimlig detekteringsgrad. Se här för konfiguration detaljer: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets

# Den nya konfigurationen ärver en baskonfiguration för att framhäva de nödvändiga ändringarna
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'

# Vi måste också ändra num_classes i head för att matcha datasetets annoteringar
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=3),
        mask_head=dict(num_classes=3)))

# Ändra datasetrelaterade inställningar
data_root = '/home/someusername/'
metainfo = {
    'classes': ('MinKlass1', 'EnAnnanKlass2', 'OchDenSista3'),
    '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

# Ändra mätrelaterade inställningar
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator

# Vi kan använda den förtränade Mask RCNN-modellen för att uppnå högre prestanda
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'

# om du gillar långa filmer
# standardinställningen här om jag minns rätt är 12
train_cfg = dict(max_epochs=24)

Något att titta på om maskerna inte behövs: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html

Träning

Anta att du har din modellkonfiguration i /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py. Träningskommandot är standardanrop till mmdetection-verktyget:

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

Inferens

Några dokument finns här: 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')

# kör det för en enda fil:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)

# eller för hela mappen
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)

Användbara länkar

Hoppas detta hjälper dig på något sätt.

Andra användbara läsningar finns på