تخطَّ إلى المحتوى
8/30الفصل 8 من 30

التنبؤ بالـ token التالي: Embeddings، وما تعنيه Perplexity

درّب نموذج أحرف على 32,033 اسمًا، وشاهد gradient descent يعيد اكتشاف جدول عدّ، ثم افهم لماذا نادرًا ما تتطابق Perplexity.

في هذه الصفحة

إليك عشرة أسماء أنتجها برنامج لم يرَ كلمة قط:

TEXT
cexze   momakurailezitynn   konimittain   llayn   ka
da      moliellavo          emia          sade    ftlsp

لا واحد منها اسم. لكن معظمها تقريبًا يحاول. إنها قابلة للنطق، وتنتهي حيث تنتهي الأسماء، وأحدها — emia — لا يفصله عن اسم حقيقي إلا حرف واحد. البرنامج الذي أنتجها يحتوي على 729 رقمًا، ولا يملك أي تصور عن كلمة أو مقطع أو شخص، وتم ضبطه بتمرير واحد فقط لعدّ الأزواج المتجاورة من الحروف.

بنهاية هذا الفصل، ستكون شبكة عصبية قد خفّضت درجة ذلك البرنامج بمقدار الثلث على القياس نفسه. الجزء الذي يستحق البقاء من أجله هو ما تفعله الشبكة أولًا: إنها تعيد إنتاج جدول العدّ حتى ثلاث منازل عشرية في كل صف ممتلئ جيدًا، من تلقاء نفسها، لأن الشيئين إجابتان عن السؤال نفسه. كل ما يأتي بعد ذلك هو ما لم يكن العدّ قادرًا على فعله أبدًا.

تركك الفصل 7 مع سلسلة من الأعداد الصحيحة ومن دون سبب يجعل واحدًا يتبع آخر. ها هو السبب، وهو سطر واحد من الفصل 2.

نموذج اللغة هو دالة تأخذ الـ tokens حتى الآن وتعيد توزيعًا على أي token سيأتي بعد ذلك: رقم واحد لكل إدخال في المفردات، غير سالب، ومجموعها واحد. لا شيء آخر. للانتقال من ذلك إلى احتمال مستند كامل، طبّق قاعدة السلسلة في الاحتمالات:

P(x1,x2,,xT)=t=1TP(xtx1,,xt1)P(x_1, x_2, \ldots, x_T) = \prod_{t=1}^{T} P(x_t \mid x_1, \ldots, x_{t-1})

هذه هوية، صحيحة لأي تسلسل من أي شيء، بلا افتراضات مضافة. لذلك فالنموذج الذي ينجز المهمة الصغيرة — الـ token التالي معطىً الـ tokens السابقة — يكون قد أنجز بالفعل المهمة الكبيرة: إسناد احتمال لكل مستند ممكن، بدقة ومجانًا. الصياغة الشائعة لهذا كحيلة رخيصة ("إنه يتنبأ بالكلمة التالية فقط") تقلب المنطق رأسًا على عقب: التنبؤ بالـ token التالي هو نمذجة التوزيع المشترك. لم يكن هناك شيء ثانٍ يجب فعله أصلًا.

وتتبع الخسارة ذلك آليًا بالقدر نفسه. في كل موضع ينتج النموذج توزيعًا qq والحقيقة هي token واحد معروف، لذلك ينطبق cross-entropy في الفصل 4 كما هو:

L=1Tt=1Tlogqθ(xtx<t)L = -\frac{1}{T}\sum_{t=1}^{T} \log q_\theta(x_t \mid x_{<t})

هذا هو متوسط السالب للـ log-likelihood — وصفة الفصل 2 لكن مع توزيع فئوي في الموضع الذي كان فيه Gaussian. وبما أن التوزيع الحقيقي one-hot، فإن إنتروبيته صفر، لذلك وبحسب هوية الفصل 4 فإن cross-entropy يساوي KL divergence: خفض هذا الرقم وسحب معتقدات النموذج نحو بياناته هما الفعل نفسه.

تستحق إحدى النتائج جملة مستقلة، لأنها الحقيقة الاقتصادية تحت الحقل كله. الـ labels هي البيانات، مزاحة موضعًا واحدًا. لا أحد يوسم شيئًا. تريليون tokens من النص هي تريليون أمثلة موسومة مسبقًا، وهذا سبب أن corpus تدريب نموذج حديث هو "الإنترنت" وليس "مجموعة بيانات بناها شخص ما".

قبل أي شبكة، خط الأساس: 32,033 اسمًا، اسم واحد في كل سطر، والمهمة هي إنتاج المزيد منها حرفًا بحرف.1

المفردات هي 26 حرفًا إضافة إلى رمز حدّي . يعلّم بداية الاسم ونهايته معًا، لذلك على النموذج أن يتعلم أين تبدأ الأسماء وأين تتوقف. هذا يعني 27 رمزًا، وأصغر نموذج ممكن هو جدول يبيّن عدد مرات مجيء كل رمز بعد كل رمز آخر.

bigram.pyPYTHON
N = torch.zeros((27, 27), dtype=torch.int32)
for w in words:
    cs = ["."] + list(w) + ["."]
    for a, b in zip(cs, cs[1:]):
        N[stoi[a], stoi[b]] += 1

