Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători
În acest articol, voi explica cum să configurezi un mediu pentru învățarea automată în 30 de minute, să creezi o rețea neurală pentru recunoașterea imaginilor și apoi să rulezi aceeași rețea pe un procesor grafic (GPU).

Pentru început, să definim ce este o rețea neurală.

În cazul nostru, aceasta este un model matematic, precum și o implementare programatică sau hardware, construită conform principiilor de organizare și funcționare ale rețelelor neuronale biologice — rețelele de celule nervoase ale unui organism viu. Acest concept a apărut în urma studiului proceselor ce au loc în creier și a încercărilor de a le modela.

Rețelele neuronale nu sunt programate în sensul obișnuit al cuvântului, ci sunt antrenate. Capacitatea de a învăța este unul dintre principalele avantaje ale rețelelor neuronale în comparație cu algoritmii tradiționali. Tehnic, învățarea constă în găsirea coeficientului de legătură între neuroni. Pe parcursul învățării, rețeaua neurală devine capabilă să descopere dependențe complexe între datele de intrare și cele de ieșire, precum și să facă generalizări.

Din perspectiva învățării automate, o rețea neurală reprezintă un caz special al metodelor de recunoaștere a patternurilor, analizei discriminante, metodelor de clusterizare și altor tehnici.

Echipament

Mai întâi, să ne ocupăm de echipament. Avem nevoie de un server cu un sistem de operare Linux instalat. Echipamentul necesar pentru funcționarea sistemelor de învățare automată trebuie să fie destul de puternic și, prin urmare, costisitor. Cei care nu au un computer performant la îndemână sunt sfătuiți să ia în considerare ofertele furnizorilor de cloud. Serverul necesar poate fi închiriat rapid și se plătește doar pentru timpul de utilizare.

În proiectele unde este necesară crearea rețelelor neuronale, folosesc servere de la unul dintre furnizorii ruși de servicii cloud. Compania oferă servere cloud dedicate închiriate special pentru învățarea automată, dotate cu procesoare grafice (GPU) Tesla V100 de la NVIDIA. Pe scurt: utilizarea unui server cu GPU poate fi de zeci de ori mai eficientă (rapidă) în comparație cu un server similar ca preț, unde calculul se bazează pe CPU (celebra unitate centrală de procesare). Acest lucru se realizează prin specificitățile arhitecturii GPU, care finalizează calculele mai rapid.

Pentru a executa exemplele descrise mai jos, am închiriat un astfel de server pentru câteva zile:

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

Pe mașină ne-au instalat Ubuntu 18.04.

Instalăm mediul

Acum vom instala pe server tot ce este necesar pentru funcționare. Deoarece articolul nostru este mai ales pentru începători, voi vorbi despre câteva momente care le vor fi utile lor.

Foarte mult din muncă în configurarea mediului se face prin linia de comandă. Majoritatea utilizatorilor folosesc Windows ca sistem de operare de bază. Consola standard din acest OS lasă de dorit. De aceea, vom folosi un instrument convenabil Cmder/. Descărcăm versiunea mini și lansăm Cmder.exe. Apoi, trebuie să ne conectăm la server prin protocolul SSH:

ssh root@server-ip-or-hostname

În loc de server-ip-or-hostname, specificați adresa IP sau numele DNS al serverului dumneavoastră. Apoi introduceți parola și, dacă ne conectăm cu 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. Iar cea mai populară platformă pentru utilizarea sa pe Linux este Anaconda.

O vom instala pe serverul nostru.

Începem cu actualizarea managerului local de pachete:

sudo apt-get update

Instalăm curl (un program de utilitate prin linia de comandă):

sudo apt-get install curl

Descărcăm cea mai recentă versiune a Anaconda Distribution:

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

Pornim instalarea:

bash Anaconda3-2019.10-Linux-x86_64.sh

În timpul instalării va fi necesar să confirmați acordul de licență. Dacă instalarea a fost efectuată cu succes, ar trebui să vedeți acest mesaj:

Thank you for installing Anaconda3!

Pentru dezvoltarea modelelor ML, acum există numeroase cadre, noi lucrăm cu cele mai populare: PyTorch și Tensorflow.

Utilizarea unui cadru permite creșterea vitezei de dezvoltare și folosirea instrumentelor deja existente pentru sarcini standard.

