
In dit artikel leg ik uit hoe je in 30 minuten een omgeving voor machine learning kunt instellen, een neurale netwerk kunt creëren voor beeldherkenning en vervolgens hetzelfde netwerk op een grafische processor (GPU) kunt uitvoeren.
Laten we beginnen met het definiëren van wat een neurale netwerk is.
In ons geval is het een wiskundig model, evenals de programmatische of hardwarematige belichaming ervan, opgebouwd volgens het principe van de organisatie en werking van biologische neurale netwerken - netwerken van zenuwcellen in een levend organisme. Dit begrip kwam voort uit het bestuderen van processen die zich in de hersenen afspelen, en de poging om deze processen te modelleren.
Neurale netwerken worden niet geprogrammeerd in de gebruikelijke zin van het woord, ze worden getraind. De mogelijkheid tot training is een van de belangrijkste voordelen van neurale netwerken ten opzichte van traditionele algoritmen. Technisch gezien bestaat training uit het vinden van de gewichten van de verbindingen tussen de neuronen. Tijdens het training proces is een neurale netwerk in staat om complexe afhankelijkheden tussen de invoer- en uitvoergegevens te identificeren, en ook generalisaties uit te voeren.
Vanuit het perspectief van machine learning is een neurale netwerk een specifieke uitvoering van methoden voor patroonherkenning, discriminantanalyse, clustering methoden en andere technieken.
Apparatuur
Laten we eerst naar de hardware kijken. We hebben een server nodig met een geïnstalleerd besturingssysteem Linux. De hardware voor machine learning systemen moet behoorlijk krachtig en dus duur zijn. Voor degenen die geen goede machine binnen handbereik hebben, raad ik aan om te kijken naar de aanbiedingen van cloudproviders. De benodigde server kan snel worden gehuurd en je betaalt alleen voor de tijd dat je deze gebruikt.
In projecten waar het creëren van neurale netwerken noodzakelijk is, maak ik gebruik van de servers van een van de Russische cloudproviders. Het bedrijf verhuurt cloudservers speciaal voor machine learning met krachtige grafische processors (GPU) Tesla V100 van NVIDIA. Om het kort te houden: het gebruik van een server met GPU kan tientallen keren efficiënter (sneller) zijn in vergelijking met een server van gelijke kosten die gebruik maakt van CPU (de welbekende centrale verwerkingseenheid). Dit wordt bereikt door de architectonische eigenschappen van de GPU, die sneller met berekeningen omgaat.
Voor het uitvoeren van de voorbeelden die verderop worden beschreven, hebben we voor een paar dagen zo'n server aangeschaft:
- SSD-schijf van 150 GB
- RAM van 32 GB
- Processor Tesla V100 16 Gb met 4 kernen
Op de machine is Ubuntu 18.04 geïnstalleerd.
Omgeving instellen
Laten we nu alles installeren wat nodig is om te kunnen werken op de server. Aangezien ons artikel vooral voor beginners is, zal ik een aantal punten bespreken die hen specifiek zullen helpen.
Er wordt veel werk verricht bij het instellen van de omgeving via de opdrachtregel. De meeste gebruikers gebruiken Windows als hun werk-OS. De standaardconsole in dit besturingssysteem laat veel te wensen over. Daarom zullen we een handig hulpmiddel gebruiken. . Download de mini-versie en start Cmder.exe. Vervolgens moet je verbinding maken met de server via het SSH-protocol:
ssh root@server-ip-or-hostnameIn plaats van server-ip-or-hostname vul je het IP-adres of de DNS-naam van je server in. Voer vervolgens het wachtwoord in en bij een succesvolle verbinding zouden we ongeveer deze melding moeten krijgen.
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)De belangrijkste programmeertaal voor het ontwikkelen van ML-modellen is Python. Het populairste platform voor gebruik op Linux is .
Laten we het op onze server installeren.
We beginnen met het bijwerken van de lokale pakketbeheerder:
sudo apt-get updateInstalleer curl (een hulpprogramma voor de opdrachtregel):
sudo apt-get install curlDownload de laatste versie van Anaconda Distribution:
cd /tmp
curl –O https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.shStart de installatie:
bash Anaconda3-2019.10-Linux-x86_64.shTijdens de installatie moet je de licentieovereenkomst bevestigen. Bij een succesvolle installatie zou je dit moeten zien:
Thank you for installing Anaconda3!Voor het ontwikkelen van ML-modellen zijn er tegenwoordig veel frameworks beschikbaar, en wij werken met de meest populaire: en .
Het gebruik van een framework maakt het mogelijk om de ontwikkeling te versnellen en al beschikbare tools voor standaardtaken te gebruiken.
In dit voorbeeld zullen we met PyTorch werken. Laten we het installeren:
conda install pytorch torchvision cudatoolkit=10.1 -c pytorchNu moeten we Jupyter Notebook opstarten — een populair ontwikkelingsinstrument onder ML-specialisten. Hiermee kunt u code schrijven en onmiddellijk de resultaten van de uitvoering ervan zien. Jupyter Notebook maakt deel uit van Anaconda en is al op onze server geïnstalleerd. We moeten verbinding maken met het vanaf ons bureaussysteem.
Hiervoor starten we eerst Jupyter op de server en geven we poort 8080 op:
jupyter notebook --no-browser --port=8080 --allow-rootVervolgens openen we in onze Cmder-console nog een tabblad (bovenste menu — Nieuw consolevenster) en verbinden we via SSH met de server op poort 8080:
ssh -L 8080:localhost:8080 root@server-ip-or-hostnameBij het invoeren van het eerste commando krijgen we links voorgeschoteld om Jupyter in onze browser te openen:
Om toegang te krijgen tot het notebook, opent u dit bestand in een browser:
file://root/.local/share/jupyter/runtime/nbserver-18788-open.html
Of kopieer en plak een van deze URL's:
http://localhost:8080/?token=cca0bd0b30857821194b9018a5394a4ed2322236f116d311
of 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.
We maken een nieuw notebook aan: Nieuw — Notebook — Python 3.
Laten we de correcte werking van alle componenten die we hebben geïnstalleerd controleren. We voeren het volgende voorbeeld van PyTorch in Jupyter in en starten de uitvoering (knop Uitvoeren):
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
Het resultaat zou ongeveer zo moeten zijn:

Als u hetzelfde resultaat krijgt, betekent dit dat we alles correct hebben ingesteld en dat we kunnen beginnen met het ontwikkelen van het neurale netwerk!
We creëren een neuraal netwerk
We zullen een neuraal netwerk maken voor beeldherkenning. We nemen dit als basis .
Voor het trainen van het netwerk zullen we de openbaar beschikbare dataset CIFAR10 gebruiken. Het heeft de klassen: ‘vliegtuig’, ‘auto’, ‘vogel’, ‘kat’, ‘hert’, ‘hond’, ‘kikker’, ‘paard’, ‘schip’, ‘vrachtwagen’. Afbeeldingen in CIFAR10 hebben een formaat van 3x32x32, dat wil zeggen 3-kanaals kleurafbeeldingen van 32 × 32 pixels.

Voor ons werk zullen we het PyTorch-pakket voor afbeeldingen gebruiken — torchvision.
We zullen de volgende stappen in volgorde uitvoeren:
- Het uploaden en normaliseren van trainings- en testdatasets
- Het definiëren van het neurale netwerk
- Het trainen van het netwerk op de trainingsgegevens
- Het testen van het netwerk op de testgegevens
- We herhalen de training en testen met behulp van een GPU
De onderstaande code zullen we uitvoeren in Jupyter Notebook.
Het uploaden en normaliseren van CIFAR10
Kopieer en voer de volgende code in Jupyter uit:
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 als volgt 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 verifiedLaten we enkele trainingsvoorbeelden weergeven ter controle:
import matplotlib.pyplot as plt
import numpy as np
# functies om een afbeelding te tonen
def imshow(img):
img = img / 2 + 0.5 # ontnormaliseren
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# haal enkele willekeurige trainingsafbeeldingen op
dataiter = iter(trainloader)
images, labels = dataiter.next()
# toon afbeeldingen
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

Het definiëren van het neurale netwerk
Laten we eerst bekijken hoe het neurale netwerk voor het herkennen van afbeeldingen werkt. Dit is een eenvoudig feedforward netwerk. Het neemt inputgegevens, voert ze door verschillende lagen een voor een, en geeft uiteindelijk de output.

Laten we een vergelijkbaar 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()
Laten we ook de verliesfunctie en de optimizer definiëren
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)Het trainen van het netwerk op de trainingsgegevens
We beginnen met de training van ons neuraal netwerk. Let op dat je, nadat je deze code hebt uitgevoerd, een tijdje moet wachten tot het proces is voltooid. Voor mij duurde het 5 minuten. Het trainen van het netwerk kost tijd.
voor epoch in range(2): # herhaal het dataset meerdere keren
lopend_verlies = 0.0
voor i, data in enumerate(trainloader, 0):
# krijg de inputs; data is een lijst van [inputs, labels]
inputs, labels = data
# nul de parametergradiënten
optimizer.zero_grad()
# vooruit + achteruit + optimaliseer
outputs = net(inputs)
verlies = criterion(outputs, labels)
verlies.backward()
optimizer.step()
# print statistieken
lopend_verlies += verlies.item()
als i % 2000 == 1999: # print elke 2000 mini-batches
print('[%d, ] verlies: %.3f' %
(epoch + 1, i + 1, lopend_verlies / 2000))
lopend_verlies = 0.0
print('Training Voltooid')
We krijgen het volgende resultaat:

We slaan ons getrainde model op:
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)Het testen van het netwerk op de testgegevens
We hebben het netwerk getraind met een dataset. Maar we moeten controleren of het netwerk iets heeft geleerd.
We zullen dit controleren door de klassetiketten te voorspellen die het neuraal netwerk produceert en deze te verifiëren. Als de voorspelling klopt, voegen we het monster toe aan de lijst met correcte voorspellingen.
Laten we een afbeelding tonen uit de testset:
dataiter = iter(testloader)
images, labels = dataiter.next()
# print afbeeldingen
imshow(torchvision.utils.make_grid(images))
print('Grondwaarheid: ', ' '.join('%5s' % classes[labels[j]] for j in range(4))) 
Laten we nu het neuraal 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('Voorspeld: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(4)))

De resultaten lijken behoorlijk goed: het netwerk heeft drie van de vier afbeeldingen correct herkend.
Laten we bekijken hoe het netwerk presteert op 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('Nauwkeurigheid van het netwerk op de 10000 testafbeeldingen: %d %%' % (
100 * correct / total)) 
Het lijkt erop dat het netwerk iets weet en functioneert. Als het de klassen willekeurig had bepaald, zou de nauwkeurigheid 10% zijn geweest.
Laten we nu kijken welke klassen het netwerk beter bepaalt:
class_correct = list(0. voor i in range(10))
class_total = list(0. voor i in range(10))
met torch.no_grad():
voor data in testloader:
beelden, labels = data
outputs = net(beelden)
_, voorspeld = torch.max(outputs, 1)
c = (voorspeld == labels).squeeze()
voor i in range(4):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
voor i in range(10):
print('Nauwkeurigheid van %5s : %%' % (
classes[i], 100 * class_correct[i] / class_total[i])) 
Het lijkt erop dat het netwerk het beste auto's en schepen herkent: 71% nauwkeurigheid.
Dus het netwerk werkt. Laten we proberen om het op de grafische processor (GPU) te draaien en kijken wat er verandert.
Training van het neurale netwerk op de GPU.
Laten we eerst kort uitleggen wat CUDA is. CUDA (Compute Unified Device Architecture) is een platform voor parallelle computing, ontwikkeld door NVIDIA, voor algemene berekeningen op grafische processors (GPU's). Met CUDA kunnen ontwikkelaars rekenkundige applicaties aanzienlijk versnellen door gebruik te maken van de mogelijkheden van grafische processors. Op onze server, die we hebben aangeschaft, is dit platform al geïnstalleerd.
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")
# Aangenomen dat we op een CUDA-machine zijn, zou dit een CUDA-apparaat moeten afdrukken:
print(device) 
We sturen het netwerk naar de GPU:
net.to(device)Daarnaast moeten we de invoeren en labels bij elke stap naar de GPU sturen:
inputs, labels = data[0].to(device), data[1].to(device)Laten we het netwerk opnieuw trainen, deze keer op de GPU:
import torch.optim als optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
voor epoch in range(2): # herhaal het dataset meerdere keren
lopend_verlies = 0.0
voor i, data in enumerate(trainloader, 0):
# krijg de inputs; data is een lijst van [inputs, labels]
inputs, labels = data[0].to(device), data[1].to(device)
# nul de parametergradiënten
optimizer.zero_grad()
# vooruit + achteruit + optimaliseer
outputs = net(inputs)
verlies = criterion(outputs, labels)
verlies.backward()
optimizer.step()
# print statistieken
lopend_verlies += verlies.item()
als i % 2000 == 1999: # print elke 2000 mini-batches
print('[%d, ] verlies: %.3f' %
(epoch + 1, i + 1, lopend_verlies / 2000))
lopend_verlies = 0.0
print('Training Voltooid')Deze keer duurde de training van het netwerk ongeveer 3 minuten. Ter herinnering, dezelfde fase op een gewone processor duurde 5 minuten. Het verschil is niet aanzienlijk, dit gebeurt omdat ons netwerk niet zo groot is. Bij het gebruik van grotere datasets voor training zal het verschil in snelheid tussen de GPU en de traditionele processor toenemen.
Dat lijkt alles te zijn. Wat we hebben bereikt:
- We hebben bekeken wat een GPU is en een server gekozen waarop deze is geïnstalleerd;
- We hebben de software-omgeving ingesteld voor het maken van een neurale netwerk;
- We hebben een neurale netwerk gecreëerd voor beeldherkenning en deze getraind;
- We hebben de training van het netwerk herhaald met gebruik van de GPU en een snelheidstoename behaald.
Ik ben blij om vragen in de reacties te beantwoorden.
Bron: habr.com
