Continuando minha série sobre a construção de redes neurais convolucionais clássicas que revolucionaram o campo da visão computacional na última década, em seguida, construiremos a rede VGG, uma rede convolucional muito profunda, a partir do zero usando PyTorch. Você pode ver os artigos anteriores da série no meu perfil, principalmente LeNet5 e AlexNet.
Como antes, nossa análise será voltada para a arquitetura e intuição por trás da VGG e como os resultados eram na época. Em seguida, exploraremos o nosso conjunto de dados, CIFAR100, e carregaremos em nosso programa usando código eficiente em memória. Em seguida, implementaremos a VGG16 (o número se refere ao número de camadas, basicamente existem duas versões: VGG16 e VGG19) a partir do zero usando PyTorch e, em seguida, treinaremos com o nosso conjunto de dados e avaliaremos no nosso conjunto de testes para ver como ela se comporta com dados não vistos.
VGG
Com base no trabalho de AlexNet, o VGG se concentra em outro aspecto crucial das Redes Neurais Convolucionais (CNNs), a profundidade. Foi desenvolvido por Simonyan e Zisserman. Normalmente consiste em 16 camadas convolucionais, mas pode ser estendido a 19 camadas (portanto as duas versões, VGG-16 e VGG-19). Todas as camadas convolucionais consistem em filtros de 3×3. Você pode ler mais sobre a rede no artigo oficial aqui
Arquitetura VGG16. Fonte
Carregamento de Dados
Conjunto de Dados
Antes de construir o modelo, uma das coisas mais importantes em qualquer projeto de Aprendizagem de Máquina é carregar, analisar e pré-processar o conjunto de dados. Neste artigo, usaremos o conjunto de dados CIFAR-100. Este conjunto de dados é semelhante ao CIFAR-10, com a diferença de que ele tem 100 classes com 600 imagens cada. Há 500 imagens de treinamento e 100 imagens de teste por classe. As 100 classes no CIFAR-100 são agrupadas em 20 superclasses. Cada imagem vem com um “fine” label (a classe à qual ela pertence) e um “coarse” label (a superclasse à qual ela pertence). Aqui, usaremos o label “fine”. Aqui está a lista das classes no CIFAR-100:
Lista de classes para o conjunto de dados CIFAR-100
Importando as bibliotecas
Principalmente, trabalharmos com torch
(usado para construir o modelo e treiná-lo), torchvision
(para carregar/processar dados, contém conjuntos de dados e métodos para processar esses conjuntos de dados em visão computacional) e numpy
(para manipulação matemática). Também definiremos uma variável device
para que o programa use a GPU, se disponível.
Carregando os Dados
torchvision
é uma biblioteca que fornece acesso fácil a toneladas de conjuntos de dados de visão computacional e métodos para pré-processar esses conjuntos de dados de uma maneira fácil e intuitiva
- Nós definimos uma função
data_loader
que retorna ou dados de treinamento/validação ou dados de teste dependendo dos argumentos - Começamos definindo a variável
normalize
com as médias e desvios padrão de cada canal (vermelho, verde e azul) no conjunto de dados. Esses valores podem ser calculados manualmente, mas estão também disponíveis online. Isso é usado na variáveltransform
onde redimensionamos os dados, convertemos-os em tensores e depois normalizamos-os - Se o argumento
test
for verdadeiro, simplesmente carregamos a divisão de teste do conjunto de dados e o retornamos usando carregadores de dados (explicado abaixo) - No caso em que
test
for falso (comportamento padrão também), carregamos a divisão de treinamento do conjunto de dados e dividimos-lo aleatoriamente em treinamento e validação (0.9:0.1) - Finalmente, fazemos uso de carregadores de dados. Isto pode não afetar o desempenho no caso de um pequeno conjunto de dados como o CIFAR100, mas pode realmente impedir o desempenho no caso de grandes conjuntos de dados e é geralmente considerada uma boa prática. Os carregadores de dados permitem que nós iteramos pelos dados em lotes, e o dado é carregado enquanto estiver iterando e não é carregado todo de uma só vez no início do seu RAM.
VGG16 a partir do zero
Para construir o modelo a partir do zero, precisamos primeiro entender como funcionam as definições de modelos em torch
e os diferentes tipos de camadas que vamos usar aqui:
- Todos os modelos personalizados precisam herdar da classe
nn.Module
porque ela fornece algumas funcionalidades básicas que ajudam o modelo a treinar. - Em segundo lugar, há duas coisas principais que precisamos fazer. Primeiro, definir as diferentes camadas do nosso modelo dentro da função
__init__
e a sequência em que essas camadas serão executadas na entrada dentro da funçãoforward
Vamos agora definir os diferentes tipos de camadas que estamos usando aqui:
nn.Conv2d
: Essas são as camadas convolucionais que aceitam o número de canais de entrada e saída como argumentos, juntamente com o tamanho do kernel para o filtro. Ela também aceita quaisquer passos ou preenchimento se você quiser aplicar essesnn.BatchNorm2d
: Isso aplica normalização por lote à saída da camada convolucionalnn.ReLU
: Essa é a ativação aplicada a várias saídas na redenn.MaxPool2d
: Isto aplica max pooling na saída com o tamanho do kernel dadonn.Dropout
: Isso é usado para aplicar dropout na saída com uma probabilidade dadann.Linear
: Essencialmente, isto é uma camada totalmente conectadann.Sequential
: Technicamente, isto não é um tipo de camada, mas ajuda na combinação de diferentes operações que fazem parte do mesmo passo
Usando esse conhecimento, agora podemos construir o nosso modelo VGG16 usando a arquitetura descrita no artigo:
VGG16 a Parte
Hiperparâmetros
Um dos importantes aspectos de qualquer projeto de máquina ou aprendizado profundo é a otimização dos hiperparâmetros. Aqui, não vamos experimentar com valores diferentes para eles, mas precisaremos defini-los antes. Isso inclui definir o número de épocas, tamanho do lote, taxa de aprendizagem, função de perda juntamente com o otimizador
Definindo os hiperparâmetros
Treinamento
Agora estamos prontos para treinar nosso modelo. Primeiro vamos olhar para como treinamos nosso modelo em torch
e depois olharmos para o código:
- Para cada época, passamos pelas imagens e rótulos dentro de nossa
train_loader
e movemos essas imagens e rótulos para a GPU se disponível. Isso acontece automaticamente - Usamos o nosso modelo para fazer previsões nos rótulos (
model(images)
) e depois calculamos a perda entre as previsões e os rótulos verdadeiros usando nossa função de perda (criterion(outputs, labels)
) - Então usamos essa perda para propagar de volta (
loss.backward
) e atualizar as pesos (optimizer.step()
). Mas lembre-se de definir os gradientes para zero antes de cada atualização. Isso é feito usandooptimizer.zero_grad()
- Também, no final de cada época, usamos nossa base de validação para calcular a precisão do modelo. Nesse caso, não precisamos de gradientes, portanto usamos
with torch.no_grad()
para avaliação mais rápida
Agora, combinamos tudo isso no seguinte código:
Treino
Podemos ver a saída do código acima como segue, que mostra que o modelo está realmente aprendendo, pois a perda está decrescendo com cada época:
Perdas de Treino
Testando
Para testar, usamos exatamente o mesmo código como validação, mas com o test_loader
:
Testando
Usando o código acima e treinando o modelo por 20 épocas, conseguimos alcançar uma precisão de 75% no conjunto de teste.
Conclusão
Vamos concluir agora o que fizemos neste artigo:
- Começamos entendendo a arquitetura e diferentes tipos de camadas no modelo VGG-16
- A seguir, carregamos e pré-processamos o conjunto de dados CIFAR100 usando
torchvision
- Em seguida, usamos
PyTorch
para construir nosso modelo VGG-16 de raiz em diante, juntamente com o entendimento de diferentes tipos de camadas disponíveis emtorch
- Finalmente, treinamos e testamos nosso modelo no conjunto de dados CIFAR100, e o modelo pareceu se sair bem no conjunto de teste com 75% de precisão
Trabalho Futuro
Usando este artigo, você obtém uma boa introdução e aprendizado prático, mas você aprenderá muito mais se extende isso e vê o que você pode fazer de else:
- Você pode tentar usar diferentes conjuntos de dados. Um desses conjuntos de dados é o CIFAR10 ou um subconjunto do conjunto de dados ImageNet.
- Você pode experimentar com diferentes hiperparâmetros e ver a melhor combinação deles para o modelo
- Finalmente, você pode tentar adicionar ou remover camadas do conjunto de dados para ver o impacto delas na capacidade do modelo. Ainda melhor, tente construir a versão VGG-19 deste modelo.
Source:
https://www.digitalocean.com/community/tutorials/vgg-from-scratch-pytorch