A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes
Neste artigo, vouche dicir como configurar un ambiente de aprendizaxe automática en 30 minutos, crear unha rede neuronal para o recoñecemento de imaxes e, a continuación, executar a mesma rede nun procesador gráfico (GPU).

En primeiro lugar, imos definir o que é unha rede neuronal.

No noso caso, este é un modelo matemático, así como a súa incorporación de software ou hardware, construído sobre o principio de organización e funcionamento das redes neuronais biolóxicas: redes de células nerviosas dun organismo vivo. Este concepto xurdiu mentres se estudaban os procesos que ocorren no cerebro e se trataba de modelar estes procesos.

As redes neuronais non están programadas no sentido habitual da palabra, están adestradas. A capacidade de aprender é unha das principais vantaxes das redes neuronais fronte aos algoritmos tradicionais. Tecnicamente, a aprendizaxe consiste en atopar os coeficientes de conexións entre neuronas. Durante o proceso de adestramento, a rede neuronal é capaz de identificar dependencias complexas entre os datos de entrada e os datos de saída, así como realizar a xeneralización.

Desde o punto de vista da aprendizaxe automática, unha rede neuronal é un caso especial de métodos de recoñecemento de patróns, análise discriminante, métodos de agrupación e outros métodos.

Оборудование

En primeiro lugar, vexamos o equipamento. Necesitamos un servidor co sistema operativo Linux instalado. O equipo necesario para operar sistemas de aprendizaxe automática é bastante potente e, como resultado, caro. Para aqueles que non teñan unha boa máquina á man, recoméndolles prestar atención ás ofertas dos provedores na nube. Podes alugar o servidor necesario rapidamente e pagar só polo tempo de uso.

En proxectos nos que é necesario crear redes neuronais, uso os servidores dun dos provedores de nube rusos. A compañía ofrece servidores na nube para alugar especificamente para a aprendizaxe automática con potentes procesadores gráficos (GPU) Tesla V100 de NVIDIA. En resumo: usar un servidor cunha GPU pode ser decenas de veces máis eficiente (rápido) en comparación cun servidor de custo similar que utiliza unha CPU (a coñecida unidade central de procesamento) para os cálculos. Isto conséguese debido ás características da arquitectura GPU, que afronta os cálculos máis rápido.

Para implementar os exemplos descritos a continuación, compramos o seguinte servidor durante varios días:

  • Disco SSD de 150 GB
  • RAM 32 GB
  • Procesador Tesla V100 de 16 Gb con 4 núcleos

Instalamos Ubuntu 18.04 na nosa máquina.

Configurando o medio ambiente

Agora imos instalar todo o necesario para traballar no servidor. Dado que o noso artigo é principalmente para principiantes, falarei sobre algúns puntos que lles serán útiles.

Gran parte do traballo ao configurar un ambiente realízase a través da liña de comandos. A maioría dos usuarios usan Windows como o seu sistema operativo. A consola estándar deste sistema operativo deixa moito que desexar. Polo tanto, utilizaremos unha ferramenta conveniente Cmder/. Descarga a versión mini e executa Cmder.exe. A continuación, cómpre conectarse ao servidor mediante SSH:

ssh root@server-ip-or-hostname

En lugar de server-ip-or-hostname, especifique o enderezo IP ou o nome DNS do seu servidor. A continuación, introduza o contrasinal e se a conexión se realiza correctamente, deberíamos recibir unha mensaxe semellante a esta.

Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)

A linguaxe principal para desenvolver modelos de ML é Python. E a plataforma máis popular para o seu uso en Linux é jibóia.

Instalámolo no noso servidor.

Comezamos actualizando o xestor de paquetes local:

sudo apt-get update

Instalar curl (utilidade de liña de comandos):

sudo apt-get install curl

Descarga a última versión de Anaconda Distribution:

cd /tmp
curl –O https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh

Imos comezar a instalación:

bash Anaconda3-2019.10-Linux-x86_64.sh

Durante o proceso de instalación, pediráselle que confirme o acordo de licenza. Tras a instalación exitosa, deberías ver isto:

Thank you for installing Anaconda3!

Agora creáronse moitos frameworks para o desenvolvemento de modelos de ML; traballamos cos máis populares: PyTorch и Fluxo tensor.

Usar o marco permítelle aumentar a velocidade de desenvolvemento e utilizar ferramentas preparadas para tarefas estándar.

Neste exemplo traballaremos con PyTorch. Instalémolo:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Agora necesitamos lanzar Jupyter Notebook, unha ferramenta de desenvolvemento popular para especialistas en ML. Permítelle escribir código e ver inmediatamente os resultados da súa execución. Jupyter Notebook está incluído con Anaconda e xa está instalado no noso servidor. Debes conectarte a el desde o noso sistema de escritorio.

Para iso, primeiro lanzaremos Jupyter no servidor especificando o porto 8080:

jupyter notebook --no-browser --port=8080 --allow-root

A continuación, abrindo outra pestana na nosa consola Cmder (menú superior - Cadro de diálogo Nova consola) conectarémonos a través do porto 8080 ao servidor mediante SSH:

ssh -L 8080:localhost:8080 root@server-ip-or-hostname

Cando introduzamos o primeiro comando, ofrecerémonos ligazóns para abrir Jupyter no noso navegador:

To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-18788-open.html
    Or copy and paste one of these URLs:
        http://localhost:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311
     or http://127.0.0.1:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311

Usemos a ligazón para localhost:8080. Copia o camiño completo e pégao na barra de enderezos do navegador local do teu PC. Abrirase o Jupyter Notebook.

Imos crear un novo caderno: Novo - Caderno - Python 3.

