グラフィックス プロセッシング ユニット (GPU) 上の最初のニューラル ネットワーク。 初心者向けガイド

グラフィックス プロセッシング ユニット (GPU) 上の最初のニューラル ネットワーク。 初心者向けガイド
В этой статье я расскажу как за 30 минут настроить среду для машинного обучения, создать нейронную сеть для распознавания изображений a потом запустить ту же сеть на графическом процессоре (GPU).

Для начала определим что такое нейронная сеть.

В нашем случае это математическая модель, а также её программное или аппаратное воплощение, построенная по принципу организации и функционирования биологических нейронных сетей — сетей нервных клеток живого организма. Это понятие возникло при изучении процессов, протекающих в мозге, и при попытке смоделировать эти процессы.

ニューラル ネットワークは、通常の意味でプログラムされているのではなく、トレーニングされています。 学習能力は、従来のアルゴリズムに対するニューラル ネットワークの主な利点の XNUMX つです。 技術的には、学習はニューロン間の接続係数を見つけることで構成されます。 トレーニング プロセス中に、ニューラル ネットワークは入力データと出力データの間の複雑な依存関係を特定し、一般化を実行できます。

С точки зрения машинного обучения, нейронная сеть представляет собой частный случай методов распознавания образов, дискриминантного анализа, методов кластеризации и прочих методов.

機器

まずは装備を見てみましょう。 Linux オペレーティング システムがインストールされたサーバーが必要です。 機械学習システムを運用するために必要な機器は非常に強力であり、その結果、高価になります。 手元に良いマシンがない人は、クラウドプロバイダーのオファーに注目することをお勧めします。 必要なサーバーをすぐにレンタルでき、料金は使用した時間分だけ支払うことができます。

ニューラル ネットワークを作成する必要があるプロジェクトでは、ロシアのクラウド プロバイダーのサーバーを使用しています。 同社は、NVIDIA の強力な Tesla V100 グラフィックス プロセッサ (GPU) を搭載した機械学習専用のレンタル クラウド サーバーを提供しています。 つまり、GPU を搭載したサーバーを使用すると、計算に CPU (よく知られた中央処理装置) を使用する同様のコストのサーバーと比較して、数十倍効率 (高速) になる可能性があります。 これは、計算をより高速に処理する GPU アーキテクチャの機能によって実現されます。

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

  • SSDディスク150GB
  • RAM 32GB
  • Tesla V100 16 Gb プロセッサー (4 コア)

マシンに Ubuntu 18.04 をインストールしました。

Устанавливаем окружение

次に、作業に必要なものをすべてサーバーにインストールしましょう。 今回の記事は主に初心者向けですので、初心者にとって役立ついくつかのポイントについてお話します。

環境をセットアップするときの作業の多くは、コマンド ラインを通じて行われます。 ほとんどのユーザーは Windows を作業 OS として使用します。 この OS の標準コンソールには、まだ改善の余地がたくさんあります。 そこで便利なツールを使います 指揮官/。 ミニバージョンをダウンロードし、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. Установим его:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

次に、ML スペシャリストに人気の開発ツールである Jupyter Notebook を起動する必要があります。 コードを記述して、その実行結果をすぐに確認できます。 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 (Compute Unified Device Architecture) は、グラフィックス プロセッシング ユニット (GPU) での一般的なコンピューティングのために NVIDIA によって開発された並列コンピューティング プラットフォームです。 CUDA を使用すると、開発者は GPU の能力を活用してコンピューティング アプリケーションを劇的に高速化できます。 このプラットフォームは、購入したサーバーにすでにインストールされています。

まず、最初に表示される cuda デバイスとして GPU を定義しましょう。

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

コメントを追加します