Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids
In dit artikel vertel ik je hoe je in 30 minuten een machine learning-omgeving kunt opzetten, een neuraal netwerk voor beeldherkenning kunt creëren en hetzelfde netwerk vervolgens op een grafische processor (GPU) kunt laten draaien.

Laten we eerst definiëren wat een neuraal netwerk is.

In ons geval is dit een wiskundig model, evenals de software- of hardware-uitvoering ervan, gebouwd op het principe van de organisatie en werking van biologische neurale netwerken - netwerken van zenuwcellen van een levend organisme. Dit concept ontstond tijdens het bestuderen van de processen die in de hersenen plaatsvinden en bij het proberen deze processen te modelleren.

Neurale netwerken zijn niet geprogrammeerd in de gebruikelijke zin van het woord, ze zijn getraind. Het vermogen om te leren is een van de belangrijkste voordelen van neurale netwerken ten opzichte van traditionele algoritmen. Technisch gezien bestaat leren uit het vinden van de coëfficiënten van verbindingen tussen neuronen. Tijdens het trainingsproces kan het neurale netwerk complexe afhankelijkheden tussen invoergegevens en uitvoergegevens identificeren en generalisatie uitvoeren.

Vanuit het oogpunt van machinaal leren is een neuraal netwerk een speciaal geval van patroonherkenningsmethoden, discriminantanalyse, clustermethoden en andere methoden.

Uitrusting

Laten we eerst eens kijken naar de apparatuur. We hebben een server nodig waarop het Linux-besturingssysteem is geïnstalleerd. De apparatuur die nodig is om machine learning-systemen te bedienen is behoorlijk krachtig en daardoor duur. Voor degenen die geen goede machine bij de hand hebben, raad ik aan om op de aanbiedingen van cloudproviders te letten. U kunt de benodigde server snel huren en alleen betalen voor de gebruikstijd.

Bij projecten waarbij het nodig is om neurale netwerken te creëren, maak ik gebruik van de servers van een van de Russische cloudproviders. Het bedrijf biedt cloudservers te huur specifiek voor machine learning met krachtige Tesla V100 grafische processors (GPU) van NVIDIA. Kortom: het gebruik van een server met een GPU kan tientallen keren efficiënter (snel) zijn vergeleken met een server van vergelijkbare kosten die een CPU (de bekende centrale verwerkingseenheid) gebruikt voor berekeningen. Dit wordt bereikt dankzij de kenmerken van de GPU-architectuur, die sneller met berekeningen omgaat.

Om de hieronder beschreven voorbeelden te implementeren, hebben we voor meerdere dagen de volgende server aangeschaft:

  • SSD-schijf 150 GB
  • RAM-geheugen 32 GB
  • Tesla V100 16 Gb processor met 4 kernen

We hebben Ubuntu 18.04 op onze machine geïnstalleerd.

Het opzetten van de omgeving

Laten we nu alles installeren wat nodig is voor het werk op de server. Omdat ons artikel voornamelijk voor beginners is bedoeld, zal ik enkele punten bespreken die voor hen nuttig zullen zijn.

Veel van het werk bij het opzetten van een omgeving wordt gedaan via de opdrachtregel. De meeste gebruikers gebruiken Windows als hun werkende besturingssysteem. De standaardconsole in dit besturingssysteem laat veel te wensen over. Daarom zullen we een handig hulpmiddel gebruiken Commandant/. Download de miniversie en voer Cmder.exe uit. Vervolgens moet u via SSH verbinding maken met de server:

ssh root@server-ip-or-hostname

Geef in plaats van server-ip-of-hostnaam het IP-adres of de DNS-naam van uw server op. Voer vervolgens het wachtwoord in en als de verbinding succesvol is, zouden we een soortgelijk bericht moeten ontvangen.

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

De belangrijkste taal voor het ontwikkelen van ML-modellen is Python. En het meest populaire platform voor gebruik op Linux is Anaconda.

