Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët
Në këtë artikull, unë do t'ju tregoj se si të konfiguroni një mjedis të mësimit të makinës në 30 minuta, të krijoni një rrjet nervor për njohjen e imazhit dhe më pas të ekzekutoni të njëjtin rrjet në një procesor grafik (GPU).

Së pari, le të përcaktojmë se çfarë është një rrjet nervor.

Në rastin tonë, ky është një model matematikor, si dhe mishërimi i tij softuer ose harduer, i ndërtuar mbi parimin e organizimit dhe funksionimit të rrjeteve nervore biologjike - rrjetet e qelizave nervore të një organizmi të gjallë. Ky koncept u ngrit gjatë studimit të proceseve që ndodhin në tru dhe përpjekjes për të modeluar këto procese.

Rrjetet nervore nuk janë të programuara në kuptimin e zakonshëm të fjalës, ato janë të trajnuar. Aftësia për të mësuar është një nga avantazhet kryesore të rrjeteve nervore ndaj algoritmeve tradicionale. Teknikisht, të mësuarit konsiston në gjetjen e koeficientëve të lidhjeve midis neuroneve. Gjatë procesit të trajnimit, rrjeti nervor është në gjendje të identifikojë varësitë komplekse midis të dhënave hyrëse dhe të dhënave dalëse, si dhe të kryejë përgjithësimin.

Nga pikëpamja e mësimit të makinerive, një rrjet nervor është një rast i veçantë i metodave të njohjes së modeleve, analizave diskriminuese, metodave të grupimit dhe metodave të tjera.

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

Së pari, le të shohim pajisjet. Ne kemi nevojë për një server me sistemin operativ Linux të instaluar në të. Pajisjet e nevojshme për funksionimin e sistemeve të mësimit të makinerive janë mjaft të fuqishme dhe, si rezultat, të shtrenjta. Për ata që nuk kanë një makinë të mirë në dorë, unë rekomandoj t'i kushtojnë vëmendje ofertave të ofruesve të cloud. Ju mund të merrni me qira serverin e kërkuar shpejt dhe të paguani vetëm për kohën e përdorimit.

Në projektet ku është e nevojshme të krijohen rrjete nervore, unë përdor serverët e një prej ofruesve rusë të cloud. Kompania ofron serverë cloud me qira posaçërisht për mësimin e makinerive me procesorë grafik të fuqishëm Tesla V100 (GPU) nga NVIDIA. Shkurtimisht: përdorimi i një serveri me një GPU mund të jetë dhjetëra herë më efikas (i shpejtë) në krahasim me një server me kosto të ngjashme që përdor një CPU (njësia e njohur e përpunimit qendror) për llogaritjet. Kjo arrihet për shkak të veçorive të arkitekturës GPU, e cila përballon më shpejt llogaritjet.

Për të zbatuar shembujt e përshkruar më poshtë, ne blemë serverin e mëposhtëm për disa ditë:

  • Disk SSD 150 GB
  • RAM 32 GB
  • Procesor Tesla V100 16 Gb me 4 bërthama

Ne instaluam Ubuntu 18.04 në makinën tonë.

Vendosja e mjedisit

Tani le të instalojmë gjithçka që nevojitet për të punuar në server. Meqenëse artikulli ynë është kryesisht për fillestarët, unë do të flas për disa pika që do të jenë të dobishme për ta.

Një pjesë e madhe e punës gjatë konfigurimit të një mjedisi bëhet përmes linjës së komandës. Shumica e përdoruesve përdorin Windows si sistemin e tyre operativ. Konsola standarde në këtë OS lë shumë për të dëshiruar. Prandaj, ne do të përdorim një mjet të përshtatshëm Cmder/. Shkarkoni versionin mini dhe ekzekutoni Cmder.exe. Tjetra ju duhet të lidheni me serverin përmes SSH:

ssh root@server-ip-or-hostname

Në vend të serverit-ip-or-hostname, specifikoni adresën IP ose emrin DNS të serverit tuaj. Më pas, futni fjalëkalimin dhe nëse lidhja është e suksesshme, duhet të marrim një mesazh të ngjashëm me këtë.

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

Gjuha kryesore për zhvillimin e modeleve ML është Python. Dhe platforma më e njohur për përdorimin e saj në Linux është Anaconda.

Le ta instalojmë në serverin tonë.

