دليل PyTorch: من الـ Tensors إلى الـ Production في

٤ مايو ٢٠٢٦

PyTorch Guide: Tensors to Production in 2026

ملخص

  • PyTorch هو إطار عمل مفتوح المصدر للتعلم العميق مبني حول رسوم بيانية حسابية ديناميكية ("eager") و API برمجية بأسلوب Python. تم إصداره لأول مرة في يناير 2017 بواسطة Facebook AI Research ويتبع الآن لمؤسسة PyTorch Foundation التابعة لـ Linux Foundation.12
  • الإصدار المستقر الحالي هو PyTorch 2.11.0 (مارس 2026)، ويدعم Python من الإصدار 3.10 إلى 3.14، ويشحن ملفات wheels قابلة للتثبيت مع مكتبات CUDA runtime مدمجة عبر pip.34
  • torch.compile هي الميزة الأبرز في PyTorch 2.x — فمن خلال 165 نموذجاً مفتوح المصدر في الاختبار المرجعي الرسمي، حققت تسريعاً متوسطاً بنسبة 20% عند استخدام float32 و36% عند دقة AMP، مع العمل بنجاح على 93% من النماذج المختبرة.5
  • لتعلم نقل البيانات (transfer learning) في الرؤية الحاسوبية، استخدم API الحالي weights= (مثل torchvision.models.resnet18(weights=ResNet18_Weights.DEFAULT)). تم إهمال المعامل القديم pretrained=True منذ إصدار torchvision 0.13 (يونيو 2022).6
  • يستعرض هذا الدليل الموترات (tensors)، والاشتقاق التلقائي (autograd)، وبناء وتدريب النماذج، وتعلم نقل البيانات باستخدام API الحالي، وتسريع GPU، و torch.compile، ومسارات النشر (TorchScript، ONNX، TorchServe).

ما ستتعلمه

  1. تثبيت PyTorch بشكل صحيح لـ CPU أو CUDA في بيئة Python حديثة (3.10–3.14).
  2. التعامل مع الموترات (tensors) — الإنشاء، والعمليات الحسابية، وإعادة التشكيل، ونقل البيانات بين CPU و GPU.
  3. استخدام autograd لحساب الاشتقاقات تلقائياً وفهم كيفية عمله في عملية التدريب.
  4. بناء الشبكات العصبية باستخدام nn.Module و API الخاص بـ nn.functional.
  5. تحميل ومعالجة البيانات في دفعات باستخدام Dataset و DataLoader، بما في ذلك torchvision.datasets المدمجة.
  6. كتابة حلقة تدريب كاملة مع التحقق (validation)، وجدولة معدل التعلم، وتقليم الاشتقاق (gradient clipping).
  7. إجراء تعلم نقل البيانات باستخدام نظام الأوزان المتعددة الجديد في torchvision.
  8. تسريع التدريب باستخدام الدقة المختلطة (torch.amp) و torch.compile.
  9. نشر نموذج مدرب عبر TorchScript أو ONNX، وخدمته باستخدام TorchServe.
  10. استكشاف أخطاء أوضاع الفشل الشائعة وإصلاحها (نفاد ذاكرة CUDA، عدم تطابق الأجهزة، أخطاء الأوضاع، وتلاشي الاشتقاقات).

المتطلبات الأساسية

يجب أن تكون مرتاحاً في التعامل مع Python (الدوال، الكلاسات، الاستيراد، البيئات الافتراضية) وأن تكون قد أخذت فكرة على الأقل عن NumPy. لا تحتاج إلى دكتوراه في الرياضيات، ولكن معرفة ما هو المتجه، والمصفوفة، والمشتقة، وقاعدة السلسلة ستجعل autograd يبدو بديهياً بدلاً من كونه سحراً.

بالنسبة للأجهزة: لابتوب يعمل بـ CPU فقط يكفي للأمثلة الواردة في هذا الدليل. للقيام بتدريب حقيقي على نطاق واسع، ستحتاج إلى NVIDIA GPU مع تعريف حديث — ملفات pip wheels الخاصة بـ PyTorch تتضمن مكتبات CUDA runtime مدمجة، لذا لا تحتاج إلى تثبيت CUDA Toolkit منفصل على مستوى النظام، بل فقط تعريف NVIDIA متوافق.4