În acest exemplu, vom lucra cu PyTorch. Să-l instalăm:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Acum trebuie să pornim Jupyter Notebook — un instrument popular printre specialiștii ML. Acesta permite scrierea codului și vizualizarea imediată a rezultatelor execuției acestuia. Jupyter Notebook este inclus în Anaconda și este deja instalat pe serverul nostru. Este necesar să ne conectăm la el din sistemul nostru desktop.

Pentru aceasta, mai întâi vom porni Jupyter pe server specificând portul 8080:

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

Apoi, deschizând în consola noastră Cmder un alt tab (meniul de sus — New console dialog) ne vom conecta prin portul 8080 la server prin SSH:

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

La introducerea primei comenzi ni se vor oferi linkuri 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

Vom folosi linkul pentru localhost:8080. Copiați calea completă și lipiți-o în bara de adrese a browserului local de pe PC-ul dvs. Jupyter Notebook se va deschide.

Să creăm un nou notebook: New — Notebook — Python 3.

Vom verifica funcționarea corectă a tuturor componentelor pe care le-am instalat. Vom introduce în Jupyter un exemplu de cod PyTorch și vom rula execuția (butonul Run):

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

Rezultatul ar trebui să fie aproximativ așa:

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Dacă aveți un rezultat similar, înseamnă că am configurat totul corect și putem începe dezvoltarea rețelei neuronale!

Creăm o rețea neuronală

Vom crea o rețea neuronală pentru recunoașterea imaginilor. Vom lua ca bază această ghid.

Pentru antrenarea rețelei, vom folosi datasetul public CIFAR10. Acesta are clase: „avion”, „mașină”, „pasăre”, „pisică”, „cerb”, „câine”, „broscuță”, „cal”, „nava”, „truck”. Imaginile din CIFAR10 au dimensiunea 3x32x32, adică imaginile color cu 3 canale de dimensiune 32×32 pixeli.

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători
Pentru lucru, vom folosi pachetul PyTorch creat pentru lucrul cu imagini — torchvision.

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

  • Încărcarea și normalizarea seturilor de date de antrenament și testare
  • Definirea rețelei neuronale
  • Antrenarea rețelei pe datele de antrenament
  • Testarea rețelei pe datele de testare
  • Vom repeta antrenarea și testarea folosind GPU

Tot codul de mai jos va fi executat în Jupyter Notebook.

Încărcarea și normalizarea CIFAR10

Copiați și executaț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 astfel:

Se descarcă https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz la ./data/cifar-10-python.tar.gz
Se extrage ./data/cifar-10-python.tar.gz la ./data
Fișierele au fost deja descărcate și verificate

Să afișăm câteva imagini de antrenament pentru verificare:


import matplotlib.pyplot as plt
import numpy as np

# funcții pentru a afișa o imagine

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

# obține câteva imagini de antrenament aleatorii
dataiter = iter(trainloader)
images, labels = dataiter.next()

# afișați imaginile
imshow(torchvision.utils.make_grid(images))
# printați etichetele
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Definirea rețelei neuronale

Să analizăm mai întâi cum funcționează rețeaua neuronală de recunoaștere a imaginilor. Este o rețea simplă de conexiune directă. Aceasta primește date de intrare, le trece prin mai multe straturi unul după altul și, în cele din urmă, produce datele de ieșire.

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Să creăm o rețea similară în mediu 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()

Să definim de asemenea funcția de pierdere și optimizatorul


import torch.optim as optim

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

Antrenarea rețelei pe datele de antrenament

Începem antrenamentul rețelei noastre neuronale. Vă atrag atenția că, după ce veți executa acest cod, va trebui să așteptați ceva timp până la finalizarea lucrării. La mine, a durat 5 minute. Pentru a antrena rețeaua, este nevoie de timp.

 pentru epoch în range(2): # iterează asupra dataset-ului de mai multe ori

 running_loss = 0.0
 pentru i, data în enumerate(trainloader, 0):
 # obțineți intrările; data este o listă de [intrări, etichete]
 intrări, etichete = data

 # zeroați grupele de parametri
 optimizer.zero_grad()

 # înainte + înapoi + optimizează
 outputs = net(intrări)
 loss = criterion(outputs, etichete)
 loss.backward()
 optimizer.step()

 # afișați statistici
 running_loss += loss.item()
 if i % 2000 == 1999: # afișați la fiecare 2000 de mini-batch-uri
 print('[%d, ] loss: %.3f' %
 (epoch + 1, i + 1, running_loss / 2000))
 running_loss = 0.0

