Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących
W tym artykule opowiem, jak w ciągu 30 minut skonfigurować środowisko do uczenia maszynowego, stworzyć sieć neuronową do rozpoznawania obrazów, a następnie uruchomić tę samą sieć na procesorze graficznym (GPU).

Na początek zdefiniujmy, czym jest sieć neuronowa.

W naszym przypadku jest to matematyczny model oraz jego programowa lub sprzętowa realizacja, zbudowana na zasadzie organizacji i funkcjonowania biologicznych sieci neuronowych — sieci komórek nerwowych żywego organizmu. Pojęcie to pojawiło się podczas badania procesów zachodzących w mózgu i próby modelowania tych procesów.

Sieci neuronowe nie są programowane w tradycyjnym sensie tego słowa, lecz uczą się. Możliwość uczenia się to jedna z głównych zalet sieci neuronowych w porównaniu do tradycyjnych algorytmów. Technicznie rzecz ujmując, uczenie się polega na znalezieniu współczynników łączących neuronów. W procesie uczenia sieć neuronowa potrafi ujawniać złożone zależności między danymi wejściowymi a wyjściowymi oraz dokonywać uogólnień.

Z perspektywy uczenia maszynowego, sieć neuronowa stanowi szczególny przypadek metod rozpoznawania wzorców, analizy dyskryminacyjnej, metod klasteryzacji oraz innych metod.

Sprzęt

Najpierw zajmijmy się sprzętem. Potrzebujemy serwera z zainstalowanym systemem operacyjnym Linux. Sprzęt do pracy systemów uczenia maszynowego musi być wystarczająco mocny, a co za tym idzie, kosztowny. Tym, którzy nie mają pod ręką dobrego komputera, polecam zwrócić uwagę na ofertę dostawców chmurowych. Potrzebny serwer można szybko wynająć i płacić tylko za czas użytkowania.

W projektach, gdzie niezbędne jest tworzenie sieci neuronowych, korzystam z serwerów jednego z rosyjskich dostawców chmury. Firma oferuje w wynajem serwery chmurowe specjalnie do uczenia maszynowego z potężnymi procesorami graficznymi (GPU) Tesla V100 od firmy NVIDIA. Krótko mówiąc: użycie serwera z GPU może być nawet dziesięciokrotnie bardziej efektywne (szybsze) w porównaniu do analogicznego serwera o tej samej cenie, w którym do obliczeń używany jest CPU (wszystkim dobrze znany procesor centralny). Osiąga się to dzięki szczególnym właściwościom architektury GPU, która szybciej wykonuje obliczenia.

Aby wykonać dalsze opisywane przykłady, zakupiliśmy na kilka dni taki serwer:

  • Dysk SSD 150 GB
  • Pamięć RAM 32 GB
  • Procesor Tesla V100 16 Gb z 4 rdzeniami

Na maszynie zainstalowano Ubuntu 18.04.

Instalujemy środowisko

Teraz zainstalujemy na serwerze wszystko, co potrzebne do pracy. Ponieważ nasz artykuł jest przede wszystkim dla początkujących, będę opowiadał o niektórych aspektach, które będą przydatne właśnie im.

Wiele pracy podczas konfiguracji środowiska wykonuje się za pomocą wiersza poleceń. Większość użytkowników korzysta z Windows jako systemu operacyjnego. Standardowa konsola w tym systemie pozostawia wiele do życzenia. Dlatego będziemy korzystać z wygodnego narzędzia Cmder/. Pobieramy wersję mini i uruchamiamy Cmder.exe. Następnie należy połączyć się z serwerem za pomocą protokołu SSH:

ssh root@server-ip-or-hostname

Zamiast server-ip-or-hostname wpisz adres IP lub nazwę DNS swojego serwera. Następnie wprowadź hasło, a po pomyślnym połączeniu powinniśmy otrzymać mniej więcej taką wiadomość.

Witamy w Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)

Podstawowym językiem do tworzenia modeli ML jest Python. Najpopularniejszą platformą do jego używania w systemie Linux jest Anaconda.

Zainstalujemy ją na naszym serwerze.

