Tutorial PyTorch: regressão, exemplo de classificação de imagens

Resumo do tutorial Pytorch

Neste tutorial pytorch, você aprenderá todos os conceitos do zero. Este tutorial cobre tópicos básicos a avançados, como definição de pytorch, vantagens e desvantagens de pytorch, comparação, instalação, estrutura pytorch, regressão e classificação de imagens. Este tutorial pytorch é totalmente gratuito.

O que é o PyTorch?

PyTorch é uma biblioteca de aprendizado de máquina baseada em Torch de código aberto para processamento de linguagem natural usando Python. É semelhante ao NumPy, mas com suporte poderoso para GPU. Ele oferece gráficos computacionais dinâmicos que você pode modificar em qualquer lugar com a ajuda do autograd. PyTorch também é mais rápido do que alguns outros frameworks. Foi desenvolvido pelo Grupo de Pesquisa de IA do Facebook em 2016.

Vantagens e desvantagens do PyTorch

A seguir estão as vantagens e desvantagens do PyTorch:

Vantagens do PyTorch

  1. Biblioteca Simples
    O código PyTorch é simples. É fácil de entender e você usa a biblioteca instantaneamente. Por exemplo, dê uma olhada no trecho de código abaixo:
class Net(torch.nn.Module):
   def __init__(self):
       super(Net, self).__init__()
       self.layer = torch.nn.Linear(1, 1)

   def forward(self, x):
       x = self.layer(x)      
       return x

Conforme mencionado acima, você pode definir o modelo de rede facilmente e entender o código rapidamente, sem muito treinamento.

  1. Gráfico Computacional Dinâmico

Gráfico Computacional Dinâmico

Fonte da imagem: Explorando o aprendizado profundo com PyTorch

Pytorch oferece Gráfico Computacional Dinâmico (DAG). Gráficos computacionais são uma forma de expressar expressões matemáticas em modelos de grafos ou teorias como nós e arestas. O nó fará a operação matemática, e a aresta é um Tensor que será alimentado nos nós e carrega a saída do nó no Tensor.

DAG é um gráfico que possui formato arbitrário e é capaz de realizar operações entre diferentes gráficos de entrada. A cada iteração, um novo gráfico é criado. Assim, é possível ter a mesma estrutura de gráfico ou criar um novo gráfico com uma operação diferente, ou podemos chamá-lo de gráfico dinâmico.

  1. Melhor Performance

Comunidades e pesquisadores avaliam e comparam estruturas para ver qual delas é mais rápida. Um repositório GitHub Referência em estruturas de aprendizado profundo e GPUs relataram que PyTorch é mais rápido que o outro framework em termos de imagens processadas por segundo.

Como você pode ver abaixo, os gráficos de comparação com vgg16 e resnet152

Vantagens do PyTorch

Vantagens do PyTorch

  1. Nativo Python

PyTorch é mais baseado em python. Por exemplo, se quiser treinar um modelo, você pode usar fluxo de controle nativo, como loops e recursões, sem a necessidade de adicionar mais variáveis ​​ou sessões especiais para poder executá-los. Isso é muito útil para o processo de treinamento.

Pytorch também implementa Programação Imperativa e é definitivamente mais flexível. Assim, é possível imprimir o valor do tensor no meio de um processo de computação.

Desvantagem do PyTorch

PyTorch requer aplicativos de terceiros para visualização. Também precisa de um servidor API para produção.

A seguir neste tutorial do PyTorch, aprenderemos sobre a diferença entre PyTorch e TensorFlow.

PyTorch vs. Fluxo tensor

Parâmetro PyTorch Tensorflow
Definição de Modelo O modelo é definido em uma subclasse e oferece pacotes fáceis de usar O modelo é definido com muitos e você precisa entender a sintaxe
Suporte GPU Sim Sim
Tipo de Gráfico Dinâmico Estático
Ferramentas Nenhuma ferramenta de visualização Você pode usar a ferramenta de visualização Tensorboard
Comunidade A comunidade continua crescendo Grandes comunidades ativas

Instalando o PyTorch

Linux

É simples instalá-lo no Linux. Você pode optar por usar um ambiente virtual ou instalá-lo diretamente com acesso root. Digite este comando no terminal

