Aprendizado profundo – conjunto de dados de sinal de trânsito alemão com Keras

Navin krishnakumar Blocked Unblock Seguir Seguindo 12 de janeiro

O curso Deep Learning oferecido pela New York Data Science Academy é ótimo para você começar sua jornada com aprendizado profundo e também o incentiva a fazer um projeto de aprendizado profundo. Decidi fazer um desafio de reconhecimento de imagem usando o conjunto de dados de sinal de tráfego alemão. Eu nunca trabalhei em reconhecimento de imagem antes e, portanto, este projeto foi uma grande experiência de aprendizado pessoalmente.

Declaração do problema e objetivo do projeto

O benchmark alemão de sinais de trânsito é um desafio de classificação de imagem única e multi-classe realizado na Conferência Conjunta Internacional sobre Redes Neurais (IJCNN) 2011 .

Benchmarks alemães do sinal de tráfego
J. Stallkamp, M. Schlipsing, J. Salmen, C. Igel, homem vs. computador: algoritmos de aprendizagem de máquina de benchmarking para o tráfego… benchmark.ini.rub.de

Detecção de sinal de tráfego é um problema de visão computacional de alta relevância e é a base para muitas aplicações na indústria, tais como automóveis, etc. Sinais de trânsito podem fornecer uma ampla gama de variações entre classes em termos de cor, forma e presença de pictogramas ou texto.

Neste desafio, desenvolveremos um algoritmo de aprendizado profundo que treinará imagens de sinais de trânsito alemães e, então, classificará os sinais de trânsito não rotulados. O modelo de aprendizagem profunda será construído usando o Keras (API de alto nível para o tensorflow) e também entenderemos várias maneiras de pré-processar imagens usando o OpenCV e também usar um provedor de serviços de GPU na nuvem.

Nós estaremos trabalhando com Keras para o nosso algoritmo de construção. Keras foi escolhido por ser fácil de aprender e usar. O Keras também se integra perfeitamente ao TensorFlow. Após o Tensorflow, o Keras parece ser o framework que é amplamente utilizado pela comunidade de aprendizagem profunda.

O código inteiro do projeto pode ser encontrado na minha conta do GitHub .

Navkrish04 / German-Traffic-Sign-Classification
Algoritmo de Aprendizado Profundo para Desafio de Reconhecimento de Imagem – Navkrish04 / German-Traffic-Sign-Classification github.com

Processo Algoritmico

Semelhante a qualquer processo de construção de modelo de aprendizado de máquina, também executaremos as mesmas etapas de ouro definidas abaixo

  1. Entenda os dados
  2. Pré-processar os dados
  3. Construa a arquitetura do modelo
  4. Teste o modelo
  5. Iterar o mesmo processo até conseguir os melhores resultados
  6. Implantar o modelo (não considerado para este exercício)

Entendimento de dados

O conjunto de dados da imagem consiste em 43 classes (imagens exclusivas de sinal de trânsito).

Conjunto de treinamento tem 34799 imagens, conjunto de teste tem 12630 imagens eo conjunto de validação tem 4410 imagens.

 # Compreenda os dados 
print ("Conjunto de treino:", len (X_train))
print ("Conjunto de Testes:", len (y_test))
print ("Conjunto de validação:", len (X_valid))
print ("Dimensões da Imagem:", np.shape (X_train [1]))
print ("Número de classes:", len (np.unique (y_train)))
n_classes = len (np.unique (y_train))

Distribuição de Classe de Imagens de Amostra

Algumas inferências dos dados que abordaremos durante o estágio de pré-processamento

a) Questão de viés de classe, pois algumas classes parecem estar sub-representadas

b) O contraste da imagem parece ser baixo para muitas imagens

Estabelecendo uma pontuação sem qualquer pré-processamento

É sempre uma boa prática entender onde seu modelo está sem fazer nenhum pré-processamento, pois isso ajudaria a estabelecer uma pontuação para o seu modelo, que você poderia melhorar em cada iteração. A métrica de avaliação para o nosso modelo seria a pontuação de " precisão ". Eu tinha restrições de recursos e estava executando o modelo de testes no meu mac (8GB de RAM) e, portanto, usei uma arquitetura de rede neural simples “densa” ou “totalmente” para as pontuações da linha de base e outros testes.

Arquitetura de Rede Densa

 model = Sequential () 
model.add (Densi (128, ativação = 'relu', input_shape = (32 * 32 * 3,)))
model.add (BatchNormalization ())
model.add (denso (128, ativação = 'relu'))
model.add (BatchNormalization ())
model.add (Rejeição (0.5))
model.add (denso (128, ativação = 'relu'))
model.add (BatchNormalization ())
model.add (Rejeição (0.5))
model.add (denso (128, ativação = 'relu'))
model.add (BatchNormalization ())
model.add (denso (n_classes, ativação = 'softmax'))