Zaczynamy od zaktualizowania lokalnego menedżera pakietów:

sudo apt-get update

Instalujemy curl (program narzędziowy wiersza poleceń):

sudo apt-get install curl

Pobieramy najnowszą wersję Anaconda Distribution:

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

Uruchamiamy instalację:

bash Anaconda3-2019.10-Linux-x86_64.sh

W trakcie instalacji konieczne będzie potwierdzenie umowy licencyjnej. Po pomyślnej instalacji powinieneś zobaczyć:

Dziękujemy za zainstalowanie Anaconda3!

Obecnie stworzono wiele frameworków do tworzenia modeli ML, pracujemy z najbardziej popularnymi: PyTorch i Tensorflow.

Użycie frameworka pozwala zwiększyć szybkość rozwoju i korzystać z już gotowych narzędzi do standardowych zadań.

W tym przykładzie będziemy pracować z PyTorch. Zainstalujemy go:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Teraz musimy uruchomić Jupyter Notebook – popularne narzędzie dla specjalistów ML. Umożliwia pisanie kodu i natychmiastowe zobaczenie wyników jego wykonania. Jupyter Notebook jest częścią Anaconda i jest już zainstalowany na naszym serwerze. Należy połączyć się z nim z naszego systemu stacjonarnego.

Najpierw uruchomimy Jupyter na serwerze, wskazując port 8080:

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

Następnie otworzymy w naszej konsoli Cmder nowe okno (górne menu — Nowy dialog konsoli) i połączymy się przez port 8080 z serwerem przez SSH:

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

Po wprowadzeniu pierwszej komendy zostaną zaproponowane linki do otwarcia Jupyter w naszej przeglądarce:

Aby uzyskać dostęp do notebooka, otwórz ten plik w przeglądarce:
        file://root/.local/share/jupyter/runtime/nbserver-18788-open.html
    Lub skopiuj i wklej jeden z tych adresów URL:
        http://localhost:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311
     lub http://127.0.0.1:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311

Skorzystamy z linku dla localhost:8080. Skopiuj pełną ścieżkę i wklej ją w pasek adresu lokalnej przeglądarki na swoim PC. Otworzy się Jupyter Notebook.

Stwórzmy nowy notatnik: Nowy — Notatnik — Python 3.

Sprawdzimy poprawność działania wszystkich komponentów, które zainstalowaliśmy. Wprowadźmy w Jupyter przykład kodu PyTorch i uruchommy jego wykonanie (przycisk Uruchom):

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

Wynik powinien wyglądać mniej więcej tak:

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Jeśli uzyskasz podobny rezultat, oznacza to, że wszystko zostało poprawnie skonfigurowane i możemy przejść do opracowywania sieci neuronowej!

Tworzymy sieć neuronową

Stworzymy sieć neuronową do rozpoznawania obrazów. Na podstawie tego przewodnik.

Do trenowania sieci wykorzystamy publicznie dostępny zbiór danych CIFAR10. Zawiera on klasy: „samolot”, „samochód”, „ptak”, „kot”, „jeleń”, „pies”, „żaba”, „koń”, „statek”, „ciężarówka”. Obrazy w CIFAR10 mają rozmiar 3x32x32, czyli są 3-kanałowymi kolorowymi obrazami o wymiarach 32×32 piksele.

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących
Do pracy będziemy korzystać z przygotowanego pakietu PyTorch do pracy z obrazami — torchvision.

Wykonamy następujące kroki w kolejności:

  • Ładowanie i normalizacja zbiorów danych treningowych i testowych
  • Definicja sieci neuronowej
  • Trening sieci na danych treningowych
  • Testowanie sieci na danych testowych
  • Powtórzymy trening i testowanie z wykorzystaniem GPU

Cały poniższy kod będziemy wykonywać w Jupyter Notebook.

Ładowanie i normalizacja CIFAR10

Skończ kopiując i wykonując w Jupyter następujący kod:


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 = ('samolot', 'samochód', 'ptak', 'kot',
           'jeleń', 'pies', 'żaba', 'koń', 'statek', 'ciężarówka')

Odpowiedź powinna być taka:

Pobieranie https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz do ./data/cifar-10-python.tar.gz
Rozpakowywanie ./data/cifar-10-python.tar.gz do ./data
Pliki już pobrane i zweryfikowane

Wyświetlimy kilka obrazów treningowych do weryfikacji:


import matplotlib.pyplot as plt
import numpy as np

# funkcje do wyświetlania obrazu

def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# pobierz kilka losowych obrazów treningowych
dataiter = iter(trainloader)
images, labels = dataiter.next()

# pokaż obrazy
imshow(torchvision.utils.make_grid(images))
# wyświetl etykiety
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Definicja sieci neuronowej

Rozważmy najpierw jak działa sieć neuronowa do rozpoznawania obrazów. To prosta sieć o pełnym połączeniu. Przyjmuje dane wejściowe, przepuszcza je przez kilka warstw jeden po drugim, a następnie w końcu zwraca dane wyjściowe.

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Stwórzmy podobną sieć w naszym środowisku:


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

Zdefiniujmy także funkcję straty i optymalizator


import torch.optim as optim

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

Trening sieci na danych treningowych

Rozpoczynamy trening naszej sieci neuronowej. Zwracam uwagę, że po uruchomieniu tego kodu, trzeba poczekać trochę czasu na zakończenie pracy. Zajęło mi to 5 minut. Proces uczenia sieci wymaga czasu.

 dla epoch w zakresie(2): # powtarzanie zbioru danych wielokrotnie

 bieżąca_strata = 0.0
 dla i, dane w enumerate(trainloader, 0):
 # pobierz dane wejściowe; dane to lista [wejścia, etykiety]
 wejścia, etykiety = dane

 # wyzeruj gradienty parametrów
 optimizer.zero_grad()

 # przód + tył + optymalizacja
 wyniki = net(wejścia)
 strata = criterion(wyniki, etykiety)
 strata.backward()
 optimizer.step()

 # wyświetl statystyki
 bieżąca_strata += strata.item()
 jeśli i % 2000 == 1999: # drukuj co 2000 mini-partii
 print('[%d, ] strata: %.3f' %
 (epoch + 1, i + 1, bieżąca_strata / 2000))
 bieżąca_strata = 0.0

print('Zakończono szkolenie')

Otrzymamy taki wynik:

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Zapisujemy nasz wytrenowany model:

ŚCIEŻKA = './cifar_net.pth'
torch.save(net.state_dict(), ŚCIEŻKA)

Testowanie sieci na danych testowych

Wytrenowaliśmy sieć przy użyciu zbioru danych treningowych. Ale musimy sprawdzić, czy sieć w ogóle się czegoś nauczyła.

Sprawdzimy to, przewidując etykietę klasy, którą przewiduje sieć neuronowa, i weryfikując ją pod kątem prawdziwości. Jeśli prognoza jest poprawna, dodajemy próbkę do listy poprawnych prognoz.
Pokażmy obrazek z zestawu testowego:

dataiter = iter(testloader)
obrazy, etykiety = dataiter.next()

# drukuj obrazy
imshow(torchvision.utils.make_grid(obrazy))
print('Prawda: ', ' '.join('%5s' % classes[etykiety[j]] for j in range(4)))

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Teraz poprośmy sieć neuronową, aby powiedziała nam, co znajduje się na tych obrazkach:


net = Net()
net.load_state_dict(torch.load(ŚCIEŻKA))

wyjścia = net(obrazy)

_, przewidziane = torch.max(wyjścia, 1)

print('Przewidziane: ', ' '.join('%5s' % classes[przewidziane[j]]
                              for j in range(4)))

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Wyniki wydają się całkiem dobre: sieć poprawnie zidentyfikowała trzy obrazki z czterech.

Zobaczmy, jak sieć działa na całym zbiorze danych.


poprawne = 0
total = 0
z torch.no_grad():
    dla danych w testloader:
        obrazy, etykiety = dane
        wyjścia = net(obrazy)
        _, przewidziane = torch.max(wyjścia.data, 1)
        total += etykiety.size(0)
        poprawne += (przewidziane == etykiety).sum().item()