print('Antrenare finalizată')

Vom obține un astfel de rezultat:

Prima ta rețea neurală pe un procesor 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 verifica acest lucru, prezicând eticheta clasei pe care o produce rețeaua neuronală și verificând-o pentru corectitudine. Dacă prezicerea este corectă, vom adăuga exemplarul în lista prezicerilor corecte.
Să arătăm o imagine din setul de testare:

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

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

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

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


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

outputs = net(images)

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

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

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

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

Să vedem cum funcționează rețeaua pe î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('Precizia rețelei pe cele 10000 de imagini de test: %d %%' % (
    100 * correct / total))

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

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

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

class_correct = list(0. pentru i în range(10))
class_total = list(0. pentru i în range(10))
cu torch.no_grad():
 pentru data în testloader:
 imagini, etichete = data
 outputs = net(imagini)
 _, predicted = torch.max(outputs, 1)
 c = (predicted == etichete).squeeze()
 pentru i în range(4):
 label = etichete[i]
 class_correct[label] += c[i].item()
 class_total[label] += 1


pentru i în range(10):
 print('Acuratețea %5s : %%' % (
 classes[i], 100 * class_correct[i] / class_total[i]))

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Se pare că rețeaua definește cel mai bine mașinile și navele: 71% precizie.

Așadar, rețeaua funcționează. Acum vom încerca să transferăm funcționarea acesteia pe un procesor grafic (GPU) și să vedem ce se va schimba.

Antrenarea rețelei neuronale pe GPU

Mai întâi, voi explica pe scurt ce este CUDA. CUDA (Compute Unified Device Architecture) este o platformă de calcul paralel, dezvoltată de NVIDIA, pentru computații generale pe procesoare grafice (GPU). Cu ajutorul CUDA, dezvoltatorii pot accelera semnificativ aplicațiile de calcul, utilizând capabilitățile procesoarelor grafice. Pe serverul nostru, pe care l-am achiziționat, această platformă este deja instalată.

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

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Presupunând că ne aflăm pe o mașină CUDA, acesta ar trebui să afișeze un dispozitiv CUDA:
print(device)

Prima ta rețea neurală pe un procesor grafic (GPU). Ghid pentru începători

Trimitem rețeaua pe GPU:

net.to(device)

De asemenea, va trebui să trimitem intrările și obiectivele la fiecare pas pe GPU:

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

Să reluăm antrenamentul rețelei deja pe GPU:

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
pentru epoch în range(2): # iterează asupra dataset-ului de mai multe ori

 running_loss = 0.0
 pentru i, data în enumerate(trainloader, 0):
 # obțineți intrările; data este o listă de [intrări, etichete]
 intrări, etichete = data[0].to(device), data[1].to(device)

 # zeroați grupele de parametri
 optimizer.zero_grad()

 # înainte + înapoi + optimizează
 outputs = net(intrări)
 loss = criterion(outputs, etichete)
 loss.backward()
 optimizer.step()

 # afișați statistici
 running_loss += loss.item()
 if i % 2000 == 1999: # afișați la fiecare 2000 de mini-batch-uri
 print('[%d, ] loss: %.3f' %
 (epoch + 1, i + 1, running_loss / 2000))
 running_loss = 0.0

print('Antrenare finalizată')

În această rundă, antrenamentul rețelei a durat aproximativ 3 minute. Să ne amintim că aceeași etapă pe un procesor obișnuit a durat 5 minute. Diferența nu este semnificativă, se întâmplă deoarece rețeaua noastră nu este atât de mare. Când se utilizează seturi mari pentru antrenament, diferența dintre viteza GPU și cea a procesorului tradițional va crește.

Aici se termină. Ce am reușit să facem:

  • Am explorat ce este GPU-ul și am ales serverul pe care este instalat;
  • Am configurat mediul software pentru a crea rețeaua neurală;
  • Am creat o rețea neurală pentru recunoașterea imaginilor și am antrenat-o;
  • Am reluat antrenamentul rețelei utilizând GPU-ul și am obținut un câștig de viteză.

Voi fi fericit să răspund la întrebările din comentarii.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster