Deteção de objetos usando R-CNN rápido
Tabela de Conteúdos
- Resumo
- Configuração
- Executar o exemplo de brinquedo
- Treine os dados do VOC pascal
- Treine cNTK Fast R-CNN nos seus próprios dados
- Detalhes técnicos
- Detalhes do algoritmo
Resumo
Este tutorial descreve como usar O R-CNN rápido na API python CNTK. O R-CNN rápido usando BrainScript e cnkt.exe é descrito aqui.
Acima são exemplos de imagens e anotações de objetos para o conjunto de dados de mercearia (à esquerda) e o conjunto de dados pascal VOC (à direita) usado neste tutorial.
Fast R-CNN é um algoritmo de deteção de objetos proposto por Ross Girshick em 2015. O papel é aceite no ICCV 2015, e arquivado em https://arxiv.org/abs/1504.08083. A Fast R-CNN baseia-se em trabalhos anteriores para classificar eficientemente as propostas de objetos utilizando redes profundas convolucionais. Em comparação com o trabalho anterior, a Fast R-CNN emprega uma região de pooling de interesses que permite reutilizar os cálculos das camadas convolucionais.
Configuração
Para executar o código neste exemplo, você precisa de um ambiente CNTK Python (consulte aqui para obter ajuda de configuração). Por favor, instale os seguintes pacotes adicionais no seu ambiente cntk Python
pip install opencv-python easydict pyyaml dlib
Binários pré-compilados para regressão da caixa de delimitação e supressão não máxima
A pasta Examples\Image\Detection\utils\cython_modules
contém binários pré-compilados que são necessários para executar Fast R-CNN. As versões que estão atualmente contidas no repositório são Python 3.5 para Windows e Python 3.5, 3.6 para Linux, todas 64 bits. Se precisar de uma versão diferente, pode compilá-la seguindo os passos descritos em
- Linux: https://github.com/rbgirshick/py-faster-rcnn
- Windows: https://github.com/MrGF/py-faster-rcnn-windows
Copie os binários gerados cython_bbox
cpu_nms
e /ou /ou gpu_nms
de $FRCN_ROOT/lib/utils
.$CNTK_ROOT/Examples/Image/Detection/utils/cython_modules
Dados de exemplo e modelo de base
Utilizamos um modelo AlexNet pré-treinado como base para o treino Fast-R-CNN (para VGG ou outros modelos base ver usando um modelo base diferente. Tanto o conjunto de dados de exemplo como o modelo AlexNet pré-treinado podem ser descarregados executando o seguinte comando Python a partir da pasta FastRCNN:
python install_data_and_model.py
- Saiba como usar um modelo base diferente
- Saiba como executar Fast R-CNN em dados do VOC pascal
- Saiba como executar o Fast R-CNN nos seus próprios dados
Executar o exemplo de brinquedo
Para treinar e avaliar a corrida Fast R-CNN
python run_fast_rcnn.py
Os resultados para a formação com 2000 ROIs na mercearia utilizando o AlexNet como modelo base devem ser semelhantes a estes:
AP for gerkin = 1.0000
AP for butter = 1.0000
AP for joghurt = 1.0000
AP for eggBox = 1.0000
AP for mustard = 1.0000
AP for champagne = 1.0000
AP for orange = 1.0000
AP for water = 0.5000
AP for avocado = 1.0000
AP for tomato = 1.0000
AP for pepper = 1.0000
AP for tabasco = 1.0000
AP for onion = 1.0000
AP for milk = 1.0000
AP for ketchup = 0.6667
AP for orangeJuice = 1.0000
Mean AP = 0.9479
Para visualizar as caixas e etiquetas de delimitação previstas nas imagens abertas FastRCNN_config.py
a FastRCNN
partir da pasta e definidas
__C.VISUALIZE_RESULTS = True
As imagens serão guardadas na FastRCNN/Output/Grocery/
pasta se correr python run_fast_rcnn.py
.
Comboio em Pascal VOC
Para descarregar os dados pascal e criar os ficheiros de anotação para Pascal no formato CNTK, executar os seguintes scripts:
python Examples/Image/DataSets/Pascal/install_pascalvoc.py
python Examples/Image/DataSets/Pascal/mappings/create_mappings.py
Alterar o dataset_cfg
método get_configuration()
de run_fast_rcnn.py
from utils.configs.Pascal_config import cfg as dataset_cfg
Agora está pronto para treinar os dados do Pascal VOC 2007 usando python run_fast_rcnn.py
. Cuidado que o treino pode demorar um pouco.
Treine os seus próprios dados
Preparar um conjunto de dados personalizado
Opção #1: Ferramenta de marcação de objetos visuais (recomendado)
A Ferramenta de Marcação de Objetos Visuais (VOTT) é uma ferramenta de anotação de plataforma cruzada para a marcação de ativos de vídeo e imagem.
Vott fornece as seguintes características:
- Marcação assistida por computador e rastreio de objetos em vídeos usando o algoritmo de rastreamento Camshift.
- Exportação de etiquetas e ativos para o formato CNTK Fast-RCNN para a formação de um modelo de deteção de objetos.
- Executar e validar um modelo de deteção de objetos CNTK treinado em novos vídeos para gerar modelos mais fortes.
Como anotar com VOTT:
- Descarregue o mais recente Lançamento
- Siga o Readme para executar um trabalho de marcação
- Depois de marcar as etiquetas de exportação para o diretório de conjuntos de dados
Opção #2: Utilização de Scripts de Anotação
Para formar um modelo CNTK Fast R-CNN no seu próprio conjunto de dados, fornecemos dois scripts para anotar regiões retangulares em imagens e atribuir rótulos a essas regiões.
Os scripts armazenarão as anotações no formato correto, conforme exigido pelo primeiro passo de execução fast R-CNN (A1_GenerateInputROIs.py
).
Primeiro, guarde as suas imagens na seguinte estrutura de pasta
<your_image_folder>/negative
- imagens usadas para o treino que não contenham quaisquer objetos<your_image_folder>/positive
- imagens utilizadas para o treino que contêm objetos<your_image_folder>/testImages
- imagens utilizadas para testes que contenham objetos
Para as imagens negativas não é necessário criar anotações. Para as outras duas pastas, utilize os scripts fornecidos:
- Corra
C1_DrawBboxesOnImages.py
para desenhar caixas de delimitação nas imagens.- No conjunto
imgDir = <your_image_folder>
de scripts (/positive
ou/testImages
) antes de correr. - Adicione anotações utilizando o cursor do rato. Uma vez anotados todos os objetos numa imagem, a tecla premente 'n' escreve o ficheiro .bboxes.txt e, em seguida, segue para a imagem seguinte, 'u' desfaz (isto é, remove) o último retângulo, e 'q' deixa a ferramenta de anotação.
- No conjunto
- Corra
C2_AssignLabelsToBboxes.py
para atribuir etiquetas às caixas de delimitação.- No conjunto
imgDir = <your_image_folder>
de scripts (/positive
ou/testImages
) antes de correr... - ... e adaptar as aulas no script para refletir as categorias de objetos, por exemplo
classes = ("dog", "cat", "octopus")
. - O script carrega estes retângulos anotados manualmente para cada imagem, exibe-os um a um e pede ao utilizador que forneça a classe do objeto clicando no respetivo botão à esquerda da janela. As anotações da verdade no chão marcadas como "indecisas" ou "excluir" estão totalmente excluídas do processamento.
- No conjunto
Treine no conjunto de dados personalizado
Depois de armazenar as suas imagens na estrutura descrita da pasta e anotando-as, por favor, corra
python Examples/Image/Detection/utils/annotations/annotations_helper.py
depois de ter mudado a pasta do guião para a pasta de dados. Finalmente, crie uma MyDataSet_config.py
na pasta seguindo utils\configs
os exemplos existentes:
__C.CNTK.DATASET == "YourDataSet":
__C.CNTK.MAP_FILE_PATH = "../../DataSets/YourDataSet"
__C.CNTK.CLASS_MAP_FILE = "class_map.txt"
__C.CNTK.TRAIN_MAP_FILE = "train_img_file.txt"
__C.CNTK.TEST_MAP_FILE = "test_img_file.txt"
__C.CNTK.TRAIN_ROI_FILE = "train_roi_file.txt"
__C.CNTK.TEST_ROI_FILE = "test_roi_file.txt"
__C.CNTK.NUM_TRAIN_IMAGES = 500
__C.CNTK.NUM_TEST_IMAGES = 200
__C.CNTK.PROPOSAL_LAYER_SCALES = [8, 16, 32]
Note que __C.CNTK.PROPOSAL_LAYER_SCALES
não é usado para Fast R-CNN, apenas para R-CNN mais rápido.
Para treinar e avaliar o Fast R-CNN nos seus dados altere o dataset_cfg
get_configuration()
método de run_fast_rcnn.py
from utils.configs.MyDataSet_config import cfg as dataset_cfg
e correr python run_fast_rcnn.py
.
Detalhes técnicos
O algoritmo R-CNN rápido é explicado na secção de detalhes do Algoritmo juntamente com uma visão geral de alto nível de como é implementado na API python CNTK. Esta secção centra-se na configuração do Fast R-CNN e na utilização de diferentes modelos base.
Parâmetros
Os parâmetros são agrupados em três partes:
- Parâmetros do detetor (ver
FastRCNN/FastRCNN_config.py
) - Parâmetros de definição de dados (ver por exemplo
utils/configs/Grocery_config.py
) - Parâmetros do modelo base (ver por exemplo
utils/configs/AlexNet_config.py
)
As três partes são carregadas e fundidas no get_configuration()
método em run_fast_rcnn.py
. Nesta secção vamos cobrir os parâmetros do detetor. Os parâmetros de conjunto de dados são descritos aqui, parâmetros de base aqui. No seguinte, passamos pelos parâmetros mais importantes em FastRCNN_config.py
. Todos os parâmetros também são comentados no ficheiro. A configuração utiliza o EasyDict
pacote que permite fácil acesso a dicionários aninhados.
# Number of regions of interest [ROIs] proposals
__C.NUM_ROI_PROPOSALS = 200 # use 2000 or more for good results
# the minimum IoU (overlap) of a proposal to qualify for training regression targets
__C.BBOX_THRESH = 0.5
# Maximum number of ground truth annotations per image
__C.INPUT_ROIS_PER_IMAGE = 50
__C.IMAGE_WIDTH = 850
__C.IMAGE_HEIGHT = 850
# Use horizontally-flipped images during training?
__C.TRAIN.USE_FLIPPED = True
# If set to 'True' conv layers weights from the base model will be trained, too
__C.TRAIN_CONV_LAYERS = True
As propostas roi são calculadas em voo na primeira época utilizando a implementação seletiva da pesquisa a dlib
partir do pacote. O número de propostas geradas é controlado pelo __C.NUM_ROI_PROPOSALS
parâmetro. Recomendamos a utilização de cerca de 2000 propostas. A cabeça de regressão só é treinada nos ROIs que têm uma sobreposição (IoU) com uma caixa de verdade terrestre de pelo menos __C.BBOX_THRESH
.
__C.INPUT_ROIS_PER_IMAGE
especifica o número máximo de anotações de verdade terrestre por imagem. A CNTK requer atualmente a definição de um número máximo. Se houver menos anotações, serão acolchoadas internamente. __C.IMAGE_WIDTH
e __C.IMAGE_HEIGHT
são as dimensões que são usadas para redimensionar e remar as imagens de entrada.
__C.TRAIN.USE_FLIPPED = True
irá aumentar os dados de treino, invertendo todas as imagens em todas as outras épocas, ou seja, a primeira época tem todas as imagens regulares, a segunda tem todas as imagens viradas, e assim por diante. __C.TRAIN_CONV_LAYERS
determina se as camadas convolucionais, desde a entrada até ao mapa de características convolucionais, serão treinadas ou fixas. A fixação dos pesos da camada conv significa que os pesos do modelo base são tomados e não modificados durante o treino. (Também pode especificar quantas camadas conv pretende treinar, ver secção Utilizando um modelo base diferente).
# NMS threshold used to discard overlapping predicted bounding boxes
__C.RESULTS_NMS_THRESHOLD = 0.5
# If set to True the following two parameters need to point to the corresponding files that contain the proposals:
# __C.DATA.TRAIN_PRECOMPUTED_PROPOSALS_FILE
# __C.DATA.TEST_PRECOMPUTED_PROPOSALS_FILE
__C.USE_PRECOMPUTED_PROPOSALS = False
__C.RESULTS_NMS_THRESHOLD
é o limiar de SNM utilizado para descartar as caixas de delimitação previstas na avaliação. Um limiar mais baixo produz menos remoção e, portanto, caixas de delimitação mais previstas na produção final. Se definir __C.USE_PRECOMPUTED_PROPOSALS = True
o leitor, o leitor lerá ROIs pré-comutativas a partir de ficheiros de texto. Isto é, por exemplo, utilizado para a formação em dados do VOC pascal. Os nomes dos ficheiros __C.DATA.TRAIN_PRECOMPUTED_PROPOSALS_FILE
e __C.DATA.TEST_PRECOMPUTED_PROPOSALS_FILE
são especificados em Examples/Image/Detection/utils/configs/Pascal_config.py
.
# The basic segmentation is performed kvals.size() times. The k parameter is set (from, to, step_size)
__C.roi_ss_kvals = (10, 500, 5)
# When doing the basic segmentations prior to any box merging, all
# rectangles that have an area < min_size are discarded. Therefore, all outputs and
# subsequent merged rectangles are built out of rectangles that contain at
# least min_size pixels. Note that setting min_size to a smaller value than
# you might otherwise be interested in using can be useful since it allows a
# larger number of possible merged boxes to be created
__C.roi_ss_min_size = 9
# There are max_merging_iterations rounds of neighboring blob merging.
# Therefore, this parameter has some effect on the number of output rectangles
# you get, with larger values of the parameter giving more output rectangles.
# Hint: set __C.CNTK.DEBUG_OUTPUT=True to see the number of ROIs from selective search
__C.roi_ss_mm_iterations = 30
# image size used for ROI generation
__C.roi_ss_img_size = 200
Os parâmetros acima estão a configurar a procura seletiva do Dlib. Para mais detalhes, consulte a página inicial do DLIB. Os seguintes parâmetros adicionais são utilizados para filtrar roIs gerados w.r.t. comprimento mínimo e comprimento lateral máximo, área e relação de aspeto.
# minimum relative width/height of an ROI
__C.roi_min_side_rel = 0.01
# maximum relative width/height of an ROI
__C.roi_max_side_rel = 1.0
# minimum relative area of an ROI
__C.roi_min_area_rel = 0.0001
# maximum relative area of an ROI
__C.roi_max_area_rel = 0.9
# maximum aspect ratio of an ROI vertically and horizontally
__C.roi_max_aspect_ratio = 4.0
# aspect ratios of ROIs for uniform grid ROIs
__C.roi_grid_aspect_ratios = [1.0, 2.0, 0.5]
Se a procura seletiva devolver mais ROIs do que o solicitado, são amostrados aleatoriamente. Se menos ROIs forem retorno, rois adicionais são gerados numa grelha regular utilizando o especificado __C.roi_grid_aspect_ratios
.
Usando um modelo base diferente
Para utilizar um modelo base diferente, é necessário escolher uma configuração de modelo diferente no get_configuration()
método de run_fast_rcnn.py
. Dois modelos são suportados de imediato:
# for VGG16 base model use: from utils.configs.VGG16_config import cfg as network_cfg
# for AlexNet base model use: from utils.configs.AlexNet_config import cfg as network_cfg
Para descarregar o modelo VGG16, utilize o script de descarregamento em <cntkroot>/PretrainedModels
:
python download_model.py VGG16_ImageNet_Caffe
Se quiser utilizar outro modelo base diferente, tem de copiar, por exemplo, o ficheiro utils/configs/VGG16_config.py
de configuração e modificá-lo de acordo com o seu modelo base:
# model config
__C.MODEL.BASE_MODEL = "VGG16"
__C.MODEL.BASE_MODEL_FILE = "VGG16_ImageNet_Caffe.model"
__C.MODEL.IMG_PAD_COLOR = [103, 116, 123]
__C.MODEL.FEATURE_NODE_NAME = "data"
__C.MODEL.LAST_CONV_NODE_NAME = "relu5_3"
__C.MODEL.START_TRAIN_CONV_NODE_NAME = "pool2" # __C.MODEL.FEATURE_NODE_NAME
__C.MODEL.POOL_NODE_NAME = "pool5"
__C.MODEL.LAST_HIDDEN_NODE_NAME = "drop7"
__C.MODEL.FEATURE_STRIDE = 16
__C.MODEL.RPN_NUM_CHANNELS = 512
__C.MODEL.ROI_DIM = 7
Para investigar os nomes dos nós do seu modelo base, pode utilizar o plot()
método a partir de cntk.logging.graph
. Por favor, note que os modelos ResNet não são suportados atualmente, uma vez que roi pooling em CNTK ainda não suporta a média de piscina roi.
Detalhes do algoritmo
R-CNN rápido
Os R-CNNs para deteção de objetos foram apresentados pela primeira vez em 2014 por Ross Girshick et al., e mostraram-se que superaram as abordagens anteriores de última geração num dos principais desafios de reconhecimento de objetos no campo: Pascal VOC. Desde então, foram publicados dois trabalhos de seguimento que contêm melhorias significativas na velocidade: Fast R-CNN e Faster R-CNN.
A ideia básica da R-CNN é pegar numa rede neural profunda que foi originalmente treinada para a classificação de imagem usando milhões de imagens anotadas e modificá-la para efeitos de deteção de objetos. A ideia básica do primeiro artigo da R-CNN é ilustrada na figura abaixo (retirada do papel): (1) Dada uma imagem de entrada, (2) num primeiro passo, são geradas propostas de uma grande parte da região. (3) Estas propostas de região, ou Regiões de Interesses (IDE), são então enviadas independentemente através da rede que produz um vetor de, por exemplo, 4096 valores de ponto flutuante para cada ROI. Finalmente, (4) aprende-se um classificador que toma a representação roi flutuante 4096 como entrada e produz um rótulo e confiança para cada ROI.
Embora esta abordagem funcione bem em termos de precisão, é muito dispendioso calcular, uma vez que a Rede Neural tem de ser avaliada para cada ROI. A Fast R-CNN aborda esta desvantagem avaliando apenas a maior parte da rede (para ser específico: as camadas de convolução) um único tempo por imagem. De acordo com os autores, isto leva a uma aceleração de 213 vezes durante os testes e uma aceleração de 9x durante o treino sem perda de precisão. Isto é conseguido usando uma camada de piscina ROI que projeta o ROI para o mapa de características convolucional e executa o máximo de pooling para gerar o tamanho de saída desejado que a camada seguinte espera.
No exemplo alexNet usado neste tutorial, a camada de agrupamento ROI é colocada entre a última camada convolucional e a primeira camada totalmente conectada. No código API da CNTK Python mostrado abaixo, este é realizado através da clonagem de duas partes da rede, a conv_layers
e a fc_layers
. A imagem de entrada é então primeiramente normalizada, empurrada através da conv_layers
camada efc_layers
, finalmente, roipooling
são adicionadas as cabeças de previsão e regressão que preveem o rótulo de classe e os coeficientes de regressão por candidato ROI, respectivamente.
def create_fast_rcnn_model(features, roi_proposals, label_targets, bbox_targets, bbox_inside_weights, cfg):
# Load the pre-trained classification net and clone layers
base_model = load_model(cfg['BASE_MODEL_PATH'])
conv_layers = clone_conv_layers(base_model, cfg)
fc_layers = clone_model(base_model, [cfg["MODEL"].POOL_NODE_NAME], [cfg["MODEL"].LAST_HIDDEN_NODE_NAME], clone_method=CloneMethod.clone)
# Normalization and conv layers
feat_norm = features - Constant([[[v]] for v in cfg["MODEL"].IMG_PAD_COLOR])
conv_out = conv_layers(feat_norm)
# Fast RCNN and losses
cls_score, bbox_pred = create_fast_rcnn_predictor(conv_out, roi_proposals, fc_layers, cfg)
detection_losses = create_detection_losses(...)
pred_error = classification_error(cls_score, label_targets, axis=1)
return detection_losses, pred_error
def create_fast_rcnn_predictor(conv_out, rois, fc_layers, cfg):
# RCNN
roi_out = roipooling(conv_out, rois, cntk.MAX_POOLING, (6, 6), spatial_scale=1/16.0)
fc_out = fc_layers(roi_out)
# prediction head
cls_score = plus(times(fc_out, W_pred), b_pred, name='cls_score')
# regression head
bbox_pred = plus(times(fc_out, W_regr), b_regr, name='bbox_regr')
return cls_score, bbox_pred
A implementação original do Caffe usada nos jornais R-CNN pode ser encontrada no GitHub: RCNN, Fast R-CNN e Faster R-CNN.
Formação SVM vs NN
Patrick Buehler fornece instruções sobre como treinar um SVM na saída CNTK Fast R-CNN (utilizando as funcionalidades 4096 da última camada totalmente conectada) bem como uma discussão sobre prós e contras aqui.
Pesquisa seletiva
A Busca Seletiva é um método para encontrar um grande conjunto de possíveis localizações de objetos numa imagem, independentemente da classe do objeto real. Funciona agrupando pixels de imagem em segmentos, e, em seguida, executando agrupamentos hierárquicos para combinar segmentos do mesmo objeto em propostas de objetos.
Para complementar os ROIs detetados da Pesquisa Seletiva, adicionamos ROIs que cobrem a imagem em diferentes escalas e relações de aspeto. A imagem à esquerda mostra uma saída de exemplo de Pesquisa Seletiva, onde cada possível localização do objeto é visualizada por um retângulo verde. As CR que são demasiado pequenas, demasiado grandes, etc. são descartadas (médias) e, finalmente, ROIs que cobrem uniformemente a imagem são adicionadas (à direita). Estes retângulos são então utilizados como Regiões de Interesses (NEA) no gasoduto R-CNN.
O objetivo da geração ROI é encontrar um pequeno conjunto de ROIs que, por mais apertado que cubra o maior número possível de objetos na imagem. Esta computação tem de ser suficientemente rápida, ao mesmo tempo que encontra localizações de objetos em escalas e relações de aspeto diferentes. A Selective Search mostrou-se a funcionar bem para esta tarefa, com boa precisão para acelerar as trocas.
NMS (supressão não máxima)
Os métodos de deteção de objetos frequentemente descodam múltiplas deteções que cobrem total ou parcialmente o mesmo objeto numa imagem.
Estes ROIs precisam de ser fundidos para poderem contar objetos e obter as suas localizações exatas na imagem.
Isto é tradicionalmente feito usando uma técnica chamada Não Supressão Máxima (NMS). A versão de NMS que utilizamos (e que também foi utilizada nas publicações R-CNN) não funde roIs, mas tenta identificar quais os ROIs que melhor cobrem as localizações reais de um objeto e descarta todos os outros ROIs. Isto é implementado selecionando iterativamente o ROI com maior confiança e removendo todos os outros ROIs que se sobrepõem significativamente a este ROI e são classificados como sendo da mesma classe. O limiar para a sobreposição pode ser definido PARAMETERS.py
(detalhes).
Resultados de deteção antes (à esquerda) e depois (à direita) Supressão Não Máxima:
mAP (precisão média média)
Uma vez treinado, a qualidade do modelo pode ser medida com critérios diferentes, tais como precisão, recolha, precisão, área-sub-curva, etc. Uma métrica comum que é usada para o desafio de reconhecimento de objetos Pascal VOC é medir a precisão média (AP) para cada classe. A seguinte descrição de Average Precision é tirada de Everingham et. al. A precisão média média (mAP) é calculada tomando a média acima dos APs de todas as classes.
Para uma determinada tarefa e classe, a curva de precisão/recordação é calculada a partir da saída classificada de um método. A recuperação é definida como a proporção de todos os exemplos positivos classificados acima de um determinado rank. Precisão é a proporção de todos os exemplos acima desse escalão que são da classe positiva. O AP resume a forma da curva de precisão/recordação, e é definido como a precisão média num conjunto de onze níveis de recuperação igualmente espaçados [0,0.1, . . . ,1]:
A precisão em cada nível de recolha r é interpolada tomando a precisão máxima medida para um método para o qual a recordação correspondente excede r:
onde p é a precisão medida na recordação. A intenção de interpolar a curva de precisão/recordação desta forma é reduzir o impacto dos "movimentos" na curva de precisão/recuperação, causada por pequenas variações no ranking de exemplos. Note-se que, para obter uma pontuação elevada, um método deve ter precisão a todos os níveis de recuperação – isto penaliza métodos que recuperam apenas um subconjunto de exemplos com elevada precisão (por exemplo, vistas laterais dos automóveis).