Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців
У цій статті я розповім як за 30 хвилин налаштувати середовище для машинного навчання, створити нейронну мережу для розпізнавання зображень, а потім запустити ту саму мережу на графічному процесорі (GPU).

Для початку визначимо, що таке нейронна мережа.

У нашому випадку це математична модель, а також її програмне або апаратне втілення, побудоване за принципом організації та функціонування біологічних нейронних мереж – мереж нервових клітин живого організму. Це поняття виникло щодо процесів, які у мозку, і за спробі змоделювати ці процеси.

Нейронні мережі не програмуються у звичному значенні цього слова, вони навчаються. Можливість навчання - одна з головних переваг нейронних мереж перед традиційними алгоритмами. Технічно навчання полягає у знаходженні коефіцієнтів зв'язків між нейронами. У процесі навчання нейронна мережа здатна виявляти складні залежності між вхідними даними та вихідними, а також виконувати узагальнення.

З точки зору машинного навчання, нейронна мережа є окремим випадком методів розпізнавання образів, дискримінантного аналізу, методів кластеризації та інших методів.

Обладнання

Спочатку розберемося з обладнанням. Нам необхідний сервер із встановленою на ньому операційною системою Linux. Обладнання для роботи систем машинного навчання потрібно досить потужне і як наслідок дороге. Тим, хто не має під рукою гарної машини, рекомендую звернути увагу на пропозицію хмарних провайдерів. Необхідний сервер можна отримати в оренду швидко та платити лише за час використання.

У проектах, де необхідне створення нейронних мереж, я використовую сервери одного з російських хмарних провайдерів. Компанія пропонує в оренду хмарні сервери спеціально для машинного навчання із потужними графічними процесорами (GPU) Tesla V100 від компанії NVIDIA. Якщо коротко: використання сервера з GPU може бути в десятки разів більш ефективним (швидким) порівняно з аналогічним за вартістю сервером, де для обчислень використовується CPU (усім добре знайомий центральний процесор). Це досягається за рахунок особливостей архітектури GPU, яка швидше впорається з розрахунками.

Для виконання прикладів, описаних далі, ми придбали на кілька днів такий сервер:

  • SSD диск 150 ГБ
  • ОЗУ 32 ГБ
  • Процесор Tesla V100 16 Gb з 4-ма ядрами

На машину встановили Ubuntu 18.04.

Встановлюємо оточення

Тепер встановимо на сервер все потрібне для роботи. Оскільки наша стаття в першу чергу для початківців, розповідатиму в ній про деякі моменти, які стануть у нагоді саме їм.

Дуже багато роботи при настроюванні середовища виконується через командний рядок. Більшість користувачів як робочої ОС використовують Windows. Стандартна консоль у цій ОС залишає бажати кращого. Тому ми будемо використовувати зручний інструмент Cmder/. Завантажуємо mini версію та запускаємо Cmder.exe. Далі необхідно підключитися до сервера за протоколом SSH:

ssh root@server-ip-or-hostname

Замість server-ip-or-hostname вказуєте IP-адресу або DNS ім'я вашого сервера. Далі вводимо пароль і при успішному підключенні ми маємо отримати приблизно таке повідомлення.

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

Основною мовою розробки ML моделей є Python. А найбільш популярною платформою для його використання по Linux є Анаконда.

Встановимо її на наш сервер.

Починаємо з оновлення локального менеджера пакетів:

sudo apt-get update

Встановлюємо curl (службова програма командного рядка):

sudo apt-get install curl

Завантажуємо останню версію Anaconda Distribution:

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

Запускаємо установку:

bash Anaconda3-2019.10-Linux-x86_64.sh

У процесі встановлення необхідно буде підтвердити ліцензійну угоду. При успішному встановленні ви повинні будете побачити це:

Thank you for installing Anaconda3!

Для розробки ML моделей зараз створено безліч фреймворків, ми працюємо з найпопулярнішими: PyTorch и Тензорний потік.

Використання фреймворку дозволяє збільшити швидкість розробки та використовувати вже готові інструменти для стандартних завдань.

У цьому прикладі будемо працювати з PyTorch. Встановимо його:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

Тепер нам необхідно запустити Jupyter Notebook – популярний у ML фахівців інструмент розробки. Він дозволяє писати код і одразу бачити результати його виконання. Jupyter Notebook входить до складу Anaconda та вже встановлений на нашому сервері. Необхідно підключитися до нього із нашої настільної системи.

Для цього ми спочатку запустимо Jupyter на сервері, вказавши порт 8080:

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

Далі відкривши в нашій консолі Cmder ще одну вкладку (верхнє меню - New console dialog) підключимося по порту 8080 до сервера через SSH:

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

При введенні першої команди нам буде запропоновано посилання для відкриття Jupyter у нашому браузері:

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

Скористайтеся посиланням на localhost:8080. Скопіюйте повний шлях та вставте в адресний рядок локального браузера вашого ПК. Відкриється Jupyter Notebook.