Ne fillojmë duke përditësuar menaxherin lokal të paketave:

sudo apt-get update

Instaloni curl (nën programin e linjës së komandës):

sudo apt-get install curl

Shkarkoni versionin më të fundit të Anaconda Distribution:

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

Le të fillojmë instalimin:

bash Anaconda3-2019.10-Linux-x86_64.sh

Gjatë procesit të instalimit, do t'ju kërkohet të konfirmoni marrëveshjen e licencës. Pas instalimit të suksesshëm, duhet të shihni këtë:

Thank you for installing Anaconda3!

Tani janë krijuar shumë korniza për zhvillimin e modeleve ML; ne punojmë me më të njohurit: PyTorch и Rrjedhja e tensionit.

Përdorimi i kornizës ju lejon të rritni shpejtësinë e zhvillimit dhe të përdorni mjete të gatshme për detyra standarde.

Në këtë shembull do të punojmë me PyTorch. Le ta instalojmë:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Tani na duhet të lançojmë Jupyter Notebook, një mjet i njohur zhvillimi për specialistët e ML. Kjo ju lejon të shkruani kodin dhe të shihni menjëherë rezultatet e ekzekutimit të tij. Jupyter Notebook është përfshirë me Anaconda dhe është instaluar tashmë në serverin tonë. Duhet të lidheni me të nga sistemi ynë i desktopit.

Për ta bërë këtë, ne fillimisht do të nisim Jupyter në serverin që specifikon portin 8080:

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

Më pas, duke hapur një skedë tjetër në tastierën tonë Cmder (menyja e sipërme - Dialogu i konsolës së re) do të lidhemi përmes portit 8080 me serverin përmes SSH:

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

Kur të futim komandën e parë, do të na ofrohen lidhje për të hapur Jupyter në shfletuesin tonë:

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

Le të përdorim lidhjen për localhost:8080. Kopjoni shtegun e plotë dhe ngjisni në shiritin e adresave të shfletuesit lokal të kompjuterit tuaj. Jupyter Notebook do të hapet.

Le të krijojmë një fletore të re: E re - Notebook - Python 3.

Le të kontrollojmë funksionimin e saktë të të gjithë komponentëve që kemi instaluar. Le të fusim shembullin e kodit PyTorch në Jupyter dhe të ekzekutojmë ekzekutimin (butoni Run):

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

Rezultati duhet të jetë diçka e tillë:

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Nëse keni një rezultat të ngjashëm, atëherë ne kemi konfiguruar gjithçka në mënyrë korrekte dhe mund të fillojmë të zhvillojmë një rrjet nervor!

Krijimi i një rrjeti nervor

Ne do të krijojmë një rrjet nervor për njohjen e imazhit. Le ta marrim këtë si bazë udhëheqja.

Ne do të përdorim të dhënat e disponueshme publikisht CIFAR10 për të trajnuar rrjetin. Ka klasa: "aeroplan", "makinë", "zog", "mace", "dre", "qen", "bretkocë", "kalë", "anije", "kamion". Imazhet në CIFAR10 janë 3x32x32, domethënë imazhe me ngjyra me 3 kanale prej 32x32 piksele.

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët
Për punë, ne do të përdorim paketën e krijuar nga PyTorch për të punuar me imazhe - torchvision.

Ne do të bëjmë hapat e mëposhtëm me radhë:

  • Ngarkimi dhe normalizimi i grupeve të të dhënave të trajnimit dhe testimit
  • Përkufizimi i rrjetit nervor
  • Trajnim në rrjet mbi të dhënat e trajnimit
  • Testimi i rrjetit në të dhënat e provës
  • Le të përsërisim trajnimin dhe testimin duke përdorur GPU

Ne do të ekzekutojmë të gjithë kodin më poshtë në Jupyter Notebook.

Ngarkimi dhe normalizimi i CIFAR10

Kopjoni dhe ekzekutoni kodin e mëposhtëm 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')

Përgjigja duhet të jetë:

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

Le të shfaqim disa imazhe trajnimi për testim:


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

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Përkufizimi i rrjetit nervor

Le të shqyrtojmë fillimisht se si funksionon një rrjet nervor për njohjen e imazhit. Ky është një rrjet i thjeshtë pikë-për-pikë. Ai merr të dhëna hyrëse, i kalon ato nëpër disa shtresa një nga një dhe më në fund prodhon të dhëna dalëse.

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Le të krijojmë një rrjet të ngjashëm në mjedisin tonë:


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

