У гэтым артыкуле я распавяду як за 30 хвілін наладзіць асяроддзе для машыннага навучання, стварыць нейронавую сетку для распазнання малюнкаў a потым запусціць тую ж сетку на графічным працэсары (GPU).
Для пачатку вызначым што такое нейронавая сетка.
У нашым выпадку гэта матэматычная мадэль, а таксама яе праграмнае ці апаратнае ўвасабленне, пабудаваная па прынцыпе арганізацыі і функцыянавання біялагічных нейронавых сетак - сетак нервовых клетак жывога арганізма. Гэта паняцце ўзнікла пры вывучэнні працэсаў, якія праходзяць у мозгу, і пры спробе змадэляваць гэтыя працэсы.
Нейронныя сеткі не праграмуюцца ў звыклым сэнсе гэтага слова, яны вучацца. Магчымасць навучання - адна з галоўных пераваг нейронавых сетак перад традыцыйнымі алгарытмамі. Тэхнічна навучанне заключаецца ў знаходжанні каэфіцыентаў сувязей паміж нейронамі. У працэсе навучання нейронавая сетка здольная выяўляць складаныя залежнасці паміж уваходнымі дадзенымі і выходнымі, а таксама выконваць абагульненне.
З пункту гледжання машыннага навучання, нейронавая сетка ўяўляе сабой прыватны выпадак метадаў распазнання выяў, дыскрымінантнага аналізу, метадаў кластарызацыі і іншых метадаў.
Абсталяванне
Спачатку разбяромся з абсталяваннем. Нам неабходны сервер з усталяванай на ім аперацыйнай сістэмай Linux. Абсталяванне для працы сістэм машыннага навучання патрабуецца дастаткова магутнае і як следства дарагое. Тым, у каго няма пад рукой добрай машыны, рэкамендую звярнуць увагу на прапанову хмарных правайдэраў. Неабходны сервер можна атрымаць у арэнду хутка і плаціць толькі за час выкарыстання.
У праектах, дзе неабходна стварэнне нейронавых сетак я выкарыстоўваю сервера аднаго з расійскіх хмарных правайдэраў. Кампанія прапануе ў арэнду хмарныя серверы спецыяльна для машыннага навучання з магутнымі графічнымі працэсарамі (GPU) Tesla V100 ад кампаніі NVIDIA. Калі сцісла: выкарыстанне сервера з GPU можа быць у дзясяткі разоў быць больш эфектыўным (хуткім) у параўнанні з аналагічным па кошце серверам дзе для вылічэнняў выкарыстоўваецца CPU (усім добра знаёмы цэнтральны працэсар). Гэта дасягаецца за рахунак асаблівасцяў архітэктуры GPU, якая хутчэй спраўляецца з разлікамі.
Для выканання прыкладаў апісаных далей, мы набылі на некалькі дзён такі сервер:
- SSD дыск 150 ГБ
- АЗП 32 ГБ
- Працэсар Tesla V100 16 Gb з 4-ма ядрамі
На машыну нам устанавілі Ubuntu 18.04.
Усталёўваны асяроддзе
Цяпер усталюем на сервер усё неабходнае для працы. Паколькі наш артыкул у першую чаргу для пачаткоўцаў, буду расказваць у ім пра некаторыя моманты, якія спатрэбяцца менавіта ім.
Вельмі шмат працы пры наладзе асяроддзя выконваецца праз камандны радок. Большасць з карыстачоў у якасці працоўнай АС выкарыстоўваюць Windows. Стандартная кансоль у гэтай АС пакідае жадаць лепшага. Таму мы будзем выкарыстоўваць зручны інструмент
ssh root@server-ip-or-hostname
Замест server-ip-or-hostname паказваеце IP адрас ці DNS імя вашага сервера. Далей уводзім пароль і пры паспяховым падлучэнні мы павінны атрымаць прыкладна такое паведамленне.
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)
Асноўнай мовай для распрацоўкі ML мадэляў з'яўляецца Python. А найболей папулярнай платформай для яго выкарыстанне па Linux з'яўляецца
Усталюем яе на наш сервер.
Пачынаем з абнаўлення лакальнага мэнэджара пакетаў:
sudo apt-get update
Усталёўваны curl (службовая праграма каманднага радка):
sudo apt-get install curl
Спампоўваем апошнюю версію Anaconda Distribution:
cd /tmp
curl –O https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
Запускаем ўстаноўку:
bash Anaconda3-2019.10-Linux-x86_64.sh
У працэсе ўстаноўкі неабходна будзе пацвердзіць ліцэнзійную дамову. Пры паспяховай усталёўцы вы павінны будзеце ўбачыць гэта:
Thank you for installing Anaconda3!
Для распрацоўкі ML мадэляў зараз створана мноства фрэймворкаў, мы працуем з найболей папулярнымі:
Выкарыстанне фрэймворка дазваляе павялічыць хуткасць распрацоўкі і выкарыстоўваць ужо гатовыя прылады для стандартных задач.
У гэтым прыкладзе будзем працаваць з PyTorch. Усталюем яго:
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch
Зараз нам неабходна запусціць Jupyter Notebook - папулярны ў ML спецыялістаў інструмент распрацоўкі. Ён дазваляе пісаць код і адразу бачыць вынікі яго выканання. Jupyter Notebook уваходзіць у склад Anaconda і ўжо ўсталяваны на нашым серверы. Неабходна падключыцца да яго з нашай настольнай сістэмы.
Для гэтага мы спачатку запусцім Jupyter на серверы паказаўшы порт 8080:
jupyter notebook --no-browser --port=8080 --allow-root
Далей адкрыўшы ў нашай кансолі Cmder яшчэ адну ўкладку (верхняе меню – New console dialog) падлучымся па порце 8080 да сервера праз SSH:
ssh -L 8080:localhost:8080 root@server-ip-or-hostname
Пры ўводзе першай каманды нам будзе прапанаваны спасылкі для адкрыцця 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
Скарыстаемся спасылкай на localhost:8080. Скапіюйце поўны шлях і ўстаўце ў адрасны радок лакальнага браўзэра вашага ПК. Адкрыецца Jupyter Notebook.
Створым новы наўтбук: New - Notebook - Python 3.
Праверым карэктную працу ўсіх кампанентаў якія мы ўстанавілі. Увядзем у Jupyter прыклад кода PyTorch і запусцім выкананне (кнопка Run):
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
Вынік павінен быць прыкладна такім:
Калі ў вас аналагічны вынік - значыць мы ўсё наладзілі правільна і можам прыступаць да распрацоўкі нейронавай сеткі!
Ствараем нейронавую сетку
Будзем ствараць нейронавую сетку для распазнання малюнкаў. За аснову возьмем гэта
Для трэніроўкі сеткі мы будзем выкарыстоўваць агульнадаступны набор даных CIFAR10. У яго ёсць класы: "самалёт", "аўтамабіль", "птушка", "котка", "алень", "сабака", "жаба", "конь", "карабель", "грузавік". Выявы ў CIFAR10 маюць памер 3x32x32, гэта значыць 3-канальныя каляровыя выявы памерам 32×32 пікселяў.
Для працы мы будзем выкарыстоўваць створаны PyTorch пакет для працы з выявамі - torchvision.
Мы зробім наступныя крокі па парадку:
- Загрузка і нармалізацыя набораў навучальных і тэставых даных
- Вызначэнне нейронавай сеткі
- Трэніроўка сеткі на трэніровачных дадзеных
- Тэставанне сеткі на тэставых дадзеных
- Паўторым трэніроўку і тэсціраванне з выкарыстаннем GPU
Увесь прыведзены ніжэй код мы будзем выконваць у Jupyter Notebook.
Загрузка і нармалізацыя CIFAR10
Скапіюйце і выканайце ў 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')
Адказ павінен быць такі:
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
Вывядзем некалькі трэніровачных вобразаў для праверкі:
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)))
Вызначэнне нейронавай сеткі
Разгледзім спачатку як працуе нейронавая сетка па распазнанні малюнкаў. Гэта простая сетка прамой сувязі. Ён прымае ўваходныя дадзеныя, прапускае іх праз некалькі пластоў адзін за іншым, а затым, нарэшце, выдае выходныя дадзеныя.
Створым падобную сетку ў нашым асяроддзі:
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()
Азначальны гэтак жа функцыю страт і аптымізатар
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
Трэніроўка сеткі на трэніровачных дадзеных
Пачынаем трэніроўку нашай нейронавай сеткі. Звяртаю ўвагу, што пасля таго як вы запусціце на выкананне гэты код, трэба будзе пачакаць некаторы час да завяршэння працы. У мяне гэта заняло 5 хвіл. Для навучанне сеткі патрэбны час.
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')
Атрымаем такі вынік:
Захоўваем нашу навучаную мадэль:
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)
Тэставанне сеткі на тэставых дадзеных
Мы навучылі сетку выкарыстоўваю набор навучальных дадзеных. Але нам трэба праверыць, ці навучылася сетка наогул нечаму.
Мы праверым гэта, прадказаўшы пазнаку класа, якую выводзіць нейронавая сетка, і праверыўшы яе на прадмет праўдзівасці. Калі прагноз правільны, мы дадаем ўзор у спіс правільных прагнозаў.
Давайце пакажам малюнак з тэставага набору:
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)))
Зараз папросім нейронавую сетку паведаміць нам што на гэтых карцінках:
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)))
Вынікі здаюцца даволі добрымі: сетка вызначыла правільна тры карцінкі з чатырох.
Давайце паглядзім, як сетка працуе ва ўсім наборы дадзеных.
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))
Падобна на тое сетка нешта ведае і працуе. Калі б ён вызначала класы наўздагад, то дакладнасць была б 10%.
Цяпер паглядзім якія класы сетка вызначае лепш:
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]))
Выглядае што лепш за ўсё сетка вызначае аўтамабілі і караблі: 71% дакладнасці.
Такім чынам сетка працуе. Цяпер паспрабуем перанесці яе працу на графічны працэсар (GPU) і паглядзі што зменіцца.
Трэніроўка нейронавай сеткі на GPU
Спачатку растлумачу сцісла што такое CUDA. CUDA (Compute Unified Device Architecture) – платформа паралельных вылічэнняў, распрацаваная NVIDIA, для агульных вылічэнняў на графічных працэсарах (GPU). З дапамогай CUDA распрацоўшчыкі могуць значна паскорыць вылічальныя прыкладанні, выкарыстоўваючы магчымасці графічных працэсараў. На нашым сэрвэры, які мы набылі, дадзеная платформа ўжо ўсталявана.
Давайце спачатку вызначым наша GPU як першая бачная прылада 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 )
Адпраўляем сетку на GPU:
net.to(device)
Гэтак жа нам давядзецца адпраўляць уваходы і мэты на кожным кроку і ў GPU:
inputs, labels = data[0].to(device), data[1].to(device)
Запусцім паўторнае навучанне сеткі ўжо на 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')
На гэты раз навучанне сеткі працягвалася па часе каля 3 хвілін. Нагадаем, што той жа этап на звычайным працэсары доўжыўся 5 хвілін. Розніца не істотная, гэта адбываецца таму, што наша сетка не такая вялікая. Пры выкарыстанні вялікіх масіваў для навучання розніца паміж хуткасцю працы GPU і традыцыйнага працэсара будзе ўзрастаць.
На гэтым здаецца ўсё. Што нам удалося зрабіць:
- Мы разгледзелі, што такое GPU і выбралі сервер на якім ён усталяваны;
- Мы наладзілі праграмнае асяроддзе для стварэння нейронавай сеткі;
- Мы стварылі нейронавую сетку для распазнання малюнкаў і навучылі яе;
- Мы паўтарылі навучанне сеткі з выкарыстаннем GPU і атрымалі прырост у хуткасці.
Буду рады адказаць на пытанні ў каментарах.
Крыніца: habr.com