Å ajÄ rakstÄ es jums pastÄstÄ«Å”u, kÄ 30 minÅ«tÄs iestatÄ«t maŔīnmÄcÄ«Å”anÄs vidi, izveidot neironu tÄ«klu attÄlu atpazÄ«Å”anai un pÄc tam palaist to paÅ”u tÄ«klu grafikas procesorÄ (GPU).
PirmkÄrt, definÄsim, kas ir neironu tÄ«kls.
MÅ«su gadÄ«jumÄ tas ir matemÄtisks modelis, kÄ arÄ« tÄ programmatÅ«ras vai aparatÅ«ras iemiesojums, kas veidots pÄc bioloÄ£isko neironu tÄ«klu - dzÄ«va organisma nervu Ŕūnu tÄ«klu - organizÄcijas un darbÄ«bas principa. Å Ä« koncepcija radÄs, pÄtot smadzenÄs notiekoÅ”os procesus un mÄÄ£inot modelÄt Å”os procesus.
Neironu tÄ«kli nav ieprogrammÄti Ŕī vÄrda parastajÄ nozÄ«mÄ, tie ir apmÄcÄ«ti. SpÄja mÄcÄ«ties ir viena no galvenajÄm neironu tÄ«klu priekÅ”rocÄ«bÄm salÄ«dzinÄjumÄ ar tradicionÄlajiem algoritmiem. Tehniski mÄcÄ«Å”anÄs sastÄv no neironu savienojumu koeficientu atraÅ”anas. ApmÄcÄ«bas procesÄ neironu tÄ«kls spÄj identificÄt sarežģītas atkarÄ«bas starp ievaddatiem un izvaddatiem, kÄ arÄ« veikt vispÄrinÄÅ”anu.
No maŔīnmÄcÄ«Å”anÄs viedokļa neironu tÄ«kls ir Ä«paÅ”s modeļu atpazÄ«Å”anas metožu, diskriminantu analÄ«zes, klasterizÄcijas metožu un citu metožu gadÄ«jums.
ŠŠ±Š¾ŃŃŠ“Š¾Š²Š°Š½ŠøŠµ
Vispirms apskatÄ«sim aprÄ«kojumu. Mums ir nepiecieÅ”ams serveris ar instalÄtu Linux operÄtÄjsistÄmu. MaŔīnmÄcÄ«Å”anÄs sistÄmu darbÄ«bai nepiecieÅ”amais aprÄ«kojums ir diezgan jaudÄ«gs un lÄ«dz ar to dÄrgs. Tiem, kam pie rokas nav labas maŔīnas, iesaku pievÄrst uzmanÄ«bu mÄkoÅpakalpojumu sniedzÄju piedÄvÄjumiem. NepiecieÅ”amo serveri var Ätri iznomÄt un maksÄt tikai par lietoÅ”anas laiku.
Projektos, kur nepiecieÅ”ams izveidot neironu tÄ«klus, izmantoju kÄda Krievijas mÄkoÅpakalpojumu sniedzÄja serverus. UzÅÄmums piedÄvÄ nomÄt mÄkoÅserverus Ä«paÅ”i maŔīnmÄcÄ«bai ar jaudÄ«giem Tesla V100 grafikas procesoriem (GPU) no NVIDIA. ÄŖsÄk sakot: servera ar GPU izmantoÅ”ana var bÅ«t desmitiem reižu efektÄ«vÄka (ÄtrÄka) salÄ«dzinÄjumÄ ar lÄ«dzÄ«gu izmaksu serveri, kas aprÄÄ·iniem izmanto CPU (labi zinÄmo centrÄlo procesoru). Tas tiek panÄkts, pateicoties GPU arhitektÅ«ras iezÄ«mÄm, kas ÄtrÄk tiek galÄ ar aprÄÄ·iniem.
Lai Ä«stenotu tÄlÄk aprakstÄ«tos piemÄrus, mÄs uz vairÄkÄm dienÄm iegÄdÄjÄmies Å”Ädu serveri:
- SSD disks 150 GB
- RAM 32 GB
- Tesla V100 16 Gb procesors ar 4 kodoliem
MÄs savÄ datorÄ instalÄjÄm Ubuntu 18.04.
Vides iekÄrtoÅ”ana
Tagad instalÄsim visu darbam nepiecieÅ”amo uz servera. TÄ kÄ mÅ«su raksts galvenokÄrt ir paredzÄts iesÄcÄjiem, es runÄÅ”u par dažiem punktiem, kas viÅiem bÅ«s noderÄ«gi.
Liela daļa darba vides iestatÄ«Å”anas laikÄ tiek veikta, izmantojot komandrindu. LielÄkÄ daļa lietotÄju izmanto Windows kÄ savu darba OS. Standarta konsole Å”ajÄ OS atstÄj daudz ko vÄlÄties. TÄpÄc mÄs izmantosim Ärtu rÄ«ku
ssh root@server-ip-or-hostname
Servera ip vai resursdatora nosaukums vietÄ norÄdiet sava servera IP adresi vai DNS nosaukumu. PÄc tam ievadiet paroli un, ja savienojums ir veiksmÄ«gs, mums vajadzÄtu saÅemt lÄ«dzÄ«gu ziÅojumu.
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)
GalvenÄ valoda ML modeļu izstrÄdei ir Python. Un vispopulÄrÄkÄ platforma tÄs lietoÅ”anai operÄtÄjsistÄmÄ Linux ir
InstalÄsim to savÄ serverÄ«.
MÄs sÄkam ar vietÄjÄ pakotÅu pÄrvaldnieka atjauninÄÅ”anu:
sudo apt-get update
InstalÄjiet curl (komandrindas utilÄ«ta):
sudo apt-get install curl
LejupielÄdÄjiet jaunÄko Anaconda Distribution versiju:
cd /tmp
curl āO https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
SÄksim instalÄÅ”anu:
bash Anaconda3-2019.10-Linux-x86_64.sh
InstalÄÅ”anas procesa laikÄ jums tiks lÅ«gts apstiprinÄt licences lÄ«gumu. PÄc veiksmÄ«gas instalÄÅ”anas jums vajadzÄtu redzÄt Å”o:
Thank you for installing Anaconda3!
ML modeļu izstrÄdei tagad ir izveidoti daudzi ietvari, mÄs strÄdÄjam ar populÄrÄkajiem:
Izmantojot ietvaru, varat palielinÄt izstrÄdes Ätrumu un izmantot gatavus rÄ«kus standarta uzdevumiem.
Å ajÄ piemÄrÄ mÄs strÄdÄsim ar PyTorch. InstalÄsim to:
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch
Tagad mums ir jÄizlaiž Jupyter Notebook, populÄrs izstrÄdes rÄ«ks ML speciÄlistiem. Tas ļauj rakstÄ«t kodu un nekavÄjoties redzÄt tÄ izpildes rezultÄtus. Jupyter piezÄ«mjdators ir iekļauts Anaconda komplektÄcijÄ un jau ir instalÄts mÅ«su serverÄ«. Jums ir jÄizveido savienojums ar to no mÅ«su darbvirsmas sistÄmas.
Lai to izdarÄ«tu, mÄs vispirms palaidÄ«sim Jupyter serverÄ«, norÄdot portu 8080:
jupyter notebook --no-browser --port=8080 --allow-root
PÄc tam, atverot citu cilni mÅ«su Cmder konsolÄ (augÅ”ÄjÄ izvÄlne ā dialoglodziÅÅ” Jauna konsole), mÄs caur portu 8080 izveidosim savienojumu ar serveri, izmantojot SSH:
ssh -L 8080:localhost:8080 root@server-ip-or-hostname
Ievadot pirmo komandu, mums tiks piedÄvÄtas saites, lai pÄrlÅ«kprogrammÄ atvÄrtu Jupyter:
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
Izmantosim saiti uz localhost:8080. KopÄjiet pilnu ceļu un ielÄ«mÄjiet to datora lokÄlÄs pÄrlÅ«kprogrammas adreses joslÄ. Tiks atvÄrts Jupyter piezÄ«mju grÄmatiÅa.
Izveidosim jaunu piezÄ«mju grÄmatiÅu: Jauns - PiezÄ«mju grÄmatiÅa - Python 3.
PÄrbaudÄ«sim visu mÅ«su instalÄto komponentu pareizu darbÄ«bu. IevadÄ«sim PyTorch koda piemÄru Jupyter un palaidÄ«sim izpildi (poga Palaist):
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
RezultÄtam vajadzÄtu bÅ«t apmÄram Å”Ädam:
Ja jums ir lÄ«dzÄ«gs rezultÄts, tad esam visu pareizi konfigurÄjuÅ”i un varam sÄkt neironu tÄ«kla izstrÄdi!
Neironu tīkla izveide
Izveidosim neironu tÄ«klu attÄlu atpazÄ«Å”anai. Å
emsim to par pamatu
TÄ«kla apmÄcÄ«Å”anai izmantosim publiski pieejamo CIFAR10 datu kopu. Tam ir klases: "lidmaŔīna", "maŔīna", "putns", "kaÄ·is", "brieži", "suns", "varde", "zirgs", "kuÄ£is", "kravas automaŔīna". CIFAR10 attÄli ir 3x32x32, tas ir, 3 kanÄlu krÄsu attÄli ar 32x32 pikseļiem.
Darbam izmantosim PyTorch izveidoto pakotni darbam ar attÄliem - torchvision.
MÄs veiksim Å”Ädas darbÄ«bas secÄ«bÄ:
- ApmÄcÄ«bas un testa datu kopu ielÄde un normalizÄÅ”ana
- Neironu tīkla definīcija
- TÄ«kla apmÄcÄ«ba par apmÄcÄ«bu datiem
- TÄ«kla testÄÅ”ana uz testa datiem
- AtkÄrtosim apmÄcÄ«bu un testÄÅ”anu, izmantojot GPU
MÄs izpildÄ«sim visu tÄlÄk norÄdÄ«to kodu Jupyter Notebook.
CIFAR10 ielÄde un normalizÄÅ”ana
KopÄjiet un palaidiet Å”o kodu programmÄ 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')
Atbildei jÄbÅ«t Å”Ädai:
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
PÄrbaudei parÄdÄ«sim vairÄkus treniÅu attÄlus:
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)))
Neironu tīkla definīcija
Vispirms apskatÄ«sim, kÄ darbojas attÄlu atpazÄ«Å”anas neironu tÄ«kls. Å is ir vienkÄrÅ”s tÄ«kls no punkta uz punktu. Tas Åem ievades datus, izlaiž tos pa vairÄkiem slÄÅiem pa vienam un pÄc tam beidzot ražo izvaddatus.
Izveidosim lÄ«dzÄ«gu tÄ«klu mÅ«su vidÄ:
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Äs arÄ« definÄjam zaudÄjumu funkciju un optimizÄtÄju
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
TÄ«kla apmÄcÄ«ba par apmÄcÄ«bu datiem
SÄksim apmÄcÄ«t savu neironu tÄ«klu. LÅ«dzu, Åemiet vÄrÄ, ka pÄc Ŕī koda palaiÅ”anas jums bÅ«s jÄgaida zinÄms laiks, lÄ«dz darbs tiks pabeigts. Man tas aizÅÄma 5 minÅ«tes. TÄ«kla apmÄcÄ«bai nepiecieÅ”ams laiks.
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')
MÄs iegÅ«stam Å”Ädu rezultÄtu:
MÄs saglabÄjam mÅ«su apmÄcÄ«to modeli:
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)
TÄ«kla testÄÅ”ana uz testa datiem
MÄs apmÄcÄ«jÄm tÄ«klu, izmantojot apmÄcÄ«bas datu kopu. Bet mums ir jÄpÄrbauda, āāvai tÄ«kls vispÄr ir kaut ko iemÄcÄ«jies.
MÄs to pÄrbaudÄ«sim, paredzot neironu tÄ«kla izvadÄ«to klases etiÄ·eti un pÄrbaudot, vai tÄ ir patiesa. Ja prognoze ir pareiza, paraugu pievienojam pareizo prognožu sarakstam.
ParÄdÄ«sim attÄlu no testa komplekta:
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)))
Tagad palÅ«gsim neironu tÄ«klam pastÄstÄ«t, kas ir Å”ajos attÄlos:
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)))
RezultÄti Ŕķiet diezgan labi: tÄ«kls pareizi identificÄja trÄ«s no Äetriem attÄliem.
ApskatÄ«sim, kÄ tÄ«kls darbojas visÄ datu kopÄ.
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))
Å Ä·iet, ka tÄ«kls kaut ko zina un darbojas. Ja viÅÅ” nejauÅ”i noteiktu klases, precizitÄte bÅ«tu 10%.
Tagad apskatÄ«sim, kuras klases tÄ«kls identificÄ labÄk:
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]))
Å Ä·iet, ka tÄ«kls vislabÄk identificÄ automaŔīnas un kuÄ£us: 71% precizitÄte.
TÄtad tÄ«kls darbojas. Tagad mÄÄ£inÄsim pÄrsÅ«tÄ«t tÄ darbu uz grafikas procesoru (GPU) un redzÄsim, kas mainÄs.
Neironu tÄ«kla apmÄcÄ«ba uz GPU
PirmkÄrt, es Ä«si paskaidroÅ”u, kas ir CUDA. CUDA (Compute Unified Device Architecture) ir paralÄla skaitļoÅ”anas platforma, ko NVIDIA izstrÄdÄjusi vispÄrÄjai skaitļoÅ”anai grafikas apstrÄdes blokos (GPU). Izmantojot CUDA, izstrÄdÄtÄji var ievÄrojami paÄtrinÄt skaitļoÅ”anas lietojumprogrammas, izmantojot GPU jaudu. Å Ä« platforma jau ir instalÄta mÅ«su iegÄdÄtajÄ serverÄ«.
Vispirms definÄsim mÅ«su GPU kÄ pirmo redzamo Cuda ierÄ«ci.
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 )
Tīkla nosūtīŔana uz GPU:
net.to(device)
Mums bÅ«s arÄ« jÄnosÅ«ta ievades dati un mÄrÄ·i katrÄ solÄ« uz GPU:
inputs, labels = data[0].to(device), data[1].to(device)
AtkÄrtoti apmÄcÄ«sim tÄ«klu 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')
Å oreiz tÄ«kla treniÅÅ” ilga apmÄram 3 minÅ«tes. AtcerÄsimies, ka tas pats posms parastajÄ procesorÄ ilga 5 minÅ«tes. AtŔķirÄ«ba nav bÅ«tiska, tas notiek tÄpÄc, ka mÅ«su tÄ«kls nav tik liels. Izmantojot lielus masÄ«vus apmÄcÄ«bai, palielinÄsies atŔķirÄ«ba starp GPU un tradicionÄlÄ procesora Ätrumu.
Å Ä·iet, ka tas arÄ« viss. Ko mums izdevÄs paveikt:
- MÄs apskatÄ«jÄm, kas ir GPU, un izvÄlÄjÄmies serveri, kurÄ tas ir instalÄts;
- MÄs esam izveidojuÅ”i programmatÅ«ras vidi neironu tÄ«kla izveidei;
- MÄs izveidojÄm neironu tÄ«klu attÄlu atpazÄ«Å”anai un apmÄcÄm to;
- MÄs atkÄrtojÄm tÄ«kla apmÄcÄ«bu, izmantojot GPU, un saÅÄmÄm Ätruma pieaugumu.
LabprÄt atbildÄÅ”u uz jautÄjumiem komentÄros.
Avots: www.habr.com