As instruções model = Sequential () carregam a rede. A forma de entrada é 32 * 32 * 3 (como as imagens têm 3 canais de cores) . Em Keras, não há um comando específico da camada de entrada, pois a forma de entrada é a camada de entrada implícita. O número de parâmetros na primeira camada seria 393344 ((32 * 32 * 3 * 128) + 128)). Podemos calcular o número de parâmetros para as outras camadas da mesma maneira.

A função de ativação é "relu" . Durante a otimização de hiperparâmetros, podemos verificar com Tanh, Sigmoid e outra função de ativação se eles são mais adequados para a tarefa. Por enquanto, nós nos atemos ao "relu".

Existem 4 camadas ocultas de 128 neurônios com ativação relu e após cada camada oculta, exceto a última, uma função de dropout (50%) é incluída.

A camada de saída tem a ativação do softmax, uma vez que estamos lidando com classificação de múltiplas classes e existem 43 classes.

O modelo foi capaz de atingir uma pontuação de precisão de 84% sem qualquer pré-processamento.

Pré-processamento de dados

Agora que temos uma pontuação em mãos, vamos entender se o pré-processamento das imagens levaria a uma melhor pontuação de precisão e ajudaria nosso modelo.

O aumento de dados é usado para aumentar os dados do conjunto de treinamento. Aumentar os dados é basicamente criar mais imagens a partir das imagens disponíveis, mas com ligeira alteração das imagens. Geralmente, precisamos de dados proporcionais aos parâmetros que alimentamos as redes neurais.

Eu achei o OpenCV excelente para o pré-processamento de imagens. Aqui está o link para os tutoriais gerais para usar o OpenCV com a implementação do Python. Algumas das técnicas usadas no processo são Rotação, Tradução, Filtragem bilateral, Grayscaling e Equilização de Histograma Local.

Introdução aos Tutoriais do OpenCV-Python – Tutoriais do OpenCV-Python 1 documentação
E essa será uma boa tarefa para os calouros que começarem a contribuir para projetos de código aberto. Apenas bifurque o OpenCV em… opencv-python-tutroals.readthedocs.io

Ligeira Rotação de Imagens: usei 10 graus de rotação de imagens. Não faria muito sentido girar imagens mais do que isso, pois isso poderia levar a representações erradas dos sinais de trânsito. Vamos ver algumas imagens depois de uma ligeira rotação (não é perceptível em algumas imagens também)

 M_rot = cv2.getRotationMatrix2D ((cols / 2, rows / 2), 10,1) 

Imagens após 10 graus de rotação

Tradução de Imagem: Esta é uma técnica pela qual você muda a localização da imagem. Em termos leigos, se a localização da imagem for (x1, y1) posição, após a translação ela é movida para a posição (x2, y2). Como você pode ver nas imagens abaixo, o local é ligeiramente movido para baixo.

Imagens após tradução

Filtragem Bilateral: A filtragem bilateral é uma redução de ruído, preservando a suavização das imagens.

Escala de cinza: A escala de cinzas das imagens é feita para reduzir as informações fornecidas aos pixels e também reduz a complexidade.

 def gray_scale (imagem): 

retornar cv2.cvtColor (image, cv2.COLOR_RGB2GRAY)

Equalização do Histograma Local: Isso é feito para aumentar o contraste das imagens, conforme identificamos durante o “Entendimento de Dados”, de que as imagens podem precisar de um aumento no contraste.

 def local_histo_equalize (imagem): 

kernel = morp.disk (30)
img_local = rank.equalize (imagem, selem = kernel)
retornar img_local

Aqui estão as imagens depois de todo o pré-processamento.

Imagens após o pré-processamento

Fixação de viés de classe com aumento de dados: estamos configurados para aumentar as imagens do conjunto de treinamento com aumento de dados, também faria sentido abordar o problema de distorção de classe. Assim, durante o aumento, todas as classes foram alimentadas com 4000 imagens. No conjunto de dados original, a Classe 2 tinha o número máximo de imagens de treinamento com registros de 2010. O número 4000 (registros de classe Max * ~ 2) é um número arbitrário que eu tomei para fazer com que todas as classes tenham o mesmo número de registros. Nós definitivamente podemos brincar com essa distribuição ainda mais.

Aqui está o trecho de código que faz com que todas as classes tenham o mesmo número de registros que precisamos.

 para i no intervalo (0, classes): 

class_records = np.where (y_train == i) [0] tamanho
max_records = 4000
se class_records! = max_records:
ovr_sample = max_records - class_records
samples = X_train [np.where (y_train == i) [0]]
X_aug = []
Y_aug = [i] * ovr_sample

para x no intervalo (ovr_sample):
img = samples [x% class_records]
trans_img = data_augment (img)
X_aug.append (trans_img)

X_train_final = np.concatenate ((X_train_final, X_aug), eixo = 0)
y_train_final = np.concatenate ((y_train_final, Y_aug))

Y_aug_1 = Y_aug_1 + Y_aug
X_aug_1 = X_aug_1 + X_aug

Distribuição de classe após fixação do viés de classe

Pontuação do modelo após aumento de dados e após fixação da classe Bias:

A mesma arquitetura de rede neural densa usada acima foi capaz de melhorar seu escore de precisão para 88,2% após o pré-processamento de dados, o que sugere que o pré-processamento das imagens (aumentando os dados) valeu a pena.

Redes Neurais Convolucionais

O próximo passo na jornada de construção do modelo seria usar uma arquitetura muito sofisticada para impulsionar o desempenho do nosso modelo. Pesquisas no campo da visão computacional estabeleceram que as redes neurais Convolutional apresentam um desempenho extremamente superior nos desafios de reconhecimento de imagem e, portanto, devem ser a primeira escolha. Nosso objetivo do projeto era construir sistematicamente um modelo de aprendizagem profunda e entender como cada etapa afetaria o desempenho do modelo. Portanto, a CNN não foi usada em primeiro lugar. Também está além do escopo do artigo explicar como o trabalho da CNN. Aqui está um artigo intuitivo sobre o mesmo.

Um guia intuitivo para redes neurais convolucionais
Neste artigo, vamos explorar as Redes Neurais de Convolução (CNNs) e, em um alto nível, mostrar como elas são… medium.freecodecamp.org

Arquitetura de rede neural convolucional

Aqui está a arquitetura de rede neural Convolucional para o modelo

 model_conv = Sequencial () 
## Se você pré-processou com escala de cinza e equivalização de histograma local, então input_shape = (32,32,1) else (32,32,3)
model_conv.add (Conv2D (32, kernel_size = (3, 3), ativação = 'relu', input_shape = (32, 32, 1)))
model_conv.add (MaxPooling2D (pool_size = (2, 2)))
model_conv.add (Conv2D (128, kernel_size = (3, 3), ativação = 'relu'))
model_conv.add (MaxPooling2D (pool_size = (2, 2)))
model.add (BatchNormalization ())
model_conv.add (Conv2D (128, kernel_size = (3, 3), ativação = 'relu'))
model_conv.add (MaxPooling2D (pool_size = (2, 2)))
model.add (BatchNormalization ())
model_conv.add (Dropout (0,25))
model_conv.add (Conv2D (128, kernel_size = (3, 3), ativação = 'relu'))
model_conv.add (MaxPooling2D (pool_size = (2, 2)))
model.add (BatchNormalization ())
model_conv.add (Saída (0.5))
model_conv.add (Flatten ())
model_conv.add (Densi (128, ativação = 'relu'))
model_conv.add (Saída (0.5))
model_conv.add (denso (n_classes, ativação = 'softmax'))

Existem 4 camadas convolucionais + camadas Max Pooling. O tamanho do núcleo para as camadas convolucionais é (3,3). O Kernel refere-se ao tamanho do filtro. O tamanho geral usado é (5,5) ou (3,3).

Uma coisa a notar aqui é que a forma de entrada é (32,32,1). Nas densas redes que tivemos (32,32,3), como não tínhamos feito o grayscaling. Como realizamos o grayscaling em nossas imagens, o valor dos canais se tornaria um.

Uma camada de pool máximo é adicionada com um tamanho de pool de (2,2) junto com Normalização de lote. As camadas máximas de pooling são usadas para reduzir a dimensionalidade, o que ajuda a reduzir o tempo de treinamento e também ajuda a reduzir o overfitting.

Depois, há também duas camadas totalmente conectadas antes da camada de saída. Note aqui que precisamos achatar a saída antes dessa camada, pois a entrada esperada é um vetor dimensional.

Como esta é uma classificação multiclasse, a ativação solftmax é usada.

Arquitetura CNN

Eu corri o modelo no meu computador por 100 épocas e levou 4 dias para ser concluído (estava curioso para saber quanto tempo ele roda). O escore do modelo aumentou para 97,2%. Tipo de explica o hype em torno da CNN.

Agora, fazia mais sentido comprar algumas GPUs para um processamento mais rápido ou ir a um provedor de serviços em nuvem para experimentar arquiteturas diferentes. Eu encontrei o FloydHub para ser excelente a esse respeito. Usar o Floydhub é extremamente fácil. Precisamos apenas carregar o conjunto de dados e importar o código do Python por meio do GitHub ou fazer o upload do código manualmente.

O código inteiro agora é executado em aproximadamente 15 minutos e eu definitivamente posso testar com diferentes arquiteturas daqui para frente.

Caminho a seguir

Essa experiência de construir um modelo de aprendizado profundo a partir do zero e também seguir o processo de construção de um foi uma ótima experiência de aprendizado. Eu estou constantemente aprendendo coisas novas todos os dias nesta jornada e tentando novas melhorias. Os próximos passos para implementar seriam

  1. Identifique a melhor arquitetura junto com os melhores hiperparâmetros. Também para experimentar o AlexNet ou o VGGNet.
  2. Use o aprendizado de transferência

Texto original em inglês.