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
В этой статье я расскажу как за 30 минут настроить среду для машинного обучения, создать нейронную сеть для распознавания изображений a потом запустить ту же сеть на графическом процессоре (GPU).

Najpierw zdefiniujmy, czym jest sieć neuronowa.

W naszym przypadku jest to model matematyczny, a także jego oprogramowanie lub sprzęt, zbudowany w oparciu o zasadę organizacji i funkcjonowania biologicznych sieci neuronowych – sieci komórek nerwowych żywego organizmu. Koncepcja ta zrodziła się podczas badania procesów zachodzących w mózgu i prób modelowania tych procesów.

Sieci neuronowe nie są programowane w zwykłym znaczeniu tego słowa, są szkolone. Zdolność uczenia się jest jedną z głównych przewag sieci neuronowych nad tradycyjnymi algorytmami. Technicznie rzecz biorąc, uczenie się polega na znajdowaniu współczynników połączeń między neuronami. W procesie uczenia sieć neuronowa potrafi identyfikować złożone zależności pomiędzy danymi wejściowymi i wyjściowymi, a także dokonywać uogólnień.

Z punktu widzenia uczenia maszynowego sieć neuronowa jest szczególnym przypadkiem metod rozpoznawania wzorców, analizy dyskryminacyjnej, metod grupowania i innych metod.

Sprzęt

Najpierw spójrzmy na sprzęt. Potrzebujemy serwera z zainstalowanym systemem operacyjnym Linux. Sprzęt wymagany do obsługi systemów uczenia maszynowego jest dość wydajny, a co za tym idzie, drogi. Tym, którzy nie mają pod ręką dobrej maszyny, polecam zwrócić uwagę na oferty dostawców usług chmurowych. Możesz szybko wynająć wymagany serwer i zapłacić tylko za czas jego użytkowania.

W projektach, w których konieczne jest utworzenie sieci neuronowych, korzystam z serwerów jednego z rosyjskich dostawców usług chmurowych. Firma oferuje do wynajęcia serwery w chmurze specjalnie do uczenia maszynowego z wydajnymi procesorami graficznymi (GPU) Tesla V100 firmy NVIDIA. W skrócie: korzystanie z serwera z procesorem graficznym może być dziesiątki razy bardziej wydajne (szybkie) w porównaniu z serwerem o podobnym koszcie, który do obliczeń wykorzystuje procesor (dobrze znaną jednostkę centralną). Osiąga się to dzięki cechom architektury GPU, która szybciej radzi sobie z obliczeniami.

Aby wdrożyć przykłady opisane poniżej, zakupiliśmy na kilka dni następujący serwer:

  • Dysk SSD 150 GB
  • ОЗУ 32 ГБ
  • Procesor Tesla V100 16 Gb z 4 rdzeniami

Zainstalowaliśmy Ubuntu 18.04 na naszym komputerze.

Konfigurowanie środowiska

Teraz zainstalujmy wszystko, co niezbędne do pracy na serwerze. Ponieważ nasz artykuł jest przeznaczony przede wszystkim dla początkujących, omówię kilka punktów, które będą dla nich przydatne.

Większość pracy podczas konfigurowania środowiska odbywa się za pomocą wiersza poleceń. Większość użytkowników używa systemu Windows jako działającego systemu operacyjnego. Standardowa konsola w tym systemie operacyjnym pozostawia wiele do życzenia. Dlatego skorzystamy z wygodnego narzędzia Cmder/. Pobierz wersję mini i uruchom Cmder.exe. Następnie musisz połączyć się z serwerem przez SSH:

ssh root@server-ip-or-hostname

Zamiast adresu IP serwera lub nazwy hosta podaj adres IP lub nazwę DNS swojego serwera. Następnie wprowadź hasło i jeśli połączenie się powiedzie, powinniśmy otrzymać komunikat podobny do tego.

Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)

Głównym językiem do tworzenia modeli ML jest Python. A najpopularniejszą platformą do jego użycia w systemie Linux jest anakonda.

Zainstalujmy go na naszym serwerze.

Zaczynamy od aktualizacji lokalnego menedżera pakietów:

sudo apt-get update

Zainstaluj curl (narzędzie wiersza poleceń):

sudo apt-get install curl

Pobierz najnowszą wersję Anaconda Distribution:

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

Rozpoczynamy instalację:

bash Anaconda3-2019.10-Linux-x86_64.sh

Podczas procesu instalacji zostaniesz poproszony o potwierdzenie umowy licencyjnej. Po pomyślnej instalacji powinieneś zobaczyć to:

Thank you for installing Anaconda3!

Powstało już wiele frameworków do rozwoju modeli ML, my pracujemy z najpopularniejszymi: PyTorch и Tensorflow.

Korzystanie z frameworka pozwala na zwiększenie szybkości rozwoju i wykorzystanie gotowych narzędzi do standardowych zadań.

W tym przykładzie będziemy pracować z PyTorch. Zainstalujmy to:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Теперь нам необходимо запустить Jupyter Notebook — популярный у ML специалистов инструмент разработки. Он позволяет писать код и сразу видеть результаты его выполнения. Jupyter Notebook входит в состав Anaconda и уже установлен на нашем сервере. Необходимо подключится к нему из нашей настольной системе.

W tym celu najpierw uruchomimy Jupytera na serwerze podając port 8080:

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

Następnie otwierając kolejną zakładkę w naszej konsoli Cmder (górne menu - Okno dialogowe Nowa konsola) połączymy się poprzez port 8080 z serwerem poprzez SSH:

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