Створимо новий ноутбук: New - Notebook - Python 3.

Перевіримо коректну роботу всіх компонентів, які ми встановили. Введемо в Jupyter приклад коду PyTorch і запустимо виконання (кнопка Run):

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

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

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Якщо у вас аналогічний результат — значить, ми всі налаштували правильно і можемо приступати до розробки нейронної мережі!

Створюємо нейронну мережу

Створюватимемо нейронну мережу для розпізнавання зображень. За основу візьмемо це керівництво.

Для тренування мережі ми використовуватимемо загальнодоступний набір даних CIFAR10. Він має класи: «літак», «автомобіль», «птах», «кішка», «олень», «собака», «жаба», «кінь», «корабель», «вантажівка». Зображення CIFAR10 мають розмір 3x32x32, тобто 3-канальні кольорові зображення розміром 32×32 пікселів.

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців
Для роботи ми будемо використовувати створений PyTorch пакет для роботи із зображеннями – torchvision.

Ми зробимо такі кроки по порядку:

  • Завантаження та нормалізація наборів навчальних та тестових даних
  • Визначення нейронної мережі
  • Тренування мережі на тренувальних даних
  • Тестування мережі на тестових даних
  • Повторимо тренування та тестування з використанням GPU

Весь наведений нижче код ми будемо виконувати у Jupyter Notebook.

Завантаження та нормалізація CIFAR10

Скопіюйте та виконайте в 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')

Відповідь має бути такою:

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

Виведемо кілька тренувальних образів для перевірки:


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

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Визначення нейронної мережі

Розглянемо спочатку як працює нейронна мережа з розпізнавання зображень. Це проста мережа прямого зв'язку. Він приймає вхідні дані, пропускає їх через кілька шарів один за одним, а потім нарешті видає вихідні дані.

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Створимо подібну мережу в нашому середовищі:


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

Визначимо також функцію втрат і оптимізатор


import torch.optim as optim

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

Тренування мережі на тренувальних даних

Починаємо тренування нашої нейронної мережі. Звертаю увагу, що після того як ви запустите на виконання цей код, потрібно буде почекати деякий час до завершення роботи. У мене це зайняло 5 хв. Для навчання мережі потрібен час.

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

Отримаємо такий результат:

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Зберігаємо нашу навчену модель:

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

Тестування мережі на тестових даних

Ми навчили мережу використовуючи набір навчальних даних. Але нам потрібно перевірити, чи навчилася мережа взагалі чогось.

Ми перевіримо це, передбачивши мітку класу, яку виводить нейронна мережа, і перевіривши її щодо істинності. Якщо прогноз є вірним, ми додаємо зразок до списку правильних прогнозів.
Давайте покажемо зображення із тестового набору:

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

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Тепер попросимо нейронну мережу повідомити нам, що на цих картинках:


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

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Результати здаються досить хорошими: мережа визначила правильно три картинки із чотирьох.

Давайте подивимося, як мережа працює у всьому наборі даних.


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

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Схоже, мережа щось знає і працює. Якби він визначала класи навмання, то точність була б 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]))

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Схоже, що найкраще мережа визначає автомобілі та кораблі: 71% точності.

Отже, мережа працює. Тепер спробуємо перенести її роботу на графічний процесор (GPU) і подивися, що зміниться.

Тренування нейронної мережі на GPU

Спочатку поясню коротко, що таке CUDA. CUDA (Compute Unified Device Architecture) – платформа паралельних обчислень, розроблена NVIDIA, для загальних обчислень на графічних процесорах (GPU). За допомогою CUDA розробники можуть значно прискорити обчислювальні програми, використовуючи можливості графічних процесорів. На нашому сервері, який ми придбали, ця платформа вже встановлена.

Давайте спочатку визначимо наш GPU як перший видимий пристрій 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 )

Ваша перша нейронна мережа на графічному процесорі (GPU). Керівництво для початківців

Відправляємо мережу на GPU:

net.to(device)

Також нам доведеться відправляти входи та цілі на кожному кроці та в GPU:

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

Запустимо повторне навчання мережі вже на 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')

На цей раз навчання мережі тривало за часом близько 3 хвилин. Нагадаємо, що той же етап на звичайному процесорі тривав 5 хвилин. Різниця не суттєва, це відбувається тому, що наша мережа не така велика. При використанні великих масивів для навчання різниця між швидкістю GPU і традиційного процесора буде зростати.

На цьому все здається. Що нам вдалося зробити:

  • Ми розглянули що таке GPU і вибрали сервер, на якому він встановлений;
  • Ми налаштували програмне оточення для створення нейронної мережі;
  • Ми створили нейронну мережу для розпізнавання зображень та навчили її;
  • Ми повторили навчання мережі з використанням GPU та отримали приріст у швидкості.

Радий відповісти на запитання в коментарях.

Джерело: habr.com

Додати коментар або відгук