P = N.float()
P = P / P.sum(1, keepdim=True)            # one distribution per row   

سطران من الحساب والنموذج مضبوط — وهذا ليس heuristic: قسمة العدّادات على مجاميع الصفوف هي تقدير maximum-likelihood لتوزيع فئوي، أي وصفة الفصل 2 بعد إنجاز التفاضل مسبقًا.

TEXT
names: 32033        train/val/test: 25626 / 3203 / 3204
training bigrams: 182583

the six most likely letters after 'a':
    a -> '.'  0.1944   a -> 'n'  0.1600   a -> 'r'  0.0967
    a -> 'l'  0.0749   a -> 'h'  0.0690   a -> 'y'  0.0606

خذ عينات منه — اختر حرفًا من صف الحرف الحالي، انتقل إلى ذلك الصف، وكرر حتى يظهر الرمز الحدّي — فتحصل على الأسماء في أعلى هذا الفصل. إنها تفشل بطريقة محددة ومفيدة: معقولة محليًا، هراء عالميًا. كل زوج متجاور من الحروف في momakurailezitynn هو زوج يظهر في أسماء حقيقية؛ المشكلة فقط أن هناك سبعة عشر زوجًا منها على التوالي. لدى النموذج ذاكرة من حرف واحد، لذلك لا يستطيع أن يعرف أنه استمر أكثر من اللازم.

الخسارة على أسماء محجوزة للاختبار هي 2.4546 nats. هذا الرقم لا يعني شيئًا وحده، ولهذا توجد Perplexity:

PPL=exp ⁣(1Ttlogq(xtx<t))=eL\mathrm{PPL} = \exp\!\left(-\frac{1}{T}\sum_t \log q(x_t \mid x_{<t})\right) = e^{L}

مكتوبة كاملة، من دون مكتبة تنجز العمل:

perplexity.pyPYTHON
@torch.no_grad()
def perplexity(logits, Y):
    logp = F.log_softmax(logits, dim=1)          # log q for every symbol
    chosen = logp[torch.arange(len(Y)), Y]       # log q of the one that came next   
    return torch.exp(-chosen.mean())             

رفع العدد للأسّ يلغي اللوغاريتم ويعيد الرقم إلى وحدات عدّ الأشياء. الطريقة النظيفة لفهم ما يعدّه هي قياس نموذج لا يعرف شيئًا إطلاقًا — نموذج يسنِد الاحتمال 1/271/27 لكل رمز بغض النظر عن السياق:

TEXT
uniform over 27 symbols            loss 3.2958 nats   ppl  27.000
bigram counts, add-one smoothed    loss 2.4546 nats   ppl  11.642

بالضبط 27.000، لأن elog27=27e^{\log 27} = 27. Perplexity هي العدد الفعّال للخيارات المتساوية الاحتمال التي يختار النموذج بينها. Perplexity قدرها 27 تعني "لا فكرة، قد يكون أي شيء". قيمة نموذج العدّ 11.642 تعني أن حرفًا واحدًا من السياق يتركه حائرًا مثل شخص يختار عشوائيًا من نحو اثني عشر خيارًا بدلًا من سبعة وعشرين — وهذا سبب اقتباس Perplexity بدلًا من الخسارة الخام.

هناك شيئان يسوءان معها، والثاني يسوء في أوراق منشورة.

الاحتمالات الصفرية قاتلة. من بين 729 خلية في الجدول، هناك 113 لا تظهر أبدًا في التدريب — 15.5 % منه فارغ. لا مشكلة في ذلك إلى أن تقع مجموعة الاختبار في واحدة منها، وقد فعلت ذلك سبعة bigrams في التحقق، من بينها dq وzj وqo مرتين. احتمال صفر يعني log -\infty، أي خسارة لا نهائية وPerplexity لا نهائية: اسم واحد بين ثلاثة آلاف يدمّر المقياس. الترقيع المعتاد هو إضافة 1 إلى كل عدّاد قبل التطبيع، وتكلفته شبه معدومة هنا (2.4546 بدلًا من 2.4524). لكن الترقيع اعتراف. نموذج العدّ لا يستطيع التعميم إطلاقًا. لا سبيل لديه إلى الاشتباه في أن qo معقول لأن qu شائع وo يتصرف مثل u في مواضع أخرى، لأنه لا يملك أي مفهوم بأن رمزين يمكن أن يتشابها. كل خلية تُتعلّم وحدها، وإصلاح ذلك هو موضوع بقية هذا الفصل.

Perplexity سعر لكل token، والـ token معامل حر. هذا هو الخطأ الذي يظهر باستمرار عند مقارنة النماذج، ومن السهل رؤيته عندما تنظر. خذ corpus النثر الإنجليزي نفسه من الفصل 7، ونموذج bigram المستوفى نفسه، وغيّر فقط طريقة تقطيع النص:

الوحدةالمفرداتtokens في الاختبارcross-entropyPerplexitybits لكل حرف
أحرف7614,4692.521712.453.6378
BPE، 512 دمجًا3296,8713.854747.212.6407
BPE، 2,048 دمجًا1,8204,2335.7468313.202.4254
كلمات2,9916,2843.562735.262.2322