نشأ PyTorch من إطار عمل Torch القديم المبني على لغة Lua. قام فريق Facebook AI Research (المعروف الآن بـ Meta AI) بنقل الأفكار الأساسية إلى Python وأصدر PyTorch 0.1 في 19 يناير 2017.12 ميزه خياران في التصميم عن منافسيه في ذلك الوقت: الرسوم البيانية الحسابية الديناميكية ("define-by-run") التي تُبنى أثناء تنفيذ كود Python الخاص بك، و API المصمم بأسلوب Python والذي يتوافق بسلاسة مع NumPy.

وصل إطار العمل إلى أول محطة استقرار للإنتاج مع PyTorch 1.0 في 7 ديسمبر 2018، والذي قدم TorchScript لنشر النماذج في بيئات الإنتاج.7 في سبتمبر 2022، نقلت Meta مشروع PyTorch إلى Linux Foundation تحت مظلة مؤسسة PyTorch Foundation الجديدة والمحايدة، مع أعضاء مؤسسين هم AMD و AWS و Google Cloud و Meta و Microsoft Azure و NVIDIA.2 توسعت المؤسسة مرة أخرى في فبراير 2026، مضيفة أعضاء من الأوساط الأكاديمية والبنية التحتية للذكاء الاصطناعي بما في ذلك جامعة Carnegie Mellon وجامعة Monash.8

أهم إصدار حديث هو PyTorch 2.0 (15 مارس 2023)، والذي قدم torch.compile — وهو مسار لالتقاط الرسم البياني وترجمته يغلف النموذج العادي وينتج كوداً أسرع دون الحاجة لإعادة كتابة المصدر.5 وحتى وقت كتابة هذا الدليل، فإن أحدث إصدار مستقر هو PyTorch 2.11.0 (مارس 2026).3

أصبح إطار العمل ضخماً حقاً الآن: المستودع الرسمي pytorch/pytorch لديه ما يقرب من 99,000 نجمة على GitHub،9 ويدعم PyTorch نظاماً بيئياً واسعاً يشمل Hugging Face Transformers و PyTorch Lightning و fast.ai و PyTorch Geometric، بالإضافة إلى التكاملات الرسمية المدمجة في ONNX و TorchServe.

التثبيت

مسار التثبيت الموصى به للجميع تقريباً هو pip من فهرس PyTorch الرسمي. اختر رابط الفهرس الصحيح لإصدار CUDA الخاص بك (أو استخدم نسخة CPU فقط):

# CPU only (any platform)
pip install torch torchvision torchaudio

# CUDA 12.1 wheels (Linux / Windows with NVIDIA GPU + driver)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

احصل دائماً على الأمر الحالي من pytorch.org/get-started/locally — حيث تتغير إصدارات CUDA المدعومة ونطاق Python مع كل إصدار. يدعم PyTorch الحالي Python 3.10–3.14.4

تحقق من التثبيت:

import torch

print(f"PyTorch version: {torch.__version__}")
print(f"CUDA available:  {torch.cuda.is_available()}")
print(f"CUDA version:    {torch.version.cuda}")
if torch.cuda.is_available():
    print(f"Device:          {torch.cuda.get_device_name(0)}")

إذا كانت torch.cuda.is_available() تعيد False على جهاز تتوقع وجود GPU فيه، فإن السبب الأكثر شيوعاً هو أن التعريف قديم جداً بالنسبة لـ CUDA runtime المدمج — قم بتحديث تعريف NVIDIA، وليس CUDA Toolkit.

الموترات (Tensors)

الموترات هي هيكل البيانات الأساسي في PyTorch: مصفوفة نونية الأبعاد (N-dimensional)، تشبه ndarray في NumPy، مع إمكانية وضعها اختيارياً على GPU وتتبع الاشتقاقات.

import torch

