Entendendo e Codificando uma ResNet em Keras

Fazendo coisas legais com dados!

Priya Dwivedi Blocked Desbloquear Seguir Seguindo 4 de janeiro

ResNet , abreviação de Residual Networks é uma rede neural clássica usada como backbone para muitas tarefas de visão de computador. Este modelo foi o vencedor do desafio ImageNet em 2015. O avanço fundamental com a ResNet nos permitiu treinar redes neurais extremamente profundas com mais de 150 camadas. Antes do treinamento do ResNet, redes neurais muito profundas eram difíceis devido ao problema dos gradientes de desaparecimento.

A AlexNet, vencedora do ImageNet 2012 e o modelo que aparentemente iniciou o foco em deep learning, tinha apenas 8 camadas convolucionais, a rede VGG 19 e Inception ou GoogleNet 22 e ResNet 152 152 camadas. Neste blog, iremos codificar uma ResNet-50 que é uma versão menor do ResNet 152 e frequentemente usada como ponto de partida para o aprendizado de transferência.

Revolução da Profundidade

No entanto, aumentar a profundidade da rede não funciona simplesmente empilhando camadas juntas. Redes profundas são difíceis de treinar por causa do notório problema do gradiente de desaparecimento – como o gradiente é propagado de volta para camadas anteriores, a multiplicação repetida pode tornar o gradiente extremamente pequeno. Como resultado, à medida que a rede se aprofunda, seu desempenho fica saturado ou começa a degradar rapidamente.

Eu aprendi sobre codificação de ResNets do curso DeepLearning.AI por Andrew Ng. Eu recomendo altamente este curso.

No meu repositório do Github , compartilhei dois cadernos, um que codifica o ResNet a partir do zero, conforme explicado no DeepLearning.AI e o outro que usa o modelo pré-formatado em Keras. Espero que você puxe o código e tente por si mesmo.

Ignorar conexão – a força do ResNet

A ResNet introduziu pela primeira vez o conceito de conexão skip. O diagrama abaixo ilustra a conexão de salto. A figura à esquerda está empilhando camadas de convolução juntas uma após a outra. À direita, ainda empilhamos camadas de convolução como antes, mas agora também adicionamos a entrada original à saída do bloco de convolução. Isso é chamado de conexão skip

Ignorar a imagem de conexão do DeepLearning.AI

Pode ser escrito como duas linhas de código:

 X_shortcut = X # Armazena o valor inicial de X em uma variável 
## Executa operações de norma de convolução + de lote em X
 X = Add () ([X, X_shortcut]) # conexão SKIP 

A codificação é bem simples, mas há uma consideração importante – já que X, X_shortcut acima são duas matrizes, você pode adicioná-las somente se elas tiverem a mesma forma. Portanto, se as operações da norma de convolução + de lote forem feitas de forma que a forma de saída seja a mesma, podemos simplesmente adicioná-las como mostrado abaixo.

Quando x e x_shortcut são da mesma forma

Caso contrário, o x_shortcut passa por uma camada de convolução escolhida de forma que a saída da mesma tenha a mesma dimensão da saída do bloco de convolução, conforme mostrado abaixo:

X_shortcut passa pelo bloco de convolução

No bloco de notas no Github, as duas funções identity_block e convolution_block são implementadas acima. Essas funções usam Keras para implementar camadas Convolution e Batch Norm com a ativação de ReLU. Saltar conexão é tecnicamente a linha X = Add()([X, X_shortcut]) .

Uma coisa importante a notar aqui é que a conexão de salto é aplicada antes da ativação do RELU, como mostrado no diagrama acima. Pesquisas descobriram que isso tem os melhores resultados.

Por que o Skip Connections funciona?

Esta é uma questão interessante. Eu acho que existem duas razões pelas quais as conexões Skip funcionam aqui:

  1. Eles atenuam o problema do gradiente de desaparecimento, permitindo que esse caminho de atalho alternativo para o gradiente flua através
  2. Eles permitem que o modelo aprenda uma função de identidade que garanta que a camada superior terá um desempenho tão bom quanto a camada inferior, e não pior