تتغير Perplexity بمعامل 25 عبر تلك الصفوف. لم يتغير شيء في النموذج؛ تغيّر فقط حجم الشيء المتوقَّع. التنبؤ بكلمة كاملة أصعب من التنبؤ بحرف، لذلك يكلف أكثر لكل تنبؤ — وفي المقابل هناك تنبؤات أقل يجب إجراؤها.

الآن اقرأ العمود الأخير، الذي يقسم التكلفة الكلية على عدد الأحرف بدلًا من ذلك ويحوّلها إلى bits. إنه يعيد ترتيب الجدول. بحسب Perplexity يكون الترتيب: الأحرف، الكلمات، BPE-512، BPE-2048؛ وبحسب bits لكل حرف يكون: الكلمات، BPE-2048، BPE-512، الأحرف. ينتقل نموذج الأحرف من المركز الأول إلى الأخير. نموذج 2,048 دمجًا، الذي يبدو بحسب Perplexity أسوأ 6.6 مرات من نموذج 512 دمجًا، هو في الحقيقة الأفضل بينهما عند 2.4254 bits مقابل 2.6407.

لذلك لا تكون Perplexity قابلة للمقارنة إلا بين نموذجين يتشاركان tokenizer، ولا يمكن مقارنة النماذج ذات tokenizers مختلفة إلا بـ bits لكل حرف — الكمية التي قاسها Shannon عام 1951 عندما طلب من بشر تخمين الحرف التالي في نص إنجليزي، وحدّدها بنحو bit واحد لكل حرف.2 أفضل bigram لدينا عند 2.23 bits، وهذا تلخيص عادل للمسافة التي لا يزال على هذا الفصل قطعها.

الآن ابنِ النموذج نفسه كشبكة. سيحتاج إلى حساب أكثر بعدة مراتب ليصل إلى المكان نفسه، والوصول إلى المكان نفسه هو بيت القصيد.

استبدل الجدول بمصفوفة أوزان واحدة WW ذات الشكل 27×2727 \times 27. حوّل الحرف الحالي إلى متجه one-hot، اضرب، وسمِّ النتيجة logits — الدرجات غير المطبَّعة من الفصل 4. ثم softmax، ثم cross-entropy، ثم gradient descent.

neural_bigram.pyPYTHON
W = torch.randn((27, 27), requires_grad=True)

for step in range(3000):
    logits = W[xs]                            
    loss = F.cross_entropy(logits, ys)
    W.grad = None
    loss.backward()
    W.data -= 50.0 * W.grad

السطر المميز يحتوي على تعريف يستحق الاحتفاظ به. ضرب متجه one-hot في مصفوفة يختار صفًا واحدًا منها، لذلك فالضرب هو lookup — وكل تنفيذ يتجاوز الحساب ويفعل الـ lookup مباشرة، وهذا هو W[xs].

ذلك هو embedding table. مصفوفة فيها صف واحد لكل إدخال في المفردات، مفهرسة بحسب token id. لا هندسة، لا دلالات، لا خوارزمية منفصلة: جدول lookup تصادف أن محتوياته تُتعلّم عبر gradient descent مع كل شيء آخر. كل الادعاءات الغامضة عن "embedding space" تنتهي هنا.

درّبه وشاهد إلى أين يذهب:

TEXT
  step     1   train 3.7550   val 3.3882   max gap to the count table 0.757269
  step   100   train 2.4732   val 2.4726   max gap to the count table 0.388354
  step  1000   train 2.4557   val 2.4549   max gap to the count table 0.041862
  step  3000   train 2.4547   val 2.4544   max gap to the count table 0.004048

العمود الأخير هو أكبر فرق مطلق بين أي خلية من softmax(W) والخلية المطابقة في جدول العدّ، وهو يتجه إلى الصفر. بعد 3,000 خطوة، أكبر خلاف في أي مكان داخل الخلايا الـ 729 هو 0.004048 والمتوسط 0.000224. أسوأ خلية هي qi، وقد شوهدت اثنتي عشرة مرة في مجموعة التدريب كلها؛ ومن بين الصفوف الـ 22 التي تضم أكثر من ألف ظهور، أسوأ خلاف هو 0.000562.

TEXT
                 count table   network
    a -> '.'        0.1945     0.1945
    a -> 'n'        0.1601     0.1601
    a -> 'r'        0.0967     0.0967

gradient descent، بدءًا من أرقام عشوائية ومن دون أن يُقال له شيء سوى "اجعل log-probability للحرف التالي كبيرًا"، أعاد اكتشاف جدول العدّ. وكان عليه ذلك: العدّادات هي تقدير maximum-likelihood، وcross-entropy هو سالب log-likelihood، لذلك تُحسّن العمليتان الهدف نفسه، ولهذا الهدف optimum واحد. لم تتعلم الشبكة شيئًا يشبه العدّ. لقد تقاربت إلى العدّ، ببطء.

وهذا يثير السؤال العادل: لماذا يتكبد أحدهم العناء؟ لأن جدول العدّ لا مكان له يذهب إليه من هنا، أما الشبكة فلديها.

