الوحدة 8 — المرمّز وفاكّ الترميز للترجمة
استخدمنا حتّى الآن شبكة تكرارية واحدة على متتالية واحدة. ماذا لو أردنا تحويل متتالية إلى أخرى، بطول مختلف؟ ترجمة جملة فرنسية إلى إنجليزية، تلخيص مقال، توليد ردّ من سؤال. الجواب البنيوي جاء عام 2014 بورقة سوتسكفير وفينالز ولو: معمارية مرمّز-فاكّ ترميز. هذه الوحدة تفكّكها، ثم تُبرز الحدّ الذي فتح باب المحوّلات.
قطيعة مع الفيل الأحمر
سلسلة الكهرباء تُدخِل خطوة وتُخرج خطوة (أو خطوة قادمة). للترجمة نحتاج شيئًا مختلفًا: مُدخَل بطول (الفرنسية)، ومُخرَج بطول مختلف تمامًا (الإنجليزية). لا يوجد ارتباط واحد لواحد بين الرمزين. نغيّر إذن مثالنا للوحدة: مدوّنة صغيرة من الجُمَل الفرنسية-الإنجليزية، كلّ سطر جملة فرنسية وترجمتها.
Bonjour le monde. → Hello world.
Il fait beau aujourd'hui. → The weather is nice today.
Je vais bien, merci. → I am fine, thank you.
عشرة آلاف زوج من هذه، ونموذج قادر أن يُترجم جُملًا لم يرها.
البنية العامّة
المرمّز شبكة تكرارية (LSTM أو GRU) تقرأ الجملة الفرنسية كلمة كلمة. لا تُنتج مُخرَجات لكلّ خطوة؛ ما يهمّنا فقط حالتها الأخيرة، وهي متّجه السياق : تلخيص للجملة كاملةً.
فاكّ الترميز شبكة تكرارية ثانية تنطلق من هذه الحالة، وتُنتج كلمات الجملة الإنجليزية واحدة تلو الأخرى:
عند كلّ خطوة، طبقة كثيفة (مفردات الإنجليزية) تُنتج توزيعًا احتمالياً على كلمة النقطة الحاضرة. الكلمة المختارة تصير مُدخَل الخطوة القادمة، وهكذا حتى ظهور رمز نهاية النصّ.
رمزا البداية والنهاية
كي يعرف فاكّ الترميز متى يبدأ ومتى ينتهي، تُوسَّع مفردات المُخرَج برمزين مخصوصَين:
<sos>(start of sentence): يُطعَم للفاكّ عند ، إشارة «ابدأ الآن»<eos>(end of sentence): يُنتِجه الفاكّ لإعلان «انتهيت»
كلّ جملة إنجليزية في التدريب تُصبح <sos> Hello world . <eos>. المُدخَل الأوّل للفاكّ دائمًا <sos>، وعند التوليد نتوقّف بمجرّد إنتاج <eos>. من دونهما، الفاكّ لا يعرف متى يكون قد انتهى، ويُنتج كلمات إلى ما لا نهاية.
Teacher forcing: كيف نُدرِّب فاكّ الترميز
هنا تكمن براعة معمارية 2014. في التوليد، الفاكّ يستقبل عند الخطوة الكلمة التي أنتجها عند . لكن في التدريب، الاعتماد على مُخرَجاته الخاطئة في البداية يُبطئ التقارب: خطأ عند يُغذّي كلّ الخطوات التالية.
الحلّ اسمه teacher forcing: في التدريب، يستقبل الفاكّ عند الخطوة الكلمة الصحيحة من مجموعة التدريب في ، لا ما أنتجه هو. الشبكة تتعلّم إذن التنبّؤ بكلٍّ من الكلمة بشرط أنّ ما سبقها كان صحيحًا.
import torch
import torch.nn as nn
class FaccTermeur(nn.Module):
def __init__(self, taille_vocab, hidden=128):
super().__init__()
self.emb = nn.Embedding(taille_vocab, hidden)
self.lstm = nn.LSTM(hidden, hidden, batch_first=True)
self.tete = nn.Linear(hidden, taille_vocab)
def forward(self, y_cible, etat_initial):
"""y_cible: (N, T) مع <sos> في البداية. etat_initial من المرمّز."""
emb = self.emb(y_cible[:, :-1]) # كلمات مدخلة: كل شيء ما عدا <eos>
sorties, _ = self.lstm(emb, etat_initial)
return self.tete(sorties) # (N, T-1, V) - كلمات متوقعة
# حلقة التدريب
sortie_mrmz, etat_final = mrmz(x_fr) # x_fr: (N, T_src)
etat_initial_fk = etat_final # نقل الحالة
predictions = fk(y_en, etat_initial_fk) # y_en يبدأ بـ<sos>
perte = critere(predictions.reshape(-1, V),
y_en[:, 1:].reshape(-1)) # نقارن بـy_en بدون <sos>
الشبكة تتدرّب بسرعة، لكنّها تعتاد على معلومة غير متوفّرة عند التوليد: كلمة الحقيقة السابقة. هذه فجوة train/test: نموذج يُتقن التدريب ويرتبك عند التوليد لأنّه ما رأى قط تسلسلًا مغلوطًا. الحلّ الجزئي هو teacher forcing المُخفَّف: نستعمل الحقيقة باحتمال يتناقص عبر التدريب (scheduled sampling).
الفكّ الجشِع
عند التوليد، الاستراتيجية الأبسط اسمها الفكّ الجشِع: عند كلّ خطوة نأخذ الكلمة ذات أعلى احتمال، ونمضي.
def traduire(mrmz, fk, x_fr, sos_id, eos_id, T_max=50):
"""يترجم جملة واحدة x_fr إلى مخرج جملي."""
with torch.no_grad():
_, etat = mrmz(x_fr.unsqueeze(0)) # (1, T_src) → حالة
entree = torch.tensor([[sos_id]]) # نبدأ بـ<sos>
sortie = []
for _ in range(T_max):
emb = fk.emb(entree)
h, etat = fk.lstm(emb, etat)
logits = fk.tete(h[:, -1, :]) # آخر خطوة
mot = logits.argmax(dim=-1) # الجشع: argmax
if mot.item() == eos_id:
break
sortie.append(mot.item())
entree = mot.unsqueeze(0)
return sortie
هذا يعمل، وهو المرجع لمعظم المشاريع. البديل الأشهر هو beam search: نحفظ فرضية في الوقت نفسه بدل واحدة، ونمدّها معًا؛ يعطي جُملًا أفضل قليلًا مقابل حساب أضعاف. للترجمة الإنتاجية، بين 4 و10 معيار جيّد.
الحدّ الجوهري: عنق الزجاجة
لنعُد إلى ما يجعل هذه المعمارية محدودة. الجملة الفرنسية كلّها — بغضّ النظر عن طولها، خمس كلمات أو خمسون — تُلخَّص في متّجه سياق واحد ذي بُعد ثابت. عبر هذا العنق يمرّ كلّ ما يحتاجه الفاكّ.
على جُمَل قصيرة، يعمل هذا حسنًا. على جُمَل طويلة، يخسر الفاكّ التفاصيل: عبارة في بداية الجملة الفرنسية تُنسى قبل أن يصل الفاكّ إلى موضعها في الإنجليزية. النتيجة: كلّما طالت الجملة، تدهورت الترجمة بشكل ملموس.
الحلّ جاء عام 2015 مع بهدانو وشو وبنجيو: آليّة الانتباه. بدل تلخيص المُدخَل في متّجه واحد، نُبقي جميع حالات المرمّز ، ونجعل الفاكّ يختار عند كلّ خطوة أيّ حالات مرمّزة يُعير الاهتمام لها. سيأتي هذا بالتفصيل في الدورة 12، وهو ما فتح الطريق نحو المحوّلات (Transformer, 2017)، التي اكتفت في النهاية بالانتباه بلا شبكة تكرارية.
هذه المعمارية عملة قوية لكنّها مكلفة. قبل استعمالها، اسأل نفسك: هل يكفي انحدار على ملخّصات؟ كثيرًا ما تكون المشكلة قابلة للحلّ بشبكة بسيطة على متغيّرات مهندَسة (طول المُدخَل، عدد الكلمات المفتاحية، كثافة رموز معيّنة). ثانيًا، هل حجم بياناتك يبرّرها؟ المرمّز وفاكّ الترميز يحتاجان عشرات الآلاف من الأزواج على الأقلّ للتعلّم من الصفر. على أقلّ من ذلك، الضبط الدقيق لنموذج مسبق التدريب (بارت، تي 5، مسلسلات صغيرة) أنفع بكثير من التدريب من الصفر.
في الخلاصة
- المرمّز يُلخّص المُدخَل في متّجه سياق ؛ فاكّ الترميز يُنتج المُخرَج كلمة كلمة انطلاقًا من هذا المتّجه، مع رمزَي
<sos>و<eos>. - Teacher forcing يُطعم الفاكّ في التدريب الحقيقة السابقة لا مُخرَجه، فيتقارب أسرع لكن يُنتج فجوة train/test تُخفَّف بأخذ عيّنات مُبَرمَجة.
- الفكّ الجشِع (argmax عند كلّ خطوة) مرجع بسيط؛ beam search يعطي جُملًا أفضل مقابل أضعاف الحساب.
- عنق الزجاجة: متّجه سياق ثابت البُعد يعجز عن حمل جملة طويلة، وهو ما فتح باب الانتباه ثم المحوّلات.
الوحدة التالية: العملانيات الحقيقية للمتتاليات — الحشو، التقنيع، وترتيب الدفعات — كي يجري كلّ ما سبق دون تسرّب ولا هدر ذاكرة.