pip3 install --upgrade torch torchvision

AWS SageMaker

Sagemaker é uma das plataformas em Amazon Serviço de internet que oferece um poderoso mecanismo de aprendizado de máquina com configurações de aprendizado profundo pré-instaladas para cientistas de dados ou desenvolvedores criarem, treinarem e implantarem modelos em qualquer escala.

Primeiro abra o Amazon Sábio console e clique em Criar instância de notebook e preencha todos os detalhes do seu notebook.

AWS SageMaker

Próxima etapa, clique em Abrir para iniciar sua instância de notebook.

AWS SageMaker

Finalmente, em Jupyter, Clique em Novo e escolha conda_pytorch_p36 e você estará pronto para usar sua instância de notebook com o Pytorch instalado.

A seguir neste tutorial do PyTorch, aprenderemos sobre os fundamentos da estrutura PyTorch.

Noções básicas da estrutura PyTorch

Vamos aprender os conceitos básicos do PyTorch antes de nos aprofundarmos. PyTorch usa Tensor para cada variável semelhante ao ndarray do numpy, mas com suporte para computação GPU. Aqui explicaremos o modelo de rede, função de perda, Backprop e Optimizer.

Modelo de rede

A rede pode ser construída subclassificando torch.nn. Existem 2 partes principais,

  1. A primeira parte é definir os parâmetros e camadas que você utilizará
  2. A segunda parte é a tarefa principal chamada processo forward que receberá uma entrada e preverá a saída.
Import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
 def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(3, 20, 5)
        self.conv2 = nn.Conv2d(20, 40, 5)
self.fc1 = nn.Linear(320, 10)

def forward(self, x):
       x = F.relu(self.conv1(x))
       x = F.relu(self.conv2(x))
       x = x.view(-1, 320)
       x = F.relu(self.fc1(x))
       return F.log_softmax(x)

net = Model()

Como você pode ver acima, você cria uma classe de nn.Module chamada Model. Ele contém 2 camadas Conv2d e uma camada Linear. A primeira camada conv2d recebe uma entrada de 3 e o formato de saída de 20. A segunda camada receberá uma entrada de 20 e produzirá um formato de saída de 40. A última camada é uma camada totalmente conectada no formato de 320 e produzirá uma saída de 10.

O processo de encaminhamento pegará uma entrada de X e a alimentará na camada conv1 e executará a função ReLU,

Da mesma forma, também alimentará a camada conv2. Depois disso, o x será remodelado em (-1, 320) e alimentado na camada FC final. Antes de enviar a saída, você usará a função de ativação softmax.

O processo de retrocesso é definido automaticamente pelo autograd, portanto, você só precisa definir o processo de encaminhamento.

Função de perda

A função de perda é usada para medir quão bem o modelo de previsão é capaz de prever os resultados esperados. PyTorch já possui muitas funções de perda padrão no módulo torch.nn. Por exemplo, você pode usar a perda de entropia cruzada para resolver um problema de classificação PyTorch multiclasse. É fácil definir a função de perda e calcular as perdas:

loss_fn = nn.CrossEntropyLoss()

#training process
loss = loss_fn(out, target)

É fácil usar seu próprio cálculo de função de perda com PyTorch.

Apoio traseiro

Para realizar a retropropagação, basta chamar los.backward(). O erro será calculado, mas lembre-se de limpar o gradiente existente com zero_grad()

net.zero_grad() # to clear the existing gradient
loss.backward() # to perform backpropragation

Optimizer

O torch.optim fornece algoritmos de otimização comuns. Você pode definir um otimizador com uma etapa simples:

optimizer = torch.optim.SGD(net.parameters(), lr = 0.01, momentum=0.9)

Você precisa passar os parâmetros do modelo de rede e a taxa de aprendizado para que a cada iteração os parâmetros sejam atualizados após o processo backprop.

Regressão Simples com PyTorch

Vamos aprender regressão simples com exemplos do PyTorch:

Etapa 1) Criando nosso modelo de rede

Nosso modelo de rede é uma camada linear simples com formato de entrada e saída 1.

from __future__ import print_function

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable

class Net(nn.Module):
   def __init__(self):
       super(Net, self).__init__()
       self.layer = torch.nn.Linear(1, 1)

   def forward(self, x):
       x = self.layer(x)      
       return x

net = Net()
print(net)

E a saída da rede deveria ser assim

Net(
  (hidden): Linear(in_features=1, out_features=1, bias=True)
)

Etapa 2) Dados de teste

Antes de iniciar o processo de treinamento, você precisa conhecer nossos dados. Você cria uma função aleatória para testar nosso modelo. Y = x3 sen(x)+ 3x+0.8 rands(100)

# Visualize our data
import matplotlib.pyplot as plt
import numpy as np

x = np.random.rand(100)
y = np.sin(x) * np.power(x,3) + 3*x + np.random.rand(100)*0.8

plt.scatter(x, y)
plt.show()

Aqui está o gráfico de dispersão da nossa função:

Gráfico de dispersão de regressão simples com PyTorch

Antes de iniciar o processo de treinamento, você precisa converter a matriz numpy em variáveis ​​​​suportadas pelo Torch e autograd, conforme mostrado no exemplo de regressão PyTorch abaixo.

# convert numpy array to tensor in shape of input size
x = torch.from_numpy(x.reshape(-1,1)).float()
y = torch.from_numpy(y.reshape(-1,1)).float()
print(x, y)

Etapa 3) Otimizador e Perda

A seguir, você deve definir o Otimizador e a Função de Perda para nosso processo de treinamento.

# Define Optimizer and Loss Function
optimizer = torch.optim.SGD(net.parameters(), lr=0.2)
loss_func = torch.nn.MSELoss()

Etapa 4) Treinamento

Agora vamos iniciar nosso processo de treinamento. Com uma época de 250, você irá iterar nossos dados para encontrar o melhor valor para nossos hiperparâmetros.

inputs = Variable(x)
outputs = Variable(y)
for i in range(250):
   prediction = net(inputs)
   loss = loss_func(prediction, outputs) 
   optimizer.zero_grad()
   loss.backward()        
   optimizer.step()       

   if i % 10 == 0:
       # plot and show learning process
       plt.cla()
       plt.scatter(x.data.numpy(), y.data.numpy())
       plt.plot(x.data.numpy(), prediction.data.numpy(), 'r-', lw=2)
       plt.text(0.5, 0, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 10, 'color':  'red'})
       plt.pause(0.1)

plt.show()

Etapa 5) Resultado

Como você pode ver abaixo, você executou com sucesso a regressão PyTorch com uma rede neural. Na verdade, a cada iteração, a linha vermelha no gráfico será atualizada e mudará de posição para se ajustar aos dados. Mas nesta imagem, ela mostra apenas o resultado final conforme mostrado no exemplo PyTorch abaixo:

Gráfico de dispersão do resultado da regressão simples

Exemplo de classificação de imagens com PyTorch

Um dos métodos populares para aprender o básico de deep learning está com o conjunto de dados MNIST. É o “Hello World” no aprendizado profundo. O conjunto de dados contém números manuscritos de 0 a 9 com o total de 60,000 amostras de treinamento e 10,000 amostras de teste já rotuladas com o tamanho de 28×28 pixels.

Classificação de imagens com PyTorch

Etapa 1) Pré-processar os dados

Na primeira etapa deste exemplo de classificação PyTorch, você carregará o conjunto de dados usando o módulo torchvision.

Antes de iniciar o processo de treinamento, você precisa compreender os dados. O Torchvision carregará o conjunto de dados e transformará as imagens com os requisitos apropriados para a rede, como formato e normalização das imagens.

import torch
import torchvision
import numpy as np
from torchvision import datasets, models, transforms

