Objekterkennungs-AI mit Label Studio & MMDetection trainieren

Etikettieren und Training benötigen etwas Klebstoff

Inhaltsverzeichnis

Als ich vor einiger Zeit object detection AI trainierte war LabelImg eine sehr nützliche Werkzeug, aber die Exportfunktion von Label Studio in das COCO-Format wurde vom MMDetection-Framework nicht akzeptiert…

Es benötigte einige Werkzeuge und Skripte, um alles zum Laufen zu bringen.

topimage

Hier sind die fehlenden Teile und einige Skripte einige davon habe ich im Internet gefunden, andere habe ich selbst geschrieben.

Grundlegende Schritte

Das Vorbereiten, Trainieren und Verwenden von KI umfasst

  1. das Erhalten von Quelldaten (Bilder für Objekterkennung und Klassifizierung)
  2. das Labeln von Bildern und das Vorbereiten des Datensatzes
  3. das Entwickeln eines neuen Modells oder das Finden eines passenden bestehenden
  4. das Trainieren des Modells, manchmal mit Hyperparameter-Tuning
  5. das Verwenden des Modells, um Labels für neue Bilder vorherzusagen (ingerring)

Hier gebe ich genaue Schritte an, wie man Daten mit Label Studio labeln kann (Schritt 2) und trainieren mit mmdetection und torchvision (Schritt 4), und berühre die Inferenz (Schritt 5)

Label Studio

Es hat einige Open-Source-Roots im LabelImg-Programm aber wird jetzt zentral entwickelt und gewartet. Und es gibt natürlich eine Enterprise-Version.

Dennoch ist es für die Selbsthostung verfügbar, was sehr schön ist.

Konfigurieren und starten

Man kann Label Studio auf verschiedene Arten installieren und starten, zum Beispiel als pip-Paket, oder als Docker-Compose-Containergruppe. Hier verwende ich einen einzelnen Docker-Container.

Vorbereiten des Quellordners

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

Lokale Speicherkonfiguration

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

# setzen Sie einige zusätzliche Berechtigungen

In ~/ai-local-store speichern Sie die Bilddateien, ~/ai-local-labels - synchronisierte Labels.

Starten Sie den 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 - aufgrund der Umleitungen der LS-Web-Oberfläche. DATA_UPLOAD_MAX_NUMBER_FILES … Django beschränkte die Upload-Dateizahl auf 100 und hatte einen schrecklichen Effekt auf Label Studio, daher war es notwendig, diesen neuen Grenzwert anzugeben. Alle anderen Konfigurationen sind sehr gut in den Label Studio Dokumentationen dokumentiert.

Importieren der Konfiguration. In den Projekt-Einstellungen in der Cloud Storage fügen Sie eine Quellenspeicherung des Typs Lokale Dateien hinzu, ähnlich wie:

topimage

Vergessen Sie nicht, das Kästchen „Jedes Bucket-Objekt als Quelldatei behandeln“ zu markieren, wenn Sie planen, Bilder zu synchronisieren (ich glaube, ja, Sie tun das), nicht die JSONs. Wenn Sie bereits einige Labels für diese Bilder in einem separaten JSON haben, konfigurieren Sie einfach diese Cloud Storage. Nicht klicken Sie auf Sync. Und dann importieren Sie das JSON.

Konfigurieren Sie dasselbe für die Ziel-Cloud Storage und ai-local-labels - wenn Sie sie synchronisieren möchten.

Importieren von vorlabelierten Daten in Label Studio

Ich liebe das COCO JSON-Format. Auch das Pascal VOC. Aber sie sind nicht direkt mit Label Studio kompatibel, daher müssen Sie sie zunächst in das proprietäre Format von LS konvertieren.

Aber vorher - Sie werden wahrscheinlich den Datensatz filtern müssen. Vielleicht benötigen Sie nur einige Labels dort, nicht alle. Ich mag das filter.py Skript von 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 . 

Konvertieren von COCO und setzen Sie den richtigen Ordner

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

Importieren Sie die output.json, indem Sie in Label Studio auf den Import-Button klicken.

Labeln

Viel kreatives Arbeit wird hier geleistet.

