Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele
Selles artiklis räägin teile, kuidas seadistada 30 minutiga masinõppekeskkond, luua pildituvastuseks närvivõrk ja seejärel käivitada sama võrk graafikaprotsessoris (GPU).

Esiteks määratleme, mis on närvivõrk.

Meie puhul on see matemaatiline mudel, aga ka selle tarkvara või riistvaraline teostus, mis on üles ehitatud bioloogiliste närvivõrkude - elusorganismi närvirakkude võrgustike - organiseerimise ja toimimise põhimõttele. See kontseptsioon tekkis ajus toimuvaid protsesse uurides ja neid protsesse modelleerida püüdes.

Närvivõrke ei programmeerita selle sõna tavapärases tähenduses, neid treenitakse. Õppimisvõime on närvivõrkude üks peamisi eeliseid traditsiooniliste algoritmide ees. Tehniliselt seisneb õppimine neuronite vaheliste seoste koefitsientide leidmises. Koolitusprotsessi käigus suudab närvivõrk tuvastada keerulisi sõltuvusi sisendandmete ja väljundandmete vahel ning teostada üldistamist.

Masinõppe seisukohalt on närvivõrk mustrituvastusmeetodite, diskriminantanalüüsi, klasterdamismeetodite ja muude meetodite erijuht.

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

Kõigepealt vaatame varustust. Vajame serverit, kuhu on installitud Linuxi operatsioonisüsteem. Masinõppesüsteemide tööks vajalikud seadmed on üsna võimsad ja sellest tulenevalt kallid. Kellel head masinat käepärast pole, soovitan tähelepanu pöörata pilvepakkujate pakkumistele. Vajaliku serveri saate kiiresti rentida ja maksta ainult kasutusaja eest.

Projektides, kus on vaja luua närvivõrke, kasutan ühe Venemaa pilvepakkuja servereid. Ettevõte pakub NVIDIA võimsate Tesla V100 graafikaprotsessoritega (GPU) spetsiaalselt masinõppe jaoks mõeldud pilvservereid rentimiseks. Lühidalt: GPU-ga serveri kasutamine võib olla kümneid kordi tõhusam (kiirem) võrreldes sarnase kuluga serveriga, mis kasutab arvutusteks CPU-d (tuntud keskprotsessorit). See saavutatakse tänu GPU arhitektuuri omadustele, mis saab arvutustega kiiremini hakkama.

Allpool kirjeldatud näidete rakendamiseks ostsime mitmeks päevaks järgmise serveri:

  • SSD ketas 150 GB
  • RAM 32 GB
  • Tesla V100 16 Gb 4 tuumaga protsessor

Installisime oma masinasse Ubuntu 18.04.

Keskkonna seadistamine

Nüüd paigaldame serverisse kõik tööks vajaliku. Kuna meie artikkel on mõeldud peamiselt algajatele, räägin mõnest punktist, mis on neile kasulik.

Suur osa tööst keskkonna seadistamisel toimub käsurea kaudu. Enamik kasutajaid kasutab Windowsi tööoperatsioonisüsteemina. Selle OS-i standardkonsool jätab palju soovida. Seetõttu kasutame mugavat tööriista cmder/. Laadige alla miniversioon ja käivitage Cmder.exe. Järgmisena peate SSH kaudu serveriga ühenduse looma:

ssh root@server-ip-or-hostname

Serveri-ip-või-hostinime asemel määrake oma serveri IP-aadress või DNS-nimi. Järgmisena sisestage parool ja kui ühendus õnnestub, peaksime saama sarnase teate.

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

ML-mudelite arendamise põhikeel on Python. Ja kõige populaarsem platvorm selle kasutamiseks Linuxis on Anakonda.

Installime selle oma serverisse.

Alustame kohaliku paketihalduri värskendamisega:

sudo apt-get update

Installige curl (käsurea utiliit):

sudo apt-get install curl

Laadige alla Anaconda Distributioni uusim versioon:

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

Alustame installimist:

bash Anaconda3-2019.10-Linux-x86_64.sh

Installimise ajal palutakse teil litsentsileping kinnitada. Eduka installimise korral peaksite nägema järgmist:

Thank you for installing Anaconda3!

ML-mudelite arendamiseks on nüüdseks loodud palju raamistikke, töötame kõige populaarsematega: PyTorch и Tensorivoog.

Raamistiku kasutamine võimaldab suurendada arenduskiirust ja kasutada standardülesannete jaoks valmis tööriistu.

Selles näites töötame PyTorchiga. Installime selle:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Nüüd peame käivitama ML-spetsialistide jaoks populaarse arendustööriista Jupyter Notebook. See võimaldab teil kirjutada koodi ja kohe näha selle täitmise tulemusi. Jupyteri sülearvuti on Anacondaga kaasas ja meie serverisse juba installitud. Peate sellega meie töölauasüsteemi kaudu ühenduse looma.

Selleks käivitame esmalt serveris Jupyteri, määrates pordi 8080:

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

Järgmisena, avades oma Cmderi konsoolis teise vahekaardi (ülemine menüü - dialoog Uus konsool), ühendame pordi 8080 kaudu serveriga SSH kaudu:

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

Kui sisestame esimese käsu, pakutakse meile linke Jupyteri avamiseks meie brauseris:

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

Kasutame linki localhost:8080 jaoks. Kopeerige kogu tee ja kleepige see oma arvuti kohaliku brauseri aadressiribale. Jupyteri märkmik avaneb.

Loome uue märkmiku: Uus – Märkmik – Python 3.

Kontrollime kõigi paigaldatud komponentide õiget toimimist. Sisestame PyTorchi näidiskoodi Jupyterisse ja käivitame täitmise (nupp Käivita):

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

Tulemus peaks olema umbes selline:

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Kui teil on sarnane tulemus, siis oleme kõik õigesti seadistanud ja saame alustada närvivõrgu arendamist!

Närvivõrgu loomine

Loome kujutise tuvastamiseks närvivõrgu. Võtame selle aluseks juhtpositsiooni.

Võrgu koolitamiseks kasutame avalikult kättesaadavat CIFAR10 andmekogumit. Sellel on klassid: "lennuk", "auto", "lind", "kass", "hirv", "koer", "konn", "hobune", "laev", "veoauto". CIFAR10 pildid on 3x32x32, st 3-kanalilised värvilised pildid 32x32 piksliga.

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele
Tööks kasutame piltidega töötamiseks PyTorchi loodud paketti - torchvision.

Teeme järgmised sammud järjekorras:

  • Treeningu- ja testiandmete laadimine ja normaliseerimine
  • Närvivõrgu määratlus
  • Võrgukoolitus treeningandmete kohta
  • Testandmete võrgu testimine
  • Kordame koolitust ja testimist GPU abil

Käivitame kogu alloleva koodi Jupyteri sülearvutis.

CIFAR10 laadimine ja normaliseerimine

Kopeerige ja käivitage Jupyteris järgmine kood:


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

Vastus peaks olema:

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

Kuvame testimiseks mitu treeningpilti:


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

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Närvivõrgu määratlus

Mõelgem esmalt, kuidas toimib pildituvastuse närvivõrk. See on lihtne punkt-punkti võrk. See võtab sisendandmed, läbib need ükshaaval läbi mitme kihi ja toodab lõpuks väljundandmed.

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Loome oma keskkonda sarnase võrgustiku:


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

Samuti määratleme kadufunktsiooni ja optimeerija


import torch.optim as optim

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

Võrgukoolitus treeningandmete kohta

Alustame oma närvivõrgu treenimist. Pange tähele, et pärast selle koodi käivitamist peate ootama mõnda aega, kuni töö on lõpetatud. Mul kulus 5 minutit. Võrgustiku treenimine võtab aega.

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

Saame järgmise tulemuse:

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Salvestame oma koolitatud mudeli:

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

Testandmete võrgu testimine

Treenisime võrku koolitusandmete komplekti kasutades. Kuid me peame kontrollima, kas võrk on üldse midagi õppinud.

Testime seda, ennustades klassi sildi, mille närvivõrk väljastab, ja testides seda, et näha, kas see vastab tõele. Kui ennustus on õige, lisame valimi õigete ennustuste loendisse.
Näitame pilti testikomplektist:

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

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Nüüd palume närvivõrgul meile öelda, mis nendel piltidel on:


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

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Tulemused tunduvad üsna head: võrk tuvastas õigesti kolm pilti neljast.

Vaatame, kuidas võrk kogu andmestiku ulatuses toimib.


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

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Tundub, et võrk teab midagi ja töötab. Kui ta määraks klassid juhuslikult, oleks täpsus 10%.

Nüüd vaatame, milliseid klasse võrk paremini tuvastab:

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

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Tundub, et võrk suudab kõige paremini tuvastada autosid ja laevu: 71% täpsus.

Nii et võrk töötab. Proovime nüüd selle töö graafikaprotsessorile (GPU) üle kanda ja vaatame, mis muutub.

Närvivõrgu treenimine GPU-l

Esiteks selgitan lühidalt, mis on CUDA. CUDA (Compute Unified Device Architecture) on paralleelarvutusplatvorm, mille on välja töötanud NVIDIA üldiseks andmetöötluseks graafikaprotsessoritel (GPU). CUDA abil saavad arendajad andmetöötlusrakendusi märkimisväärselt kiirendada, kasutades GPU-de võimsust. See platvorm on meie ostetud serverisse juba installitud.

Esmalt määratleme oma GPU esimese nähtava Cuda seadmena.

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 )

Teie esimene graafikaprotsessori (GPU) närvivõrk. Juhend algajatele

Võrgu saatmine GPU-le:

net.to(device)

Samuti peame igal etapil GPU-le saatma sisendid ja sihtmärgid:

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

Treenime võrku uuesti GPU-l:

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

Võrgustreening kestis seekord umbes 3 minutit. Meenutagem, et sama etapp kestis tavalisel protsessoril 5 minutit. Erinevus pole märkimisväärne, see juhtub seetõttu, et meie võrk pole nii suur. Treeninguks suurte massiivide kasutamisel suureneb GPU ja traditsioonilise protsessori kiiruse erinevus.

See näib olevat kõik. Millega me hakkama saime:

  • Vaatasime, mis on GPU ja valisime serveri, kuhu see on installitud;
  • Oleme üles seadnud tarkvarakeskkonna närvivõrgu loomiseks;
  • Lõime pildituvastuseks närvivõrgu ja koolitasime seda;
  • Kordasime võrgukoolitust GPU abil ja saime kiiruse tõusu.

Vastan meeleldi küsimustele kommentaarides.

Allikas: www.habr.com

Lisa kommentaar