أول شبكتك العصبية على وحدة معالجة الرسومات (GPU). دليل المبتدئين

أول شبكتك العصبية على وحدة معالجة الرسومات (GPU). دليل المبتدئين
سأخبرك في هذه المقالة بكيفية إعداد بيئة التعلم الآلي في 30 دقيقة، وإنشاء شبكة عصبية للتعرف على الصور، ثم تشغيل نفس الشبكة على معالج الرسومات (GPU).

أولاً، دعونا نحدد ما هي الشبكة العصبية.

في حالتنا، هذا نموذج رياضي، بالإضافة إلى برمجياته أو تجسيده للأجهزة، المبني على مبدأ تنظيم وعمل الشبكات العصبية البيولوجية - شبكات الخلايا العصبية للكائن الحي. نشأ هذا المفهوم أثناء دراسة العمليات التي تحدث في الدماغ ومحاولة نمذجة هذه العمليات.

الشبكات العصبية ليست مبرمجة بالمعنى المعتاد للكلمة، بل يتم تدريبها. تعد القدرة على التعلم إحدى المزايا الرئيسية للشبكات العصبية مقارنة بالخوارزميات التقليدية. من الناحية الفنية، يتكون التعلم من إيجاد معاملات الاتصالات بين الخلايا العصبية. أثناء عملية التدريب، تكون الشبكة العصبية قادرة على تحديد التبعيات المعقدة بين بيانات الإدخال وبيانات الإخراج، بالإضافة إلى إجراء التعميم.

من وجهة نظر التعلم الآلي، تعد الشبكة العصبية حالة خاصة من طرق التعرف على الأنماط والتحليل التمييزي وطرق التجميع وغيرها من الطرق.

معدات

أولاً، دعونا نلقي نظرة على المعدات. نحتاج إلى خادم مثبت عليه نظام التشغيل Linux. المعدات اللازمة لتشغيل أنظمة التعلم الآلي قوية للغاية، ونتيجة لذلك، فهي باهظة الثمن. بالنسبة لأولئك الذين ليس لديهم آلة جيدة في متناول اليد، أوصي بالانتباه إلى عروض مقدمي الخدمات السحابية. يمكنك استئجار الخادم المطلوب بسرعة والدفع فقط مقابل وقت الاستخدام.

في المشاريع التي يكون من الضروري فيها إنشاء شبكات عصبية، أستخدم خوادم أحد موفري الخدمات السحابية الروس. تقدم الشركة خوادم سحابية للإيجار خصيصًا للتعلم الآلي مع معالجات الرسومات Tesla V100 القوية (GPU) من NVIDIA. باختصار: يمكن أن يكون استخدام خادم مزود بوحدة معالجة الرسومات (GPU) أكثر كفاءة (سريعًا) بعشرات المرات مقارنةً بخادم ذي تكلفة مماثلة يستخدم وحدة المعالجة المركزية (وحدة المعالجة المركزية المعروفة) لإجراء العمليات الحسابية. يتم تحقيق ذلك بفضل ميزات بنية GPU، والتي تتواءم مع العمليات الحسابية بشكل أسرع.

لتنفيذ الأمثلة الموضحة أدناه، قمنا بشراء الخادم التالي لعدة أيام:

  • قرص SSD 150 جيجابايت
  • ذاكرة الوصول العشوائي 32 جيجابايت
  • معالج تيسلا V100 16 جيجا بايت مع 4 أنوية

لقد قمنا بتثبيت Ubuntu 18.04 على أجهزتنا.

تهيئة البيئة

الآن لنقم بتثبيت كل ما هو ضروري للعمل على الخادم. وبما أن مقالتنا مخصصة للمبتدئين في المقام الأول، فسوف أتحدث عن بعض النقاط التي ستكون مفيدة لهم.

يتم تنفيذ الكثير من العمل عند إعداد البيئة من خلال سطر الأوامر. يستخدم معظم المستخدمين Windows كنظام تشغيل خاص بهم. وحدة التحكم القياسية في نظام التشغيل هذا تترك الكثير مما هو مرغوب فيه. ولذلك، سوف نستخدم أداة مريحة القائد/. قم بتنزيل الإصدار المصغر وقم بتشغيل Cmder.exe. بعد ذلك تحتاج إلى الاتصال بالخادم عبر SSH:

ssh root@server-ip-or-hostname