Exportieren

Nachdem Sie im Label Studio auf den Export-Button geklickt und das COCO-Exportformat ausgewählt haben - schauen Sie sich die Datei an und bewundern Sie die Bildnamen. Sie würden so aussehen, wenn Sie die Labels vorher importiert haben, ohne den Basispfad der Bilder zu überschreiben

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

Oder so, wenn Sie externe Cloud Storage synchronisiert haben.

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

Diese sind nicht sehr schön. Wir möchten etwas wie

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

Um die Dateinamen zu beheben, habe ich wundervolle Skripte verwendet. Sie überschreiben die result.json-Datei, also wenn Sie eine Sicherung vorher benötigen - sorgen Sie selbst dafür:

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

Backup der Label Studio Daten und Datenbank

Stoppen Sie vorsichtig Ihren Label Studio Docker-Container und führen Sie dann etwas wie aus:

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

Zusammenführen

Manchmal muss man mehrere Datensätze in einen zusammenführen, besonders wenn man mehrere Iterationen durchführt.

Ich verwendete das COCO-merger Tool. Nachdem ich es installiert und mit dem -h-Parameter gestartet habe:

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, kann man nur zwei Dateien zusammenführen. Also wenn Sie 10 Iterationen haben, müssen Sie extra Aufwand betreiben. Dennoch mag ich es.

MMDetection

topimage

Aufteilen des Datensatzes

Um den Datensatz in Trainings- und Testdaten aufzuteilen, verwendete ich das COCOSplit Tool.

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

Es gibt nicht viel zu tun:

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

Teilt die COCO-Annotationen in Trainings- und Testdaten auf.

positionale Argumente:
  coco_annotations      Pfad zur COCO-Annotationen-Datei.
  train                 Wo die COCO-Trainings-Annotationen gespeichert werden
  test                  Wo die COCO-Test-Annotationen gespeichert werden

optionale Argumente:
  -h, --help            Zeigt diese Hilfe an und beendet das Programm
  -s SPLIT              Prozentsatz der Aufteilung; eine Zahl in (0, 1)
  --having-annotations  Alle Bilder ohne Annotationen ignorieren. Nur diese mit mindestens einer Annotation behalten
  --multi-class         Aufteilen eines mehrklassigen Datensatzes, wobei die Klassenverteilung in Trainings- und Testdaten beibehalten wird

Um die COCO-Aufteilung durchzuführen:

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

Denken Sie daran, die licenses-Eigenschaft am Anfang der Datensatz-JSON-Datei hinzuzufügen, irgendwo nach dem ersten “{”. Dieses Aufteilungstool benötigt sie wirklich.

  "licenses": [],

Konfiguration

Ja, die Modellkonfigurationen sind kompliziert.

Aber mask-rcnn ist ziemlich schnell und hat eine vernünftige Erkennungsrate. Hier finden Sie die Details zur Konfiguration: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets

# Die neue Konfiguration erbt eine Basiskonfiguration, um die notwendige Änderung hervorzuheben
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'

# Wir müssen auch die num_classes in der Kopfzeile ändern, um mit der Annotation des Datensatzes übereinzustimmen
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=3),
        mask_head=dict(num_classes=3)))

# Ändern Sie die datensatzbezogenen Einstellungen
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

# Ändern Sie die metrikbezogenen Einstellungen
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator

# Wir können das vortrainierte Mask RCNN-Modell verwenden, um eine höhere Leistung zu erzielen
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'

# wenn Sie lange Filme mögen
# der Standard hier ist, wenn ich mich richtig erinnere, 12
train_cfg = dict(max_epochs=24) 

Etwas zu beachten, wenn keine Masken benötigt werden: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html

Training

Nehmen wir an, Sie haben Ihre Modellkonfiguration in /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py. Das Trainingskript ist ein Standardaufruf des mmdetection-Tools:

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

Inferenz

Einige Dokumentationen finden Sie 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')

# führen Sie es für eine einzelne Datei aus:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)

# oder für den gesamten Ordner
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)

Hoffentlich hilft Ihnen dies auf irgendeine Weise.

Weitere nützliche Lesematerialien finden Sie auf