De fato, desde que as conexões de pulo do ResNet são usadas em muito mais arquiteturas de modelo, como a Rede Completamente Convolucional (FCN) e a U-Net . Eles são usados para fluir informações de camadas anteriores no modelo para camadas posteriores. Nestas arquiteturas, eles são usados para passar informações das camadas de downsampling para as camadas de upsampling.

Testando o modelo ResNet que construímos

Os blocos de identidade e convolução codificados no bloco de notas são então combinados para criar um modelo ResNet-50 com a arquitetura mostrada abaixo:

Modelo ResNet-50

O modelo ResNet-50 consiste em 5 estágios, cada um com um bloco de convolução e identidade. Cada bloco de convolução possui 3 camadas de convolução e cada bloco de identidade também possui 3 camadas de convolução. O ResNet-50 tem mais de 23 milhões de parâmetros treináveis.

Eu testei este modelo no conjunto de dados de sinais que também está incluído no meu repositório do Github. Este conjunto de dados tem imagens de mão correspondentes a 6 classes. Nós temos 1080 imagens de trem e 120 imagens de teste.

Conjunto de dados de sinais

Nossa ResNet-50 chega a 86% de precisão nos testes em 25 épocas de treinamento. Não é ruim!

Construindo ResNet em Keras usando biblioteca pré-formatada

Adorei codificar o modelo ResNet desde que ele me permitiu um melhor entendimento de uma rede que eu uso frequentemente em muitas tarefas de aprendizado de transferência relacionadas à classificação de imagens, localização de objetos, segmentação etc.

No entanto, para um uso mais regular, é mais rápido usar o ResNet-50 pré-formatado em Keras. Keras tem muitos desses modelos de backbone com seus pesos Imagenet disponíveis em sua biblioteca .

Modelo de Keras Pretrained

Eu carreguei um bloco de notas no meu Github que usa o Keras para carregar o ResNet-50 pré-formatado. Você pode carregar o modelo com um código de linha:

 base_model = applications.resnet50.ResNet50 (pesos = Nenhum , include_top = False , input_shape = (img_height, img_width, 3)) 

Aqui pesos = None desde que eu quero inicializar o modelo com pesos aleatórios como fiz no ResNet-50 I codificado. Caso contrário, também posso carregar os pesos pré-formatados do ImageNet. Eu defino include_top = False para não incluir o pool final e a camada totalmente conectada no modelo original. Eu adicionei Global Average Pooling e um dense layaer de saída ao modelo ResNet-50.

 x = base_model.output 
x = GlobalAveragePooling2D () (x)
x = abandono (0,7) (x)
predições = Densas (num_classes, activation = 'softmax') (x)
model = Model (inputs = base_model.input, outputs = previsões)

Como mostrado acima, Keras fornece uma interface muito conveniente para carregar os modelos pré-tratados, mas é importante codificar a ResNet também pelo menos uma vez para que você entenda o conceito e possa aplicar esse aprendizado a outra nova arquitetura que esteja criando.

O Keras ResNet chegou a uma precisão de 75% após o treinamento em 100 épocas com otimizador Adam e uma taxa de aprendizado de 0,0001. A precisão é um pouco menor do que o nosso modelo codificado e eu acho que isso tem a ver com inicializações de peso.

O Keras também fornece uma interface fácil para o aumento de dados, portanto, se você tiver uma chance, tente aumentar esse conjunto de dados e ver se isso resulta em melhor desempenho.

Conclusão

  • O ResNet é um poderoso modelo de backbone que é usado com muita frequência em muitas tarefas de visão de computador
  • ResNet usa conexão skip para adicionar a saída de uma camada anterior a uma camada posterior. Isso ajuda a mitigar o problema do gradiente de fuga
  • Você pode usar o Keras para carregar sua ResNet 50 pré-programada ou usar o código que compartilhei para codificar o ResNet você mesmo.

Outros escritos : http://deeplearninganalytics.org/blog

PS: Eu tenho minha própria consultoria de aprendizado profundo e amo trabalhar em problemas interessantes. Eu ajudei muitas startups a implementar soluções inovadoras baseadas em IA. Consulte-nos em – http://deeplearninganalytics.org/ .

Se você tem um projeto em que possamos colaborar, entre em contato comigo através do meu site ou em priya.toronto3@gmail.com

Referências