您的第一个图形处理单元 (GPU) 上的神经网络。 初学者指南

您的第一个图形处理单元 (GPU) 上的神经网络。 初学者指南
在本文中,我将告诉您如何在 30 分钟内设置机器学习环境,创建用于图像识别的神经网络,然后在图形处理器 (GPU) 上运行相同的网络。

首先,我们来定义什么是神经网络。

在我们的例子中,这是一个数学模型及其软件或硬件实施例,建立在生物神经网络(活体神经细胞网络)的组织和功能原理之上。 这个概念是在研究大脑中发生的过程并试图对这些过程进行建模时出现的。

神经网络不是通常意义上的编程,而是经过训练的。 学习能力是神经网络相对于传统算法的主要优势之一。 从技术上讲,学习包括寻找神经元之间的连接系数。 在训练过程中,神经网络能够识别输入数据和输出数据之间的复杂依赖关系,并进行泛化。

从机器学习的角度来看,神经网络是模式识别方法、判别分析、聚类方法等方法的特例。

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

首先我们来看看装备。 我们需要一台安装了Linux操作系统的服务器。 运行机器学习系统所需的设备非常强大,因此价格昂贵。 对于那些手头没有好机器的人,我建议关注云提供商的报价。 您可以快速租用所需的服务器,并且只需按使用时间付费。

在需要创建神经网络的项目中,我使用俄罗斯云提供商之一的服务器。 该公司提供专门用于机器学习的云服务器出租,配备 NVIDIA 强大的 Tesla V100 图形处理器 (GPU)。 简而言之:与使用 CPU(众所周知的中央处理单元)进行计算的类似成本的服务器相比,使用带有 GPU 的服务器可以提高数十倍的效率(快)。 这是由于 GPU 架构的特性实现的,它可以更快地处理计算。

为了实现下面描述的示例,我们购买了以下服务器几天:

  • SSD磁盘150GB
  • 32 GB RAM
  • 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 и Tensorflow.

使用该框架可以提高开发速度并使用现成的工具来完成标准任务。

在此示例中,我们将使用 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 重复进行网络训练,速度得到了提高。

我很乐意回答评论中的问题。

来源: habr.com

添加评论