بدلاً من عنوان IP للخادم أو اسم المضيف، حدد عنوان IP أو اسم DNS لخادمك. بعد ذلك، أدخل كلمة المرور وإذا نجح الاتصال، فيجب أن نتلقى رسالة مشابهة لهذه.

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

اللغة الرئيسية لتطوير نماذج تعلم الآلة هي لغة بايثون. والنظام الأساسي الأكثر شيوعًا لاستخدامه على Linux هو الأناكندة أفعى ضخمة.

دعونا تثبيته على الخادم الخاص بنا.

نبدأ بتحديث مدير الحزم المحلي:

sudo apt-get update

تثبيت الضفيرة (الأداة المساعدة لسطر الأوامر):

sudo apt-get install curl

تنزيل أحدث إصدار من توزيعة اناكوندا:

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!

لقد تم الآن إنشاء العديد من أطر العمل لتطوير نماذج تعلم الآلة، ونحن نعمل مع الأطر الأكثر شيوعًا: PyTorch и Tensorflow.

يتيح لك استخدام الإطار زيادة سرعة التطوير واستخدام الأدوات الجاهزة للمهام القياسية.

في هذا المثال سوف نعمل مع PyTorch. لنقم بتثبيته:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

نحتاج الآن إلى إطلاق Jupyter Notebook، وهي أداة تطوير شائعة لمتخصصي تعلم الآلة. يسمح لك بكتابة التعليمات البرمجية ورؤية نتائج تنفيذها على الفور. تم تضمين Jupyter Notebook مع Anaconda وهو مثبت بالفعل على خادمنا. تحتاج إلى الاتصال به من نظام سطح المكتب لدينا.

للقيام بذلك، سنقوم أولاً بتشغيل Jupyter على الخادم الذي يحدد المنفذ 8080:

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

دعنا نستخدم الرابط للمضيف المحلي:8080. انسخ المسار الكامل والصقه في شريط العناوين بالمتصفح المحلي لجهاز الكمبيوتر الخاص بك. سيتم فتح Jupyter Notebook.

لنقم بإنشاء دفتر ملاحظات جديد: جديد - Notebook - Python 3.

دعونا نتحقق من التشغيل الصحيح لجميع المكونات التي قمنا بتثبيتها. دعنا ندخل مثال كود PyTorch في Jupyter ونقوم بتشغيل التنفيذ (زر التشغيل):

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

يجب أن تكون النتيجة شيء من هذا القبيل:

أول شبكتك العصبية على وحدة معالجة الرسومات (GPU). دليل المبتدئين

إذا كانت لديك نتيجة مماثلة، فقد قمنا بتكوين كل شيء بشكل صحيح ويمكننا البدء في تطوير الشبكة العصبية!

إنشاء شبكة عصبية

سنقوم بإنشاء شبكة عصبية للتعرف على الصور. لنأخذ هذا كأساس توجيه.

سوف نستخدم مجموعة بيانات CIFAR10 المتاحة للعامة لتدريب الشبكة. لها فئات: "طائرة"، "سيارة"، "طائر"، "قطة"، "غزال"، "كلب"، "ضفدع"، "حصان"، "سفينة"، "شاحنة". الصور في CIFAR10 هي 3x32x32، أي صور ملونة ثلاثية القنوات بحجم 3x32 بكسل.

أول شبكتك العصبية على وحدة معالجة الرسومات (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 للحوسبة العامة على وحدات معالجة الرسومات (GPUs). باستخدام CUDA، يمكن للمطورين تسريع تطبيقات الحوسبة بشكل كبير من خلال الاستفادة من قوة وحدات معالجة الرسومات. تم تثبيت هذا النظام الأساسي بالفعل على خادمنا الذي اشتريناه.

دعونا أولاً نعرّف وحدة معالجة الرسومات الخاصة بنا على أنها أول جهاز 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)

سيتعين علينا أيضًا إرسال المدخلات والأهداف في كل خطوة إلى وحدة معالجة الرسومات:

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

دعونا نعيد تدريب الشبكة على وحدة معالجة الرسومات:

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) واخترنا الخادم الذي تم تثبيتها عليه؛
  • لقد أنشأنا بيئة برمجية لإنشاء شبكة عصبية؛
  • لقد أنشأنا شبكة عصبية للتعرف على الصور وقمنا بتدريبها؛
  • كررنا تدريب الشبكة باستخدام وحدة معالجة الرسومات وحصلنا على زيادة في السرعة.

سأكون سعيدًا بالإجابة على الأسئلة في التعليقات.

المصدر: www.habr.com

إضافة تعليق