# This is used to transform the images to Tensor and normalize it
transform = transforms.Compose(
   [transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

training = torchvision.datasets.MNIST(root='./data', train=True,
                                       download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(training, batch_size=4,
                                         shuffle=True, num_workers=2)

testing = torchvision.datasets.MNIST(root='./data', train=False,
                                      download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(testing, batch_size=4,
                                        shuffle=False, num_workers=2)

classes = ('0', '1', '2', '3',
          '4', '5', '6', '7', '8', '9')
         
import matplotlib.pyplot as plt
import numpy as np

#create an iterator for train_loader
# get random training images
data_iterator = iter(train_loader)
images, labels = data_iterator.next()

#plot 4 images to visualize the data
rows = 2
columns = 2
fig=plt.figure()
for i in range(4):
   fig.add_subplot(rows, columns, i+1)
   plt.title(classes[labels[i]])
   img = images[i] / 2 + 0.5     # this is for unnormalize the image
   img = torchvision.transforms.ToPILImage()(img)
   plt.imshow(img)
plt.show()

A função transform converte as imagens em tensor e normaliza o valor. A função torchvision.transforms.MNIST, irá baixar o conjunto de dados (se não estiver disponível) no diretório, definir o conjunto de dados para treinamento se necessário e fazer o processo de transformação.

Para visualizar o conjunto de dados, você usa o data_iterator para obter o próximo lote de imagens e rótulos. Você usa matplot para plotar essas imagens e seus rótulos apropriados. Como você pode ver abaixo nossas imagens e seus rótulos.

Exemplo de classificação de imagens com PyTorch

Etapa 2) Configuração do modelo de rede

Agora, neste exemplo do PyTorch, você criará uma rede neural simples para classificação de imagens do PyTorch.

Aqui, apresentamos outra maneira de criar o modelo de rede no PyTorch. Usaremos nn.Sequential para criar um modelo de sequência em vez de criar uma subclasse de nn.Module.

import torch.nn as nn

# flatten the tensor into 
class Flatten(nn.Module):
   def forward(self, input):
       return input.view(input.size(0), -1)

#sequential based model
seq_model = nn.Sequential(
           nn.Conv2d(1, 10, kernel_size=5),
           nn.MaxPool2d(2),
           nn.ReLU(),
           nn.Dropout2d(),
           nn.Conv2d(10, 20, kernel_size=5),
           nn.MaxPool2d(2),
           nn.ReLU(),
           Flatten(),
           nn.Linear(320, 50),
           nn.ReLU(),
           nn.Linear(50, 10),
           nn.Softmax(),
         )

net = seq_model
print(net)

Aqui está o resultado do nosso modelo de rede

Sequential(
  (0): Conv2d(1, 10, kernel_size=(5, 5), stride=(1, 1))
  (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (2): ReLU()
  (3): Dropout2d(p=0.5)
  (4): Conv2d(10, 20, kernel_size=(5, 5), stride=(1, 1))
  (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (6): ReLU()
  (7): Flatten()
  (8): Linear(in_features=320, out_features=50, bias=True)
  (9): ReLU()
  (10): Linear(in_features=50, out_features=10, bias=True)
  (11): Softmax()
)

Explicação da rede

  1. A sequência é que a primeira camada é uma camada Conv2D com formato de entrada 1 e formato de saída 10 com tamanho de kernel 5
  2. Em seguida, você tem uma camada MaxPool2D
  3. Uma função de ativação ReLU
  4. uma camada Dropout para eliminar valores de baixa probabilidade.
  5. Em seguida, um segundo Conv2d com formato de entrada 10 da última camada e formato de saída 20 com tamanho de kernel 5
  6. Em seguida, uma camada MaxPool2d
  7. Função de ativação ReLU.
  8. Depois disso, você achatará o tensor antes de alimentá-lo na camada Linear
  9. A Camada Linear mapeará nossa saída na segunda camada Linear com função de ativação softmax

Etapa 3) Treine o modelo

Antes de iniciar o processo de treinamento, é necessário configurar o critério e a função do otimizador.

Para o critério, você usará CrossEntropyLoss. Para o Otimizador, você usará o SGD com uma taxa de aprendizado de 0.001 e um impulso de 0.9, conforme mostrado no exemplo PyTorch abaixo.

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

O processo de encaminhamento pegará o formato de entrada e o passará para a primeira camada conv2d. A partir daí, ele será alimentado no maxpool2d e finalmente colocado na função de ativação ReLU. O mesmo processo ocorrerá na segunda camada conv2d. Depois disso, a entrada será remodelada em (-1,320) e alimentada na camada fc para prever a saída.

Agora, você iniciará o processo de treinamento. Você irá iterar em nosso conjunto de dados 2 vezes ou com uma época de 2 e imprimir a perda atual a cada lote de 2000.

for epoch in range(2): 

#set the running loss at each epoch to zero
   running_loss = 0.0
# we will enumerate the train loader with starting index of 0
# for each iteration (i) and the data (tuple of input and labels)
   for i, data in enumerate(train_loader, 0):
       inputs, labels = data

# clear the gradient
       optimizer.zero_grad()

#feed the input and acquire the output from network
       outputs = net(inputs)

#calculating the predicted and the expected loss
       loss = criterion(outputs, labels)

#compute the gradient
       loss.backward()

#update the parameters
       optimizer.step()

       # print statistics
       running_loss += loss.item()
       if i % 1000 == 0:
           print('[%d, %5d] loss: %.3f' %
                 (epoch + 1, i + 1, running_loss / 1000))
           running_loss = 0.0

Em cada época, o enumerador obterá a próxima tupla de entrada e os rótulos correspondentes. Antes de alimentarmos nosso modelo de rede com a entrada, precisamos limpar o gradiente anterior. Isso é necessário porque após o processo reverso (processo de retropropagação), o gradiente será acumulado em vez de substituído. Em seguida, calcularemos as perdas da produção prevista a partir da produção esperada. Depois disso, faremos uma retropropagação para calcular o gradiente e, por fim, atualizaremos os parâmetros.

Aqui está o resultado do processo de treinamento

[1, 	1] loss: 0.002
[1,  1001] loss: 2.302
[1,  2001] loss: 2.295
[1,  3001] loss: 2.204
[1,  4001] loss: 1.930
[1,  5001] loss: 1.791
[1,  6001] loss: 1.756
[1,  7001] loss: 1.744
[1,  8001] loss: 1.696
[1,  9001] loss: 1.650
[1, 10001] loss: 1.640
[1, 11001] loss: 1.631
[1, 12001] loss: 1.631
[1, 13001] loss: 1.624
[1, 14001] loss: 1.616
[2, 	1] loss: 0.001
[2,  1001] loss: 1.604
[2,  2001] loss: 1.607
[2,  3001] loss: 1.602
[2,  4001] loss: 1.596
[2,  5001] loss: 1.608
[2,  6001] loss: 1.589
[2,  7001] loss: 1.610
[2,  8001] loss: 1.596
[2,  9001] loss: 1.598
[2, 10001] loss: 1.603
[2, 11001] loss: 1.596
[2, 12001] loss: 1.587
[2, 13001] loss: 1.596
[2, 14001] loss: 1.603

Etapa 4) Teste o modelo

Depois de treinar nosso modelo, você precisa testar ou avaliar outros conjuntos de imagens.

Usaremos um iterador para test_loader, e ele gerará um lote de imagens e rótulos que serão passados ​​para o modelo treinado. A saída prevista será exibida e comparada com a saída esperada.

#make an iterator from test_loader
#Get a batch of training images
test_iterator = iter(test_loader)
images, labels = test_iterator.next()

results = net(images)
_, predicted = torch.max(results, 1)

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

fig2 = plt.figure()
for i in range(4):
   fig2.add_subplot(rows, columns, i+1)
   plt.title('truth ' + classes[labels[i]] + ': predict ' + classes[predicted[i]])
   img = images[i] / 2 + 0.5     # this is to unnormalize the image
   img = torchvision.transforms.ToPILImage()(img)
   plt.imshow(img)
plt.show()

Exemplo de classificação de imagens com PyTorch

Resumo

  • PyTorch é um Torch de código aberto baseado Machine Learning biblioteca para processamento de linguagem natural utilização Python.
  • Vantagens do PyTorch: 1) Biblioteca Simples, 2) Gráfico Computacional Dinâmico, 3) Melhor Desempenho, 4) Nativo Python
  • PyTorch usa Tensor para cada variável semelhante ao ndarray do numpy, mas com suporte para computação GPU.
  • Um dos métodos populares para aprender os fundamentos do aprendizado profundo é com o conjunto de dados MNIST.