# Creation
scalar = torch.tensor(3.14)
vector = torch.tensor([1.0, 2.0, 3.0])
matrix = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)

zeros  = torch.zeros(2, 3)         # 2x3 of zeros
ones   = torch.ones(2, 3)          # 2x3 of ones
randn  = torch.randn(2, 3)         # standard normal
arange = torch.arange(12).view(3, 4)  # 0..11 reshaped to 3x4

# Element-wise and matmul
a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])
print(a + b)          # tensor([5., 7., 9.])
print(a * b)          # element-wise
print(torch.dot(a, b))  # scalar dot product

m1 = torch.randn(2, 3)
m2 = torch.randn(3, 4)
print(torch.matmul(m1, m2).shape)  # torch.Size([2, 4])

# Shapes and dtype
t = torch.randn(2, 3)
print(t.shape, t.dtype, t.device)

# Move to GPU if available
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
t_gpu = t.to(device)

نقطتان عمليتان تهمان المبتدئين:

  • view مقابل reshape: تتطلب view أن يكون الموتر متصلاً (contiguous) في الذاكرة؛ بينما ستلجأ reshape إلى النسخ إذا لزم الأمر. يفضل استخدام reshape إلا إذا كنت تعلم يقيناً أن الموتر متصل.
  • التوافق مع NumPy بدون نسخ على CPU: يشترك كل من t.numpy() و torch.from_numpy(arr) في الذاكرة. إذا قمت بتعديل أحدهما، فسيتم تعديل الآخر. تنكسر هذه العلاقة بمجرد نقل الموتر إلى GPU.

الاشتقاق التلقائي (Autograd)

يتتبع PyTorch العمليات على الموترات التي تحتوي على requires_grad=True ويحسب الاشتقاقات باستخدام .backward(). هذا هو المحرك وراء كل حلقة تدريب ستكتبها.

import torch

x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1
y.backward()
print(x.grad)  # tensor(7.) — d/dx(x² + 3x + 1) at x=2 is 2*2 + 3

بالنسبة للتدريب، عادةً لا تقوم بإدارة requires_grad يدويًا — فمعاملات nn.Module يتم ضبطها تلقائيًا، وتقوم باستدعاء .backward() على الخسارة (loss) لملء .grad لكل معامل قابل للتعلم.

# Hand-rolled linear regression with autograd
x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])

w = torch.tensor([[0.5]], requires_grad=True)
b = torch.tensor([[0.0]], requires_grad=True)

lr = 0.05
for _ in range(200):
    pred = x_data @ w + b
    loss = ((pred - y_data) ** 2).mean()
    loss.backward()
    with torch.no_grad():
        w -= lr * w.grad
        b -= lr * b.grad
        w.grad.zero_()
        b.grad.zero_()

print(f"w ≈ {w.item():.3f}, b ≈ {b.item():.3f}")  # ~ w=2, b=0

نمطان يجب تذكرهما:

  • قم بتغليف تحديثات المعاملات بـ with torch.no_grad(): حتى لا يتم تتبعها.
  • تصفير الاشتقاقات (gradients) بين الخطوات. نسيان optimizer.zero_grad() (أو في الحالة اليدوية أعلاه، w.grad.zero_()) هو الخطأ الأكثر شيوعًا في autograd — حيث تتراكم الاشتقاقات عبر استدعاءات .backward() حسب التصميم، وهو أمر مفيد لتراكم الاشتقاقات ولكنه خطأ عندما لا ترغب في ذلك.

بناء الشبكات العصبية

في الممارسة العملية، لا تقوم بإدارة التنسورات (tensors) والاشتقاقات بنفسك — بل تقوم بإنشاء فئة فرعية من nn.Module، وتصرح عن الطبقات في __init__، وتحدد التمرير الأمامي (forward pass):

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

class MNISTClassifier(nn.Module):
    def __init__(self, hidden: int = 128, num_classes: int = 10):
        super().__init__()
        self.fc1 = nn.Linear(28 * 28, hidden)
        self.fc2 = nn.Linear(hidden, num_classes)
        self.dropout = nn.Dropout(0.3)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = x.view(x.size(0), -1)   # flatten N×1×28×28 → N×784
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        return self.fc2(x)          # raw logits

