Commit f93183c2 authored by João Porto's avatar João Porto
Browse files

v2.0.1, README e scripts atualizados

parent e92e37c5
# __compara_detectores_tf2
__autores__: Hemerson Pistori (pistori@ucdb.br), Fabio Prestes (fpcrezende@gmail.com), Joao Vitor Porto (jvaporto@gmail.com)
__versao__: 2.0.0
# Compara Detectores MMDetection
- **autores**: Hemerson Pistori (pistori@ucdb.br), Fabio Prestes (fpcrezende@gmail.com), Joao Vitor Porto (jvaporto@gmail.com)
- **versao**: 2.0.0
Scripts e patches para facilitar a instalação e utilização do MMDetection
Scripts e patches para facilitar a instalação e utilização do MMDetection.
Testado no Ubuntu 20.04 com python 3.7.7.
### Instalação e dependências:
## Instalação e dependências:
Leia o arquivo install.sh para ver os comandos necessarios para instalar o projeto, ou crie o ambiente e instale todas as dependencias usando o seguinte comando:
Testado no Ubuntu 20.04 com python 3.7.7
Leia o arquivo install.sh para ver o que é preciso instalar, ou crie o ambiente e instale todas as dependencias usando o seguinte comando:
```shell
sh install.sh
```
Caso o script em si nao rode corretamente, rode cada linha de comando do script install.sh linha por linha.
Placa gráfica: GTX 1070
Caso o script em si nao rode corretamente, rode cada linha de comando do script `install.sh` linha por linha.
Placa gráfica: GTX 1070
Driver nvidia: 450.66
## Preparação do mmdetection para novos dados
- Inicialmente o software está preparado para um problema de contagem de pupas de Spodoptera Frugiperda, um problema de duas (2) classes. Devido ao jeito que o MMDetection foi implementado, nao eh necessario uma classe para o fundo.
- Caso queira usar novos dados/datasets, sera necessario mudar certas variaveis em alguns arquivos espalhados pelo projeto.
- Para simplificar a utilizacao variada do MMDetection, todos os arquivos que devem ser mudados para novos datasets se encontram em utils/
- class_names.py
```python
# Modificar a funcao que contem o tipo de dataset sendo usado. Por exemplo, para datasets baseados no Coco/CocoDataset:
# Linha 67
def coco_classes():
return [
'Classe1', 'Classe2', [...], 'ClasseN'
]
```
- coco.py
```python
# Modificar o vetor de classes a ser usado no novo dataset
# Linha 22
CLASSES = ('Classe1', 'Classe2', 'Classe3', [...], 'ClasseN')
```
- coco_detection.py
```python
# Modificar o tipo de dataset, e os caminhos para as pastas de imagens e os arquivos de anotacoes.
# Exemplo: coco_detection.py, linha 32 para frente:
data = dict(
samples_per_gpu=2,
workers_per_gpu=2,
train=dict(
type=dataset_type,
classes=('Classe1', 'Classe2', 'Classe3', [...], 'ClasseN'), # As classes sendo usadas
ann_file=data_root + 'train/_annotations.coco.json', # Diretorio para o arquivo de anotacoes de treino
img_prefix=data_root + 'train/', # Diretorio para a pasta com todas as imagens de treino
pipeline=train_pipeline),
val=dict(
type=dataset_type,
classes=('Classe1', 'Classe2', 'Classe3', [...], 'ClasseN'), # As classes sendo usadas
ann_file=data_root + 'valid/_annotations.coco.json', # Diretorio para o arquivo de anotacoes de validacao
img_prefix=data_root + 'valid/', # Diretorio para a pasta com todas as imagens de validacao
pipeline=test_pipeline),
test=dict(
type=dataset_type,
classes=('Classe1', 'Classe2', 'Classe3', [...], 'ClasseN'), # As classes sendo usadas
ann_file=data_root + 'test/_annotations.coco.json', # Diretorio para o arquivo de anotacoes de teste
img_prefix=data_root + 'test/', # Diretorio para a pasta com todas as imagens de teste
pipeline=test_pipeline))
```
- Quaisquer arquivo de configuracao de rede que sera usado, dependendo do arquivo.
Eh recomendado utilizar a [documentacao do MMDetetion](https://mmdetection.readthedocs.io/en/latest/tutorials/config.html) para aprender exatamente o que cada arquivo base e variavel modifica na rede. Em geral, a maioria das redes vao ser compostas de 4 componentes, mas podem ter menos ou nenhum componente base pronto:
- default_runtime.py
- schedule_1x.py/schedule_2x.py
- coco_detection.py
- Se usado, alguma rede base preparada previamente. Para saber quais redes ja se tem prontas para usar como base, verifique `./mmdetection/configs/_base_/models/`
- Todos estes arquivos podem ser encontrados originalmente dentro de `./mmdetection/configs/_base_/`. Para simplificacao de uso do projeto, estes arquivos tambem se encontram dentro da pasta `./utils`, e os arquivos localizados dentro desta pasta substituem os arquivos originais, entao caso modificacoes nestes arquivos sejam desejados, modifique os arquivos dentro de `./utils/`.
## Usando outra arquitetura
- Troque o nome do arquivo de configuração da arquitetura (sem o .py) no arquivo `./run/arquitetura.txt`
- Opções disponíveis até agora para deteccao usando anotacoes tipo CocoJson, seguindo formatacao de dataset do [Roboflow](https://roboflow.com/):
- [x] faster_rcnn_r50_fpn_1x_voc0712
- [x] faster_rcnn_r101_fpn_1x_voc0712
- [x] retinanet_r50_fpn_1x_voc0712
- [x] retinanet_r101_fpn_1x_voc0712
- [x] fovea_r50_fpn_1x_voc0712
- [x] fovea_r101_fpn_1x_voc0712
- [x] sabl_faster_rcnn_r50_fpn_1x_voc0712
- [x] sabl_faster_rcnn_r101_fpn_1x_voc0712
- Para outras redes, verifique o [README.md original da MMDetection](mmdetection/README.md) para verificar todas as redes implementadas, caso nao queira rodar os scripts prontos acima.
## Exemplo de uso:
### Para utilizar datasets PASCAL VOC
1. Use o labelImg para anotar as imagens no formato pascalVOC
2. As imagens e os arquivos de anotação xml devem estar todos juntos em ./data/all/
3. Altere o arquivo ./utils/geraPascalVOC.sh se quiser usar um valor diferente de 0.8 (80%) para "treinamento+validação" (e portanto, 20% para teste)
4. Finalmente, seguir o [workflow basico a seguir](README.md#workflow-basico)
### Preparação do mmdetection para novos dados
#
# - Inicialmente o software está preparado para um problema de contagem de ovos do
# Aedes Aegypt. Um problema de uma classe (egg) além do fundo.
# - Você deve abrir e buscar por "TROQUE AQUI" dentro dos arquivos
# que aparecem abaixo, depois de "gedit", se quiser usar novos dados
cd ./utils/
gedit class_names.py faster_rcnn_r50_fpn_1x_voc0712.py voc.py
### Usando outra arquitetura
#
# - Troque o nome do arquivo de configuração da arquitetura (sem o .py) no arquivo arquitetura.txt
# - Opções disponíveis até agora (ajuste outros arquivos disponíveis em mmdetection/configs para
# outras arquiteturas)
# * faster_rcnn_r50_fpn_1x_voc0712
# * retinanet_r50_fpn_1x_voc0712
cd ./run
gedit arquitetura.txt
### Exemplo de uso:
#
# - Use o labelImg para anotar as imagens no formato pascalVOC
# - As imagens e os arquivos de anotação xml devem estar todos juntos em ./data/all/
# - Altere o arquivo ./utils/geraPascalVOC.sh se quiser usar um valor diferente
# de 0.8 (80%) para "treinamento+validação" (e portanto, 20% para teste)
#
# Rode o treinamento
$ cd ../run
$ ./treina.sh
# Rode o teste
$ cd ../run
$ ./testa.sh
# Detecta os objetos em uma imagem
# Possivelmente depreciado em v2.0
$ cd ../run
$ ./detecta.sh caminho_para_arquivo_da_imagem
# Detecta os objetos em todas as imagens da pasta ./mmdetection/data/VOCdevkit/VOC2007/JPEGImages/
# Feche a janela da imagem para ver a próxima
# Possivelmente depreciado em v2.0
### Para utilizar datasets COCO
1. Use o [Roboflow](https://roboflow.com/) para anotar e dividir as imagens como desejar
2. Apos configurar o dataset, baixe-o no formato COCO
3. Pegue a pasta base criada, e insira em `./mmdetection/data/`
4. Modifique as pipelines de treino, validacao e teste para refletir o caminho para as imagens e anotacoes respectivas, como mostrado na seccao [Preparação do mmdetection para novos dados](README.md#preparação-do-mmdetection-para-novos-dados)
5. Finalmente, seguir o [workflow basico a seguir](README.md#workflow-basico)
### Workflow basico
6. Uma vez preparado o dataset, modificar `./run/arquitetura.txt` para o nome do arquivo de configuracao desejada, retirando o `.py` do final
7. Para rodar o treinamento:
```shell
cd ../run
./detectaTodas.sh
sh treina.sh
```
- Caso deseje rodar multiplas redes em paralelo (caso tenha acesso a multiplas GPUs), rode a primeira rede, modifique a variavel gpu-ids a seguir para a outra GPU que deseje usar, modifique `./run/arquitetura.txt`, e rode a nova rede.
- Cuidado: Segundo alguns experimentos, certas redes nao se lidam bem ao rodar em paralelo com outras redes, dividindo poder de processamento, podendo acarretar a problemas como a perda (*loss*) alcancando NaN e nao treinando corretamente, entre outros problemas.
8. Para rodar o teste:
```shell
cd ../run
sh testa.py
```
- Por padrao, o script de teste ira inserir as imagens resultantes dentro da pasta `./results/`, em juncao a um arquivo pickle (.pkl) contendo todas as variaveis desejadas para analise estatistica do teste.
- Tambem se tem multiplos scripts prontos para analise estatistica dentro de [`./mmdetection/tools/analysis_tools`](mmdetection/tools/analysis_tools/)
- Para mais informacoes sobre estes scripts e como rodar cada um, por favor se refira a [documentacao do MMDetection sobre estes scripts](https://mmdetection.readthedocs.io/en/latest/useful_tools.html), suas explicacoes e seus exemplos de uso
- Atualmente, apenas a ferramenta de [analise de logs](mmdetection/tools/analysis_tools/analyze_logs.py) foi usada com sucesso
- Para instalar as dependencias necessarias para este script, por favor instale as seguintes bibliotecas:
```shell
pip install numpy matplotlib seaborn
# Ou caso queira instalar em um ambiente separado do Anaconda:
conda install numpy matplotlib seaborn
```
## Funcoes possivelmente depreciadas
### Detecta os objetos em uma imagem
- Possivelmente depreciado em v2.0
```shell
cd ../run
./detecta.sh caminho_para_arquivo_da_imagem
```
### Detecta os objetos em todas as imagens da pasta ./mmdetection/data/VOCdevkit/VOC2007/JPEGImages/
- Feche a janela da imagem para ver a próxima
- Possivelmente depreciado em v2.0
```shell
cd ../run
./detectaTodas.sh
```
\ No newline at end of file
......@@ -20,7 +20,7 @@ model = dict(
num_outs=5),
bbox_head=dict(
type='RetinaHead',
num_classes=80,
num_classes=2,
in_channels=256,
stacked_convs=4,
feat_channels=256,
......
......@@ -8,4 +8,4 @@ lr_config = dict(
warmup_iters=500,
warmup_ratio=0.001,
step=[8, 11])
runner = dict(type='EpochBasedRunner', max_epochs=500)
runner = dict(type='EpochBasedRunner', max_epochs=125)
......@@ -4,4 +4,4 @@ _base_ = [
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
checkpoint_config = dict(interval=250)
checkpoint_config = dict(interval=25)
_base_ = './fovea_r50_fpn_4x4_1x_coco.py'
model = dict(
backbone=dict(
depth=101,
init_cfg=dict(type='Pretrained',
checkpoint='torchvision://resnet101')))
_base_ = [
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
# model settings
model = dict(
type='FOVEA',
backbone=dict(
type='ResNet',
depth=50,
num_stages=4,
out_indices=(0, 1, 2, 3),
frozen_stages=1,
norm_cfg=dict(type='BN', requires_grad=True),
norm_eval=True,
style='pytorch',
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),
neck=dict(
type='FPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
start_level=1,
num_outs=5,
add_extra_convs='on_input'),
bbox_head=dict(
type='FoveaHead',
num_classes=2,
in_channels=256,
stacked_convs=4,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
base_edge_list=[16, 32, 64, 128, 256],
scale_ranges=((1, 64), (32, 128), (64, 256), (128, 512), (256, 2048)),
sigma=0.4,
with_deform=False,
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=1.50,
alpha=0.4,
loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0)),
# training and testing settings
train_cfg=dict(),
test_cfg=dict(
nms_pre=1000,
score_thr=0.05,
nms=dict(type='nms', iou_threshold=0.5),
max_per_img=100))
data = dict(samples_per_gpu=2, workers_per_gpu=2)
# optimizer
optimizer = dict(type='SGD', lr=0.005, momentum=0.9, weight_decay=0.0001)
#mudar aqui pra mudar intervalo de config
checkpoint_config = dict(interval=25)
_base_ = './retinanet_r50_fpn_1x_coco.py'
model = dict(
backbone=dict(
depth=101,
init_cfg=dict(type='Pretrained',
checkpoint='torchvision://resnet101')))
_base_ = [
'../_base_/models/retinanet_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)
checkpoint_config = dict(interval=125)
_base_ = [
'../_base_/models/faster_rcnn_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
model = dict(
backbone=dict(
depth=101,
init_cfg=dict(type='Pretrained',
checkpoint='torchvision://resnet101')),
roi_head=dict(
bbox_head=dict(
_delete_=True,
type='SABLHead',
num_classes=2,
cls_in_channels=256,
reg_in_channels=256,
roi_feat_size=7,
reg_feat_up_ratio=2,
reg_pre_kernel=3,
reg_post_kernel=3,
reg_pre_num=2,
reg_post_num=1,
cls_out_channels=1024,
reg_offset_out_channels=256,
reg_cls_out_channels=256,
num_cls_fcs=1,
num_reg_fcs=0,
reg_class_agnostic=True,
norm_cfg=None,
bbox_coder=dict(
type='BucketingBBoxCoder', num_buckets=14, scale_factor=1.7),
loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
loss_bbox_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox_reg=dict(type='SmoothL1Loss', beta=0.1,
loss_weight=1.0))))
checkpoint_config = dict(interval=25)
_base_ = [
'../_base_/models/faster_rcnn_r50_fpn.py',
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
model = dict(
roi_head=dict(
bbox_head=dict(
_delete_=True,
type='SABLHead',
num_classes=80,
cls_in_channels=256,
reg_in_channels=256,
roi_feat_size=7,
reg_feat_up_ratio=2,
reg_pre_kernel=3,
reg_post_kernel=3,
reg_pre_num=2,
reg_post_num=1,
cls_out_channels=1024,
reg_offset_out_channels=256,
reg_cls_out_channels=256,
num_cls_fcs=1,
num_reg_fcs=0,
reg_class_agnostic=True,
norm_cfg=None,
bbox_coder=dict(
type='BucketingBBoxCoder', num_buckets=14, scale_factor=1.7),
loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
loss_bbox_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox_reg=dict(type='SmoothL1Loss', beta=0.1,
loss_weight=1.0))))
faster_rcnn_r101_fpn_1x_coco
sabl_faster_rcnn_r101_fpn_1x_coco
......@@ -18,7 +18,7 @@ bash ../utils/moveConfigs.sh
echo 'Executando ' $config
cd ../mmdetection
python tools/train.py $config --gpu-ids 0
python tools/train.py $config --gpu-ids 1
echo 'Salvou pesos aprendidos em ' $pesos
......
_base_ = [
'../_base_/default_runtime.py', '../_base_/datasets/coco_detection.py'
]
# model settings
model = dict(
type='CornerNet',
backbone=dict(
type='HourglassNet',
downsample_times=5,
num_stacks=2,
stage_channels=[256, 256, 384, 384, 384, 512],
stage_blocks=[2, 2, 2, 2, 2, 4],
norm_cfg=dict(type='BN', requires_grad=True)),
neck=None,
bbox_head=dict(
type='CentripetalHead',
num_classes=80,
in_channels=256,
num_feat_levels=2,
corner_emb_channels=0,
loss_heatmap=dict(
type='GaussianFocalLoss', alpha=2.0, gamma=4.0, loss_weight=1),
loss_offset=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1),
loss_guiding_shift=dict(
type='SmoothL1Loss', beta=1.0, loss_weight=0.05),
loss_centripetal_shift=dict(
type='SmoothL1Loss', beta=1.0, loss_weight=1)),
# training and testing settings
train_cfg=None,
test_cfg=dict(
corner_topk=100,
local_maximum_kernel=3,
distance_threshold=0.5,
score_thr=0.05,
max_per_img=100,
nms=dict(type='soft_nms', iou_threshold=0.5, method='gaussian')))
# data settings
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile', to_float32=True),
dict(type='LoadAnnotations', with_bbox=True),
dict(
type='PhotoMetricDistortion',
brightness_delta=32,
contrast_range=(0.5, 1.5),
saturation_range=(0.5, 1.5),
hue_delta=18),
dict(
type='RandomCenterCropPad',
crop_size=(511, 511),
ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3),
test_mode=False,
test_pad_mode=None,
**img_norm_cfg),
dict(type='Resize', img_scale=(511, 511), keep_ratio=False),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
]
test_pipeline = [
dict(type='LoadImageFromFile', to_float32=True),
dict(
type='MultiScaleFlipAug',
scale_factor=1.0,
flip=True,
transforms=[
dict(type='Resize'),
dict(
type='RandomCenterCropPad',
crop_size=None,
ratios=None,
border=None,
test_mode=True,
test_pad_mode=['logical_or', 127],
**img_norm_cfg),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(
type='Collect',
keys=['img'],
meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape',
'scale_factor', 'flip', 'img_norm_cfg', 'border')),
])
]
data = dict(
samples_per_gpu=6,
workers_per_gpu=3,
train=dict(pipeline=train_pipeline),
val=dict(pipeline=test_pipeline),
test=dict(pipeline=test_pipeline))
# optimizer
optimizer = dict(type='Adam', lr=0.0005)
optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2))
# learning policy
lr_config = dict(
policy='step',
warmup='linear',
warmup_iters=500,
warmup_ratio=1.0 / 3,
step=[190])
runner = dict(type='EpochBasedRunner', max_epochs=210)
......@@ -4,4 +4,4 @@ _base_ = [
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
checkpoint_config = dict(interval=125)
checkpoint_config = dict(interval=25)
_base_ = './fovea_r50_fpn_4x4_1x_coco.py'
model = dict(
backbone=dict(
depth=101,
init_cfg=dict(type='Pretrained',
checkpoint='torchvision://resnet101')))
_base_ = [
'../_base_/datasets/coco_detection.py',
'../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]
# model settings
model = dict(
type='FOVEA',
backbone=dict(
type='ResNet',
depth=50,
num_stages=4,
out_indices=(0, 1, 2, 3),
frozen_stages=1,
norm_cfg=dict(type='BN', requires_grad=True),
norm_eval=True,
style='pytorch',
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),
neck=dict(
type='FPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
start_level=1,
num_outs=5,
add_extra_convs='on_input'),
bbox_head=dict(
type='FoveaHead',
num_classes=2,
in_channels=256,
stacked_convs=4,
feat_channels=256,
strides=[8, 16, 32, 64, 128],
base_edge_list=[16, 32, 64, 128, 256],
scale_ranges=((1, 64), (32, 128), (64, 256), (128, 512), (256, 2048)),
sigma=0.4,
with_deform=False,
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=1.50,
alpha=0.4,
loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0)),
# training and testing settings
train_cfg=dict(),
test_cfg=dict(
nms_pre=1000,
score_thr=0.05,
nms=dict(type='nms', iou_threshold=0.5),
max_per_img=100))
data = dict(samples_per_gpu=2, workers_per_gpu=2)
# optimizer
optimizer = dict(type='SGD', lr=0.005, momentum=0.9, weight_decay=0.0001)
#mudar aqui pra mudar intervalo de config
checkpoint_config = dict(interval=25)
......@@ -12,3 +12,12 @@ cp ./schedule_2x.py ../mmdetection/configs/_base_/schedules/
cp ./faster_rcnn_r50_fpn_1x_coco.py ../mmdetection/configs/pupa
cp ./faster_rcnn_r101_fpn_1x_coco.py ../mmdetection/configs/pupa
cp ./retinanet_r50_fpn_1x_coco.py ../mmdetection/configs/pupa
cp ./retinanet_r101_fpn_1x_coco.py ../mmdetection/configs/pupa
cp ./fovea_r50_fpn_4x4_1x_coco.py ../mmdetection/configs/pupa
cp ./fovea_r101_fpn_4x4_1x_coco.py ../mmdetection/configs/pupa
cp ./sabl_faster_rcnn_r50_fpn_1x_coco.py ../mmdetection/configs/pupa
cp ./sabl_faster_rcnn_r101_fpn_1x_coco.py ../mmdetection/configs/pupa
_base_ = './retinanet_r50_fpn_1x_coco.py'
model = dict(
backbone=dict(
depth=101,
init_cfg=dict(type='Pretrained',
checkpoint='torchvision://resnet101')))
_base_ = [
'../_base_/models/retinanet_r50_fpn.py',