الوحدة 5 — فكّ الترميز: درجة الحرارة، top-k، top-p
النموذج لا ينتج نصًّا فورًا. ينتج، لكلّ موضع، توزيعًا احتماليًا على مفرداته البالغة عشرات الآلاف. طريقة اختيار الرمز من هذا التوزيع هي فكّ الترميز. ولها أثر ملموس على المخرج، بأثر يوازي أحيانًا أثر تبديل النموذج نفسه. لمساعد الدعم، هذا الأثر مباشر: نفس النموذج المُدرَّب سيكون رصينًا موثوقًا بضبطٍ ما، وسيصير مُلْتَفًّا مُبدعًا خارج السياق بضبط آخر.
ما هو التوزيع الذي نتحدّث عنه؟
في كلّ خطوة توليد، تُنتج طبقة المخرج شعاعًا من الأعداد الخام (logits) بحجم القاموس: قد يكون ذلك 128 ألف قيمة. تُطبَّق سوفتماكس على هذا الشعاع فيصير توزيعًا احتماليًا يجمع مجموعه إلى 1. الرمز الأكثر احتمالًا هو ما سيُختار في المسار الأبسط، لكنّه ليس الخيار الوحيد.
البحث الجَشِع، وأثر البحث الشعاعي
أبسط طريقة، البحث الجَشِع، تختار في كلّ خطوة الرمز ذا الاحتمال الأعلى. حتمي بالكامل: نفس المُطالبة تعطي دائمًا نفس الجواب. لكنّه يُعطي أحيانًا نصوصًا رديئة، لأنّه يبني قرارات محلّية دون رؤية أبعد. تكرار الجُمل، والتعلّق بلفظة بعينها، وسقوط في حلقات — كلّها أعراض معروفة.
يُصلح البحث الشعاعي بعض هذه المشاكل بحمل فرضيّة بالتوازي والحفاظ على الأفضل. مفيد للترجمة الآلية، لكن غير مناسب لمهام حوار: يُنتج نصوصًا مسطّحة ومعمَّمة، لأنّه يبحث عن الأعلى احتمالًا، وهذا في التوليد الحرّ يُنتج ملل التعميم.
في مساعد الدعم عند التلخيص أو الترجمة أو استخلاص كيان، البحث الجَشِع هو الافتراض الجيّد. عند التوليد الحرّ للردود، نحتاج إلى العينة.
درجة الحرارة
قبل تطبيق سوفتماكس، تُقسَم الأعداد الخام على درجة الحرارة :
قيمة لا تغيّر شيئًا. قيمة أدنى، مثل ، تضخّم الفرقاء: الاحتمال العالي يصير أعلى، والمنخفض أدنى. النموذج يصير قريبًا من الجَشِع، بحتميّة عالية. قيمة أعلى، مثل ، تُسطِّح التوزيع: احتمالات الرموز النادرة ترتفع، والمخرج يصير أكثر تنوّعًا وأحيانًا أكثر فوضويّة.
يمكن رؤية أثر الحرارة على مثال بسيط. لنفرض أنّ النموذج يعطي شعاع الأعداد الخام التالي بعد الجملة «العاصمة هي»:
| الرمز | ال عدد الخام | |||
|---|---|---|---|---|
| «تونس» | 3.0 | 0.71 | 0.87 | 0.51 |
| «القاهرة» | 1.5 | 0.16 | 0.11 | 0.24 |
| «الرباط» | 1.0 | 0.10 | 0.02 | 0.15 |
| «باريس» | -0.5 | 0.02 | 0.00 | 0.05 |
بحرارة منخفضة يبتلع «تونس» تسعين بالمائة من الاحتمال؛ بحرارة عالية «باريس» تصير خيارًا محتملًا رغم عدم مناسبتها.
Top-k
طريقة أخرى للتحكّم بالتنوّع: احتفظ فقط بأعلى رمزًا، ثم اسحب عيّنة من بينها. مع ، نحتفظ بأفضل 40 رمزًا من ألف احتمالي، ونُوزّع الاحتمال بينها فقط. المزيّة: نطرد ذيول التوزيع المتضمّنة أخطاء عشوائيّة. العيب: العدد ثابت، لا يتكيّف مع حالة التوزيع.
Top-p (nucleus sampling)
اقترحت ورقة Nucleus Sampling عام 2019 حلًّا يتكيّف. بدلًا من عدد ثابت، نحتفظ بأصغر مجموعة من الرموز مجموع احتمالاتها يبلغ ، ثم نسحب من بينها. مع ، سنحتفظ أحيانًا برمز واحد فقط (حين يكون النموذج واثقًا) وأحيانًا بمئة رمز (حين يكون مُترنّحًا). الطريقة متكيّفة مع مستوى ثقة النموذج.
في الممارسة، تُدمَج الحرارة مع top-p تدميجًا واسعًا:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
tok = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B-Instruct")
modele = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct", torch_dtype=torch.bfloat16, device_map="auto"
)
messages = [{"role": "user", "content": "اقترح ثلاث نبرات لردٍّ على عميل يشكو من تأخّر معاملة."}]
prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
entrees = tok(prompt, return_tensors="pt").to(modele.device)
sortie = modele.generate(
**entrees,
max_new_tokens=200,
do_sample=True,
temperature=0.7,
top_p=0.9,
top_k=50,
repetition_penalty=1.1,
)
print(tok.decode(sortie[0, entrees.input_ids.shape[1]:], skip_special_tokens=True))
عقوبة التكرار
مشكلة كلاسيكية: النموذج ينزلق أحيانًا في حلقة تكرار. «شكرًا شكرًا شكرًا شكرًا…» إلى ما لا نهاية. تكافح العقوبة على التكرار هذا: يُخفَّض احتمال الرموز التي ظهرت قبلًا في السياق. القيمة الشائعة بين 1.1 و1.2. قيمة أعلى (1.5+) تجعل النموذج يتجنّب حتّى إعادة كلمات مشروعة، فيتحوّل السياق إلى مزيج غريب من مفردات لا يعاد استخدام أيّ منها.
الحتميّة: مسألة أعمق مما تبدو
للتقييم أو للتصحيح، نحتاج إلى مخرج حتمي: نفس المُطالبة تُعطي دائمًا نفس الجواب. الطريقة المتوقعة: do_sample=False، أو temperature=0. لكنّ هذا في الواقع لا يكفي دائمًا. على معالجات رسومية متعدّدة، عمليات الجمع بالفاصلة العائمة ليست ترابطيّة، وترتيب العمليات قد يختلف بين تشغيل وآخر، فيتغيّر الرمز المختار عند نقاط التساوي. لتقييم صارم، ثبّت البذرة torch.manual_seed(...) ولا تعتمد على temperature=0 وحده.