model = MNISTClassifier()
print(model)
print(f"Parameters: {sum(p.numel() for p in model.parameters()):,}")

بضع ملاحظات حول الاصطلاحات:

  • يعيد التمرير الأمامي logits، وليس احتمالات softmax. يتوقع nn.CrossEntropyLoss الـ logits ويطبق log-softmax داخليًا.
  • nn.Sequential جيد للمجموعات الخطية البسيطة ولكنه لا يسمح لك بالتعبير عن اتصالات التخطي (skip connections) أو الفروع أو أي شيء ديناميكي — بمجرد أن يحتوي نموذجك على أي منطق شرطي، يفضل استخدام nn.Module حقيقي.
  • قم بتهيئة الانحياز (bias) لقيمة معقولة إذا كان ذلك يهمك: القيم الافتراضية في PyTorch غالبًا ما تكون جيدة، ولكن بالنسبة للشبكات الأعمق ستحتاج إلى استدعاءات صريحة لـ nn.init.kaiming_normal_ (لـ ReLU) أو nn.init.xavier_uniform_ (لـ tanh/sigmoid) داخل __init__.

مجموعات البيانات ومحملات البيانات (Datasets and DataLoaders)

يفصل PyTorch بين "ما هو المثال الواحد" (Dataset) وبين "كيف أقوم بالتقسيم إلى دفعات (batching) والخلط (shuffling)" (DataLoader). تستخدم معظم دروس رؤية الكمبيوتر فئة torchvision.datasets مدمجة:

from torch.utils.data import DataLoader
from torchvision import datasets, transforms

transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,)),  # MNIST mean/std
])

train_set = datasets.MNIST("./data", train=True,  download=True, transform=transform)
test_set  = datasets.MNIST("./data", train=False, download=True, transform=transform)

train_loader = DataLoader(train_set, batch_size=64, shuffle=True,  num_workers=2, pin_memory=True)
test_loader  = DataLoader(test_set,  batch_size=512, shuffle=False, num_workers=2, pin_memory=True)

لبياناتك الخاصة، قم بإنشاء فئة فرعية من Dataset:

from torch.utils.data import Dataset

class CSVDataset(Dataset):
    def __init__(self, df, feature_cols, label_col, transform=None):
        self.X = df[feature_cols].to_numpy(dtype="float32")
        self.y = df[label_col].to_numpy(dtype="int64")
        self.transform = transform

    def __len__(self) -> int:
        return len(self.y)

    def __getitem__(self, idx: int):
        x = torch.from_numpy(self.X[idx])
        y = int(self.y[idx])
        if self.transform is not None:
            x = self.transform(x)
        return x, y

نصائح عملية: اضبط num_workers على رقم موجب صغير (2-8) على Linux/macOS لتحميل البيانات بالتوازي، واستخدم pin_memory=True عند التدريب على GPU لتسريع عمليات النقل من المضيف (host) إلى الجهاز.

حلقة تدريب كاملة

تجميع القطع معًا لمصنف MNIST الخاص بنا:

import torch
import torch.nn as nn
import torch.optim as optim

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MNISTClassifier().to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)

def evaluate(model, loader, device) -> tuple[float, float]:
    model.eval()
    total_loss, correct, total = 0.0, 0, 0
    with torch.no_grad():
        for x, y in loader:
            x, y = x.to(device), y.to(device)
            logits = model(x)
            total_loss += criterion(logits, y).item() * x.size(0)
            correct += (logits.argmax(dim=1) == y).sum().item()
            total += x.size(0)
    return total_loss / total, correct / total

EPOCHS = 5
for epoch in range(EPOCHS):
    model.train()
    running_loss = 0.0
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        optimizer.zero_grad()
        logits = model(x)
        loss = criterion(logits, y)
        loss.backward()
        # Optional: clip gradients to stabilize deeper networks
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
        optimizer.step()
        running_loss += loss.item() * x.size(0)

    scheduler.step()
    train_loss = running_loss / len(train_loader.dataset)
    val_loss, val_acc = evaluate(model, test_loader, device)
    print(
        f"epoch {epoch+1:>2}/{EPOCHS} | "
        f"train_loss={train_loss:.4f} | "
        f"val_loss={val_loss:.4f} | "
        f"val_acc={val_acc:.4f}"
    )

