В этой статье я расскажу как за 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
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
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:
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)
Результат должен быть примерно таким:
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.
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)))
Определение нейронной сети
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.
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:
Сохраняем нашу обученную модель:
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)))
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)))
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))
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]))
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 )
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