وسّع النموذج لينظر إلى أكثر من حرف سابق واحد. هذه معمارية Bengio لعام 2003، السلف المباشر لكل نموذج في بقية هذه الدورة:4 خذ الأحرف الثلاثة الأخيرة، ومرّر كلًا منها عبر embedding table إلى صف ذي 10 أبعاد، والصق الصفوف في 30 رقمًا، وادفعها عبر الطبقة المخفية في الفصل 5، وأنهِ بطبقة إخراج تنتج logit واحدًا لكل إدخال في المفردات.

mlp.pyPYTHON
C  = torch.randn((27, 10))          # the embedding table
W1 = torch.randn((3 * 10, 200))     # the hidden layer from Chapter 5
W2 = torch.randn((200, 27))         # one output per vocabulary entry

emb = C[X].view(-1, 30)             # three lookups, concatenated   
h = torch.tanh(emb @ W1 + b1)
logits = h @ W2 + b2                
loss = F.cross_entropy(logits, Y)

لاحظ ما الجديد وما ليس جديدًا. الطبقة المخفية هي طبقة الفصل 5، بلا تغيير؛ والخسارة هي خسارة الفصل 4، بلا تغيير. المستجدات هي embedding table في البداية وطبقة إخراج بعرض مفردات الفصل 7 — وهذه الثانية هي الجزء المكلف في كل نموذج لغة بُني يومًا، لأن المفردات الحقيقية تضم 100,000 إدخال وهذا الضرب المصفوفي يعمل عند كل موضع.

الكود نفسه، مدرّب بالطريقة نفسها، مع تغيير حجم context window فقط:

السياقالمعلماتخسارة التحققPerplexity التحقق
عدّ، حرف واحد7292.454611.642
عصبي، حرف واحد7,8972.457711.678
عصبي، 3 أحرف11,8972.11458.285
عصبي، 8 أحرف21,8972.05067.773

الصف الثاني هو المثير للاهتمام. شبكة بطبقة مخفية من 200 وحدة وبعدد معلمات يزيد أحد عشر ضعفًا على جدول العدّ تؤدي تمامًا بقدر أداء جدول العدّ ولا أفضل. لم تكن السعة هي القيد قط. حرف واحد من السياق يسمح بخسارة معينة، ولا شيء تضيفه يمكن أن ينزل دونها، لأن المعلومات غير موجودة.

امنحه ثلاثة أحرف فتنخفض Perplexity من 11.68 إلى 8.29 — خفض بنسبة 29 %، ثمنه 4,000 معلمة إضافية. يتفوق على العدّ هنا للسبب نفسه الذي شُخّص سابقًا: نموذج عدّ على سياقات من ثلاثة أحرف يحتاج إلى 273=19,68327^3 = 19{,}683 صفوف، معظمها فارغ أو يحمل ملاحظة واحدة، ويتعلم كل واحد وحده. الشبكة تشارك. إذا انتهت a وe وi إلى صفوف embedding متشابهة، فإن ما يتعلمه بعد bra ينتقل إلى bre من دون أن يكون قد رأى bre قط. هذا النقل هو القيمة الكاملة لـ embedding table، وهو الفجوة بين الصفين الثاني والثالث.

تتحسن العينات تبعًا لذلك:

TEXT
deliah   nellara   joce     kael      quintis
salayson  reety    khyrmin  mahnen    madiaryxia

لا تزال ليست قائمة أسماء حقيقية. لكن deliah وnellara وkael لن تبدو غريبة في واحدة، وقد اختفت الوحوش المتمددة: أطول عينة من عشرين عينة من نموذج العدّ طولها تسعة عشر حرفًا، وأطول عينة من عشرين من هذا النموذج طولها ثلاثة عشر.

الجدول هو 27×1027 \times 10: صف واحد من عشرة أرقام لكل حرف، كلها مهيأة عشوائيًا ولا تتحرك إلا بفعل gradient خسارة الحرف التالي. لم يضع أحد شيئًا هناك. فما الذي انتهى إليه؟

الأداة للسؤال هي cosine similarity، وهي حاصل الضرب النقطي من الفصل 1 بعد قسمة الأطوال:

cos(a,b)=abab\cos(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\lVert \mathbf{a} \rVert \, \lVert \mathbf{b} \rVert}

إنها تقيس الزاوية بين متجهين وتتجاهل أطوالهما، وهذا ما تريده عندما يعكس طول الصف عدد مرات ظهور token أكثر مما يعكس معناه. طبّع كل متجه إلى طول 1 أولًا — كما تفعل الأنظمة الحقيقية، مرة واحدة، عند الفهرسة — وتصبح cosine similarity ببساطة حاصل الضرب النقطي.

إليك أقرب الجيران لبعض الأحرف في الجدول المدرّب:

TEXT
  'c' -> 'k':+0.598      'j' -> 'z':+0.650      'i' -> 'y':+0.541
  'u' -> 'e':+0.482      'a' -> 'h':+0.367      '.' -> 'q':+0.077

بعض ذلك هو ما تعد به الحكايات الشائعة. c وk قابلان للتبادل في الأسماء، وكذلك i وy؛ وj وz كلاهما ساكنان نادران، يظهران غالبًا في البداية ويتصرفان بشكل متشابه. الرمز الحدّي . ليس قريبًا من شيء تقريبًا — 0.077 إلى أقرب حرف — لأنه الرمز الوحيد الذي يعلّم موضعًا لا صوتًا.

