المجلد الثاني
⚡ المحولات والتعلم العميق المتقدم
من الانتباه إلى النماذج التوليدية — رحلة في عمق الذكاء الاصطناعي
يغوص هذا المجلد في أعماق هندسة المحولات (Transformers) التي غيّرت مسار الذكاء الاصطناعي،
ويغطي أحدث التطورات في الرؤية الحاسوبية والشبكات التوليدية والتعلم المعزز،
مع أمثلة عملية بلغة PyTorch لكل مفهوم.
📅 الجمعة، 12 يونيو 2026
📄 8 فصول · 30+ مفهوم
⚡ المستوى: متقدم
🐍 PyTorch · Transformers · OpenCV
🔮 آلية الانتباه (Attention)
الانتباه هو المفهوم الأكثر تأثيراً في深度学习 الحديث. قبل المحولات، كانت
الشبكات العصبية تعالج التسلسلات خطوة بخطوة عبر RNNs أو LSTMs، مما يجعلها بطيئة ويصعب
تدريبها على التسلسلات الطويلة. الانتباه غيّر هذا تماماً: أصبح بإمكان النموذج أن ينظر إلى كل
الكلمات في وقت واحد ويقرر أيها الأكثر أهمية في كل خطوة.
💡 الفكرة الجوهرية: بدلاً من معالجة الكلمات تسلسلياً، يحسب الانتباه درجة
ارتباط كل كلمة بكل كلمة أخرى — مما يخلق "خريطة علاقات" كاملة للتسلسل.
Scaled Dot-Product Attention
هذا هو النوع الأساسي من الانتباه المستخدم في المحولات. يعتمد على ثلاث مصفوفات:
Q (Query — الاستعلام)، K (Key — المفتاح)،
وV (Value — القيمة).
Attention(Q, K, V) = softmax( QKT / √dk ) V
الخطوات بالتفصيل:
- Query · Key: نضرب Q في منقول K لنحصل على أوزان الانتباه الأولية.
- Scaling (√dk): نقسم على جذر بُعد المفاتيح لمنع انفجار القيم.
- Softmax: نحول الأوزان إلى توزيع احتمالي (مجموعها = 1).
- Weighted Sum: نضرب الأوزان في V لنحصل على المخرجات النهائية.
import torch
import torch.nn as nn
import torch.nn.functional as F
class ScaledDotProductAttention(nn.Module):
def __init__(self, d_k):
super().__init__()
self.d_k = d_k
self.scale = d_k ** 0.5
def forward(self, Q, K, V, mask=None):
# Q, K, V: (batch, seq_len, d_k)
scores = torch.matmul(Q, K.transpose(-2, -1)) # (batch, seq, seq)
scores = scores / self.scale # Scaling
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
attn_weights = F.softmax(scores, dim=-1) # (batch, seq, seq)
output = torch.matmul(attn_weights, V) # (batch, seq, d_k)
return output, attn_weights
Multi-Head Attention
بدلاً من آلية انتباه واحدة، تستخدم المحولات رؤوس انتباه متعددة (Multi-Head).
كل رأس يتعلم التركيز على جوانب مختلفة من العلاقات بين الكلمات. هذا يشبه وجود عدة
"خبراء" ينظرون إلى نفس الجملة من زوايا مختلفة.
MultiHead(Q, K, V) = Concat(head1, …, headh) WO
headi = Attention(Q WiQ, K WiK, V WiV)
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads
self.W_Q = nn.Linear(d_model, d_model)
self.W_K = nn.Linear(d_model, d_model)
self.W_V = nn.Linear(d_model, d_model)
self.W_O = nn.Linear(d_model, d_model)
def forward(self, Q, K, V, mask=None):
batch_size = Q.size(0)
# 1. Linear projections + reshape for heads
Q = self.W_Q.forward(Q).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_K.forward(K).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_V.forward(V).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# 2. Apply attention per head
attn_output, attn_weights = scaled_dot_product_attention(Q, K, V, mask)
# 3. Concatenate heads + final projection
attn_output = attn_output.transpose(1, 2).contiguous() \
.view(batch_size, -1, self.d_model)
output = self.W_O.forward(attn_output)
return output
Self-Attention vs Cross-Attention
🔄 Self-Attention
Q, K, V كلها من نفس المصدر — كل كلمة تنظر إلى كل الكلمات الأخرى في نفس التسلسل.
- المصدر: نفس التسلسل (X → Q, K, V)
- الاستخدام: التشفير (BERT) وفك التشفير (GPT)
- الغرض: فهم السياق الداخلي لكل كلمة
- مثال: "القطة أكلت السمكة" — "هي" تفهم أنها تشير إلى "القطة"
🔁 Cross-Attention
Q من مصدر و K, V من مصدر آخر — التسلسل الهدف ينظر إلى التسلسل المصدر.
- المصدر: Q من الهدف، K و V من المصدر
- الاستخدام: الترجمة (Encoder-Decoder)
- الغرض: الربط بين تسلسلين مختلفين
- مثال: الترجمة: الجملة الإنجليزية ← الجملة العربية
🏆 لماذا الانتباه غير مسبوق؟
• التوازي: يمكن معالجة كل الكلمات في وقت واحد (عكس RNN).
• المدى البعيد: يمكن ربط كلمتين متباعدتين بسهولة (عكس CNN).
• الشفافية: يمكن رؤية أوزان الانتباه ومعرفة ما "يركز عليه" النموذج.
• المرونة: نفس الآلية تعمل للنص والصورة والصوت والفيديو.
🏗️ Transformer Architecture
في ورقة "Attention Is All You Need" (2017)، قدمت Google هندسة
المحول (Transformer) التي تستخدم الانتباه فقط — بدون أي RNNs أو CNNs. هذه الهندسة
أصبحت الأساس لجميع نماذج اللغة الكبيرة اليوم.
↑
Decoder
(GPT Style)
Linear + Softmax
↑
Encoder
(BERT Style)
Add & Norm
↑
Multi-Head
Attention
Feed Forward
(MLP)
↑
Positional
Encoding
Input
Embedding
↑
🧱 هيكل المحول الأساسي — تكديس طبقات الانتباه والتغذية الأمامية مع التوصيلات المتبقية
BERT (2018) من Google يستخدم فقط المشفّر (Encoder) من المحول.
BERT ثنائي الاتجاه — كل كلمة ترى كل الكلمات الأخرى في كلا الاتجاهين.
🧠 خصائص BERT
- ثنائي الاتجاه: كل كلمة تنظر إلى اليمين واليسار في نفس الوقت.
- Masked Language Model (MLM): نخفي 15% من الكلمات ونتوقعها.
- Next Sentence Prediction (NSP): هل الجملة B تلي A؟
- الاستخدامات: تصنيف النصوص، الإجابة على الأسئلة، التعرف على الكيانات.
class TransformerEncoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, num_heads)
self.ff = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.ReLU(),
nn.Linear(d_ff, d_model)
)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
# Self-attention + residual + norm
attn_out = self.self_attn.forward(x, x, x, mask)
x = self.norm1.forward(x + self.dropout.forward(attn_out))
# Feed-forward + residual + norm
ff_out = self.ff.forward(x)
x = self.norm2.forward(x + self.dropout.forward(ff_out))
return x
# Stack multiple encoder layers
class BERTEncoder(nn.Module):
def __init__(self, vocab_size, d_model=768, num_layers=12,
num_heads=12, d_ff=3072, max_len=512):
super().__init__()
self.embed = nn.Embedding(vocab_size, d_model)
self.pos_embed = nn.Embedding(max_len, d_model)
self.layers = nn.ModuleList([
TransformerEncoderLayer(d_model, num_heads, d_ff)
for _ in range(num_layers)
])
def forward(self, token_ids, pos_ids, mask=None):
x = self.embed.forward(token_ids) + self.pos_embed.forward(pos_ids)
for layer in self.layers:
x = layer.forward(x, mask)
return x
GPT (2018) من OpenAI يستخدم فقط فك التشفير (Decoder).
GPT أحادي الاتجاه (Causal) — كل كلمة ترى فقط الكلمات التي قبلها. هذا يجعله مثالياً
لتوليد النصوص.
🛠️ خصائص GPT
- أحادي الاتجاه (Causal): كل كلمة ترى فقط ما قبلها (سببية).
- Autoregressive: توليد كلمة كلمة — كل كلمة جديدة تعتمد على السابقة.
- Masked Self-Attention: قناع يمنع الرؤية إلى المستقبل.
- الاستخدامات: توليد النصوص، chat، البرمجة، الإبداع.
def create_causal_mask(seq_len):
# Upper triangular mask: prevents attending to future tokens
mask = torch.tril(torch.ones(seq_len, seq_len))
mask = mask.unsqueeze(0).unsqueeze(0) # (1, 1, seq, seq)
return mask # 1 = attend, 0 = mask
class CausalSelfAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
self.attn = MultiHeadAttention(d_model, num_heads)
def forward(self, x):
seq_len = x.size(1)
causal_mask = create_causal_mask(seq_len).to(x.device)
return self.attn.forward(x, x, x, causal_mask)
class GPTDecoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = CausalSelfAttention(d_model, num_heads)
self.ff = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(), # GPT uses GELU not ReLU
nn.Linear(d_ff, d_model)
)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
# Causal self-attention + residual
x = x + self.dropout.forward(self.self_attn.forward(x))
x = self.norm1.forward(x)
# FF + residual
x = x + self.dropout.forward(self.ff.forward(x))
x = self.norm2.forward(x)
return x
T5 (2019) من Google يستخدم الهندسة الكاملة: مشفّر + مفكّك تشفير.
كل مهمة NLP تُصاغ كمهمة نص إلى نص (Text-to-Text). هذا مثالي للترجمة والتلخيص.
📥 Encoder (BERT)
- ثنائي الاتجاه (Bidirectional)
- يفهم النص بالكامل
- مثالي للفهم والتصنيف
- يُنتج تمثيلاً غنياً
📤 Decoder (GPT)
- أحادي الاتجاه (Causal)
- يولّد النص تسلسلياً
- مثالي للتوليد والإبداع
- يستخدم masked attention
الانتباه ليس له مفهوم "ترتيب" — فهو يرى كل الكلمات كمجموعة غير مرتبة. لذلك نحتاج
إلى إضافة معلومات عن موقع كل كلمة في التسلسل. هذه هي مهمة
التشفير الموضعي (Positional Encoding).
PE(pos, 2i) = sin(pos / 100002i/d)
PE(pos, 2i+1) = cos(pos / 100002i/d)
لماذا الموجات الجيبية؟
- الدورية: تساعد النموذج على فهم الأنماط المتكررة.
- الاستمرارية: المواقع المتقاربة لها ترميزات متشابهة.
- التعميم: يمكن للنموذج التعامل مع تسلسلات أطول مما رآه في التدريب.
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super().__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * -(torch.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term) # even indices
pe[:, 1::2] = torch.cos(position * div_term) # odd indices
pe = pe.unsqueeze(0) # (1, max_len, d_model)
self.register_buffer('pe', pe) # not trainable
def forward(self, x):
# x: (batch, seq_len, d_model)
return x + self.pe[:, :x.size(1)]
🔗 Residual Connections (التوصيلات المتبقية)
الفكرة: x ← x + F(x) بدلاً من x ← F(x).
- تسمح بتدفق التدرج عبر 100+ طبقة.
- تمنع مشكلة اختفاء التدرج (Vanishing Gradient).
- كل طبقة تتعلم "التصحيح" بدلاً من التعلم من الصفر.
📊 Layer Normalization
تطبّع عبر أبعاد الميزات (وليس batch).
- تُحسّب المتوسط والانحراف لكل عينة.
- تثبّت التدريب وتسرّعه.
- ضرورية للمحولات (عكس BatchNorm في CNNs).
# Post-LN (original Transformer): Norm بعد الجمع
x = LayerNorm(x + Attention(x)) # الأصل في ورقة 2017
# Pre-LN (GPT/BERT modern): Norm قبل الدخول
x = x + Attention(LayerNorm(x)) # أكثر استقراراً في التدريب
# RMSNorm (LLaMA): تبسيط LayerNorm
class RMSNorm(nn.Module):
def __init__(self, d_model, eps=1e-6):
super().__init__()
self.weight = nn.Parameter(torch.ones(d_model))
self.eps = eps
def forward(self, x):
# RMS = sqrt(mean(x^2) + eps)
rms = torch.sqrt(torch.mean(x ** 2, dim=-1, keepdim=True) + self.eps)
return x / rms * self.weight
🧩 Embeddings — تمثيل الكلمات والمفاهيم
التضمينات (Embeddings) هي طريقة تحويل الكلمات أو الرموز إلى متجهات رقمية
يفهمها النموذج. هذا الفصل يغطي تطور تمثيل الكلمات من الأساليب التقليدية
إلى التقنيات الحديثة المستخدمة في المحولات.
Word Embeddings: Word2Vec & GloVe
📖 Word2Vec (Mikolov et al., 2013)
فكرة Word2Vec بسيطة وعميقة: "الكلمة تُعرف من جيرانها" (You shall know a word by the company it keeps).
- CBOW (Continuous Bag of Words): توقع الكلمة من سياقها.
- Skip-gram: توقع السياق من الكلمة — أفضل للكلمات النادرة.
📖 GloVe (Pennington et al., 2014)
يجمع GloVe بين مزايا Word2Vec والتحليل الإحصائي للمصفوفات التكرارية.
- يستخدم إحصائيات الحدوث المشترك (Co-occurrence) على مستوى المجموعة الكاملة.
- العلاقات الخطية: "ملك" - "رجل" + "امرأة" ≈ "ملكة".
import torch
import torch.nn as nn
# طبقة تضمين أساسية (كل محول يستخدمها)
vocab_size = 30000
d_model = 512
embed = nn.Embedding(vocab_size, d_model)
# مثال: تحويل كلمات إلى متجهات
token_ids = torch.tensor([[12, 45, 789, 3, 1024]]) # (batch=1, seq=5)
embedded = embed.forward(token_ids) # (1, 5, 512)
# -------------------------------------------------
# Word2Vec Skip-gram (نسخة مبسطة)
class SkipGramModel(nn.Module):
def __init__(self, vocab_size, emb_dim):
super().__init__()
self.center_emb = nn.Embedding(vocab_size, emb_dim)
self.context_emb = nn.Embedding(vocab_size, emb_dim)
def forward(self, center, context):
# center: البُعد المركزي, context: كلمة السياق
center_vec = self.center_emb.forward(center)
context_vec = self.context_emb.forward(context)
score = (center_vec * context_vec).sum(dim=-1)
return score
# تشابه الكلمات عبر cosine similarity
def cosine_sim(word_embed, word1, word2):
v1 = word_embed[word1] # نفترض word_embed مصفوفة (vocab, dim)
v2 = word_embed[word2]
return torch.cosine_similarity(v1.unsqueeze(0), v2.unsqueeze(0))
Subword Tokenization — BPE, WordPiece, SentencePiece
الكلمات وحدها مشكلة: كيف نتعامل مع كلمة لم نرها من قبل؟ الحل هو تقسيم الكلمات
إلى أجزاء أصغر (subwords). بهذه الطريقة، يمكن للنموذج فهم كلمات جديدة
من خلال أجزائها المألوفة.
| التقنية |
المبدأ |
المميزات |
يستخدمها |
| BPE (Byte-Pair Encoding) |
دمج أزواج الرموز الأكثر تكراراً |
بسيط، فعال، سريع |
GPT, GPT-2, LLaMA |
| WordPiece |
دمج بناءً على زيادة الاحتمالية |
أفضل رياضياً من BPE |
BERT, DistilBERT |
| SentencePiece |
يتعامل مع النص كسلسلة Unicode |
لا يحتاج مسافات مسبقة، يدعم كل اللغات |
T5, ALBERT, XLNet |
Positional Embeddings: Learnable vs Sinusoidal
📐 Sinusoidal (ثابتة)
الأصل في ورقة المحول. موجات جيبية وجيب التمام.
- غير قابلة للتعلم (fixed).
- تتعمم على أطوال غير مرئية.
- تستخدم في: Transformer الأصلي.
🎯 Learnable (قابلة للتعلم)
مصفوفة Embedding عادية يتم تعلمها مع التدريب.
- قابلة للتعلم — يتكيف مع البيانات.
- محدودة بأقصى طول رؤية في التدريب.
- تستخدم في: BERT, GPT.
class BERTEmbeddings(nn.Module):
def __init__(self, vocab_size, d_model=768, max_len=512,
type_vocab_size=2): # sentence A/B
super().__init__()
self.word_emb = nn.Embedding(vocab_size, d_model)
self.pos_emb = nn.Embedding(max_len, d_model)
self.type_emb = nn.Embedding(type_vocab_size, d_model)
self.layer_norm = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(0.1)
def forward(self, input_ids, token_type_ids=None):
seq_len = input_ids.size(1)
pos_ids = torch.arange(seq_len, device=input_ids.device).unsqueeze(0)
word_vec = self.word_emb.forward(input_ids)
pos_vec = self.pos_emb.forward(pos_ids)
if token_type_ids is None:
token_type_ids = torch.zeros_like(input_ids)
type_vec = self.type_emb.forward(token_type_ids)
embeddings = word_vec + pos_vec + type_vec
return self.dropout.forward(self.layer_norm.forward(embeddings))
👁️ CNN المتقدمة للرؤية الحاسوبية
قبل المحولات، كانت الشبكات العصبية الالتفافية (CNNs) هي المسيطرة على الرؤية
الحاسوبية. هذا الفصل يغطي أهم التطورات في CNNs التي ما زالت أساسية حتى اليوم،
بالإضافة إلى كيف بدأت المحولات في تجاوزها.
Convolution & Pooling
الالتفاف (Convolution) هو عملية رياضية حيث نمرّر نواة (kernel)
صغيرة على الصورة لاكتشاف الأنماط مثل الحواف والأشكال.
التجميع (Pooling) يقلل أبعاد الصورة مع الاحتفاظ بالمعلومات المهمة.
import torch.nn as nn
# 2D Convolution — الطبقة الأساسية
conv = nn.Conv2d(
in_channels=3, # RGB → 3 قنوات
out_channels=64, # نريد 64 فلتراً مختلفاً
kernel_size=3, # نواة 3×3
stride=1, # خطوة واحدة
padding=1 # حشو للحفاظ على الحجم
)
# Max Pooling — يقلل الأبعاد
pool = nn.MaxPool2d(kernel_size=2, stride=2) # يخفض الطول والعرض للنصف
# مثال تطبيقي كامل — كتلة CNN واحدة
class ConvBlock(nn.Module):
def __init__(self, in_c, out_c):
super().__init__()
self.conv = nn.Conv2d(in_c, out_c, 3, padding=1)
self.bn = nn.BatchNorm2d(out_c) # تطبيع الدفعة
self.relu = nn.ReLU(inplace=True)
self.pool = nn.MaxPool2d(2)
def forward(self, x):
x = self.conv.forward(x)
x = self.bn.forward(x)
x = self.relu.forward(x)
x = self.pool.forward(x)
return x
# طبقات متعددة: 3 → 64 → 128 → 256
model = nn.Sequential(
ConvBlock(3, 64),
ConvBlock(64, 128),
ConvBlock(128, 256),
)
ResNet & EfficientNet
ResNet — Residual Networks (Residual Connections)
ResNet (2015) حل مشكلة أساسية: كلما زادت طبقات الشبكة، يصبح
التدريب أصعب (Degradation Problem). الحل: التوصيلات المتبقية (Skip Connections)
التي تسمح للشبكة بتعلم الفرق (residual) بدلاً من التعلم الكامل.
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, 3,
stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, 3,
padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
# Skip connection: إذا تغير حجم القنوات، نعدل الأبعاد
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1,
stride=stride, bias=False),
nn.BatchNorm2d(out_channels)
)
def forward(self, x):
# المسار الرئيسي
out = self.relu.forward(self.bn1.forward(self.conv1.forward(x)))
out = self.bn2.forward(self.conv2.forward(out))
# المسار المختصر (Skip Connection)
out += self.shortcut.forward(x) # ★ هذا هو الابتكار
out = self.relu.forward(out)
return out
EfficientNet — التوسع المتوازن
EfficientNet (2019) يطرح سؤالاً: كيف نوسع الشبكة CNN بشكل أفضل؟
الجواب: توسيع الأبعاد الثلاثة معاً — العمق (depth)، العرض (width)،
ودقة الصورة (resolution) — بنسبة ثابتة.
Vision Transformer (ViT) — المحول في الرؤية
Vision Transformer (ViT) من Google (2020) أثبت أن المحولات يمكنها
منافسة CNNs في الرؤية الحاسوبية — بل وتفوقها. الفكرة: نقسّم الصورة إلى
قطع صغيرة (patches) ونعالجها كتسلسل من الكلمات.
class PatchEmbed(nn.Module):
def __init__(self, img_size=224, patch_size=16,
in_chans=3, embed_dim=768):
super().__init__()
self.img_size = img_size
self.patch_size = patch_size
self.num_patches = (img_size // patch_size) ** 2
# Conv2d بحجم النواة = patch_size → كل نواة تلتقط patch
self.proj = nn.Conv2d(in_chans, embed_dim,
kernel_size=patch_size, stride=patch_size)
def forward(self, x):
# x: (batch, 3, 224, 224)
x = self.proj.forward(x) # (batch, 768, 14, 14) — 224/16=14
x = x.flatten(2) # (batch, 768, 196)
x = x.transpose(1, 2) # (batch, 196, 768) ← "تسلسل" من 196 patch
return x
# مثال استخدام
patch_embed = PatchEmbed(img_size=224, patch_size=16, embed_dim=768)
x = torch.randn(2, 3, 224, 224) # batch=2, RGB
patches = patch_embed.forward(x) # (2, 196, 768)
print(patches.shape) # torch.Size([2, 196, 768]) ✓
🎨 الشبكات التوليدية — GANs, VAE, Diffusion
الشبكات التوليدية تهدف إلى تعلّم توزيع البيانات ثم توليد عينات
جديدة منها. هذا الفصل يغطي أهم ثلاث عوائل من النماذج التوليدية التي غيّرت مجال
الذكاء الاصطناعي.
GANs — Generative Adversarial Networks
GANs (Goodfellow et al., 2014) هي فكرة عبقريّة: نموذجان
يتنافسان — المولّد (Generator) يحاول خلق صور واقعية، والمميّز (Discriminator)
يحاول اكتشاف المزيّف. مع الوقت، يصبح المولّد ماهراً جداً لدرجة أنه يخدع المميّز.
🎯 ديناميكية GAN: مثل مزوّر لوحات (Generator) وخبير فني (Discriminator).
المزوّّر يتحسن حتى يصعب على الخبير التفريق بين الحقيقي والمزوّر.
class Generator(nn.Module):
# يحول ضوضاء عشوائية (latent vector) إلى صورة 64×64
def __init__(self, latent_dim=100):
super().__init__()
self.model = nn.Sequential(
nn.ConvTranspose2d(latent_dim, 512, 4, 1, 0), # 4×4
nn.BatchNorm2d(512), nn.ReLU(inplace=True),
nn.ConvTranspose2d(512, 256, 4, 2, 1), # 8×8
nn.BatchNorm2d(256), nn.ReLU(inplace=True),
nn.ConvTranspose2d(256, 128, 4, 2, 1), # 16×16
nn.BatchNorm2d(128), nn.ReLU(inplace=True),
nn.ConvTranspose2d(128, 64, 4, 2, 1), # 32×32
nn.BatchNorm2d(64), nn.ReLU(inplace=True),
nn.ConvTranspose2d(64, 3, 4, 2, 1), # 64×64
nn.Tanh() # output in [-1, 1]
)
def forward(self, z):
# z: (batch, 100, 1, 1)
return self.model.forward(z)
class Discriminator(nn.Module):
# يحاول التمييز بين الحقيقي والمزيّف
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 64, 4, 2, 1), # 32×32
nn.LeakyReLU(0.2, inplace=True),
nn.Conv2d(64, 128, 4, 2, 1), # 16×16
nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True),
nn.Conv2d(128, 256, 4, 2, 1), # 8×8
nn.BatchNorm2d(256), nn.LeakyReLU(0.2, inplace=True),
nn.Conv2d(256, 1, 4, 1, 0), # 1×1
nn.Sigmoid() # احتمال: 0 = fake, 1 = real
)
def forward(self, x):
return self.model.forward(x).view(-1)
StyleGAN — تحكم في الأنماط
StyleGAN (2019) من NVIDIA يضيف تحكماً غير مسبوق في خصائص الصورة
المولّدة — مثل العمر، الجنس، الإضاءة، والخلفية — بشكل منفصل.
Variational Autoencoders (VAE)
VAE هو نموذج توليدي يتعلم تمثيلاً مضغوطاً (latent space) للبيانات.
الفكرة: نشفّر الصورة إلى توزيع احتمالي (متوسط + انحراف معياري) ثم نأخذ عينة منه
ونفكّ التشفير.
class VAE(nn.Module):
def __init__(self, latent_dim=128):
super().__init__()
# Encoder
self.encoder = nn.Sequential(
nn.Linear(784, 512), nn.ReLU(),
nn.Linear(512, 256), nn.ReLU(),
)
self.mu = nn.Linear(256, latent_dim) # متوسط
self.log_var = nn.Linear(256, latent_dim) # log التباين
# Decoder
self.decoder = nn.Sequential(
nn.Linear(latent_dim, 256), nn.ReLU(),
nn.Linear(256, 512), nn.ReLU(),
nn.Linear(512, 784), nn.Sigmoid()
)
def reparameterize(self, mu, log_var):
# ★ خدعة إعادة التقييس (Reparameterization Trick)
std = torch.exp(log_var * 0.5)
eps = torch.randn_like(std)
return mu + eps * std
def forward(self, x):
h = self.encoder.forward(x)
mu = self.mu.forward(h)
log_var = self.log_var.forward(h)
z = self.reparameterize(mu, log_var) # عينة من التوزيع
recon = self.decoder.forward(z)
return recon, mu, log_var
# دالة الخسارة: إعادة البناء + تباعد KL
def vae_loss(recon_x, x, mu, log_var):
recon_loss = F.binary_cross_entropy(recon_x, x, reduction='sum')
kl_loss = -0.5 * torch.sum(1 + log_var - mu ** 2 - log_var.exp())
return recon_loss + kl_loss
نماذج الانتشار (Diffusion Models)
نماذج الانتشار هي أحدث وأقوى تقنية توليد للصور — وهي ما تستخدمه
Stable Diffusion وDALL·E 3 وMidjourney. الفكرة: نبدأ من صورة عشوائية (ضوضاء خالصة)
ونزيل الضوضاء تدريجياً حتى نحصل على صورة نظيفة.
🔄 كيف تعمل نماذج الانتشار؟
- Forward Process (الانتشار الأمامي): نأخذ صورة حقيقية ونضيف ضوضاء
تدريجياً على T خطوة حتى تصبح ضوضاء خالصة.
- Reverse Process (الانتشار العكسي): ندرّب شبكة عصبية (U-Net) على
توقع الضوضاء المضافة وإزالتها خطوة بخطوة.
- التوليد: نبدأ من ضوضاء خالصة ونطبق الانتشار العكسي — نزيل الضوضاء
تدريجياً حتى تظهر الصورة.
Forward: q(xt | xt-1) = 𝒩(xt; √(1-βt)·xt-1, βtI)
Reverse: pθ(xt-1 | xt) = 𝒩(xt-1; μθ(xt, t), Σθ(xt, t))
import torch
import torch.nn as nn
import torch.nn.functional as F
class SinusoidalPositionEmbeddings(nn.Module):
# تضمين خطوة الوقت t — ضروري لمعرفة في أي خطوة نحن
def __init__(self, dim):
super().__init__()
self.dim = dim
def forward(self, t):
half_dim = self.dim // 2
emb = torch.log(torch.tensor(10000.0)) / (half_dim - 1)
emb = torch.exp(torch.arange(half_dim, device=t.device) * -emb)
emb = t[:, None].float() * emb[None, :]
emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1)
return emb
class DDPM(nn.Module):
# نموذج DDPM بسيط (U-Net مبسط)
def __init__(self, img_channels=3, T=1000):
super().__init__()
self.T = T
# جدول الضوضاء (noise schedule) — من β_1 إلى β_T
self.beta = torch.linspace(1e-4, 0.02, T)
self.alpha = 1.0 - self.beta
self.alpha_bar = torch.cumprod(self.alpha, dim=0)
# U-Net مبسط (للتوضيح — النموذج الحقيقي أكبر بكثير)
self.time_embed = SinusoidalPositionEmbeddings(256)
self.input_proj = nn.Conv2d(img_channels, 64, 3, padding=1)
self.mid_block = nn.Sequential(
nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(),
nn.Conv2d(128, 64, 3, padding=1), nn.ReLU(),
)
self.output_proj = nn.Conv2d(64, img_channels, 3, padding=1)
def forward(self, x, t):
# x: صورة (قد تكون فيها ضوضاء), t: خطوة الوقت
t_emb = self.time_embed.forward(t)
x = self.input_proj.forward(x)
x = self.mid_block.forward(x + t_emb[:, :, None, None])
x = self.output_proj.forward(x)
return x # توقع الضوضاء المضافة
# دالة إضافة ضوضاء مباشرة (Forward Process)
def add_noise(model, x0, t):
# x0: الصورة الأصلية, t: خطوات الضوضاء
alpha_bar_t = model.alpha_bar[t].view(-1, 1, 1, 1)
noise = torch.randn_like(x0)
x_t = torch.sqrt(alpha_bar_t) * x0 + torch.sqrt(1 - alpha_bar_t) * noise
return x_t, noise
# التدريب: توقع الضوضاء المضافة
# loss = MSE(model(x_t, t), noise)
Stable Diffusion — الانتشار في الفضاء الكامن
Stable Diffusion يطبق الانتشار ليس على الصورة مباشرة (باهظة الثمن)
بل على الفضاء الكامن (Latent Space) بعد ضغط الصورة بمشفّر
(VAE). هذا يجعله أسرع بكثير ويحتاج ذاكرة أقل.
🤖 التعلم المعزز (Reinforcement Learning)
التعلم المعزز (RL) هو فرع من الذكاء الاصطناعي حيث يتعلم الوكيل
(Agent) من خلال التفاعل مع البيئة — يجرب أفعالاً، ويحصل على مكافآت أو عقوبات،
ويتعلم مع مرور الوقت ما هي أفضل الاستراتيجيات.
💡 الفكرة الأساسية: مثل تدريب كلب — عندما يفعل الشيء الصحيح،
نعطيه مكافأة (reward). مع الوقت، يتعلم أي السلوكيات تؤدي إلى أكبر مكافأة.
MDP (Markov Decision Process) & Q-Learning
MDP هو الإطار الرياضي لـ RL. يتكون من:
- S — مجموعة الحالات (States) — أين نحن الآن؟
- A — مجموعة الأفعال (Actions) — ماذا يمكننا أن نفعل؟
- P — احتمالات الانتقال (Transition Probabilities) — أين سنصل؟
- R — دالة المكافأة (Reward Function) — ما جودة ما فعلناه؟
- γ — عامل الخصم (Discount Factor) — هل المكافأة المستقبلية مهمة؟
Q-Learning هو خوارزمية تتعلم قيمة كل فعل في كل حالة:
Q(s, a) ← Q(s, a) + α [ R + γ · maxa' Q(s', a') — Q(s, a) ]
import numpy as np
class QLearningAgent:
def __init__(self, n_states, n_actions, lr=0.1, gamma=0.99, eps=1.0):
self.n_actions = n_actions
self.lr = lr # معدل التعلم (α)
self.gamma = gamma # عامل الخصم (γ)
self.eps = eps # استكشاف vs استغلال
self.Q = np.zeros((n_states, n_actions)) # جدول Q
def choose_action(self, state):
# ε-greedy: أحياناً نستكشف (عشوائي)، أحياناً نستغل (أفضل Q)
if np.random() < self.eps:
return np.random.randint(self.n_actions) # استكشاف
return np.argmax(self.Q[state]) # استغلال
def update(self, state, action, reward, next_state):
# معادلة Bellman لتحديث Q
best_next = np.max(self.Q[next_state])
td_target = reward + self.gamma * best_next
td_error = td_target - self.Q[state, action]
self.Q[state, action] += self.lr * td_error
Deep Q-Networks (DQN)
عندما تصبح الحالات كثيرة جداً (مثل البكسل في لعبة فيديو)، لا يمكننا استخدام جدول
Q. الحل: شبكة عصبية (Deep Q-Network) تتعلم تقريب دالة Q.
🧠 DQN (Mnih et al., 2015) — DeepMind's Atari Breakthrough
- Experience Replay: نخزّن التجارب السابقة ونتعلم منها مراراً — يمنع النسيان.
- Target Network: شبكة هدف منفصلة تثبّت التدريب.
- Epsilon Greedy: توازن بين الاستكشاف والاستغلال.
class DQN(nn.Module):
def __init__(self, n_observations, n_actions):
super().__init__()
self.net = nn.Sequential(
nn.Linear(n_observations, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, n_actions) # Q-values لكل فعل
)
def forward(self, x):
return self.net.forward(x)
# === Experience Replay Buffer ===
from collections import deque
import random
class ReplayBuffer:
def __init__(self, capacity=10000):
self.buffer = deque(maxlen=capacity)
def push(self, state, action, reward, next_state, done):
self.buffer.append((state, action, reward, next_state, done))
def sample(self, batch_size):
return random.sample(self.buffer, batch_size)
def __len__(self):
return len(self.buffer)
# === DQN Training Loop (مبسّطة) ===
def train_dqn_step(policy_net, target_net, buffer, optimizer, batch_size=128, gamma=0.99):
if len(buffer) < batch_size:
return
batch = buffer.sample(batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = torch.tensor(states, dtype=torch.float)
actions = torch.tensor(actions, dtype=torch.long).unsqueeze(1)
rewards = torch.tensor(rewards, dtype=torch.float)
next_states = torch.tensor(next_states, dtype=torch.float)
dones = torch.tensor(dones, dtype=torch.float)
# Q(s, a) الحالية
current_q = policy_net.forward(states).gather(1, actions).squeeze()
# Q(s', a') القصوى من الشبكة الهدف
next_q = target_net.forward(next_states).max(1)[0]
expected_q = rewards + gamma * next_q * (1 - dones)
loss = F.mse_loss(current_q, expected_q)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Policy Gradients & PPO
Policy Gradients — التعلم المباشر للسياسة
بدلاً من تعلّم قيم Q (غير مباشر)، تتعلم طرق تدرّج السياسة (Policy Gradients)
السياسة مباشرة: π(a|s) — احتمال اختيار الفعل a في الحالة s.
∇J(θ) = E[ ∇log πθ(a|s) · Gt ]
حيث Gt = Σ γk Rt+k+1 (العائد التراكمي)
PPO — Proximal Policy Optimization
PPO (Schulman et al., 2017) هو أشهر خوارزمية RL حالياً (يستخدمها
ChatGPT للتدريب). يحل مشكلة عدم الاستقرار في طرق تدرّج السياسة عن طريق
قصّ (clipping) التحديثات لمنع التغييرات الكبيرة جداً.
def ppo_clip_loss(
log_probs_current, # log π_θ(a|s) — السياسة الحالية
log_probs_old, # log π_{old}(a|s) — السياسة القديمة
advantages, # ميزة كل فعل (advantage)
eps_clip=0.2 # نطاق القص
):
# نسبة الاحتمالات: r(θ) = π_θ / π_old
ratios = torch.exp(log_probs_current - log_probs_old)
# الخسارة غير المقصوصة
surr1 = ratios * advantages
# الخسارة المقصوصة — ★ ابتكار PPO
surr2 = torch.clamp(ratios, 1.0 - eps_clip, 1.0 + eps_clip) * advantages
# نأخذ min(...) — نختار الأكثر تحفظاً
loss = -torch.min(surr1, surr2).mean()
return loss
# مكونات خسارة PPO الكاملة:
# 1. خسارة السياسة (PPO Clip) — أعلاه
# 2. خسارة القيمة (Value Loss) — MSE بين قيمة الحالة والعائد
# 3. خسارة الإنتروبيا (Entropy Bonus) — تشجيع الاستكشاف
# total_loss = policy_loss + c1 * value_loss — c2 * entropy
🖼️ المحولات في الرؤية — ViT, Swin, DETR
هذا الفصل يدمج بين المحولات والرؤية الحاسوبية. بعد نجاح المحولات في NLP،
بدأ الباحثون في تطبيقها على الصور — وكانت النتائج مذهلة.
Vision Transformer (ViT) & Swin Transformer
ViT — Vision Transformer (راجع القسم 4.3)
كما رأينا في القسم 4.3، ViT يقسم الصورة إلى patches ويدخلها إلى محول قياسي.
ما يميّز ViT هو بساطته — نفس هندسة المحول تعمل للصور بدون
أي تعديلات كبيرة.
📊 أداء ViT
- على ImageNet (1.3M صورة): دقة 88.6% (منافس لـ EfficientNet).
- على JFT-300M (300M صورة): دقة 90.45% — يتفوق على أفضل CNNs.
- الدرس: المحولات تحتاج بيانات كثيرة لتعميم جيد.
Swin Transformer — المحول الهرمي
Swin Transformer (2021) من Microsoft يحل مشكلة في ViT: الحسابات
ثقيلة (N² لكل طبقة). Swin يطبق الانتباه في نوافذ محلية (Windows)
بدلاً of عالمي، ثم يدمج المعلومات عبر النوافذ.
🟦 ViT (Global Attention)
- انتباه عالمي — كل patch يرى كل الـ patches.
- O(N² · d) — ثقيل حسابياً N=196 (224px).
- حجم ثابت للـ patches.
- يكافح مع الصور عالية الدقة.
🟦 Swin (Hierarchical + Window Attention)
- انتباه محلي (7×7 نافذة) + انتباه متحول (Shifted).
- O(N · M² · d) — أخف بكثير M=49.
- هرمي: يبني ميزات متعددة المقاييس (مثل CNN).
- يتعامل مع الدقة العالية بكفاءة.
class SwinTransformerBlock(nn.Module):
def __init__(self, dim, num_heads, window_size=7):
super().__init__()
self.dim = dim
self.window_size = window_size
self.num_heads = num_heads
self.norm1 = nn.LayerNorm(dim)
self.attn = WindowAttention(dim, num_heads, window_size)
self.norm2 = nn.LayerNorm(dim)
self.mlp = nn.Sequential(
nn.Linear(dim, 4 * dim), nn.GELU(),
nn.Linear(4 * dim, dim)
)
def forward(self, x):
# Split into windows, apply attention, merge back
shortcut = x
x = self.norm1.forward(x)
x = window_partition(x, self.window_size) # → windows
x = self.attn.forward(x)
x = window_reverse(x, self.window_size) # → merge
x = shortcut + x # residual
# MLP block
x = x + self.mlp.forward(self.norm2.forward(x))
return x
# Patch Merging (Swin's downsampling — مثل Pooling في CNN)
class PatchMerging(nn.Module):
def __init__(self, dim):
super().__init__()
self.norm = nn.LayerNorm(4 * dim)
self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False)
def forward(self, x, H, W):
# يدمج كل 2×2 من الـ patches → يقلص H,W للنصف ويضاعف dim
B, L, C = x.shape
x = x.view(B, H, W, C)
# يأخذ الركن العلوي الأيسر من كل 2×2
x0 = x[:, 0::2, 0::2, :]
x1 = x[:, 0::2, 1::2, :]
x2 = x[:, 1::2, 0::2, :]
x3 = x[:, 1::2, 1::2, :]
x = torch.cat([x0, x1, x2, x3], -1) # (B, H/2, W/2, 4*C)
x = self.norm.forward(x)
x = self.reduction.forward(x)
return x.view(B, -1, 2*C)
DETR — Detection Transformer
DETR (Detection Transformer, 2020) من Facebook AI يغيّر طريقة
اكتشاف الأشياء بالكامل. بدلاً من أنظمة الكشف المعقدة (مثل YOLO وFaster R-CNN
التي تحتاج الكثير من المكونات)، DETR يستخدم محول واحد فقط.
🎯 كيف يعمل DETR؟
- CNN Backbone: يستخرج ميزات من الصورة (مثل ResNet).
- Transformer Encoder: يعالج ميزات الصورة بفهم السياق الكامل.
- Transformer Decoder: يستخدم عدداً ثابتاً من "object queries"
(استعلامات كائن) لاكتشاف الأشياء — كل query يتعلم البحث عن شيء معين.
- Bipartite Matching: يطابق التوقعات مع الحقيقة الأرضية
(باستخدام Hungarian Algorithm).
class DETR(nn.Module):
def __init__(self, num_classes=80, num_queries=100,
d_model=256):
super().__init__()
# CNN backbone (مثال: ResNet-50)
self.backbone = nn.Sequential(
nn.Conv2d(3, 64, 7, 2, 3), nn.ReLU(),
nn.Conv2d(64, d_model, 3, 2, 1), nn.ReLU(),
)
# Transformer Encoder
encoder_layer = nn.TransformerEncoderLayer(d_model, nhead=8)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=6)
# Object queries (قابلة للتعلم — تبحث عن الكائنات)
self.query_embed = nn.Embedding(num_queries, d_model)
# Transformer Decoder
decoder_layer = nn.TransformerDecoderLayer(d_model, nhead=8)
self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=6)
# رؤوس التنبؤ: الفئة والمربع المحيط
self.class_head = nn.Linear(d_model, num_classes + 1) # +1 for no-object
self.bbox_head = nn.Sequential(
nn.Linear(d_model, d_model), nn.ReLU(),
nn.Linear(d_model, 4) # [x, y, w, h]
)
def forward(self, x):
# 1. CNN extracts features
features = self.backbone.forward(x) # (B, d, H', W')
B, D, H, W = features.shape
features = features.flatten(2).permute(2, 0, 1) # (H*W, B, D)
# 2. Transformer Encoder
memory = self.encoder.forward(features)
# 3. Queries + Decoder
queries = self.query_embed.forward(torch.arange(queries.shape[0]))
queries = queries.unsqueeze(1).repeat(1, B, 1) # (num_q, B, D)
output = self.decoder.forward(queries, memory)
# 4. Predict classes & boxes
class_logits = self.class_head.forward(output) # (num_q, B, num_classes+1)
bboxes = self.bbox_head.forward(output).sigmoid() # (num_q, B, 4)
return class_logits, bboxes
🎵 المحولات في الصوت — AST, Whisper
بعد نجاح المحولات في النص والصور، كان الصوت هو المجال التالي. هذا الفصل يغطي
أهم تطبيقين للمحولات في معالجة الصوت: AST لتصنيف الصوت، وWhisper للتعرف على الكلام.
AST — Audio Spectrogram Transformer
AST (Gong et al., 2021) هو أول محول يُطبّق مباشرة على
الصوت — بدون CNNs. الفكرة: نحول الصوت إلى طيف (Spectrogram)
ثم نعامله كصورة! نطبّق نفس فكرة ViT — تقسيم الطيف إلى patches.
🔊 كيف يعمل AST خطوة بخطوة
- استخراج الطيف: نحول الصوت الخام إلى Mel-Spectrogram
(تردد × الزمن) باستخدام STFT (Short-Time Fourier Transform).
- تقسيم إلى Patches: نقطع الطيف إلى patches صغيرة (مثل 16×16).
- خطي + Positional: نحول كل patch إلى متجه ونضيف التشفير الموضعي.
- محول قياسي: نمرر التسلسل عبر محول مثل BERT.
- CLS Token: نستخدم [CLS] token للتصنيف النهائي.
import torchaudio
import torchaudio.functional as F_audio
class AudioPreprocessor:
# يحول الصوت الخام إلى Mel-Spectrogram
def __init__(self, sample_rate=16000, n_mels=128,
n_fft=1024, hop_length=512):
self.mel_spec = torchaudio.transforms.MelSpectrogram(
sample_rate=sample_rate, n_mels=n_mels,
n_fft=n_fft, hop_length=hop_length
)
def __call__(self, waveform):
# waveform: (1, samples) → mel: (128, time_frames)
mel = self.mel_spec.forward(waveform)
mel = torchaudio.amplitude_to_DB(mel, multiplier=10,
amin=1e-10, top_db=80.0)
return mel # (n_mels, time)
class ASTModel(nn.Module):
def __init__(self, n_mels=128, patch_size=16, embed_dim=768,
num_classes=527): # AudioSet classes
super().__init__()
self.patch_embed = nn.Conv2d(1, embed_dim,
kernel_size=patch_size, stride=patch_size)
num_patches = (n_mels // patch_size) * (100 // patch_size)
self.cls_token = nn.Parameter(torch.randn(1, 1, embed_dim))
self.pos_embed = nn.Parameter(torch.randn(1, num_patches + 1, embed_dim))
self.dropout = nn.Dropout(0.1)
# Transformer encoder (مثل ViT)
encoder_layer = nn.TransformerEncoderLayer(embed_dim, nhead=12)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=12)
self.mlp_head = nn.Sequential(
nn.LayerNorm(embed_dim),
nn.Linear(embed_dim, num_classes)
)
def forward(self, mel_spec):
# mel_spec: (B, 1, n_mels, T)
x = self.patch_embed.forward(mel_spec) # (B, D, H', W')
x = x.flatten(2).transpose(1, 2) # (B, num_patches, D)
# Add CLS token + positional embeddings
cls_token = self.cls_token.expand(x.size(0), -1, -1)
x = torch.cat([cls_token, x], dim=1)
x = x + self.pos_embed[:, :x.size(1), :]
x = self.dropout.forward(x)
x = self.transformer.forward(x.transpose(0, 1)).transpose(0, 1)
cls_out = x[:, 0, :] # CLS token
return self.mlp_head.forward(cls_out)
Whisper — التعرف على الكلام متعدد اللغات
Whisper (OpenAI, 2022) هو نموذج تعرف على الكلام
متعدد اللغات يستخدم هندسة Encoder-Decoder من المحولات. ما يجعله فريداً:
درّب على 680,000 ساعة من البيانات متعددة اللغات ويدعم 99 لغة.
🌍 لماذا Whisper ثوري؟
- متعدد اللغات: 99 لغة — العربية، الصينية، الإنجليزية، وغيرها.
- يكتب باللغة الأصلية: يكتب النص العربي بالعربية مباشرة.
- مقاوم للضوضاء: يعمل بشكل جيد في البيئات الصاخبة.
- مهام متعددة: تعرف على الكلام، ترجمة، تحديد اللغة.
- مفتوح المصدر: يمكن تشغيله محلياً (أحجام: tiny→large).
# تثبيت المكتبات:
# pip install openai-whisper torch
# أو استخدام transformers 🤗
import whisper
# تحميل النموذج (tiny, base, small, medium, large)
model = whisper.load_model("base") # ~1GB للـ base
# نسخ صوت عربي
result = model.transcribe("audio_arabic.mp3")
print(result["text"])
# "مرحباً بكم في درس الذكاء الاصطناعي"
# تحديد اللغة تلقائياً
print(result["language"]) # 'ar'
# === استخدام HuggingFace Transformers ===
from transformers import WhisperProcessor, WhisperForConditionalGeneration
processor = WhisperProcessor.from_pretrained("openai/whisper-small")
model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small")
# معالجة الصوت
inputs = processor(librosa.load("speech.mp3")[0],
sampling_rate=16000, return_tensors="pt")
# توليد النص
generated_ids = model.generate(inputs.input_features)
transcription = processor.batch_decode(generated_ids,
skip_special_tokens=True)
print(transcription[0])
هندسة Whisper (Encoder-Decoder مع المحولات)
↑
Decoder (GPT-style)
Autoregressive
↑
Cross-Attention
Q from Decoder, K,V from Encoder
↑
Encoder (BERT-style)
Bidirectional
↑
Conv + Sinusoidal PE
Mel-Spectrogram → Features
↑
🎤 Audio Input
(Mel-Spectrogram)
🧱 هندسة Whisper: Encoder-Decoder مع محولات — مثل T5 ولكن للصوت
🧪 تجربة عملية — تشغيل Whisper على صوت عربي:
whisper audio.mp3 --model small --language Arabic
# النتيجة: "بسم الله الرحمن الرحيم، الحمد لله رب العالمين"
📊 مقارنة شاملة: المحولات في النص والصورة والصوت
| المجال |
المُدخل |
طريقة التقسيم |
أشهر نموذج |
الهندسة |
| 📝 النص |
Token IDs |
Subword (BPE/WordPiece) |
GPT-4, BERT, T5 |
Encoder / Decoder / Both |
| 🖼️ الصورة |
Image Patches |
16×16 patches |
ViT, Swin, DETR |
Encoder (معظم) |
| 🎵 الصوت |
Mel-Spectrogram |
Patches + Time frames |
AST, Whisper |
Encoder / Encoder-Decoder |
| 🎬 الفيديو |
Frame Patches + Time |
Spatial + Temporal |
VideoMAE, TimeSformer |
Encoder |