您的第一個圖形處理單元 (GPU) 上的神經網路。 初學者指南

您的第一個圖形處理單元 (GPU) 上的神經網路。 初學者指南
在本文中,我將告訴您如何在 30 分鐘內設定機器學習環境,建立用於影像識別的神經網絡,然後在圖形處理器 (GPU) 上運行相同的網路。

首先,我們來定義什麼是神經網路。

在我們的例子中,這是一個數學模型及其軟體或硬體實施例,建立在生物神經網路(活體神經細胞網路)的組織和功能原理之上。 這個概念是在研究大腦中發生的過程並試圖對這些過程進行建模時出現的。

神經網路不是通常意義上的編程,而是經過訓練的。 學習能力是神經網路相對於傳統演算法的主要優勢之一。 從技術上講,學習包括尋找神經元之間的連接係數。 在訓練過程中,神經網路能夠識別輸入資料和輸出資料之間的複雜依賴關係,並進行泛化。

從機器學習的角度來看,神經網路是模式辨識方法、判別分析、聚類方法等方法的特殊情況。

Оборудование

首先我們來看看裝備。 我們需要一台安裝了Linux作業系統的伺服器。 運行機器學習系統所需的設備非常強大,因此價格昂貴。 對於那些手邊沒有好機器的人,我建議關注雲端提供者的報價。 您可以快速租用所需的伺服器,並且只需按使用時間付費。

在需要創建神經網路的專案中,我使用俄羅斯雲端提供者之一的伺服器。 該公司提供專門用於機器學習的雲端伺服器出租,配備 NVIDIA 強大的 Tesla V100 圖形處理器 (GPU)。 簡而言之:與使用 CPU(眾所周知的中央處理單元)進行計算的類似成本的伺服器相比,使用具有 GPU 的伺服器可以提高數十倍的效率(快)。 這是由於 GPU 架構的特性實現的,它可以更快地處理運算。

為了實現下面描述的範例,我們購買了以下伺服器幾天:

  • SSD磁碟150GB
  • 記憶體 32 GB
  • Tesla V100 16 Gb 處理器,4 核心

我們在我們的機器上安裝了 Ubuntu 18.04。

設定環境

現在讓我們安裝伺服器上工作所需的一切。 由於我們的文章主要針對初學者,因此我將討論一些對他們有用的觀點。

設定環境時的許多工作都是透過命令列完成的。 大多數用戶使用 Windows 作為他們的工作作業系統。 該作業系統中的標準控制台還有很多不足之處。 因此,我們將使用一個方便的工具 指揮/。 下載迷你版並執行 Cmder.exe。 接下來需要透過 SSH 連接到伺服器:

ssh root@server-ip-or-hostname

指定伺服器的 IP 位址或 DNS 名稱,而不是 server-ip-or-hostname。 接下來,輸入密碼,如果連線成功,我們應該會收到類似的訊息。

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

開發機器學習模型的主要語言是Python。 Linux 上最受歡迎的使用平台是 蟒蛇.

讓我們將其安裝在我們的伺服器上。

我們首先更新本機套件管理器:

sudo apt-get update

安裝curl(命令列實用程式):

sudo apt-get install curl

下載最新版本的 Anaconda 發行版:

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。 讓我們安裝它:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

現在我們需要啟動 Jupyter Notebook,這是一個深受 ML 專家歡迎的開發工具。 它允許您編寫程式碼並立即查看其執行結果。 Jupyter Notebook 包含在 Anaconda 中,並且已安裝在我們的伺服器上。 您需要從我們的桌面系統連接到它。

為此,我們首先在指定連接埠 8080 的伺服器上啟動 Jupyter:

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

接下來,在 Cmder 控制台(頂部選單 - 新控制台對話框)中開啟另一個選項卡,我們將透過連接埠 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。

讓我們檢查一下我們安裝的所有組件是否正確運作。 讓我們將範例 PyTorch 程式碼輸入 Jupyter 並運行執行(運行按鈕):

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

結果應該是這樣的:

您的第一個圖形處理單元 (GPU) 上的神經網路。 初學者指南

如果您有類似的結果,那麼我們已經正確配置了所有內容,我們可以開始開發神經網路!

創建神經網絡

我們將創建一個用於圖像識別的神經網路。 我們以此為基礎 領導.

我們將使用公開的 CIFAR10 資料集來訓練網路。 它有類別:「飛機」、「汽車」、「鳥」、「貓」、「鹿」、「狗」、「青蛙」、「馬」、「船」、「卡車」。 CIFAR10中的影像為3x32x32,即3x32像素的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(統一運算設備架構)是 NVIDIA 開發的用於圖形處理單元(GPU)上通用運算的平行運算平台。 借助 CUDA,開發人員可以利用 GPU 的強大功能顯著加速運算應用程式。 這個平台已經安裝在我們購買的伺服器上。

我們首先將 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 重複進行網路訓練,速度提高了。

我很樂意回答評論中的問題。

來源: www.habr.com

添加評論