وبعضه ليس كذلك. أقرب جار لـ a هو h، لا حرف علة آخر. بالمتوسط على كل الأزواج:

TEXT
mean cosine, vowel to vowel         : +0.1889
mean cosine, consonant to consonant : +0.0765
mean cosine, vowel to consonant     : -0.0042

حروف العلة أشبه ببعضها من شبهها بالحروف الساكنة، والأثر حقيقي لكنه صغير. عند اختباره مقابل 2,000 مجموعة عشوائية من خمسة أحرف، هناك 58 مجموعة تنفصل بالنظافة نفسها على الأقل — فجوة معنوية بنحو p=0.03p = 0.03. إذن هو حقيقي، لكنه لا يشبه الجزيرة الهندسية الصافية التي توحي بها الروايات الشائعة عن embeddings.

هذا هو الوصف الصادق لـ embedding table ويستحق التمسك به لبقية الدورة. إنه ليس خريطة للمعنى. إنه تغيير إحداثيات، متعلَّم لا مصمَّم، ومهمته الوحيدة تسهيل مهمة الطبقة التالية — الجملة نفسها التي استخدمها الفصل 5 للطبقة المخفية التي طوت المستوى لحل XOR. أي بنية تجدها فيه موجودة لأنها خفضت الخسارة، والبنية التي لا تخفض الخسارة ببساطة غير موجودة.

word2vec وGloVe والحساب الذي يقتبسه الجميع

رابط إلى القسم: word2vec وGloVe والحساب الذي يقتبسه الجميع

إذا كان الجزء المفيد هو الجدول، فيمكنك استهدافه مباشرة. هذا هو word2vec: احتفظ بـ embedding lookup، وارمِ نموذج اللغة.5

هدف skip-gram with negative sampling سطر واحد. لزوج حقيقي (مركز، سياق) مسحوب من corpus، ارفع حاصل ضربهما النقطي؛ ولـ kk أزواج زائفة مسحوبة من توزيع ضجيج، اخفضه:6

logσ(vcvo)+i=1klogσ(vcvni)\log \sigma(\mathbf{v}_c \cdot \mathbf{v}_o) + \sum_{i=1}^{k} \log \sigma(-\mathbf{v}_c \cdot \mathbf{v}_{n_i})

هذا تصنيف ثنائي — "هل ظهرت هاتان الكلمتان معًا فعلًا؟" — وهو رخيص تحديدًا لأنه لا يلمس المفردات كاملة أبدًا، وهذا ما جعل التدريب على مليارات الكلمات عمليًا في 2013. يصل GloVe إلى متجهات مشابهة من الاتجاه الآخر، عبر تحليل مصفوفة عدّادات التزامن العالمية بدل التدفق عبر الأمثلة.7 كلاهما مضبوط على الإحصاء نفسه الذي بُني منه جدول العدّ. إنهما عدّ مضغوط.

عند التدريب على text8 — 17,005,207 كلمة من ويكيبيديا الإنجليزية، 71,290 منها تظهر خمس مرات على الأقل، 100 بُعد، ثلاث تمريرات — تخرج المتجهات بالخاصية التي جعلتها مشهورة:

TEXT
king     -> charles 0.700, son 0.693, queen 0.686, henry 0.669, throne 0.667
physics  -> chemistry 0.672, electromagnetism 0.661, quantum 0.654, theoretical 0.624
guitar   -> bass 0.733, vocals 0.732, acoustic 0.728, guitars 0.703, drums 0.685
three    -> seven 0.892, two 0.877, one 0.875, five 0.871, four 0.870

لم يزوّد أحد فئة للآلات الموسيقية أو للأعداد. الآن الجزء الشهير: خذ king، اطرح man، أضف woman، وابحث عن أقرب متجه إلى النتيجة.

TEXT
king - man + woman
   nothing excluded : king 0.693, elizabeth 0.657, wife 0.629, woman 0.607
   a, b, c excluded : elizabeth 0.657, wife 0.629, mary 0.607   (queen is 4th, 0.604)

أقرب متجه إلى king - man + woman هو king. هذه ليست غرابة في مثال واحد. مجموعة تقييم Mikolov تطرح أسئلة من الشكل a : b :: c : ? — 8,869 دلالية (paris : france :: rome : italy) و10,675 تركيبية (walking : walked :: swimming : swam) — وعبر 4,103 سؤالًا دلاليًا تستطيع هذه المفردات الإجابة عنه، يكون الفائز إحدى الكلمات الثلاث المدخلة 99.8 % من الوقت. العروض المنشورة لا تذكر ذلك، لأن قاعدة التسجيل القياسية تحذف a وb وc قبل النظر. إنها قاعدة مشروعة، وهي تنجز عملًا أكثر من الحساب:

كيف تُختار الإجابةدلاليتركيبي
offset، مع استبعاد المدخلات (قياسي)17.0 %11.9 %
offset، من دون استبعاد شيء0.1 %0.4 %
أقرب جار لـ c وحده، مع استبعاد المدخلات13.1 %9.3 %
أقرب جار لـ b وحده، مع استبعاد المدخلات2.3 %0.4 %

