Treinamento de Detetor de Objetos de IA com Label Studio e MMDetection
A rotulagem e o treinamento precisam de alguma colagem.
Quando treinei um detector de objetos com IA há algum tempo, o LabelImg foi uma ferramenta muito útil, mas a exportação do Label Studio para o formato COCO não era aceita pelo framework MMDetection..
Foi necessário algum suporte de ferramentas e scripts para fazer tudo funcionar.

Listo aqui as partes faltantes e alguns scripts, alguns que encontrei na internet e outros que eu próprio escrevi.
Passos básicos
Preparar, treinar e usar IA envolve:
- obter dados de origem (imagens para detecção e classificação de objetos)
- rotular imagens e preparar o conjunto de dados
- desenvolver um novo modelo ou encontrar um existente adequado
- treinar o modelo, às vezes com ajuste de hiperparâmetros
- usar o modelo para prever rótulos para novas imagens (inferência)
Aqui, dou passos exatos sobre como rotular dados com o Label Studio (passo 2) e treinar com mmdetection e torchvision (passo 4), além de abordar a inferência (passo 5).
Label Studio
Tem raízes de código aberto no programa LabelImg, mas agora é desenvolvido e mantido de forma muito centralizada. E tem, claro, uma versão empresarial.
Ainda assim, está disponível para auto-hospedagem, o que é muito bom.
Configurar e executar
Pode instalar e executar o Label Studio de várias maneiras, como o pacote pip, por exemplo, ou um grupo de containers docker compose. Aqui estou usando um único container docker.
Prepare a pasta de origem
mkdir ~/ls-data
sudo chown -R 1001:1001 ~/ls-data10
Configuração de armazenamento local
mkdir ~/ai-local-store
mkdir ~/ai-local-labels
# configure algumas permissões extras
Em ~/ai-local-store você mantém os arquivos de imagem, em ~/ai-local-labels - os rótulos sincronizados para fora.
Inicie o container 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/someusername/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 - devido aos redirecionamentos da web UI do LS. DATA_UPLOAD_MAX_NUMBER_FILES … O Django limitava o número de arquivos de upload para 100 e isso teve um efeito terrível no label studio, então foi necessário fornecer este novo limite. Todas as outras configurações estão muito bem documentadas na documentação do Label Studio.
Importe a configuração. Nas configurações do projeto em Armazenamento em Nuvem, adicione um Armazenamento de Origem do tipo Arquivos Locais, semelhante a:

Não se esqueça de marcar “Tratar cada objeto do bucket como um arquivo de origem” se você planeja sincronizar imagens (acho que sim), e não os jsons. Se você já tem alguns rótulos para essas imagens em um json separado - você apenas configura este Armazenamento em Nuvem. Não clique em Sincronizar. E então importe o json.
Configure o mesmo para o Armazenamento em Nuvem de Destino e ai-local-labels - se você quiser sincronizá-los para fora.
Importar dados pré-rotulados no Label Studio
Adoro o formato json COCO. E o Pascal VOC também. Mas eles não são diretamente compatíveis com o Label Studio, então precisam ser convertidos para o formato proprietário do LS primeiro.
Mas antes - provavelmente precisará filtrar o conjunto de dados. Você pode precisar apenas de alguns rótulos ali, não de todos. Gosto do script filter.py do 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
Ok, agora, instale o conversor. Como o site oficial do conversor recomenda:
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 .
Converta do coco e definindo a pasta correta
label-studio-converter import coco -i your-input-file.json -o output.json
Importe o output.json clicando no botão Importar no Label Studio.
Rotulagem
Muito trabalho extremamente criativo é feito aqui.
Exportação
Após clicar no botão Exportar no Label Studio e selecionar o formato de exportação COC - olhe dentro deste arquivo e admire os nomes das imagens. Eles ficariam assim se você importasse rótulos antes de sobrescrever o caminho base da imagem
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "\/data\/local-files\/?d=\/iteration1001\/123.jpg"
},
Ou ficariam assim se você sincronizasse o Armazenamento em Nuvem externo.
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "http:\/\/localhost:8080\/data\/local-files\/?d=iteration1001\/123.jpg"
},
Estes não são muito bons. Queremos algo como
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "iteration1001/123.jpg"
},
Para corrigir os nomes dos arquivos, usei scripts adoráveis. Eles estão sobrescrevendo o arquivo result.json, então se você precisar de um backup antes - cuide disso vocês mesmos:
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 de dados e banco de dados do Label Studio
Pare cuidadosamente o container docker do seu Label Studio e depois execute algo como
cp ~/ls-data ~/all-my-backups
cp ~/ai-local-store ~/all-my-backups
cp ~/ai-local-labels ~/all-my-backups
Mesclar
Às vezes é necessário mesclar vários conjuntos de dados em um só, especialmente se estiver executando várias iterações.
Usei a ferramenta COCO-merger. Após instalar e executar com o parâmetro -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
Sim. Só pode mesclar dois arquivos. Então se você tem 10 iterações - precisa de um esforço extra. Ainda assim, gosto disso.
MMDetection

Dividir o conjunto de dados
Para dividir o conjunto de dados em treinamento e teste, usei a ferramenta COCOSplit.
git clone https://github.com/akarazniewicz/cocosplit.git
cd cocosplit
pip install -r requirements
Não é muito complicado:
$ 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
Para executar a divisão do coco:
python cocosplit.py --having-annotations \
--multi-class \
-s 0.8 \
source_coco_annotations.json \
train.json \
test.json
Lembre-se apenas de adicionar a propriedade de licenças no início do json do conjunto de dados, em algum lugar após o primeiro “{”. Esta ferramenta de divisão realmente quer isso.
"licenses": [],
Configuração
Sim, as configurações de modelo são delicadas.
Mas o mask-rcnn é bastante rápido e tem uma taxa de detecção razoável. Veja aqui os detalhes da configuração: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets
# A nova configuração herda uma configuração base para destacar a modificação necessária
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'
# Também precisamos alterar o num_classes na cabeça para corresponder à anotação do conjunto de dados
model = dict(
roi_head=dict(
bbox_head=dict(num_classes=3),
mask_head=dict(num_classes=3)))
# Modificar configurações relacionadas ao conjunto de dados
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
# Modificar configurações relacionadas a métricas
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator
# Podemos usar o modelo Mask RCNN pré-treinado para obter desempenho superior
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'
# se você gosta de filmes longos
# o padrão aqui, se não me engano, é 12
train_cfg = dict(max_epochs=24)
Algo para olhar se as máscaras não forem necessárias: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html
Treinamento
Vamos assumir que você tem sua configuração de modelo em /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py . O script de treinamento é uma chamada padrão à ferramenta 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
Inferência
Algumas documentações estão aqui: 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')
# execute para um arquivo único:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)
# ou para a pasta inteira
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)
Links úteis
Espero que isso ajude de alguma forma.
Outras leituras úteis, veja em
- Site do Label Studio: https://labelstud.io/
- Documentação MMDetection: https://mmdetection.readthedocs.io/en/latest/get_started.html
- Bash Cheat Sheet
- Detectando tampas de barras de concreto com tensorflow
- Python Cheatsheet
- Conda Cheatsheet
- Flux text to image
- Ollama cheatsheet
- Docker Cheatsheet
- Layered Lambdas with AWS SAM and Python
- Generating PDF in Python - Libraries and examples