Kiedy wpiszemy pierwsze polecenie, zaoferowane zostaną nam linki umożliwiające otwarcie Jupytera w naszej przeglądarce:

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

Użyjmy linku do localhost:8080. Skopiuj pełną ścieżkę i wklej ją w pasku adresu przeglądarki lokalnej na komputerze. Otworzy się Notatnik Jupytera.

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

Sprawdźmy poprawność działania wszystkich komponentów, które zainstalowaliśmy. Wprowadźmy przykładowy kod PyTorch do Jupytera i uruchommy wykonanie (przycisk Uruchom):

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

Результат должен быть примерно таким:

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

Jeśli masz podobny wynik, to wszystko poprawnie skonfigurowaliśmy i możemy przystąpić do tworzenia sieci neuronowej!

Tworzenie sieci neuronowej

Stworzymy sieć neuronową do rozpoznawania obrazu. Przyjmijmy to jako podstawę руководство.

Do szkolenia sieci wykorzystamy publicznie dostępny zbiór danych CIFAR10. Posiada klasy: „samolot”, „samochód”, „ptak”, „kot”, „jeleń”, „pies”, „żaba”, „koń”, „statek”, „ciężarówka”. Obrazy w CIFAR10 mają rozmiar 3x32x32, czyli 3-kanałowe kolorowe obrazy o wymiarach 32x32 pikseli.

Twoja pierwsza sieć neuronowa na procesorze graficznym (GPU). Przewodnik dla początkujących
Do pracy wykorzystamy stworzony przez PyTorch pakiet do pracy z obrazami - torchvision.

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

  • Ładowanie i normalizowanie zbiorów danych uczących i testowych
  • Определение нейронной сети
  • Trening sieciowy na danych treningowych
  • Testowanie sieci na danych testowych
  • Powtórzmy szkolenie i testowanie przy użyciu procesora graficznego

Cały poniższy kod wykonamy w Jupyter Notebook.

Ładowanie i normalizowanie CIFAR10

Skopiuj i uruchom następujący kod w 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')

Odpowiedź powinna brzmieć:

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

Wyświetlmy kilka obrazów szkoleniowych do testów:


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

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

Определение нейронной сети

Przyjrzyjmy się najpierw, jak działa sieć neuronowa do rozpoznawania obrazów. Jest to prosta sieć punkt-punkt. Pobiera dane wejściowe, przepuszcza je przez kilka warstw jedna po drugiej, a następnie generuje 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()

Definiujemy 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 sieciowy na danych treningowych

Zacznijmy trenować naszą sieć neuronową. Pamiętaj, że po uruchomieniu tego kodu będziesz musiał poczekać trochę czasu, aż praca się zakończy. Zajęło mi to 5 minut. Uczenie sieci wymaga czasu.

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

Otrzymujemy następujący wynik:

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

Сохраняем нашу обученную модель:

PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)

Testowanie sieci na danych testowych

Uczyliśmy sieć korzystając ze zbioru danych uczących. Musimy jednak sprawdzić, czy sieć w ogóle się czegokolwiek nauczyła.

Przetestujemy to, przewidując etykietę klasy wysyłaną przez sieć neuronową i testując ją, aby sprawdzić, czy jest ona prawdziwa. Jeśli przewidywanie jest prawidłowe, dodajemy próbkę do listy prawidłowych przewidywań.
Pokażmy obraz ze zbioru testowego:

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

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 zdjęciach:


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

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

Wyniki wydają się całkiem niezłe: sieć poprawnie zidentyfikowała trzy z czterech zdjęć.

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


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

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 klasy ustalił losowo, dokładność wyniosłaby 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]))

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

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

Итак сеть работает. Теперь попробуем перенести ее работу на графический процессор (GPU) и посмотри что поменяется.

Тренировка нейронной сети на GPU

Na początek krótko wyjaśnię czym jest CUDA. CUDA (Compute Unified Device Architecture) to platforma obliczeń równoległych opracowana przez firmę NVIDIA do ogólnych obliczeń na jednostkach przetwarzania grafiki (GPU). Dzięki CUDA programiści mogą radykalnie przyspieszyć aplikacje obliczeniowe, wykorzystując moc procesorów graficznych. Platforma ta jest już zainstalowana na naszym zakupionym przez nas serwerze.

Najpierw zdefiniujmy nasz procesor graficzny jako pierwsze widoczne urządzenie 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 )

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

Wysyłanie sieci do GPU:

net.to(device)

Będziemy również musieli wysyłać dane wejściowe i cele na każdym kroku do procesora graficznego:

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

Przetrenujmy 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')

Tym razem szkolenie sieci trwało około 3 minut. Przypomnijmy, że ten sam etap na konwencjonalnym procesorze trwał 5 minut. Różnica nie jest znacząca, dzieje się tak dlatego, że nasza sieć nie jest aż tak duża. W przypadku korzystania z dużych macierzy do treningu, różnica pomiędzy szybkością GPU, a tradycyjnym procesorem będzie się zwiększać.

To chyba wszystko. Co udało nam się zrobić:

  • Przyjrzeliśmy się, czym jest procesor graficzny i wybraliśmy serwer, na którym jest zainstalowany;
  • Stworzyliśmy środowisko programowe do stworzenia sieci neuronowej;
  • Stworzyliśmy sieć neuronową do rozpoznawania obrazów i przeszkoliliśmy ją;
  • Powtórzyliśmy szkolenie sieciowe przy użyciu procesora graficznego i uzyskaliśmy wzrost prędkości.

Chętnie odpowiem na pytania w komentarzach.

Źródło: www.habr.com

Dodaj komentarz