Ne gjithashtu përcaktojmë një funksion humbjeje dhe një optimizues


import torch.optim as optim

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

Trajnim në rrjet mbi të dhënat e trajnimit

Le të fillojmë trajnimin e rrjetit tonë nervor. Ju lutemi vini re se pasi të keni ekzekutuar këtë kod, do t'ju duhet të prisni pak kohë derisa puna të përfundojë. M'u deshën 5 minuta. Duhet kohë për të trajnuar rrjetin.

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

Ne marrim rezultatin e mëposhtëm:

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Ne ruajmë modelin tonë të trajnuar:

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

Testimi i rrjetit në të dhënat e provës

Ne trajnuam rrjetin duke përdorur një grup të dhënash trajnimi. Por ne duhet të kontrollojmë nëse rrjeti ka mësuar ndonjë gjë fare.

Ne do ta testojmë këtë duke parashikuar etiketën e klasës që nxjerr rrjeti nervor dhe duke e testuar atë për të parë nëse është e vërtetë. Nëse parashikimi është i saktë, ne e shtojmë mostrën në listën e parashikimeve të sakta.
Le të tregojmë një imazh nga grupi i provës:

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

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Tani le të kërkojmë nga rrjeti nervor të na tregojë se çfarë është në këto foto:


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

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Rezultatet duken mjaft të mira: rrjeti identifikoi saktë tre nga katër fotografi.

Le të shohim se si funksionon rrjeti në të gjithë grupin e të dhënave.


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

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Duket sikur rrjeti di diçka dhe po funksionon. Nëse ai i përcaktonte klasat në mënyrë të rastësishme, saktësia do të ishte 10%.

Tani le të shohim se cilat klasa i identifikon më mirë rrjeti:

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

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Duket se rrjeti është më i miri në identifikimin e makinave dhe anijeve: saktësi 71%.

Pra, rrjeti po funksionon. Tani le të përpiqemi ta transferojmë punën e tij në procesorin grafik (GPU) dhe të shohim se çfarë ndryshon.

Trajnimi i një rrjeti nervor në GPU

Së pari, unë do të shpjegoj shkurtimisht se çfarë është CUDA. CUDA (Compute Unified Device Architecture) është një platformë llogaritëse paralele e zhvilluar nga NVIDIA për llogaritjen e përgjithshme në njësitë e përpunimit grafik (GPU). Me CUDA, zhvilluesit mund të përshpejtojnë në mënyrë dramatike aplikacionet kompjuterike duke shfrytëzuar fuqinë e GPU-ve. Kjo platformë është instaluar tashmë në serverin tonë që kemi blerë.

Le të përcaktojmë fillimisht GPU-në tonë si pajisjen e parë të dukshme cuda.

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 )

Rrjeti juaj i parë nervor në një njësi përpunimi grafik (GPU). Udhëzues për fillestarët

Dërgimi i rrjetit në GPU:

net.to(device)

Ne gjithashtu do të duhet të dërgojmë inpute dhe objektiva në çdo hap në GPU:

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

Le të ritrajnojmë rrjetin në 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')

Këtë herë, trajnimi në rrjet zgjati rreth 3 minuta. Le të kujtojmë se e njëjta fazë në një procesor konvencional zgjati 5 minuta. Dallimi nuk është i rëndësishëm, kjo ndodh sepse rrjeti ynë nuk është aq i madh. Kur përdorni grupe të mëdha për stërvitje, ndryshimi midis shpejtësisë së GPU dhe një procesori tradicional do të rritet.

Kjo duket të jetë e gjitha. Çfarë arritëm të bënim:

  • Ne shikuam se çfarë është një GPU dhe zgjodhëm serverin në të cilin është instaluar;
  • Ne kemi krijuar një mjedis softuerësh për të krijuar një rrjet nervor;
  • Ne krijuam një rrjet nervor për njohjen e imazheve dhe e trajnuam atë;
  • Ne përsëritëm trajnimin e rrjetit duke përdorur GPU dhe morëm një rritje të shpejtësisë.

Do të jem i lumtur t'u përgjigjem pyetjeve në komente.

Burimi: www.habr.com

Shto një koment