torch.save(model.state_dict(), "mnist_classifier.pt")

ما تغطيه هذه الحلقة في مكان واحد: وضع الجهاز (device placement)، تبديل وضع التدريب/التقييم، تصفير الاشتقاقات وخطوة المحسن (optimizer)، قص الاشتقاقات (gradient clipping)، جدولة معدل التعلم، ودالة تقييم نظيفة باستخدام torch.no_grad(). تنسيق حفظ state_dict هو الطريقة الموصى بها للاحتفاظ بالأوزان — حيث إن حفظ كائن النموذج بالكامل يقوم بـ pickle لتعريفات الفئات ويميل إلى التعطل عبر عمليات إعادة الهيكلة (refactors).

التعلم بنقل الخبرة (Transfer Learning - الواجهة الحالية)

بالنسبة لأعمال رؤية الكمبيوتر، لا تقوم أبدًا بالتدريب من الصفر تقريبًا — بل تقوم بتحميل نموذج تم تدريبه مسبقًا على ImageNet وتقوم بضبطه (fine-tuning). تستخدم واجهة torchvision الحالية weights=، وليس pretrained=True. تم إهمال الأخير منذ إصدار torchvision 0.13 (يونيو 2022) ويصدر UserWarning.6

import torch
import torch.nn as nn
import torchvision
from torchvision.models import ResNet18_Weights

# Load pre-trained ResNet18 with the multi-weight API
weights = ResNet18_Weights.DEFAULT          # current best weights
model = torchvision.models.resnet18(weights=weights)

# The weights enum bundles the matching preprocessing transforms — no
# more guessing the right Normalize() means and stds.
preprocess = weights.transforms()

# Replace the final classifier head for our 10-class task
in_features = model.fc.in_features
model.fc = nn.Linear(in_features, 10)

# Optionally freeze everything except the new head for fast fine-tuning
for name, param in model.named_parameters():
    param.requires_grad = name.startswith("fc.")

# Now `preprocess` is the right transform to put inside your dataset
# (or apply on each tensor before forward). Train as usual.

هناك شيئان تقوم بهما هذه الواجهة بشكل صحيح ولم تفعلهما الواجهة القديمة:

  • تعيد weights.transforms() خط أنابيب المعالجة المسبقة الدقيق الذي تم تدريب الشبكة عليه. لست مضطرًا لنسخ متوسطات وانحرافات ImageNet من إجابة على Stack Overflow.
  • تكشف weights.meta عن تسميات الفئات والبيانات الوصفية الأخرى، بحيث يمكنك ربط مؤشرات مخرجات النموذج بتسميات مقروءة بشريًا بدون ملف منفصل.

تسريع GPU والدقة المختلطة (Mixed Precision)

الانتقال إلى GPU هو أمر ميكانيكي: أرسل النموذج وكل دفعة إلى الجهاز. التدريب بدقة مختلطة هو أسهل طريقة لجعل GPU أسرع دون لمس كود النموذج الخاص بك.

import torch
from torch.amp import autocast, GradScaler

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
use_amp = device.type == "cuda"
scaler = GradScaler(device="cuda", enabled=use_amp)

for x, y in train_loader:
    x, y = x.to(device, non_blocking=True), y.to(device, non_blocking=True)
    optimizer.zero_grad()
    with autocast(device_type=device.type, dtype=torch.float16, enabled=use_amp):
        logits = model(x)
        loss = criterion(logits, y)
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()

يقوم الحارس enabled=use_amp بتحويل autocast ومقياس الاشتقاق (gradient scaler) إلى عمليات لا تفعل شيئًا (no-ops) عندما تعود إلى CPU، بحيث تعمل نفس حلقة التدريب على أي من الجهازين.

