Training van een objectdetectie AI met Label Studio & MMDetection
Labelen en training vereist wat lijmwerk
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.
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
- het verkrijgen van brondata (afbeeldingen voor objectdetectie en classificatie)
- het labelen van afbeeldingen en het voorbereiden van het dataset
- het ontwikkelen van een nieuw model of het vinden van een geschikt bestaand model
- het trainen van het model, soms met het afstemmen van hyperparameters
- 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:
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
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)
Nuttige links
Hopelijk helpt dit je op enige manier.
Andere nuttige lezingen vind je op
- Label Studio site: https://labelstud.io/
- MMDetection docs: https://mmdetection.readthedocs.io/en/latest/get_started.html
- Bash Cheat Sheet
- Detecting Concrete Reo Bar Caps with tensorflow
- Python Cheatsheet
- Conda Cheatsheet
- Flux tekst naar beeld
- Ollama Cheatsheet
- Docker Cheatsheet
- Gestapelde Lambdas met AWS SAM en Python
- PDF genereren in Python - Bibliotheken en voorbeelden"