
Selles artiklis rÀÀgin, kuidas 30 minutiga seadistada keskkond masinÔppe jaoks, luua pildituvastamiseks nÀrvivÔrk ja seejÀrel kÀivitada sama vÔrk graafikaprotsessoril (GPU).
Alustame sellega, mis on nÀrvivÔrk.
Meie puhul on see matemaatiline mudel, samuti selle programmiline vĂ”i riistvaraline kehastus, mis on ĂŒles ehitatud bioloogiliste nĂ€rvivĂ”rkude â elusorganismide nĂ€rvirakkude â organisatsiooni ja toimimise printsiipide jĂ€rgi. See mĂ”isted tekkisid aju toimimise uurimise kĂ€igus ja selle protsesside modelleerimise katses.
NĂ€rvivĂ”rke ei programmeerita tavas mĂ”ttes, vaid need Ă”pitakse. Ăppimise vĂ”imalus on nĂ€rvivĂ”rkude ĂŒks peamisi eeliseid traditsiooniliste algoritmide ees. Tehniliselt seisneb Ă”ppimine neuronite vaheliste ĂŒhenduste koefitsientide leidmises. Ăppeprotsessi kĂ€igus suudab nĂ€rvivĂ”rk tuvastada keerulisi seoseid sissesiandmete ja vĂ€ljundite vahel ning teostada ĂŒldistamist.
MasinĂ”ppe vaatenurgast on nĂ€rvivĂ”rk erijuht tunnustamistuvastuse, diskrimineerimisanalĂŒĂŒsi, klasterdamismeetodite ja muude meetodite osas.
Varustus
Esmalt vaatame varustust. Me vajame serverit, millel on paigaldatud Linuxi operatsioonisĂŒsteem. MasinĂ”ppe sĂŒsteemide tööks vajalik riistvara peab olema piisavalt vĂ”imas ja seega ka kallis. Neile, kes ei saa head masinat kĂ€eulatuses, soovitan pöörata tĂ€helepanu pilveteenuse pakkujate pakkumistele. Vajalikku serverit saab kiiresti rentida ja maksta ainult kasutamise aja eest.
Projektides, kus on vajalik nĂ€rvivĂ”rkude loomine, kasutan ĂŒhe vene pilveteenuse pakkuja servereid. EttevĂ”te pakub masinĂ”ppe jaoks spetsiaalselt tugevaid Tesla V100 graafikaprotsessoreid (GPU) rentimiseks. Ătlen lĂŒhidalt: GPU kasutamine vĂ”ib olla kĂŒmneid kordi tĂ”husam (kiirem) vĂ”rreldes samas hinnaklassis CPU-d (keskprotsessor, millest kĂ”ik on hĂ€sti teadlikud) kasutava serveriga. See saavutatakse GPU arhitektuuri eripĂ€rade tĂ”ttu, mis suudab arvutusi kiiremini teostada.
KÀesolevas nÀites, mis on edaspidi kirjeldatud, ostsime mÔneks pÀevaks jÀrgmise serveri:
- SSD ketas 150 GB
- RAM 32 GB
- Protsessor Tesla V100 16 Gb 4 tuumaga
Meie masinale on installitud Ubuntu 18.04.
Installime keskkonna
NĂŒĂŒd installime serverile kĂ”ik vajalikud tööriistad. Kuna meie artikkel on peamiselt suunatud algajatele, rÀÀgin selles mĂ”ningatest punktidest, mis neile kasulikud on.
Palju tööd keskkonna seadistamisel tehakse kĂ€surea kaudu. Enamik kasutajatest kasutab tööoperatsioonisĂŒsteemina Windowsi. Selle opsĂŒsteemi standardne konsool jĂ€tab soovida. SeetĂ”ttu kasutame mugavat tööriista . Laadige alla mini versioon ja kĂ€ivitage Cmder.exe. Edasi tuleb serveriga ĂŒhendada SSH protokolli kaudu:
ssh root@server-ip-or-hostnameServeri IP-koodi vĂ”i DNS-nime sisestamiseks asendage server-ip-or-hostname. Edasi sisestage parool ja edukal ĂŒhendamisel peaksime saama umbes sellise sĂ”numi.
Tere tulemast Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)ML mudelite arendamiseks on peamine keel Python. Ja kÔige populaarsem platvorm selle kasutamiseks Linuxi all on .
Installime selle meie serverile.
Alustame kohaliku pakihalduri vÀrskendamisega:
sudo apt-get updateInstallime curl (kÀsklusprogramm):
sudo apt-get install curlLaadime alla Anaconda Distributsiooni viimase versiooni:
cd /tmp
curl âO https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.shKĂ€ivitame installatsiooni:
bash Anaconda3-2019.10-Linux-x86_64.shInstallimise kÀigus tuleb nÔustuda litsentsilepinguga. Eduka installimise korral peaksite nÀgema seda:
AitÀh, et installisite Anaconda3!ML mudelite arendamiseks on loodud palju raamistikku, me töötame kÔige populaarsematega: ja .
Raamistiku kasutamine vĂ”imaldab arenduse kiirus kasvada ja kasutada juba olemasolevaid tööriistu standardsete ĂŒlesannete tĂ€itmiseks.
Selles nÀites töötame PyTorchiga. Installime selle:
conda install pytorch torchvision cudatoolkit=10.1 -c pytorchNĂŒĂŒd peame kĂ€ivitama Jupyter Notebooki â ML spetsialistide seas populaarse arendustööriista. See vĂ”imaldab kirjutada koodi ja kohe nĂ€ha selle tĂ€itmise tulemusi. Jupyter Notebook on Anaconda osaks ja juba installitud meie serverisse. Peame sellele oma töölauasĂŒsteemist ĂŒhenduma.
Selleks kÀivitame kÔigepealt Jupyter serveris, mÀÀrates pordi 8080:
jupyter notebook --no-browser --port=8080 --allow-rootSeejĂ€rel avame meie konsoolis Cmder veel ĂŒhe vahekaart (ĂŒlemine menĂŒĂŒ â New console dialog) ja ĂŒhendame SSH kaudu serveriga pordil 8080:
ssh -L 8080:localhost:8080 root@server-ip-or-hostnameEsimese kÀsu sisestamisel pakutakse meile linke Jupyter'i avamiseks meie brauseris:
Notebooksse pÀÀsemiseks avage see fail brauseris:
file:///root/.local/share/jupyter/runtime/nbserver-18788-open.html
VÔi kopeerige ja kleepige mÔni neist URL-idest:
http://localhost:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311
vÔi http://127.0.0.1:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311
Kasutame linki localhost:8080. Kopeerige tÀielik tee ja kleepige see teie PC kohalikku brauseri aadressiribale. Jupyter Notebook avaneb.
Loome uue notepad'i: New â Notebook â Python 3.
Kontrollime, et kÔik installitud komponendid töötavad Ôigesti. Sisestame Jupyterisse PyTorch'i koodi nÀite ja kÀivitame selle (nupp Run):
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
Tulemus peaks olema umbes selline:

Kui teil on sarnane tulemus â siis on meil kĂ”ik Ă”igesti seadistatud ja saame alustada nĂ€rvivĂ”rgu arendamist!
Loome nÀrvivÔrgu
Loome nÀrvivÔrgu piltide Àra tundmiseks. Meie aluseks on jÀrgmine .
VĂ”rgu treenimiseks kasutame avalikku CIFAR10 andmekogumit. Sellel on klassid: âlennukâ, âautoâ, âlindâ, âkassâ, âhirvâ, âkoerâ, âkonnâ, âhobuneâ, âlaevâ, âveokâ. CIFAR10 pildid on mÔÔtmetega 3x32x32, st kolmekanalilised vĂ€rvilised pildid, mille suurus on 32Ă32 pikslit.

Töötamiseks kasutame loodud PyTorch'i paketti piltide töötlemiseks â torchvision.
Teeme jÀrgmised sammud jÀrjekorras:
- Treening- ja testandmete komplektide laadimine ja normaliseerimine
- NÀrvivÔrgu mÀÀratlemine
- VÔrgu treenimine koolitusandmetel
- VÔrgu testimine testandmetel
- Kordame treenimist ja testimist GPU kasutamisega
Kogu allpool toodud koodi tÀidame Jupyter Notebooks.
CIFAR10 laadimine ja normaliseerimine
Kopeerige ja kÀivitage Jupyter'is 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 = ('lennuk', 'auto', 'lind', ' kass',
'hirv', 'koer', 'konn', 'hobune', 'laev', 'veok')Vastus peaks olema jÀrgmine:
Laadimine https:\/\/www.cs.toronto.edu\/~kriz\/cifar-10-python.tar.gz .\/data\/cifar-10-python.tar.gz
Pakkimine .\/data\/cifar-10-python.tar.gz .\/data
Failid on juba alla laaditud ja kontrollitudKuvame mÔned treeningpildid kontrollimiseks:
import matplotlib.pyplot as plt
import numpy as np
# funktsioon pildi kuvamiseks
def imshow(img):
img = img \/ 2 + 0.5 # normaliseerimine tagasi
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# vÔtame mÔned juhuslikud treeningpildid
dataiter = iter(trainloader)
images, labels = dataiter.next()
# kuvame pilte
imshow(torchvision.utils.make_grid(images))
# prindime sildid
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