print('Dokładność sieci na 10000 obrazkach testowych: %d %%' % (
    100 * poprawne / total))

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Wygląda na to, że sieć coś wie i działa. Gdyby klasyfikowała na oślep, dokładność wynosiłaby 10%.

Teraz zobaczmy, które klasy sieć identyfikuje najlepiej:

klasa_poprawna = lista(0. dla i w zakresie(10))
klasa_razem = lista(0. dla i w zakresie(10))
z torch.no_grad():
 dla danych w testloader:
 obrazy, etykiety = dane
 wyniki = net(obrazy)
 _, przewidywane = torch.max(wyniki, 1)
 c = (przewidywane == etykiety).squeeze()
 dla i w zakresie(4):
 etykieta = etykiety[i]
 klasa_poprawna[etykieta] += c[i].item()
 klasa_razem[etykieta] += 1


dla i w zakresie(10):
 print('Dokładność %5s : %%' % (
 klasy[i], 100 * klasa_poprawna[i] / klasa_razem[i]))

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Wygląda na to, że sieć najlepiej identyfikuje samochody i statki: 71% dokładności.

Tak więc, sieć działa. Teraz spróbujmy przenieść ją na procesor graficzny (GPU) i zobaczymy, co się zmieni.

Trening sieci neuronowej na GPU

Najpierw wyjaśnię krótko, czym jest CUDA. CUDA (Compute Unified Device Architecture) to platforma obliczeń równoległych stworzona przez firmę NVIDIA, przeznaczona do ogólnych obliczeń na procesorach graficznych (GPU). Dzięki CUDA programiści mogą znacznie przyspieszyć aplikacje obliczeniowe, wykorzystując możliwości procesorów graficznych. Na naszym serwerze, który nabyliśmy, ta platforma już jest zainstalowana.

Najpierw zdefiniujmy nasze GPU jako pierwsze widoczne urządzenie cuda.

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Zakładając, że jesteśmy na maszynie CUDA, powinno to wyświetlić urządzenie CUDA:
print(device)

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących

Wysyłamy sieć na GPU:

net.to(device)

Musimy również przesyłać dane wejściowe i cele na każdym kroku do GPU:

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

Uruchomimy ponowne uczenie sieci na GPU:

import torch.optim jako optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch w zakresie(2): # powtarzanie zbioru danych wielokrotnie

 bieżąca_strata = 0.0
 dla i, dane w enumerate(trainloader, 0):
 # pobierz dane wejściowe; dane to lista [wejścia, etykiety]
 wejścia, etykiety = dane[0].to(device), dane[1].to(device)

 # wyzeruj gradienty parametrów
 optimizer.zero_grad()

 # przód + tył + optymalizacja
 wyniki = net(wejścia)
 strata = criterion(wyniki, etykiety)
 strata.backward()
 optimizer.step()

 # wyświetl statystyki
 bieżąca_strata += strata.item()
 jeśli i % 2000 == 1999: # drukuj co 2000 mini-partii
 print('[%d, ] strata: %.3f' %
 (epoch + 1, i + 1, bieżąca_strata / 2000))
 bieżąca_strata = 0.0

print('Zakończono szkolenie')

Tym razem trening sieci trwał około 3 minut. Przypomnijmy, że ten sam etap na zwykłym procesorze trwał 5 minut. Różnica nie jest znacząca, ponieważ nasza sieć nie jest tak duża. Przy użyciu większych zbiorów danych do treningu różnica pomiędzy szybkością działania GPU a tradycyjnego procesora będzie rosła.

Na tym wydaje się wszystko. Co udało nam się zrobić:

  • Zbadaliśmy, czym jest GPU i wybraliśmy serwer, na którym jest zainstalowany;
  • Skonfigurowaliśmy środowisko programistyczne do tworzenia sieci neuronowej;
  • Stworzyliśmy sieć neuronową do rozpoznawania obrazów i ją wytrenowaliśmy;
  • Powtórzyliśmy trening sieci przy użyciu GPU i uzyskaliśmy przyspieszenie.

Chętnie odpowiem na pytania w komentarzach.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster