تدريب النماذج باستخدام PyTorch

مكتمل

PyTorch هو إطار عمل للتعلم الآلي شائع الاستخدام لتدريب نماذج التعلم العميق. في Azure Databricks، يتم تثبيت PyTorch مسبقا في مجموعات التعلم الآلي .

ملاحظه

يتم توفير قصاصات التعليمات البرمجية في هذه الوحدة كأمثلة للتأكيد على النقاط الرئيسية. سيكون لديك فرصة لتشغيل التعليمات البرمجية للحصول على مثال عمل كامل في التمرين لاحقا في هذه الوحدة النمطية.

تعريف شبكة PyTorch

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

يعرف المثال التالي التعليمات البرمجية شبكة اتصال.

import torch
import torch.nn as nn
import torch.nn.functional as F

class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.layer1 = nn.Linear(4, 5)
        self.layer2 = nn.Linear(5, 5)
        self.layer3 = nn.Linear(5, 3)

    def forward(self, x):
        layer1_output = torch.relu(self.layer1(x))
        layer2_output = torch.relu(self.layer2(layer1_output))
        y = self.layer3(layer2_output)
        return y

في حين أن التعليمات البرمجية قد تبدو معقدة في البداية، تحدد هذه الفئة شبكة بسيطة نسبيا بثلاث طبقات:

  • طبقة إدخال تقبل أربع قيم إدخال وتنشئ خمس قيم إخراج للطبقة التالية.
  • طبقة تقبل خمسة مدخلات وتنشئ خمسة مخرجات.
  • طبقة إخراج نهائية تقبل خمسة مدخلات وتنشئ ثلاثة مخرجات.

تطبق الدالة الأمامية الطبقات على بيانات الإدخال (x)، وتمرير الإخراج من كل طبقة إلى الطبقة التالية وأخيرا إرجاع الإخراج من الطبقة الأخيرة (التي تحتوي على متجه توقع التسمية، y). يتم تطبيق دالة تنشيط الوحدة الخطية المستقيمة (ReLU) على مخرجات الطبقات 1 و2 لتقييد قيم الإخراج بالأرقام الموجبة.

ملاحظه

اعتمادا على نوع معيار الخسارة المستخدم، يمكنك اختيار تطبيق دالة تنشيط مثل log_softmax على القيمة المرجعة لفرضها في النطاق من 0 إلى 1. ومع ذلك، فإن بعض معايير الخسارة (مثل CrossEntropyLoss، والتي تستخدم عادة للتصنيف متعدد الفئات) تطبق تلقائيا دالة مناسبة.

لإنشاء نموذج للتدريب، تحتاج فقط إلى إنشاء مثيل لفئة الشبكة مثل هذا:

myModel = MyNet()

إعداد البيانات للنمذجة

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

كما هو الحال مع معظم تقنيات التعلم الآلي الخاضعة للإشراف، يجب عليك تحديد مجموعات بيانات منفصلة للتدريب والتحقق من الصحة. يمكنك هذا الفصل من التحقق من أن النموذج يتنبأ بدقة عند تقديمه مع البيانات التي لم يتم تدريبه عليها.

تحدد التعليمات البرمجية التالية اثنين من أحمال البيانات؛ أحدهما للتدريب والآخر للاختبار. يفترض أن البيانات المصدر لكل محمل في هذا المثال هي صفيف Numpy من قيم الميزات وصفيف Numpy لقيم التسمية المقابلة.

# Create a dataset and loader for the training data and labels
train_x = torch.Tensor(x_train).float()
train_y = torch.Tensor(y_train).long()
train_ds = td.TensorDataset(train_x,train_y)
train_loader = td.DataLoader(train_ds, batch_size=20,
    shuffle=False, num_workers=1)

# Create a dataset and loader for the test data and labels
test_x = torch.Tensor(x_test).float()
test_y = torch.Tensor(y_test).long()
test_ds = td.TensorDataset(test_x,test_y)
test_loader = td.DataLoader(test_ds, batch_size=20,
    shuffle=False, num_workers=1)

تقوم الأحمال في هذا المثال بتقسيم البيانات إلى دفعات من 30، والتي يتم تمريرها إلى الوظيفة الأمامية أثناء التدريب أو الاستدلال.

اختيار معيار الخسارة وخوارزمية المحسن

يتم تدريب النموذج من خلال تغذية بيانات التدريب في الشبكة، وقياس الخسارة (الفرق المجمع بين القيم المتوقعة والفعلية)، وتحسين الشبكة عن طريق ضبط الأوزان والأرصدة لتقليل الخسارة. تخضع التفاصيل المحددة لكيفية حساب الخسارة وتقليلها لمعيار الخسارة وخوارزمية المحسن التي تختارها.

معايير الخسارة

