V tomto článku vám poviem, ako za 30 minút nastaviť prostredie strojového učenia, vytvoriť neurónovú sieť na rozpoznávanie obrázkov a potom spustiť rovnakú sieť na grafickom procesore (GPU).
Najprv si definujme, čo je neurónová sieť.
V našom prípade ide o matematický model, ako aj jeho softvérové či hardvérové stelesnenie, postavené na princípe organizácie a fungovania biologických neurónových sietí – sietí nervových buniek živého organizmu. Tento koncept vznikol pri štúdiu procesov prebiehajúcich v mozgu a pri pokuse o modelovanie týchto procesov.
Neurónové siete nie sú naprogramované v bežnom zmysle slova, sú natrénované. Schopnosť učiť sa je jednou z hlavných výhod neurónových sietí oproti tradičným algoritmom. Technicky učenie pozostáva z hľadania koeficientov spojení medzi neurónmi. Počas tréningového procesu je neurónová sieť schopná identifikovať zložité závislosti medzi vstupnými dátami a výstupnými dátami, ako aj vykonávať zovšeobecňovanie.
Z hľadiska strojového učenia je neurónová sieť špeciálnym prípadom metód rozpoznávania vzorov, diskriminačnej analýzy, metód zhlukovania a ďalších metód.
Оборудование
Najprv sa pozrime na výbavu. Potrebujeme server s nainštalovaným operačným systémom Linux. Zariadenia potrebné na prevádzku systémov strojového učenia sú pomerne výkonné a v dôsledku toho drahé. Pre tých, ktorí nemajú po ruke dobrý stroj, odporúčam venovať pozornosť ponukám cloudových poskytovateľov. Požadovaný server si môžete rýchlo prenajať a platiť len za čas používania.
V projektoch, kde je potrebné vytvárať neurónové siete, využívam servery jedného z ruských cloudových poskytovateľov. Spoločnosť ponúka cloudové servery na prenájom špeciálne pre strojové učenie s výkonnými grafickými procesormi Tesla V100 (GPU) od NVIDIA. Stručne povedané: používanie servera s GPU môže byť desaťkrát efektívnejšie (rýchlejšie) v porovnaní so serverom s podobnou cenou, ktorý na výpočty používa CPU (známu centrálnu procesorovú jednotku). To je dosiahnuté vďaka vlastnostiam architektúry GPU, ktorá sa rýchlejšie vyrovná s výpočtami.
Na implementáciu príkladov popísaných nižšie sme na niekoľko dní zakúpili nasledujúci server:
- SSD disk 150 GB
- RAM 32 GB
- Procesor Tesla V100 16 Gb so 4 jadrami
Na náš počítač sme nainštalovali Ubuntu 18.04.
Nastavenie prostredia
Teraz nainštalujte všetko potrebné pre prácu na serveri. Keďže náš článok je primárne pre začiatočníkov, poviem vám niekoľko bodov, ktoré budú pre nich užitočné.
Veľa práce pri nastavovaní prostredia sa vykonáva cez príkazový riadok. Väčšina používateľov používa Windows ako svoj pracovný OS. Štandardná konzola v tomto OS ponecháva veľa požiadaviek. Preto použijeme pohodlný nástroj
ssh root@server-ip-or-hostname
Namiesto adresy IP servera alebo názvu hostiteľa zadajte adresu IP alebo názov DNS vášho servera. Ďalej zadajte heslo a ak je pripojenie úspešné, mali by sme dostať správu podobnú tejto.
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)
Hlavným jazykom pre vývoj modelov ML je Python. A najobľúbenejšia platforma pre jeho použitie na Linuxe je
Poďme si ho nainštalovať na náš server.
Začneme aktualizáciou lokálneho správcu balíkov:
sudo apt-get update
Nainštalujte curl (utilita príkazového riadka):
sudo apt-get install curl
Stiahnite si najnovšiu verziu distribúcie Anaconda:
cd /tmp
curl –O https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
Začnime s inštaláciou:
bash Anaconda3-2019.10-Linux-x86_64.sh
Počas procesu inštalácie budete vyzvaní na potvrdenie licenčnej zmluvy. Po úspešnej inštalácii by ste mali vidieť toto:
Thank you for installing Anaconda3!
V súčasnosti bolo vytvorených mnoho rámcov na vývoj modelov ML; pracujeme s najpopulárnejšími:
Používanie frameworku umožňuje zvýšiť rýchlosť vývoja a využívať hotové nástroje pre štandardné úlohy.
V tomto príklade budeme pracovať s PyTorch. Poďme si to nainštalovať:
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch
Teraz musíme spustiť Jupyter Notebook, populárny vývojový nástroj pre špecialistov na ML. Umožňuje vám písať kód a okamžite vidieť výsledky jeho vykonania. Jupyter Notebook je súčasťou Anaconda a je už nainštalovaný na našom serveri. Musíte sa k nemu pripojiť z nášho desktopového systému.
Aby sme to urobili, najprv spustíme Jupyter na serveri špecifikujúcom port 8080:
jupyter notebook --no-browser --port=8080 --allow-root
Potom otvorením ďalšej karty v našej konzole Cmder (horné menu - dialógové okno Nová konzola) sa pripojíme cez port 8080 k serveru cez SSH:
ssh -L 8080:localhost:8080 root@server-ip-or-hostname
Keď zadáme prvý príkaz, ponúknu sa nám odkazy na otvorenie Jupyter v našom prehliadači:
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
Použime odkaz pre localhost:8080. Skopírujte celú cestu a vložte ju do panela s adresou v lokálnom prehliadači vášho počítača. Otvorí sa Zápisník Jupyter.
Vytvorme nový poznámkový blok: Nový - Zápisník - Python 3.
Skontrolujeme správnu činnosť všetkých komponentov, ktoré sme nainštalovali. Zadáme príklad kódu PyTorch do Jupyter a spustíme spustenie (tlačidlo Spustiť):
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
Výsledkom by malo byť niečo takéto:
Ak máte podobný výsledok, tak sme všetko správne nakonfigurovali a môžeme začať s vývojom neurónovej siete!
Vytvorenie neurónovej siete
Vytvoríme neurónovú sieť na rozpoznávanie obrazu. Zoberme si to ako základ
Na trénovanie siete použijeme verejne dostupný dataset CIFAR10. Má triedy: „lietadlo“, „auto“, „vták“, „mačka“, „jeleň“, „pes“, „žaba“, „kôň“, „loď“, „nákladné auto“. Obrázky v CIFAR10 sú 3x32x32, to znamená 3-kanálové farebné obrázky s rozmermi 32x32 pixelov.
Na prácu nám poslúži balík vytvorený PyTorchom na prácu s obrázkami – torchvision.
Urobíme nasledujúce kroky v poradí:
- Načítanie a normalizácia tréningových a testovacích dátových súborov
- Definícia neurónovej siete
- Sieťový tréning na tréningových údajoch
- Testovanie siete na testovacích údajoch
- Zopakujme si tréning a testovanie pomocou GPU
Všetky nižšie uvedené kódy spustíme v Jupyter Notebooku.
Načítavanie a normalizácia CIFAR10
Skopírujte a spustite nasledujúci kód v 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')
Odpoveď by mala byť:
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
Ukážme si niekoľko tréningových obrázkov na testovanie:
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)))
Definícia neurónovej siete
Najprv sa zamyslime nad tým, ako funguje neurónová sieť na rozpoznávanie obrázkov. Ide o jednoduchú sieť typu point-to-point. Zoberie vstupné dáta, prejde ich cez niekoľko vrstiev jednu po druhej a nakoniec vytvorí výstupné dáta.
Vytvorme podobnú sieť v našom prostredí:
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()
Definujeme tiež stratovú funkciu a optimalizátor
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
Sieťový tréning na tréningových údajoch
Začnime trénovať našu neurónovú sieť. Upozorňujeme, že po spustení tohto kódu budete musieť nejaký čas počkať, kým sa práca nedokončí. Trvalo mi to 5 minút. Natrénovanie siete si vyžaduje čas.
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')
Dostaneme nasledujúci výsledok:
Ukladáme náš vyškolený model:
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)
Testovanie siete na testovacích údajoch
Trénovali sme sieť pomocou súboru tréningových dát. Musíme však skontrolovať, či sa sieť vôbec niečo naučila.
Otestujeme to predpovedaním označenia triedy, ktoré neurónová sieť vydáva, a testovaním, či je pravdivý. Ak je predpoveď správna, vzorku pridáme do zoznamu správnych predpovedí.
Ukážme obrázok z testovacej sady:
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)))
Teraz požiadajme neurónovú sieť, aby nám povedala, čo je na týchto obrázkoch:
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)))
Výsledky sa zdajú celkom dobré: sieť správne identifikovala tri zo štyroch obrázkov.
Pozrime sa, ako funguje sieť v rámci celého súboru údajov.
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))
Zdá sa, že sieť niečo vie a funguje. Ak by triedy určil náhodne, presnosť by bola 10 %.
Teraz sa pozrime, ktoré triedy sieť identifikuje lepšie:
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]))
Zdá sa, že sieť je najlepšia na identifikáciu áut a lodí: presnosť 71 %.
Takže sieť funguje. Teraz skúsme preniesť jeho prácu na grafický procesor (GPU) a uvidíme, čo sa zmení.
Trénovanie neurónovej siete na GPU
Najprv stručne vysvetlím, čo je CUDA. CUDA (Compute Unified Device Architecture) je paralelná výpočtová platforma vyvinutá spoločnosťou NVIDIA pre všeobecné výpočty na grafických procesoroch (GPU). S CUDA môžu vývojári výrazne urýchliť výpočtové aplikácie využitím výkonu GPU. Táto platforma je už nainštalovaná na našom serveri, ktorý sme zakúpili.
Najprv definujme náš GPU ako prvé viditeľné cuda zariadenie.
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 )
Odoslanie siete do GPU:
net.to(device)
Budeme tiež musieť odoslať vstupy a ciele v každom kroku do GPU:
inputs, labels = data[0].to(device), data[1].to(device)
Poďme znova natrénovať sieť na 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')
Tentoraz tréning siete trval približne 3 minúty. Pripomeňme, že rovnaká fáza na bežnom procesore trvala 5 minút. Rozdiel nie je výrazný, stáva sa to preto, lebo naša sieť nie je taká veľká. Pri použití veľkých polí na tréning sa rozdiel medzi rýchlosťou GPU a tradičného procesora zväčší.
Zdá sa, že to je všetko. Čo sa nám podarilo:
- Pozreli sme sa na to, čo je GPU, a vybrali sme server, na ktorom je nainštalovaný;
- Nastavili sme softvérové prostredie na vytvorenie neurónovej siete;
- Vytvorili sme neurónovú sieť na rozpoznávanie obrazu a natrénovali sme ju;
- Zopakovali sme sieťový tréning pomocou GPU a dosiahli sme zvýšenie rýchlosti.
Na otázky rád odpoviem v komentároch.
Zdroj: hab.com