الصف الثالث هو الذي يستحق التأمل. ارمِ a وb، لا تجرِ أي حساب إطلاقًا، أعد أي شيء هو الأقرب إلى c — وستحتفظ بـ 77 % من الدرجة الدلالية. معظم ما يبدو reasoning تماثليًا هو قرب زائد قاعدة تمنع الإجابات الواضحة، وهذا ما قاسه Linzen على متجهات مدرّبة كما ينبغي، وما تكرره خطوط الأساس أعلاه.8 هذه المتجهات بالذات صغيرة — 17 مليون كلمة مقابل المليارات خلف النماذج المنشورة — لذلك اقرأ النسب كشكل، لا كحالة الفن. الشكل هو ما يبقى عند كل مقياس: الحساب حقيقي، وأضعف بكثير من العرض الوحيد الذي يقتبسه الجميع.

Static وcontextual: متجه واحد لكل كلمة، أو واحد لكل ظهور

رابط إلى القسم: Static وcontextual: متجه واحد لكل كلمة، أو واحد لكل ظهور

كل ما سبق له حدّ صلب مضمّن في بنية البيانات. للجدول صف واحد لكل token. كلمة bank تحصل على متجه واحد، المتجه نفسه في جملة عن نهر وجملة عن رهن عقاري — بالضرورة، لأن lookup بحسب id لا يمكن أن يعتمد على أي شيء آخر.

الإصلاح هو التوقف عن قراءة المتجه من الجدول والبدء في حسابه من الجملة. هذا هو contextual embedding، الذي قدّمه ELMo في 2018 وجعله BERT معيارًا في العام نفسه.910 عند القياس على النموذج الحقيقي، تكون الأرقام أوضح من الشرح:

TEXT
sentence A: "He sat on the bank of the river and watched the water go by."
sentence B: "She deposited the cheque at the bank on the corner of the street."

static vector for 'bank' (a row of the input embedding table)
    cosine A vs B ........................ 1.000000

contextual vector for 'bank', layer by layer
    layer  |  A vs B  |  A vs another river sentence  |  B vs another money sentence
        0  |  0.9512  |            0.9512             |            0.9359
        4  |  0.5647  |            0.8987             |            0.7716
        9  |  0.4284  |            0.8699             |            0.7568
       12  |  0.5278  |            0.8702             |            0.7335

الصف الأول دقيق، لا تقريبي: المتجه static لكلمة bank هو الأرقام الـ 768 نفسها في الجملتين، لذلك يكون cosine مساويًا لـ 1 بحكم البناء. بعد تسع طبقات، يقع الظهوران عند 0.43، بينما تبقى bank في جملتين مختلفتين عن النهر عند 0.87. لم يوسم أحد معنىً في أي مكان من هذه العملية؛ انفصلت المعاني لأن فصلها يجعل هدف التدريب — تخمين token مخفي من جيرانه — أسهل إرضاءً.

تفصيلان يستحقان الانتباه. الطبقة 0 هي بالفعل 0.9512 بدلًا من 1.0، لأن position embeddings أُضيفت والكلمة تقع في موضع مختلف في كل جملة. كما أن التشابه يرتفع من جديد في الطبقتين 11 و12: الطبقات الأخيرة من نموذج pretrained متخصصة في هدف تدريبه، وغالبًا ليست أفضل مكان لأخذ تمثيل منه.

عرض التفاصيل

اختياري: weight tying.

في bert-base-uncased، embedding table هو 30,522×76830{,}522 \times 768 — 23,440,896 رقمًا، أي 21.4 % من معلمات النموذج البالغة 109,482,240. في نموذج لغة صغير تكون النسبة أكبر أيضًا، ولهذا فإن حيلة واحدة شبه شاملة: جدول الإدخال وطبقة الإخراج التي تنتج logits هما المصفوفة نفسها، تُستخدم مرة عبر lookup صفّي ومرة منقولة.11 طبقة الإخراج تسند بالفعل متجهًا لكل إدخال في المفردات — إنها تأخذ حاصل ضرب نقطي مع كل واحد — وweight tying يقول إن المتجه المستخدم لـ قراءة token والمتجه المستخدم لـ كتابته يجب أن يكونا الكائن نفسه. يقلل المعلمات ويحسن Perplexity في آن واحد، وهذا نادر بما يكفي لملاحظته.

للبحث في corpus بحسب المعنى تحتاج إلى متجه واحد لكل جملة. عندما تملكها، يصبح البحث تافهًا — هذا هو كامل semantic retrieval، والفصل 19 يدور حول كل ما حوله:

search.pyPYTHON
E = normalise(embed(sentences))       # (200, d), every row of length 1
q = normalise(embed([query]))         # (1, d)
scores = q @ E.T                      # one matrix multiply   
top5 = scores[0].argsort()[::-1][:5]

لذلك فالسؤال الحقيقي الوحيد هو من أين يأتي embed. الحركة البديهية هي أخذ نموذج لغة pretrained، وتمرير كل جملة خلاله، ثم حساب متوسط متجهات الـ token. ها هي تلك الطريقة مقابل أربع بدائل، مسجلة بطريقتين: rank correlation بين cosine وأحكام التشابه البشرية عبر 1,379 زوجًا من معيار STS، وtop-1 retrieval على فهرس مبني من أقوى 200 زوج paraphrase بينها — يُفهرس جانب من كل زوج، ويُستخدم الآخر query.

