RNN وLSTM وGRU — نمذجة التسلسلات
“تعليم الشبكات التذكر — من النسيان الكارثي إلى الذاكرة البوابية الانتقائية”
الشبكات المتكررة للتسلسلات: RNN الأساسية وLSTM (بوابات النسيان والإدخال والإخراج وحالة الخلية) وGRU (بوابات مُبسَّطة) وBi-LSTM للسياق ثنائي الاتجاه.
المتطلبات الأساسية
المفاهيم المغطاة
∑الصيغ الرئيسية
الحالة الخفية RNN
يجمع الذاكرة السابقة مع المدخل الحالي — يعاني من النسيان الكارثي في التسلسلات الطويلة
حالة خلية LSTM
حالة الخلية مُحدَّثة بوابة النسيان ووابة الإدخال — 'الطريق السريع للتدرج'
خرج LSTM
تتحكم وابة الخرج في ما يُكشَف من حالة الخلية — اختيار انتقائي للذاكرة
تحديث GRU
بوابة تحديث وحيدة تُقحِّم الحالة الخفية القديمة والجديدة — أبسط من LSTM، غالباً بنفس الجودة
▶محاكاة تفاعلية
⬡هندسة النموذج
لماذا التسلسلات صعبة
اللغة، السلاسل الزمنية، الصوت، الحمض النووي — كل هذه لها تبعيات زمنية. 'قال إنه سيأتي' — 'هو' و'سيأتي' مفصولان بـ5 كلمات لكنهما مرتبطان ارتباطاً وثيقاً. الشبكة الأمامية تعالج كل خطوة زمنية بشكل مستقل. تتشارك RNNs المعاملات عبر الزمن وتحافظ على حالة خفية تلخص المدخلات السابقة — مما يتيح سياقاً غير محدود.
اختفاء التدرج عبر الزمن
في BPTT (الانتشار الخلفي عبر الزمن)، تُضرب التدرجات بمصفوفة الأوزان W في كل خطوة زمنية. إذا كانت أكبر قيمة ذاتية لـW < 1، تتناقص التدرجات أسياً. لتسلسل من 100 خطوة، يُضرب التدرج من الخطوة 1 بـW¹⁰⁰. تحل LSTMs هذا بالحالة الخلوية — 'طريق سريع' يحمل المعلومات بتحديثات جمعية فقط (لا ضربية).
تتدفق تدرجات LSTM عبر c_t = f_t ⊙ c_{t-1} + i_t ⊙ c̃_t. بوابة النسيان f_t تمنع تدرجات c من الاختفاء — إنها جمعيات مشروطة، لا ضروب مصفوفية.
معادلات بوابات LSTM
أربعة حسابات للبوابات تحدد ما يجب نسيانه وتعلمه وإنتاجه في كل خطوة. جميع البوابات تستخدم sigmoid (مخرج 0-1 = 'كم تسمح بالمرور'). حالة الخلية المرشحة تستخدم tanh (مخرج -1 إلى 1 = المحتوى الفعلي).
LSTM لتوقع السلاسل الزمنية
import torch import torch.nn as nn from torch.utils.data import TensorDataset, DataLoader class="tok-comment"># ── Sample sequential dataloader ─────────────────────────────────────── class="tok-comment"># Shape: (n_samples, seq_len, features) → predict next value X_seq = torch.randn(class="tok-num">500, class="tok-num">20, class="tok-num">10) class="tok-comment"># class="tok-num">500 samples, seq_len=class="tok-num">20, class="tok-num">10 features y_seq = torch.randn(class="tok-num">500) class="tok-comment"># class="tok-num">500 scalar targets dataloader = DataLoader(TensorDataset(X_seq, y_seq), batch_size=class="tok-num">32, shuffle=True) class LSTMForecaster(nn.Module): def __init__(self, input_dim, hidden_dim, num_layers, output_dim, dropout=class="tok-num">0.2): super().__init__() self.lstm = nn.LSTM( input_dim, hidden_dim, num_layers, batch_first=True, dropout=dropout, bidirectional=False ) self.fc = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, x, h0=None, c0=None): class="tok-comment"># x: (batch, seq_len, features) out, (hn, cn) = self.lstm(x, (h0, c0) if h0 is not None else None) class="tok-comment"># Use last timestep's output return self.fc(self.dropout(out[:, -class="tok-num">1, :])) class="tok-comment"># Training with teacher forcing + scheduled sampling model = LSTMForecaster(input_dim=class="tok-num">10, hidden_dim=class="tok-num">128, num_layers=class="tok-num">2, output_dim=class="tok-num">1) optimizer = torch.optim.Adam(model.parameters(), lr=class="tok-num">1e-3) class="tok-comment"># Gradient clipping is ESSENTIAL for RNN training for x, y in dataloader: pred = model(x) loss = nn.MSELoss()(pred.squeeze(), y) optimizer.zero_grad() loss.backward() nn.utils.clip_grad_norm_(model.parameters(), max_norm=class="tok-num">1.0) optimizer.step()
?اختبار المعرفة
يتم حفظ التقدم في متصفحك — لا حاجة لحساب.