Laten we het op onze server installeren.

We beginnen met het updaten van de lokale pakketbeheerder:

sudo apt-get update

Installeer curl (opdrachtregelhulpprogramma):

sudo apt-get install curl

Download de nieuwste versie van Anaconda Distribution:

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

Laten we beginnen met de installatie:

bash Anaconda3-2019.10-Linux-x86_64.sh

Tijdens het installatieproces wordt u gevraagd de licentieovereenkomst te bevestigen. Na een succesvolle installatie zou u dit moeten zien:

Thank you for installing Anaconda3!

Er zijn inmiddels veel raamwerken gemaakt voor de ontwikkeling van ML-modellen; we werken met de meest populaire: PyTorch и tensorstroom.

Door het raamwerk te gebruiken, kunt u de ontwikkelingssnelheid verhogen en kant-en-klare tools gebruiken voor standaardtaken.

In dit voorbeeld gaan we werken met PyTorch. Laten we het installeren:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Nu moeten we Jupyter Notebook lanceren, een populaire ontwikkelingstool voor ML-specialisten. Hiermee kunt u code schrijven en onmiddellijk de resultaten van de uitvoering ervan zien. Jupyter Notebook wordt meegeleverd met Anaconda en is al op onze server geïnstalleerd. U moet er verbinding mee maken vanaf ons desktopsysteem.

Om dit te doen, starten we Jupyter eerst op de server met poort 8080:

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

Als we vervolgens een ander tabblad openen in onze Cmder-console (bovenste menu - Dialoogvenster Nieuwe console), zullen we via poort 8080 verbinding maken met de server via SSH:

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

Wanneer we de eerste opdracht invoeren, krijgen we links aangeboden om Jupyter in onze browser te openen:

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

Laten we de link voor localhost:8080 gebruiken. Kopieer het volledige pad en plak het in de adresbalk van de lokale browser van uw pc. Jupyter Notebook wordt geopend.

Laten we een nieuw notitieboekje maken: Nieuw - Notebook - Python 3.

Laten we de juiste werking controleren van alle componenten die we hebben geïnstalleerd. Laten we de voorbeeld-PyTorch-code in Jupyter invoeren en de uitvoering uitvoeren (knop Uitvoeren):

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

Het resultaat zou ongeveer zo moeten zijn:

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Als je een soortgelijk resultaat hebt, hebben we alles correct geconfigureerd en kunnen we beginnen met het ontwikkelen van een neuraal netwerk!

Het creëren van een neuraal netwerk

We zullen een neuraal netwerk creëren voor beeldherkenning. Laten we dit als basis nemen руководство.

We zullen de openbaar beschikbare CIFAR10-dataset gebruiken om het netwerk te trainen. Het heeft klassen: "vliegtuig", "auto", "vogel", "kat", "hert", "hond", "kikker", "paard", "schip", "vrachtwagen". Afbeeldingen in CIFAR10 zijn 3x32x32, dat wil zeggen 3-kanaals kleurenafbeeldingen van 32x32 pixels.

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids
Voor werk zullen we het pakket gebruiken dat door PyTorch is gemaakt voor het werken met afbeeldingen - torchvision.

We zullen de volgende stappen achtereenvolgens uitvoeren:

  • Trainings- en testdatasets laden en normaliseren
  • Neurale netwerkdefinitie
  • Netwerktraining op trainingsgegevens
  • Netwerktesten op testgegevens
  • Laten we de training en tests herhalen met behulp van GPU

We zullen alle onderstaande code uitvoeren in Jupyter Notebook.

CIFAR10 laden en normaliseren

Kopieer de volgende code en voer deze uit in 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')

Het antwoord zou moeten zijn:

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

Laten we verschillende trainingsafbeeldingen weergeven om te testen:


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

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Neurale netwerkdefinitie