كيف تُضمَّن الجملةrank correlationtop-1 على فهرس من 200 جملة
تداخل كلمات ثنائي (بلا نموذج إطلاقًا)0.550089.0 %
متوسط المتجهات static المدرّبة أعلاه0.526385.5 %
BERT، الـ token [CLS]0.203067.0 %
BERT، متوسط متجهات الـ token0.472984.0 %
MiniLM، مدرّب contrastively0.820392.0 %

اقرأ الصفوف الثلاثة الوسطى مقابل أول صفين. transformer pretrained بـ 109 ملايين معلمة، مستخدمًا بالطريقة البديهية، أسوأ في الحكم على تشابه الجمل من عدّ عدد الكلمات المشتركة بين جملتين — وأسوأ من متوسط متجهات text8 ذات الـ 100 بُعد التي دربناها قبل لحظة. token [CLS]، الذي لا تزال الدروس توصي به لأن BERT دُرّب مسبقًا مع هدف على مستوى الجملة ملحق به، أسوأ من نصف ذلك.

هذا ليس عيبًا في BERT. إنه الهدف. يُدرَّب نموذج اللغة بحيث تتنبأ حالاته المخفية بـ token؛ لا شيء هناك يطلب من paraphrases أن تنتهي قريبة من بعضها، ولا شيء يكافئ هندسة يعني فيها cosine "المعنى نفسه". الصف الأخير نموذج بخمس الحجم (22,713,216 معلمة) مدرّب على خسارة مختلفة تمامًا: contrastive learning، حيث تكون الأمثلة أزواجًا — سؤالًا وجوابه، جملة وparaphrase لها — والهدف يسحب الأزواج الصحيحة معًا ويدفع السلبيات المعيّنة بعيدًا. هذه مساهمة Sentence-BERT وأصل صناعة embedding model كلها.12 يطبّق Dense Passage Retrieval الوصفة نفسها مباشرة على البحث، مع encoder واحد للاستعلامات وآخر للمقاطع.13

إذن، القاعدة العملية:

embedding model ليس نموذج لغة بعد إزالة طبقته الأخيرة. إنه نموذج مختلف على هدف مختلف، غالبًا أصغر بكثير، ويعني فيه cosine ما تريده أن يعنيه لأنه دُرّب على أزواج كان ذلك هو الهدف فيها. الجدول أعلاه هو تكلفة استبدال أحدهما بالآخر.

وهذه العائلة تفشل في ترتيب الكلمات. "The dog bit the man" و"the man bit the dog" لهما كيس الكلمات نفسه، لذلك يعطيهما تداخل الكلمات ومتوسط المتجهات static قيمة cosine تساوي بالضبط 1.000000، وBERT المجمّع بالمتوسط، مع أنه يرى الموضع، يهبط قريبًا جدًا من ذلك — وحتى MiniLM المدرّب contrastively يضعهما عند 0.979. إذا كانت مهمة retrieval لديك تعتمد على من فعل ماذا بمن، فلن ينقذك أي عتبة cosine.

يبني الفصل 19 نظام retrieval إنتاجيًا على هذا الأساس ويصل إلى حدّ cosine ملموس. القياس الأخير في هذا الفصل هو ما يجعل مثل هذا الرقم قابلًا للدفاع بدلًا من أن يكون سحرًا.

للـ embeddings الحقيقية مئات أو آلاف المكونات، والمسافات تتصرف بغرابة هناك. خذ 1,000 نقطة عشوائية في مكعب الوحدة ذي dd أبعاد، وانظر إلى النسبة بين أكبر وأصغر مسافة بين أي نقطتين:

الأبعادأقرب زوجأبعد زوجالنسبة
20.00071.36121921.66
100.23612.33979.91
1003.00475.17521.72
1,00011.780914.03061.19
10,00039.615242.01251.06

في عشرة آلاف بُعد، يكون أبعد زوج من النقاط أبعد بنسبة 6 % فقط من أقرب زوج. كل شيء على مسافة متقاربة تقريبًا من كل شيء آخر، و"أقرب جار" يتوقف عن حمل معلومات كثيرة، وتلك هي لعنة الأبعاد — وهي أيضًا أحد أسباب أن قواعد البيانات المتجهية الكبيرة لا تجري بحث أقرب جار دقيقًا. الوجه الآخر للعملة نفسها هو ما يجعل عتبات cosine قابلة للعمل: عند القياس على ألف زوج من متجهات وحدة عشوائية، يقع متوسط cosine عند 0.0052-0.0052 في 100 بُعد و+0.0003+0.0003 في 768، مع انحرافين معياريين 0.0968 و0.0357 — وفي 768 بُعدًا لا يتجاوز سوى 0.2 % من الأزواج العشوائية قيمة 0.1 بالقيمة المطلقة. لذلك فتشابه مقاس قدره 0.4 لا يعني "متشابهان 40 %"؛ بل هو بعيد جدًا عن أي شيء تنتجه الصدفة، ولهذا تفصل العتبات بين 0.3 و0.7 الإشارة عن الضجيج بدلًا من أن تقع في منتصفه.

