Partilhar via


Deteção de objetos usando R-CNN rápido

Tabela de Conteúdos

Resumo

imagem

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

Copie os binários gerados cython_bboxcpu_nms e /ou /ou gpu_nmsde $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

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.

Tiro de tela vott

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:

  1. Descarregue o mais recente Lançamento
  2. Siga o Readme para executar um trabalho de marcação
  3. 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.
  • 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.

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_cfgget_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.

imagem

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_layerscamada 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.

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.

imagemimagem

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:

imagem

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]:

imagem

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:

imagem

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).