Continuando minha série sobre a construção de redes neurais convolucionais clássicas que revolucionaram o campo da visão computacional nos últimos 1-2 décadas, vamos construir agora 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, vamos olhar 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 ele no nosso programa usando código eficiente em memória. Em seguida, implementaremos a VGG16 (o número refere-se ao número de camadas, existem duas versões básicas, VGG16 e VGG19) a partir do zero usando PyTorch e então treinaremos-la em nosso conjunto de dados, além de avaliá-la no nosso conjunto de teste para ver como ela se comporta em dados não vistos.
VGG
Com base no trabalho de AlexNet, o VGG se concentra em outro aspecto crucial das Redes Convolucionais Neurais (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 Aprendizado de Máquina é carregar, analisar e pré-processar o conjunto de dados. Neste artigo, nós vamos usar o conjunto de dados CIFAR-100. Este conjunto de dados é semelhante ao CIFAR-10, exceto 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 para qual ela pertence) e um “coarse” label (a superclasse para qual ela pertence). Nós vamos usar o “fine” label aqui. Aqui está a lista de classes no CIFAR-100:
Lista de Classes para o conjunto de dados CIFAR-100
Importando as bibliotecas
Nós vamos trabalhar principalmente 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). Nós também vamos definir uma variável device
para que o programa possa usar o GPU, se disponível.
Carregando os Dados
torchvision
é uma biblioteca que fornece acesso fácil a montes 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 seja 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ões 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) - Caso o
test
seja falso (comportamento padrão também), carregamos a divisão de treinamento do conjunto de dados e dividimos aleatoriamente em treinamento e validação (0.9:0.1) - Finalmente, usamos 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 é considerado常规mente uma boa prática. Carregadores de dados permitem que iteramos pelos dados em lotes, e o dado é carregado enquanto iteramos 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, existem 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 no input na funçãoforward
Vamos agora definir os diferentes tipos de camadas que estamos usando aqui:
nn.Conv2d
: Estas são as camadas de convolução que aceitam o número de canais de entrada e saída como argumentos, juntamente com o tamanho do kernel para o filtro. Também aceita quaisquer strides ou padding se você quiser aplicar essesnn.BatchNorm2d
: Isso aplica normalização em lote à saída da camada de convoluçãonn.ReLU
: Esta é a ativação aplicada a várias saídas na redenn.MaxPool2d
: Isto aplica o pooling máximo 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
: Isto não é tecnicamente um tipo de camada, mas ajuda a combinar diferentes operações que fazem parte do mesmo passo
Usando este conhecimento, agora podemos construir o nosso modelo VGG16 usando a arquitetura descrita no artigo:
VGG16 de raiz
Hiperparâmetros
Um dos componentes importantes de qualquer projeto de machine learning ou aprendizado profundo é otimizar os hiperparâmetros. Aqui, nós não vamos experimentar com valores diferentes para eles, mas vamos ter que defini-los antes mesmo. Eles incluem definir o número de épocas, tamanho do lote, taxa de aprendizado, função de perda juntamente com o otimizador
Configurando os hiperparâmetros
Treinamento
Agora estamos prontos para treinar o nosso modelo. Primeiro, vamos olhar para como treinamos o nosso modelo em torch
e depois olharmos para o código:
- Para cada época, passamos pelas imagens e rótulos dentro de nosso
train_loader
e movemos essas imagens e rótulos para a GPU se disponível. Isso acontece automaticamente - Usamos o nosso modelo para prever sobre os rótulos (
model(images)
) e depois calculamos a perda entre as previsões e os rótulos reais usando nossa função de perda (criterion(outputs, labels)
) - Em seguida, 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 o nosso conjunto de validação para calcular a precisão do modelo. Neste caso, não precisamos de gradientes, então 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 seguinte, que mostra que o modelo está realmente aprendendo, pois a perda está decrescendo com cada época:
Perdas de treinamento
Testando
Para testar, usamos exatamente o mesmo código que para 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 o que fizemos neste artigo:
- Começamos entendendo a arquitetura e diferentes tipos de camadas na modelo VGG-16
- A seguir, carregamos e pré-processamos o conjunto de dados CIFAR100 usando
torchvision
- Em seguida, usamos
PyTorch
para construir o nosso modelo VGG-16 de raiz, juntamente com o entendimento de diferentes tipos de camadas disponíveis emtorch
- Finalmente, treinamos e testamos o nosso modelo no conjunto de dados CIFAR100, e o modelo pareceu-se 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 esticar isto e ver o que você pode fazer de mais:
- Pode tentar usar diferentes conjuntos de dados. Um desses conjuntos de dados é o CIFAR10 ou um subconjunto do conjunto de dados ImageNet.
- Pode experimentar com diferentes hiperparâmetros e ver a melhor combinação deles para o modelo
- Finalmente, pode tentar adicionar ou remover camadas do conjunto de dados para ver o impacto delas na capacidade do modelo. Ainda melhor, tentar construir a versão VGG-19 deste modelo.
Source:
https://www.digitalocean.com/community/tutorials/vgg-from-scratch-pytorch