النموذج في هذا الفصل يقرأ عددًا ثابتًا من الأحرف السابقة، يبحث عن كل واحد منها ويلصق النتائج معًا بالترتيب. لهذا التصميم مشكلتان، وهما المشكلة نفسها.

انظر مرة أخرى إلى جدول السياق: الانتقال من ثلاثة أحرف إلى ثمانية ضاعف المعلمات تقريبًا واشترى 0.06 nats. الكلفة تنمو خطيًا مع السياق — كل موضع إضافي يحتاج إلى شريحة خاصة به من مصفوفة الأوزان الأولى — أما الفائدة فلا. ادفعه إلى ألف tokens وستصبح الطبقة الأولى وحدها أثقل من بقية النموذج، ومعظمها مصروف على مواضع لا تهم لأي تنبؤ بعينه.

وهذه هي المشكلة الثانية: لا يملك النموذج أي طريقة ليقرر أيًا من الـ tokens السابقة يهم. الموضع الثاني له أوزانه والموضع السابع له أوزانه، بشكل دائم، مهما كان ما فيهما. عندما يهجئ النموذج nell، يكون الحرف الحاسم هو الذي يسبقه مباشرة. وعندما تحتوي جملة على ضمير، قد تكون الكلمة التي تحدد مرجعه قبل أربعين tokens — ولا يمكن تخصيص خانة ثابتة لـ "أربعين إلى الوراء"، لأنها في المرة التالية ستكون ستة.

ما نريده هو نموذج يحسب، لكل تنبؤ، مقدار مساهمة كل token سابق — أوزانًا على السياق ينتجها المحتوى لا يثبتها التخطيط. اكتب ذلك بعناية فيبدأ كشيء عادي تمامًا: متوسط على الـ tokens السابقة. ثم دع أوزان ذلك المتوسط تُتعلّم، ودعها تعتمد على الـ token الذي يطرح السؤال.

هذا هو attention، وهو الفصل 9.


ومن المفيد أيضًا القراءة بالتوازي: الفصل 3 من كتاب Jurafsky وMartin Speech and Language Processing، الذي يعالج نماذج n-gram وsmoothing وPerplexity بعناية أكبر بكثير مما تتسع له المساحة هنا، بما في ذلك سبب تفوق interpolation وback-off على إضافة واحد؛ وملاحظات Stanford CS229 §17.1–17.2 لنمذجة اللغة من الجانب الاحتمالي؛ وورقة Linzen أعلاه، فهي قصيرة وتستحق القراءة كاملة.

  1. مثال توليد الأسماء، ومجموعة البيانات، والتدرج من جدول عدّ إلى شبكة بأسلوب Bengio، تتبع سلسلة Andrej Karpathy building makemore، التي تمثل أول جزأين منها أفضل رفيق لهذا الفصل.

  2. Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). مشاركون بشر يخمنون الحرف التالي من الإنجليزية، والقياس الأصلي لـ bits لكل حرف.

  3. Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). مبرهنة ترميز المصدر، وتحديد التنبؤ بوصفه ضغطًا.

  4. Bengio, Y., Ducharme, R., Vincent, P. and Jauvin, C. A Neural Probabilistic Language Model. Journal of Machine Learning Research 3, pp. 1137–1155 (2003). المعمارية المستخدمة أعلاه: embedding لكل كلمة، ملصوقة عبر نافذة ثابتة، عبر طبقة مخفية، إلى softmax على المفردات.

  5. Mikolov, T., Chen, K., Corrado, G. and Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW وskip-gram، ومجموعة القياس بالتماثلات المستخدمة أعلاه.

  6. Mikolov, T., Sutskever, I., Chen, K., Corrado, G. and Dean, J. Distributed Representations of Words and Phrases and their Compositionality. arXiv:1310.4546 (2013). negative sampling، وخفض عينات الكلمات الشائعة، وتوزيع الضجيج المرفوع إلى قوة 3/4 المستخدم أعلاه.

  7. Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. متجهات كلمات من factorisation لمصفوفة التزامن العالمية بدل النوافذ المحلية المتدفقة.

  8. Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. مصدر خطوط الأساس بلا offset التي كُررت أعلاه.

  9. Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: متجه واحد لكل ظهور، يحسبه نموذج لغة ثنائي الاتجاه.

  10. Devlin, J., Chang, M.-W., Lee, K. and Toutanova, K. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv:1810.04805 (2018). النموذج المقاس في تجربة bank.

  11. Press, O. and Wolf, L. Using the Output Embedding to Improve Language Models. arXiv:1608.05859 (2016), and Inan, H., Khosravi, K. and Socher, R. Tying Word Vectors and Word Classifiers. arXiv:1611.01462 (2016). حجتان مستقلتان للحيلة نفسها.

  12. Reimers, N. and Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). قياسه الافتتاحي — BERT المجمّع بالمتوسط يؤدي دون المتجهات static المجمّعة على تشابه الجمل — هو ما يعيده الجدول أعلاه.

  13. Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). تدريب contrastive لمسترجع ذي encoderين؛ السلف المباشر لحزمة retrieval في الفصل 19.

هل أنت مستعد لتترك الاختيار لـ LIA؟

ابنِ بكل نماذج الذكاء الاصطناعي في مكان واحد — ابدأ مجانًا اليوم.