يدعم PyTorch وظائف معايير فقدان متعددة، بما في ذلك (من بين العديد من الوظائف الأخرى):

  • cross_entropy: دالة تقيس الفرق الكلي بين القيم المتوقعة والقيم الفعلية لمتغيرات متعددة (تستخدم عادة لقياس الخسارة لاحتمالات الفئة في التصنيف متعدد الفئات).
  • binary_cross_entropy: دالة تقيس الفرق بين الاحتمالات المتوقعة والاحتمالات الفعلية (تستخدم عادة لقياس الخسارة لاحتمالات الفئة في التصنيف الثنائي).
  • mse_loss: دالة تقيس متوسط فقدان الخطأ المربع للقيم الرقمية المتوقعة والفعلية (تستخدم عادة للتراجع).

لتحديد معيار الخسارة الذي تريد استخدامه عند تدريب النموذج الخاص بك، يمكنك إنشاء مثيل للدالة المناسبة؛ أحب هذا:

import torch.nn as nn

loss_criteria = nn.CrossEntropyLoss

تلميح

لمزيد من المعلومات حول معايير الخسارة المتوفرة في PyTorch، راجع دالات الخسارة في وثائق PyTorch.

خوارزميات المحسن

بعد حساب الخسارة، يتم استخدام محسن لتحديد أفضل طريقة لضبط الأوزان والأرصدة من أجل تقليلها. المحسنون هي تطبيقات محددة لنهج الانخفاض المتدرج لتقليل دالة إلى أدنى حد. تتضمن المحسنات المتوفرة في PyTorch (من بين أمور أخرى):

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

تنشئ التعليمات البرمجية التالية مثيلا لمحسن آدم .

import torch.optim as opt

learning_rate = 0.001
optimizer = opt.Adam(model.parameters(), lr=learning_rate)

تلميح

لمزيد من المعلومات حول المحسنات المتوفرة في PyTorch، راجع الخوارزميات في وثائق PyTorch.

إنشاء وظائف التدريب والاختبار

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

إنشاء دالة تدريب

يوضح المثال التالي دالة لتدريب نموذج.

def train(model, data_loader, optimizer):

    # Use GPU if available, otherwise CPU
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)
    
    # Set the model to training mode (to enable backpropagation)
    model.train()
    train_loss = 0
    
    # Feed the batches of data forward through the network
    for batch, tensor in enumerate(data_loader):
        data, target = tensor # Specify features and labels in a tensor
        optimizer.zero_grad() # Reset optimizer state
        out = model(data) # Pass the data through the network
        loss = loss_criteria(out, target) # Calculate the loss
        train_loss += loss.item() # Keep a running total of loss for each batch

        # backpropagate adjustments to weights/bias
        loss.backward()
        optimizer.step()

    #Return average loss for all batches
    avg_loss = train_loss / (batch+1)
    print('Training set: Average loss: {:.6f}'.format(avg_loss))
    return avg_loss

يوضح المثال التالي دالة لاختبار النموذج.

def test(model, data_loader):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.to(device)
    # Switch the model to evaluation mode (so we don't backpropagate)
    model.eval()
    test_loss = 0
    correct = 0

    # Pass the data through with no gradient computation
    with torch.no_grad():
        batch_count = 0
        for batch, tensor in enumerate(data_loader):
            batch_count += 1
            data, target = tensor
            # Get the predictions
            out = model(data)

            # calculate the loss
            test_loss += loss_criteria(out, target).item()

            # Calculate the accuracy
            _, predicted = torch.max(out.data, 1)
            correct += torch.sum(target==predicted).item()
            
    # Calculate the average loss and total accuracy for all batches
    avg_loss = test_loss/batch_count
    print('Validation set: Average loss: {:.6f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        avg_loss, correct, len(data_loader.dataset),
        100. * correct / len(data_loader.dataset)))
    return avg_loss

تدريب النموذج على فترات متعددة

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

تلميح

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

التعليمات البرمجية التالية تدرب نموذج أكثر من 50 فترة.

epochs = 50
for epoch in range(1, epochs + 1):

    # print the epoch number
    print('Epoch: {}'.format(epoch))
    
    # Feed training data into the model to optimize the weights
    train_loss = train(model, train_loader, optimizer)
    print(train_loss)
    
    # Feed the test data into the model to check its performance
    test_loss = test(model, test_loader)
    print(test_loss)

حفظ حالة النموذج المدرب

بعد تدريب نموذج بنجاح، يمكنك حفظ أوزانه وتحيزاته مثل هذا:

model_file = '/dbfs/my_model.pkl'
torch.save(model.state_dict(), model_file)

لتحميل النموذج واستخدامه في وقت لاحق، قم بإنشاء مثيل لفئة الشبكة التي يستند إليها النموذج وتحميل الأوزان والتحيزات المحفوظة.

model = myNet()
model.load_state_dict(torch.load(model_file))