NÀrvivÔrgu mÀÀratlemine
Vaadakem kĂ”igepealt, kuidas töötab piltide tuvastamise nĂ€rvivĂ”rk. See on lihtne otseĂŒhenduste vĂ”rk. See vĂ”tab sisendi, edastab selle lĂ€bi mitme kihi jĂ€rjestikku ja seejĂ€rel annab lĂ”puks vĂ€ljundi.

Loome meie keskkonnas sarnase vÔrgu:
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()
MÀÀrame ka kaotuse funktsiooni ja optimeerija
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)VÔrgu treenimine koolitusandmetel
Alustame meie nÀrvivÔrgu treeningut. TÔin vÀlja, et pÀrast koodi kÀivitamist peate ootama mÔnda aega, kuni see lÔpule jÔuab. Minu jaoks vÔttis see 5 minutit. VÔrgu treenimiseks on vajalik aeg.
kuni aeg, kui vahemik on 2: # kordame andmeid mitu korda
jooksva_kadu = 0.0
kÔigi, andmete_hulgad in enumerate(trainloader, 0):
# saame sisendid; andmed on loend [sisendid, sildid]
sisendid, sildid = andmed
# nullime parameetrite gradandid
optimizer.zero_grad()
# edasi + tagasi + optimeeri
vÀljundid = net(sisendid)
kadumine = criterion(vÀljundid, sildid)
kadumine.backward()
optimizer.step()
# trĂŒki statistika
jooksva_kadu += kadumine.item()
kui i % 2000 == 1999: # prindi vÀlja iga 2000 mini-batch'ide kohta
print('[%d, ] kadumine: %.3f' %
(aeg + 1, i + 1, jooksva_kadu / 2000))
jooksva_kadu = 0.0
print('Koolitus lÔpetatud')
Saame sellise tulemuse:

Salvestame meie koolitatud mudeli:
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)VÔrgu testimine testandmetel
Olemegi koolitanud vĂ”rku, kasutades koolitusandmete kogumit. Kuid peame kontrollima, kas vĂ”rku on ĂŒldse midagi Ă”petatud.
Kontrollime seda, ennustades klassi sildi, mis vÀljundit annab nÀrvivÔrk, ja kontrollides seda tÔe suhtes. Kui ennustus on Ôige, lisame nÀite Ôigete ennustuste loendisse.
Kujutame ette pilti testimiskogust:
dataiter = iter(testloader)
pildid, sildid = dataiter.next()
# trĂŒki pildid
imshow(torchvision.utils.make_grid(pildid))
print('TÔeline tÔde: ', ' '.join('%5s' % klassid[sildid[j]] for j in range(4))) 
NĂŒĂŒd palume nĂ€rvivĂ”rgul öelda meile, mis nende piltide peal on:
net = Net()
net.load_state_dict(torch.load(PATH))
vÀljundid = net(pildid)
_, ennustatud = torch.max(vÀljundid, 1)
print('Ennustatud: ', ' '.join('%5s' % klassid[ennustatud[j]]
for j in range(4)))

Tulemused nĂ€ivad ĂŒsna head: vĂ”rk tuvastas Ă”igesti kolm pilti neljast.
Vaatame, kuidas vÔrku töötab kogu andmekogumiga.
Ôige = 0
total = 0
with torch.no_grad():
for andmed in testloader:
pildid, sildid = andmed
vÀljundid = net(pildid)
_, ennustatud = torch.max(vÀljundid.data, 1)
total += sildid.size(0)
Ôige += (ennustatud == sildid).sum().item()
print('VÔrgu tÀpsus 10000 testpildil: %d %%' % (
100 * Ôige / total)) 
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 mÀÀrab:
klass_oige = list(0. for i in range(10))
klass_kokku = list(0. for i in range(10))
with torch.no_grad():
for andmed in testloader:
pildid, sildid = andmed
vÀljundid = net(pildid)
_, ennustanud = torch.max(vÀljundid, 1)
c = (ennustanud == sildid).squeeze()
for i in range(4):
silt = sildid[i]
klass_oige[silt] += c[i].item()
klass_kokku[silt] += 1
for i in range(10):
print('TĂ€psus %5s : %%' % (
klassid[i], 100 * klass_oige[i] / klass_kokku[i])) 
Tundub, et vÔrk mÀÀrab kÔige paremini autosid ja laevu: 71% tÀpsus.
Nii et vĂ”rk töötab. NĂŒĂŒd proovime viia selle töö graafikakaardile (GPU) ja vaatame, mis muutub.
NÀrvivÔrgu treenimine GPU-l
Esialgu selgitan lĂŒhidalt, mis on CUDA. CUDA (Compute Unified Device Architecture) on NVIDIA loodud paralleelsete arvutuste platvorm ĂŒldiseks arvutamiseks graafikaprotsessoritel (GPU-del). CUDA abil saavad arendajad mĂ€rkimisvÀÀrselt kiirendada arvutusrakendusi, kasutades grafikaeidmise protsessorite vĂ”imet. Meie ostetud serveris on see platvorm juba paigaldatud.
Alustame meie GPU mÀÀratlemisega kui esimesest nÀhtavast cuda seadmetest.
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Eeldades, et oleme CUDA masinas, peaks see printima CUDA seadme:
print(device) 
Saadetame vÔrgustiku GPU-le:
net.to(device)Peame samuti saadetama sisendid ja sihid igal sammul GPU-le:
inputs, labels = data[0].to(device), data[1].to(device)KÀivitame vÔrgu uuestiÔppimise juba GPU-l:
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for aeg in range(2): # kordame andmeid mitu korda
jooksva_kadu = 0.0
for i, andmed in enumerate(trainloader, 0):
# saame sisendid; andmed on loend [sisendid, sildid]
sisendid, sildid = andmed[0].to(device), andmed[1].to(device)
# nullime parameetrite gradandid
optimizer.zero_grad()
# edasi + tagasi + optimeeri
vÀljundid = net(sisendid)
kadumine = criterion(vÀljundid, sildid)
kadumine.backward()
optimizer.step()
# trĂŒki statistika
jooksva_kadu += kadumine.item()
kui i % 2000 == 1999: # prindi vÀlja iga 2000 mini-batch'ide kohta
print('[%d, ] kadumine: %.3f' %
(aeg + 1, i + 1, jooksva_kadu / 2000))
jooksva_kadu = 0.0
print('Koolitus lÔpetatud')Seekord kestis vÔrgu Ôpetamine umbes 3 minutit. Kinnitatakse, et sama etapp tavalisel protsessoril kestis 5 minutit. Erinevus pole oluline, see toimub seetÔttu, et meie vÔrk ei ole nii suur. Suurte andmekogumite kasutamisel suureneb erinevus GPU ja traditsioonilise protsessori töökiirusel.
Tundub, et see on kÔik. Mida me saavutasime:
- Me uurisime, mis on GPU ja valisime serveri, millel see on paigaldatud;
- Me seadsime ĂŒles programmikeskkonna nĂ€rvivĂ”rgu loomiseks;
- Me tegime nÀrvivÔrgu piltide tuvastamiseks ja koolitasime seda;
- Me kordasime vÔrgu Ôpetamist GPU abil ja saime kiirusetÔusu.
Olen valmis vastama kĂŒsimustele kommentaarides.
Allikas: habr.com