Laten we eerst eens kijken hoe een neuraal netwerk voor beeldherkenning werkt. Dit is een eenvoudig point-to-point-netwerk. Het neemt invoergegevens, stuurt deze één voor één door verschillende lagen en produceert uiteindelijk uitvoergegevens.

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Laten we een soortgelijk netwerk in onze omgeving creëren:


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

We definiëren ook een verliesfunctie en een optimizer


import torch.optim as optim

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

Netwerktraining op trainingsgegevens

Laten we beginnen met het trainen van ons neurale netwerk. Houd er rekening mee dat nadat u deze code hebt uitgevoerd, u enige tijd moet wachten totdat het werk is voltooid. Het kostte mij 5 minuten. Het kost tijd om het netwerk te trainen.

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

We krijgen het volgende resultaat:

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

We slaan ons getrainde model op:

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

Netwerktesten op testgegevens

We hebben het netwerk getraind met behulp van een set trainingsgegevens. Maar we moeten controleren of het netwerk überhaupt iets heeft geleerd.

We zullen dit testen door het klassenlabel te voorspellen dat het neurale netwerk uitvoert en dit te testen om te zien of het waar is. Als de voorspelling juist is, voegen we het monster toe aan de lijst met correcte voorspellingen.
Laten we een afbeelding van de testset laten zien:

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

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Laten we nu het neurale netwerk vragen ons te vertellen wat er op deze afbeeldingen staat:


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

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

De resultaten lijken redelijk goed: het netwerk heeft drie van de vier foto's correct geïdentificeerd.

Laten we eens kijken hoe het netwerk presteert in de gehele dataset.


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

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Het lijkt erop dat het netwerk iets weet en werkt. Als hij de klassen willekeurig zou bepalen, zou de nauwkeurigheid 10% zijn.

Laten we nu eens kijken welke klassen het netwerk beter identificeert:

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

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Het lijkt erop dat het netwerk het beste is in het identificeren van auto's en schepen: 71% nauwkeurigheid.

Het netwerk werkt dus. Laten we nu proberen het werk over te dragen naar de grafische processor (GPU) en kijken wat er verandert.

Een neuraal netwerk trainen op GPU

Eerst zal ik kort uitleggen wat CUDA is. CUDA (Compute Unified Device Architecture) is een parallel computerplatform ontwikkeld door NVIDIA voor algemeen computergebruik op grafische verwerkingseenheden (GPU's). Met CUDA kunnen ontwikkelaars computertoepassingen dramatisch versnellen door gebruik te maken van de kracht van GPU's. Dit platform is al geïnstalleerd op onze server die we hebben gekocht.

Laten we eerst onze GPU definiëren als het eerste zichtbare cuda-apparaat.

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 )

Uw eerste neurale netwerk op een grafische verwerkingseenheid (GPU). beginners gids

Het netwerk naar de GPU verzenden:

net.to(device)

We zullen ook bij elke stap input en doelen naar de GPU moeten sturen:

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

Laten we het netwerk opnieuw trainen op de 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')

Deze keer duurde de netwerktraining ongeveer 3 minuten. Laten we niet vergeten dat dezelfde fase op een conventionele processor 5 minuten duurde. Het verschil is niet significant, dit komt omdat ons netwerk niet zo groot is. Bij gebruik van grote arrays voor training zal het verschil tussen de snelheid van de GPU en een traditionele processor groter worden.

Dat lijkt alles te zijn. Wat we hebben kunnen doen:

  • We hebben gekeken naar wat een GPU is en hebben de server geselecteerd waarop deze is geïnstalleerd;
  • We hebben een softwareomgeving opgezet om een ​​neuraal netwerk te creëren;
  • We hebben een neuraal netwerk voor beeldherkenning gecreëerd en getraind;
  • We herhaalden de netwerktraining met behulp van de GPU en kregen een snelheidsverhoging.

Vragen beantwoord ik graag in de reacties.

Bron: www.habr.com

Voeg een reactie