يقوم autocast بتشغيل العمليات بدقة أقل (FP16 أو BF16) حيثما كان ذلك آمنًا، ويقوم GradScaler بإعادة قياس الخسارة حتى لا تنخفض قيم الاشتقاق الصغيرة إلى الصفر (underflow). في بطاقات NVIDIA الحديثة (Ampere/Hopper)، يوفر AMP عادةً تسريعًا ملحوظًا في التدريب مع فقدان ضئيل في الدقة. أبلغ اختبار الأداء الرسمي لـ PyTorch لـ torch.compile عن سرعة أكبر بنسبة 20% تقريبًا في المتوسط عند float32 و 36% أسرع في المتوسط عند دقة AMP عبر 165 نموذجًا مفتوح المصدر.5

torch.compile (PyTorch 2.x)

يقوم torch.compile بتغليف نموذج وترجمة تمريره الأمامي باستخدام واجهة خلفية لالتقاط الرسم البياني وإعادة تشغيله (graph-capture-and-replay). إنه أمر إضافي — يظل كود eager الخاص بك يعمل — وهو خطوة التحسين الموصى بها لأي نموذج PyTorch متجه للإنتاج في 2.x.

model = MNISTClassifier().to(device)
compiled_model = torch.compile(model)  # one line

# Use compiled_model exactly like model
logits = compiled_model(x)

الاستدعاء الأول بعد الترجمة يكون بطيئًا (حيث يقوم بالتقاط وترجمة الرسم البياني)، ثم تكون الاستدعاءات اللاحقة سريعة. يمكنك اختيار وضع ترجمة لمقايضات مختلفة:

compiled_model = torch.compile(model, mode="reduce-overhead")  # cuts Python interpreter overhead
compiled_model = torch.compile(model, mode="max-autotune")     # best runtime speed, longest compile

تحذيران عمليان: لا يتوافق torch.compile بعد مع كل بنية نموذج (أبلغ الإعلان الرسمي عن 2.0 عن نجاح بنسبة 93% عبر 165 نموذجًا تم اختبارها)،5 وأي تدفق تحكم من جانب Python يعتمد على قيم التنسور في وقت التشغيل قد يؤدي إلى فواصل في الرسم البياني (graph breaks) تضر بالأداء. قم بالتحليل باستخدام torch._dynamo.explain(model)(example_input) إذا كنت تشك في وجود فواصل.

النشر (Deployment)

ثلاثة مسارات للإنتاج، لكل منها مقايضة مختلفة:

TorchScript يبقيك داخل نظام PyTorch البيئي. يقوم torch.jit.script بتحليل nn.Module الخاص بك إلى تمثيل وسيط (IR) قابل للتسلسل؛ بينما يقوم torch.jit.trace بتشغيل مثال عبر النموذج وتسجيل العمليات.

model.eval()
scripted = torch.jit.script(model)          # preserves control flow
# or
example = torch.randn(1, 1, 28, 28).to(device)
traced = torch.jit.trace(model, example)    # simpler but doesn't preserve control flow

scripted.save("mnist_classifier.ts")

ONNX يسمح لك بتقديم النموذج من بيئة تشغيل غير PyTorch — مثل ONNX Runtime أو TensorRT أو إطار عمل آخر يستقبل ONNX:

example = torch.randn(1, 1, 28, 28).to(device)
torch.onnx.export(
    model,
    example,
    "mnist_classifier.onnx",
    opset_version=17,
    input_names=["input"],
    output_names=["logits"],
    dynamic_axes={"input": {0: "batch"}, "logits": {0: "batch"}},
)

TorchServe هو خادم نماذج PyTorch الرسمي. يقوم بتعبئة النموذج في أرشيف .mar ويقدمه عبر HTTP/gRPC مع ميزات الإصدارات والتقسيم إلى دفعات والمقاييس بشكل جاهز. المسار الأبسط هو تزويده بقطعة TorchScript التي حفظتها أعلاه — --model-file مطلوب فقط عند أرشفة state_dict في وضع eager:

torch-model-archiver \
    --model-name mnist \
    --version 1.0 \
    --serialized-file mnist_classifier.ts \
    --handler image_classifier \
    --export-path model_store

torchserve --start --ncs --model-store model_store --models mnist=mnist.mar

اختر المسار الذي يناسب بنيتك التقنية. ONNX هو الأكثر قابلية للنقل، و TorchServe هو خادم الإنتاج الأقل جهدًا، و TorchScript يقع بينهما.

الأخطاء الشائعة

CUDA out of memory. قلل حجم الدفعة (batch size) أولاً، ثم قم بتشغيل AMP، ثم قم بتشغيل gradient checkpointing (torch.utils.checkpoint.checkpoint). نادرًا ما يكون torch.cuda.empty_cache() هو الحل — فهو يعيد الذاكرة المخزنة مؤقتًا إلى برنامج التشغيل ولكنه لا يحرر ما لا يزال Python يشير إليه.

التنسورات على أجهزة مختلفة. خطأ RuntimeError: expected all tensors on same device الكلاسيكي يعني أن النموذج موجود على GPU والدفعة لا تزال على CPU (أو العكس). انقل كليهما: x = x.to(device)، y = y.to(device)، model = model.to(device). اطبع x.device إذا لم تكن متأكدًا من مكان وجود شيء ما.

النموذج لا يتعلم. ثلاثة مشتبه بهم معتادون، بالترتيب: نسيان optimizer.zero_grad() (تتراكم الاشتقاقات)؛ نسيان تبديل model.train() / model.eval() (يتصرف dropout و batchnorm بشكل مختلف)؛ معدل تعلم مرتفع جدًا (تنفجر خسارة التدريب) أو منخفض جدًا (لا توجد حركة).

أفضل الممارسات

قابلية التكرار (Reproducibility). اضبط البذور (seeds) وعطل أنوية CUDA غير الحتمية للتشغيلات التي تحتاج إلى مقارنتها:

torch.manual_seed(42)
torch.cuda.manual_seed_all(42)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

لاحظ أن قابلية التكرار الدقيقة تمامًا عبر الأجهزة وإصدارات PyTorch المختلفة ليست مضمونة — فالاختلافات العددية الصغيرة أمر طبيعي.

تلاشي أو انفجار التدرجات (Vanishing or exploding gradients). أضف torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) بين loss.backward() و optimizer.step()، أو قم بتغيير تهيئة ReLU إلى nn.init.kaiming_normal_، أو أضف nn.BatchNorm / اتصالات متبقية (residual connections). بالنسبة لشبكات RNN تحديداً، فإن قص التدرج (gradient clipping) أمر إلزامي أساساً.

بطء تحميل البيانات. إذا كان استهلاك GPU أقل من 50% وكان عنق الزجاجة هو خط أنابيب الإدخال، فقم بزيادة num_workers في الـ DataLoader الخاص بك، واضبط pin_memory=True، وتجنب العمل على مستوى Python في __getitem__ — قم بالمعالجة المسبقة دون اتصال (offline) إذا استطعت.

الأسئلة الشائعة

لقد تقاربا كثيراً. يهيمن PyTorch على الأبحاث (معظم الأوراق البحثية الحديثة تقدم تطبيقات مرجعية في PyTorch أولاً) وقد لحق بأدوات الإنتاج. لا يزال وقت تشغيل Google على الأجهزة — الذي تم تغيير اسمه من TensorFlow Lite إلى LiteRT في سبتمبر 2024 10 — يمتلك أدوات قوية للأهداف المحمولة والمدمجة، ولدى Google Cloud بعض مسارات النشر الخاصة بـ TF. بالنسبة لمشروع جديد اليوم، كلاهما خيار يمكن الدفاع عنه؛ وعادةً ما يرجح نظام PyTorch البحثي الأكبر الكفة.

نشرة أسبوعية مجانية

ابقَ على مسار النيرد

بريد واحد أسبوعياً — دورات، مقالات معمّقة، أدوات، وتجارب ذكاء اصطناعي.

بدون إزعاج. إلغاء الاشتراك في أي وقت.