Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători
În acest articol, vă voi spune cum să configurați un mediu de învățare automată în 30 de minute, să creați o rețea neuronală pentru recunoașterea imaginilor și apoi să rulați aceeași rețea pe un procesor grafic (GPU).

Mai întâi, să definim ce este o rețea neuronală.

În cazul nostru, acesta este un model matematic, precum și întruchiparea software sau hardware, construit pe principiul organizării și funcționării rețelelor neuronale biologice - rețele de celule nervoase ale unui organism viu. Acest concept a apărut în timpul studierii proceselor care au loc în creier și încercând să modeleze aceste procese.

Rețelele neuronale nu sunt programate în sensul obișnuit al cuvântului, sunt antrenate. Abilitatea de a învăța este unul dintre principalele avantaje ale rețelelor neuronale față de algoritmii tradiționali. Din punct de vedere tehnic, învățarea constă în găsirea coeficienților conexiunilor dintre neuroni. În timpul procesului de antrenament, rețeaua neuronală este capabilă să identifice dependențe complexe între datele de intrare și datele de ieșire, precum și să efectueze generalizări.

Din punctul de vedere al învățării automate, o rețea neuronală este un caz special de metode de recunoaștere a modelelor, analiză discriminantă, metode de grupare și alte metode.

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

Mai întâi, să ne uităm la echipament. Avem nevoie de un server cu sistemul de operare Linux instalat pe el. Echipamentul necesar pentru operarea sistemelor de învățare automată este destul de puternic și, prin urmare, costisitor. Pentru cei care nu au o mașină bună la îndemână, recomand să fiți atenți la ofertele furnizorilor de cloud. Puteți închiria rapid serverul necesar și plătiți doar pentru timpul de utilizare.

În proiectele în care este necesară crearea de rețele neuronale, folosesc serverele unuia dintre furnizorii ruși de cloud. Compania oferă servere cloud de închiriat special pentru învățarea automată cu procesoare grafice (GPU) Tesla V100 puternice de la NVIDIA. Pe scurt: folosirea unui server cu GPU poate fi de zeci de ori mai eficientă (rapidă) în comparație cu un server de cost similar care folosește un CPU (cunoscuta unitate centrală de procesare) pentru calcule. Acest lucru se realizează datorită caracteristicilor arhitecturii GPU, care face față calculelor mai rapid.

Pentru a implementa exemplele descrise mai jos, am achiziționat următorul server pentru câteva zile:

  • disc SSD 150 GB
  • RAM 32 GB
  • Procesor Tesla V100 de 16 Gb cu 4 nuclee

Am instalat Ubuntu 18.04 pe mașina noastră.

Configurarea mediului

Acum să instalăm tot ce este necesar pentru lucrul pe server. Întrucât articolul nostru este în primul rând pentru începători, voi vorbi despre câteva puncte care le vor fi utile.

O mare parte a muncii la configurarea unui mediu se face prin linia de comandă. Majoritatea utilizatorilor folosesc Windows ca sistem de operare de lucru. Consola standard din acest sistem de operare lasă mult de dorit. Prin urmare, vom folosi un instrument convenabil Cmder/. Descărcați versiunea mini și rulați Cmder.exe. În continuare, trebuie să vă conectați la server prin SSH:

ssh root@server-ip-or-hostname

În loc de server-ip-or-hostname, specificați adresa IP sau numele DNS al serverului dvs. Apoi, introduceți parola și dacă conexiunea are succes, ar trebui să primim un mesaj similar cu acesta.

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

Limbajul principal pentru dezvoltarea modelelor ML este Python. Și cea mai populară platformă pentru utilizarea sa pe Linux este anaconda.

Să-l instalăm pe serverul nostru.

Începem prin a actualiza managerul de pachete local:

sudo apt-get update

Instalați curl (utilitatea linie de comandă):

sudo apt-get install curl

Descărcați cea mai recentă versiune de Anaconda Distribution:

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

Să începem instalarea:

bash Anaconda3-2019.10-Linux-x86_64.sh

În timpul procesului de instalare, vi se va cere să confirmați acordul de licență. După instalarea cu succes, ar trebui să vedeți acest lucru:

Thank you for installing Anaconda3!

Au fost create acum multe cadre pentru dezvoltarea modelelor ML; lucrăm cu cele mai populare: PyTorch и flux tensor.

Utilizarea cadrului vă permite să creșteți viteza de dezvoltare și să utilizați instrumente gata făcute pentru sarcini standard.

În acest exemplu vom lucra cu PyTorch. Hai să-l instalăm:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Acum trebuie să lansăm Jupyter Notebook, un instrument de dezvoltare popular pentru specialiștii ML. Vă permite să scrieți cod și să vedeți imediat rezultatele execuției acestuia. Jupyter Notebook este inclus cu Anaconda și este deja instalat pe serverul nostru. Trebuie să vă conectați la acesta de pe sistemul nostru desktop.

Pentru a face acest lucru, vom lansa mai întâi Jupyter pe server, specificând portul 8080:

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

Apoi, deschizând o altă filă în consola noastră Cmder (meniul de sus - Dialog Consolă nouă) ne vom conecta prin portul 8080 la server prin SSH:

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

Când introducem prima comandă, ni se vor oferi link-uri pentru a deschide Jupyter în browserul nostru:

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

Să folosim linkul pentru localhost:8080. Copiați calea completă și inserați-o în bara de adrese a browserului local al computerului. Jupyter Notebook se va deschide.

Să creăm un nou blocnotes: Nou - Blocnotes - Python 3.

Să verificăm funcționarea corectă a tuturor componentelor pe care le-am instalat. Să introducem exemplul de cod PyTorch în Jupyter și să rulăm execuția (butonul Run):

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

Rezultatul ar trebui să fie cam așa:

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Dacă aveți un rezultat similar, atunci am configurat totul corect și putem începe dezvoltarea unei rețele neuronale!

Crearea unei rețele neuronale

Vom crea o rețea neuronală pentru recunoașterea imaginilor. Să luăm asta ca bază conducere.

Vom folosi setul de date CIFAR10 disponibil public pentru a instrui rețeaua. Are clase: „avion”, „mașină”, „pasăre”, „pisica”, „cerb”, „câine”, „broască”, „cal”, „navă”, „camion”. Imaginile din CIFAR10 sunt 3x32x32, adică imagini color cu 3 canale de 32x32 pixeli.

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători
Pentru lucru, vom folosi pachetul creat de PyTorch pentru lucrul cu imagini - torchvision.

Vom face următorii pași în ordine:

  • Încărcarea și normalizarea seturilor de date de antrenament și de testare
  • Definiția rețelei neuronale
  • Instruire în rețea privind datele de formare
  • Testarea rețelei pe datele de testare
  • Să repetăm ​​antrenamentul și testarea folosind GPU

Vom executa tot codul de mai jos în Jupyter Notebook.

Încărcarea și normalizarea CIFAR10

Copiați și rulați următorul cod în 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')

Răspunsul ar trebui să fie:

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

Să afișăm mai multe imagini de antrenament pentru testare:


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)))

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Definiția rețelei neuronale

Să analizăm mai întâi cum funcționează o rețea neuronală pentru recunoașterea imaginilor. Aceasta este o rețea simplă punct la punct. Preia datele de intrare, le trece prin mai multe straturi unul câte unul și apoi produce în cele din urmă date de ieșire.

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Să creăm o rețea similară în mediul nostru:


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()

De asemenea, definim o funcție de pierdere și un optimizator


import torch.optim as optim

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

Instruire în rețea privind datele de formare

Să începem să ne antrenăm rețeaua neuronală. Vă rugăm să rețineți că, după ce executați acest cod, va trebui să așteptați ceva timp până când lucrarea este finalizată. Mi-a luat 5 minute. Este nevoie de timp pentru a antrena rețeaua.

 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')

Obtinem urmatorul rezultat:

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Salvăm modelul nostru antrenat:

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

Testarea rețelei pe datele de testare

Am antrenat rețeaua folosind un set de date de antrenament. Dar trebuie să verificăm dacă rețeaua a învățat ceva.

Vom testa acest lucru predicând eticheta de clasă pe care o iese rețeaua neuronală și testând-o pentru a vedea dacă este adevărată. Dacă predicția este corectă, adăugăm eșantionul la lista de predicții corecte.
Să arătăm o imagine din setul de testare:

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)))

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Acum să cerem rețelei neuronale să ne spună ce este în aceste imagini:


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)))

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Rezultatele par destul de bune: rețeaua a identificat corect trei din patru imagini.

Să vedem cum funcționează rețeaua în întregul set de date.


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))

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Se pare că rețeaua știe ceva și funcționează. Dacă ar determina clasele la întâmplare, precizia ar fi de 10%.

Acum să vedem ce clase identifică mai bine rețeaua:

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]))

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Se pare că rețeaua este cea mai bună la identificarea mașinilor și a navelor: precizie de 71%.

Deci rețeaua funcționează. Acum să încercăm să-i transferăm munca pe procesorul grafic (GPU) și să vedem ce se schimbă.

Antrenarea unei rețele neuronale pe GPU

În primul rând, voi explica pe scurt ce este CUDA. CUDA (Compute Unified Device Architecture) este o platformă de calcul paralelă dezvoltată de NVIDIA pentru calcul general pe unități de procesare grafică (GPU). Cu CUDA, dezvoltatorii pot accelera dramatic aplicațiile de calcul prin valorificarea puterii GPU-urilor. Această platformă este deja instalată pe serverul nostru pe care l-am achiziționat.

Să definim mai întâi GPU-ul nostru ca primul dispozitiv cuda vizibil.

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 )

Prima ta rețea neuronală pe o unitate de procesare grafică (GPU). Ghid pentru începători

Trimiterea rețelei la GPU:

net.to(device)

De asemenea, va trebui să trimitem intrări și ținte la fiecare pas către GPU:

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

Să reantrenăm rețeaua pe 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')

De data aceasta, antrenamentul în rețea a durat aproximativ 3 minute. Să ne amintim că aceeași etapă pe un procesor convențional a durat 5 minute. Diferența nu este semnificativă, asta se întâmplă pentru că rețeaua noastră nu este atât de mare. Când utilizați matrice mari pentru antrenament, diferența dintre viteza GPU-ului și un procesor tradițional va crește.

Asta pare să fie tot. Ce am reușit să facem:

  • Ne-am uitat la ce este un GPU și am selectat serverul pe care este instalat;
  • Am creat un mediu software pentru a crea o rețea neuronală;
  • Am creat o rețea neuronală pentru recunoașterea imaginilor și am antrenat-o;
  • Am repetat antrenamentul în rețea folosind GPU și am primit o creștere a vitezei.

Voi răspunde cu plăcere la întrebări în comentarii.

Sursa: www.habr.com

Adauga un comentariu