Comprobamos o correcto funcionamento de todos os compoñentes que instalamos. Introduzamos o código PyTorch de exemplo en Jupyter e executemos a execución (botón Executar):

from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)

O resultado debería ser algo así:

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Se tes un resultado semellante, configuramos todo correctamente e podemos comezar a desenvolver unha rede neuronal.

Creación dunha rede neuronal

Crearemos unha rede neuronal para o recoñecemento de imaxes. Tomemos isto como base liderado.

Usaremos o conxunto de datos CIFAR10 dispoñible para o público para adestrar a rede. Ten clases: “avión”, “coche”, “paxaro”, “gato”, “cervo”, “can”, “ra”, “cabalo”, “barco”, “camión”. As imaxes en CIFAR10 son 3x32x32, é dicir, imaxes en cor de 3 canles de 32x32 píxeles.

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes
Para traballar, usaremos o paquete creado por PyTorch para traballar con imaxes - torchvision.

Faremos os seguintes pasos en orde:

  • Carga e normalización de conxuntos de datos de adestramento e proba
  • Definición da rede neuronal
  • Formación en rede sobre datos de formación
  • Probas de rede sobre datos de proba
  • Repetimos o adestramento e as probas usando GPU

Imos executar todo o código a continuación en Jupyter Notebook.

Cargando e normalizando CIFAR10

Copia e executa o seguinte código en Jupyter:


import torch
import torchvision
import torchvision.transforms as transforms

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

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

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

A resposta debe ser:

Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
Extracting ./data/cifar-10-python.tar.gz to ./data
Files already downloaded and verified

Imos amosar varias imaxes de adestramento para probar:


import matplotlib.pyplot as plt
import numpy as np

# functions to show an image

def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()

# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Definición da rede neuronal

Consideremos primeiro como funciona unha rede neuronal para o recoñecemento de imaxes. Esta é unha rede simple punto a punto. Toma datos de entrada, pásaos por varias capas unha por unha e, finalmente, produce datos de saída.

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Imos crear unha rede similar no noso entorno:


import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net()

Tamén definimos unha función de perda e un optimizador


import torch.optim as optim

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

Formación en rede sobre datos de formación

Comecemos a adestrar a nosa rede neuronal. Ten en conta que despois de executar este código, terás que esperar un tempo ata que remate o traballo. Levoume 5 minutos. Leva tempo adestrar a rede.

 for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

Obtemos o seguinte resultado:

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Gardamos o noso modelo adestrado:

PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)

Probas de rede sobre datos de proba

Adestramos a rede utilizando un conxunto de datos de adestramento. Pero temos que comprobar se a rede aprendeu algo.

Probaremos isto predicindo a etiqueta de clase que saca a rede neuronal e probándoa para ver se é verdade. Se a predición é correcta, engadimos a mostra á lista de predicións correctas.
Imos mostrar unha imaxe do conxunto de probas:

dataiter = iter(testloader)
images, labels = dataiter.next()

# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Agora imos pedirlle á rede neuronal que nos diga o que hai nestas imaxes:


net = Net()
net.load_state_dict(torch.load(PATH))

outputs = net(images)

_, predicted = torch.max(outputs, 1)

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

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Os resultados parecen bastante bos: a rede identificou correctamente tres de cada catro imaxes.

Vexamos como funciona a rede en todo o conxunto de datos.


correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Parece que a rede sabe algo e está funcionando. Se determinase as clases ao chou, a precisión sería do 10%.

Agora vexamos que clases identifica mellor a rede:

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Parece que a rede é a mellor para identificar coches e barcos: 71% de precisión.

Así que a rede está funcionando. Agora imos tentar transferir o seu traballo ao procesador gráfico (GPU) e ver que cambia.

Adestramento dunha rede neuronal en GPU

En primeiro lugar, explicarei brevemente o que é CUDA. CUDA (Compute Unified Device Architecture) é unha plataforma de computación paralela desenvolvida por NVIDIA para a computación xeral en unidades de procesamento de gráficos (GPU). Con CUDA, os desenvolvedores poden acelerar drasticamente as aplicacións informáticas aproveitando o poder das GPU. Esta plataforma xa está instalada no noso servidor que compramos.

Imos primeiro definir a nosa GPU como o primeiro dispositivo cuda visible.

device = torch . device ( "cuda:0" if torch . cuda . is_available () else "cpu" )
# Assuming that we are on a CUDA machine, this should print a CUDA device:
print ( device )

A túa primeira rede neuronal nunha unidade de procesamento de gráficos (GPU). Guía para principiantes

Envío da rede á GPU:

net.to(device)

Tamén teremos que enviar entradas e obxectivos en cada paso á GPU:

inputs, labels = data[0].to(device), data[1].to(device)

Volvemos adestrar a rede na GPU:

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
    inputs, labels = data[0].to(device), data[1].to(device)

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

Esta vez, o adestramento en rede durou uns 3 minutos. Lembremos que a mesma etapa nun procesador convencional duraba 5 minutos. A diferenza non é significativa, isto ocorre porque a nosa rede non é tan grande. Cando se usan grandes matrices para adestrar, a diferenza entre a velocidade da GPU e un procesador tradicional aumentará.

Iso parece ser todo. O que conseguimos facer:

  • Observamos o que é unha GPU e seleccionamos o servidor no que está instalada;
  • Configuramos un entorno de software para crear unha rede neuronal;
  • Creamos unha rede neuronal para o recoñecemento de imaxes e adestramos;
  • Repetimos o adestramento da rede usando a GPU e recibimos un aumento de velocidade.

Estarei encantado de responder ás preguntas nos comentarios.

Fonte: www.habr.com

Engadir un comentario