---
title: 'دليل PyTorch: من الـ Tensors إلى الـ Production في'
description: دليل عملي وفعال لـ PyTorch لعام 2026. الـ Tensors، و autograd، وحلقات التدريب، والتعلم بنقل المعرفة، و torch.compile، والنشر (deployment) — كل ذلك مع كود يعمل على إصدار PyTorch 2.x الحالي.
url: https://nerdleveltech.com/ar/pytorch-guide-from-zero-to-deep-learning
language: ar
date: '2026-05-04'
category: ai-ml
tags:
  - pytorch
  - deep learning
  - machine learning
  - python
  - AI
  - neural networks
  - computer vision
  - natural language processing
markdown_url: https://nerdleveltech.com/ar/pytorch-guide-from-zero-to-deep-learning.md
attribution: 'Source: NerdLevelTech — https://nerdleveltech.com/ar/pytorch-guide-from-zero-to-deep-learning'
terms: https://nerdleveltech.com/llms.txt
---

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

## ملخص

- PyTorch هو إطار عمل مفتوح المصدر للتعلم العميق مبني حول رسوم بيانية حسابية ديناميكية ("eager") و API برمجية بأسلوب Python. تم إصداره لأول مرة في يناير 2017 بواسطة Facebook AI Research ويتبع الآن لمؤسسة PyTorch Foundation التابعة لـ Linux Foundation.[^1][^2]
- الإصدار المستقر الحالي هو PyTorch 2.11.0 (مارس 2026)، ويدعم Python من الإصدار 3.10 إلى 3.14، ويشحن ملفات wheels قابلة للتثبيت مع مكتبات CUDA runtime مدمجة عبر pip.[^3][^4]
- `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**.[^1][^2] ميزه خياران في التصميم عن منافسيه في ذلك الوقت: الرسوم البيانية الحسابية الديناميكية ("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 فقط):

```bash
# 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](https://pytorch.org/get-started/locally/) — حيث تتغير إصدارات CUDA المدعومة ونطاق Python مع كل إصدار. يدعم PyTorch الحالي **Python 3.10–3.14**.[^4]

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

```python
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 وتتبع الاشتقاقات.

```python
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()`. هذا هو المحرك وراء كل حلقة تدريب ستكتبها.

```python
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` لكل معامل قابل للتعلم.

```python
# 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):

```python
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` مدمجة:

```python
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`:

```python
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 الخاص بنا:

```python
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]

```python
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 أسرع دون لمس كود النموذج الخاص بك.

```python
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.

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

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

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

```python
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` بتشغيل مثال عبر النموذج وتسجيل العمليات.

```python
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:

```python
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:

```bash
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 غير الحتمية للتشغيلات التي تحتاج إلى مقارنتها:

```python
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 أفضل من TensorFlow للمشاريع الجديدة؟** لقد تقاربا كثيراً. يهيمن PyTorch على الأبحاث (معظم الأوراق البحثية الحديثة تقدم تطبيقات مرجعية في PyTorch أولاً) وقد لحق بأدوات الإنتاج. لا يزال وقت تشغيل Google على الأجهزة — الذي تم تغيير اسمه من TensorFlow Lite إلى LiteRT في سبتمبر 2024[^10] — يمتلك أدوات قوية للأهداف المحمولة والمدمجة، ولدى Google Cloud بعض مسارات النشر الخاصة بـ TF. بالنسبة لمشروع جديد اليوم، كلاهما خيار يمكن الدفاع عنه؛ وعادةً ما يرجح نظام PyTorch البحثي الأكبر الكفة.

**هل أحتاج إلى GPU لتعلم PyTorch؟** لا. كل مثال في هذا الدليل يعمل على CPU. ستحتاج إلى GPU بمجرد أن تبدأ في تدريب نماذج ذات حجم حقيقي على بيانات ذات حجم حقيقي — في تلك المرحلة، تكفي بطاقة NVIDIA استهلاكية واحدة، وتمنحك دفاتر Google Colab / Kaggle خياراً مجانياً للجلسات القصيرة.

**ما الفرق بين `nn.Module` و `nn.functional`؟** `nn.Module` مخصص للطبقات التي تحتوي على معاملات (parameters) أو حالة (`Linear`، `Conv2d`، `BatchNorm`). أما `nn.functional` فهو مخصص للعمليات عديمة الحالة (`relu`، `softmax`، `cross_entropy`). استخدم `nn.Module` لأي شيء تريد تسجيله كطبقة قابلة للتعلم؛ واستخدم `nn.functional` للتحويلات التي تتم لمرة واحدة داخل `forward`.

**هل يجب أن أستخدم `torch.compile` في كل مكان؟** استخدمه لتدريب الإنتاج والاستدلال بمجرد التأكد من أن نموذجك ضمن الـ 93% التي يعمل عليها. بالنسبة للنماذج الأولية أو أي شيء يهم فيه وقت التجميع أكثر من السرعة لكل خطوة، التزم بوضع eager mode.

**كيف أواكب إصدارات PyTorch؟** تابع [صفحة إصدارات PyTorch على GitHub](https://GitHub.com/pytorch/pytorch/releases) و [مدونة PyTorch الرسمية](https://pytorch.org/blog/) — يتم شحن الإصدارات الفرعية كل ثلاثة أشهر تقريباً[^11]، وتغطي المدونة الميزات الكبيرة لكل إصدار.

[^1]: [PyTorch — Wikipedia](https://en.wikipedia.org/wiki/PyTorch)

[^2]: [Meta Transitions PyTorch to the Linux Foundation — Linux Foundation press release, September 12, 2022](https://www.linuxfoundation.org/press/press-release/meta-transitions-pytorch-to-the-linux-foundation)

[^3]: [PyTorch Releases — GitHub](https://GitHub.com/pytorch/pytorch/releases)

[^4]: [Get Started with PyTorch — pytorch.org](https://pytorch.org/get-started/locally/)

[^5]: [PyTorch 2.0: Our next generation release that is faster, more Pythonic and Dynamic as ever — pytorch.org/blog](https://pytorch.org/blog/pytorch-2-0-release/)

[^6]: [Introducing TorchVision's New Multi-Weight Support API — pytorch.org/blog](https://pytorch.org/blog/introducing-torchvision-new-multi-weight-support-API/)

[^7]: [PyTorch developer ecosystem expands, 1.0 stable release now available — Engineering at Meta, December 7, 2018](https://engineering.fb.com/2018/12/07/ai-research/pytorch-developer-ecosystem-expands-1-0-stable-release/)

[^8]: [PyTorch Foundation Announces New Members as Agentic AI Demand Grows — pytorch.org/blog](https://pytorch.org/blog/pytorch-foundation-announces-new-members-as-agentic-ai-demand-grows/)

[^9]: [pytorch/pytorch — GitHub repository](https://GitHub.com/pytorch/pytorch)

[^10]: [TensorFlow Lite is now LiteRT — Google Developers Blog, September 4, 2024](https://developers.googleblog.com/tensorflow-lite-is-now-litert/)

[^11]: [PyTorch Release Cadence — PyTorch Developer Mailing List](https://dev-discuss.pytorch.org/t/release-cadence-for-year-2023-2024/1557)
