پرش به محتوا
8/30فصل 8 از 30

پیش‌بینی token بعدی: embeddingها و معنای Perplexity

یک مدل کاراکتری را روی 32,033 نام آموزش دهید و ببینید gradient descent جدول شمارش را تا چهار رقم اعشار بازمی‌یابد.

در این صفحه

اینجا ده نام را می‌بینید که برنامه‌ای تولید کرده که هرگز کلمه‌ای ندیده است:

TEXT
cexze   momakurailezitynn   konimittain   llayn   ka
da      moliellavo          emia          sade    ftlsp

هیچ‌کدامشان نام نیست. تقریباً همه‌شان تلاش می‌کنند نام باشند. قابل تلفظ‌اند، جایی تمام می‌شوند که نام‌ها تمام می‌شوند، و یکی از آن‌ها — emia — فقط یک حرف با یک نام واقعی فاصله دارد. برنامه‌ای که آن‌ها را تولید کرده 729 عدد در خود دارد، هیچ تصوری از کلمه، هجا یا انسان ندارد، و با یک گذر ساده برای شمارش جفت‌حروف مجاور برازش شده است.

تا پایان این فصل، یک شبکهٔ عصبی امتیاز همان برنامه را با همان معیار، یک‌سوم کاهش خواهد داد. بخش ارزشمند ماجرا کاری است که شبکه ابتدا انجام می‌دهد: بدون prompt، جدول شمارش را تا سه رقم اعشار روی هر ردیف پُرنمونه بازتولید می‌کند، چون این دو شیء پاسخ‌هایی به یک پرسش‌اند. هرچه بعد از آن می‌آید، چیزی است که شمارش هرگز نمی‌توانست انجام دهد.

هدف یک همانی است، نه یک انتخاب طراحی

لینک به بخش: هدف یک همانی است، نه یک انتخاب طراحی

فصل 7 شما را با دنباله‌ای از اعداد صحیح رها کرد و هیچ دلیلی نداد که چرا یکی باید پس از دیگری بیاید. دلیلش اینجاست، و فقط یک خط از فصل 2 است.

یک مدل زبانی تابعی است که tokenهای تا این لحظه را می‌گیرد و توزیعی روی اینکه کدام 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 بعدی با دانستن قبلی‌ها — از قبل کار بزرگِ نسبت‌دادن احتمال به هر سند ممکن را هم دقیقاً و رایگان انجام داده است. قاب‌بندی رایجِ این موضوع به‌عنوان یک حقهٔ ارزان («فقط کلمهٔ بعدی را پیش‌بینی می‌کند») منطق را وارونه می‌بیند: پیش‌بینی token بعدی همان مدل‌کردن توزیع مشترک است. هیچ‌وقت کار دومی وجود نداشت.

تابع زیان نیز به همان اندازه مکانیکی به‌دست می‌آید. در هر جایگاه، مدل یک توزیع qq تولید می‌کند و حقیقت یک token معلوم است، پس آنتروپی متقاطعِ فصل 4 بدون تغییر اعمال می‌شود:

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

این میانگین لگاریتم منفی درست‌نمایی است — دستور فصل 2 با یک توزیع رده‌ای در جایی که گاوسی نشسته بود. و چون توزیع واقعی one-hot است، آنتروپی‌اش صفر است؛ بنابراین طبق همانی فصل 4، آنتروپی متقاطع برابر با واگرایی KL است: پایین‌آوردن این عدد و کشیدن باورهای مدل به سمت داده‌ها یک عمل واحدند.

یک پیامد سزاوار جمله‌ای جداگانه است، چون واقعیت اقتصادیِ زیر کل این حوزه است. برچسب‌ها همان داده‌ها هستند، فقط یک جایگاه جابه‌جا شده‌اند. هیچ‌کس چیزی را annotation نمی‌کند. یک تریلیون token متن، یک تریلیون نمونهٔ ازپیش‌برچسب‌خورده است؛ برای همین corpus آموزشی یک مدل مدرن «اینترنت» است، نه «datasetای که کسی ساخته».

پیش از هر شبکه‌ای، خط پایه: 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 نیست: تقسیم شمارش‌ها بر مجموع ردیف‌ها برآورد بیشینهٔ درست‌نمایی برای یک توزیع رده‌ای است، همان دستور فصل 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 جفتی است که در نام‌های واقعی رخ می‌دهد؛ فقط هفده‌تا از آن‌ها پشت سر هم آمده‌اند. مدل فقط حافظهٔ یک‌حرفی دارد، پس نمی‌تواند بداند بیش از حد ادامه داده است.

Perplexity، و اینکه چطور آن را بخوانیم

لینک به بخش: Perplexity، و اینکه چطور آن را بخوانیم

زیان روی نام‌های کنارگذاشته‌شده 2.4546 نَت است. این عدد به‌تنهایی هیچ معنایی ندارد، و به همین دلیل 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())             

توانی‌کردن، لگاریتم را خنثی می‌کند و عدد را به واحدهای شمردن چیزها برمی‌گرداند. راه تمیز برای دیدن اینکه چه چیزی را می‌شمارد این است که مدلی را اندازه بگیریم که هیچ چیز نمی‌داند — مدلی که مستقل از context به هر نماد احتمال 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 مدل شمارشی یعنی یک حرف context، عدم‌قطعیت آن را به اندازهٔ کسی پایین می‌آورد که به‌جای بیست‌وهفت گزینه، کورکورانه از میان حدود دوازده گزینه انتخاب می‌کند — برای همین perplexity نقل می‌شود و زیان خام نه.

دو چیز در مورد آن خراب می‌شود، و دومی حتی در مقاله‌های منتشرشده هم خراب می‌شود.

احتمال‌های صفر مرگبارند. از 729 خانهٔ جدول، 113 تا هرگز در آموزش رخ نمی‌دهند — 15.5 % جدول خالی است. این مشکلی ندارد تا وقتی مجموعهٔ کنارگذاشته‌شده به یکی از آن‌ها برخورد کند، و هفت bigram در validation چنین می‌کنند، از جمله dq، zj و qo که دو بار رخ می‌دهد. احتمال صفر یعنی log -\infty، یعنی زیان بی‌نهایت و perplexity بی‌نهایت: یک نام در سه‌هزار تا معیار را نابود می‌کند. وصلهٔ معمول این است که پیش از نرمال‌سازی، به هر شمارش 1 اضافه کنیم، که اینجا تقریباً هیچ هزینه‌ای ندارد (2.4546 به‌جای 2.4524). اما این وصله یک اعتراف است. مدل شمارشی اصلاً نمی‌تواند تعمیم دهد. هیچ راهی ندارد که حدس بزند qo محتمل است چون qu رایج است و o در جاهای دیگر مثل u رفتار می‌کند، چون هیچ تصوری ندارد که دو نماد می‌توانند شبیه هم باشند. هر خانه جداگانه آموخته می‌شود، و اصلاح همین مسئله موضوع ادامهٔ این فصل است.

Perplexity قیمتی به‌ازای هر token است، و token یک پارامتر آزاد است. این اشتباهی است که دائماً هنگام مقایسهٔ مدل‌ها دیده می‌شود، و وقتی نگاه کنید به‌راحتی معلوم می‌شود. همان corpus نثر انگلیسی از فصل 7 را بردارید، همان مدل bigram درون‌یابی‌شده را، و فقط نحوهٔ خردکردن متن را تغییر دهید:

واحدواژگانtokenها در آزمونآنتروپی متقاطعperplexityبیت به‌ازای هر کاراکتر
کاراکترها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 تغییر می‌کند. هیچ‌چیز دربارهٔ مدل عوض نشده؛ فقط اندازهٔ چیزی که پیش‌بینی می‌شود تغییر کرده است. پیش‌بینی یک واژهٔ کامل از پیش‌بینی یک حرف سخت‌تر است، پس برای هر پیش‌بینی هزینهٔ بیشتری دارد — و تعداد پیش‌بینی‌های کمتری لازم است.

حالا ستون آخر را بخوانید، که به‌جای آن کل هزینه را بر تعداد کاراکترها تقسیم می‌کند و به بیت تبدیل می‌کند. ترتیب جدول را عوض می‌کند. بر اساس perplexity رتبه‌بندی این است: کاراکترها، واژه‌ها، BPE-512، BPE-2048؛ بر اساس بیت به‌ازای هر کاراکتر: واژه‌ها، BPE-2048، BPE-512، کاراکترها. مدل کاراکتری از رتبهٔ اول به آخر می‌رود. مدل 2,048-merge که با perplexity حدود 6.6 برابر بدتر از مدل 512-merge به نظر می‌رسد، در واقع با 2.4254 بیت در برابر 2.6407، بهترِ این دو است.

پس perplexity فقط میان دو مدلی قابل مقایسه است که tokenizer مشترک دارند، و مدل‌هایی با tokenizerهای متفاوت را فقط می‌توان با بیت به‌ازای هر کاراکتر مقایسه کرد — کمیتی که شانون در 1951 با واداشتن انسان‌ها به حدس‌زدن حرف بعدی متن انگلیسی اندازه گرفت و حدوداً با یک بیت به‌ازای هر کاراکتر کران‌بندی کرد.2 بهترین bigram ما روی 2.23 بیت نشسته است، که خلاصهٔ منصفانه‌ای از این است که این فصل هنوز چقدر راه دارد.

همان چیز، این بار آموخته‌شده

لینک به بخش: همان چیز، این بار آموخته‌شده

حالا همان مدل را به‌صورت شبکه بسازید. چندین مرتبهٔ بزرگی محاسبهٔ بیشتری لازم دارد تا به همان جا برسد، و رسیدن به همان جا دقیقاً نکتهٔ ماجراست.

جدول را با یک ماتریس وزن WW با شکل 27×2727 \times 27 جایگزین کنید. حرف فعلی را به یک بردار one-hot تبدیل کنید، ضرب کنید، و نتیجه را logits بنامید — امتیازهای نرمال‌نشدهٔ فصل 4. بعد softmax، بعد آنتروپی متقاطع، بعد 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 است. ماتریسی با یک ردیف برای هر ورودی واژگان، که با token id شاخص‌گذاری می‌شود. نه هندسه‌ای در کار است، نه معناشناسی، نه الگوریتمی جداگانه: یک جدول lookup که محتویاتش همراه با همه‌چیز دیگر با gradient descent آموخته می‌شود. هر ادعای رازآلود دربارهٔ «فضای embedding» در نهایت به همین‌جا ختم می‌شود.

آموزشش دهید و ببینید به کجا می‌رود:

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، از اعداد تصادفی شروع کرد و جز «احتمال لگاریتمی حرف بعدی را بزرگ کن» چیزی به آن گفته نشد، اما جدول شمارش را دوباره کشف کرد. و باید هم این کار را می‌کرد: شمارش‌ها برآورد بیشینهٔ درست‌نمایی‌اند، آنتروپی متقاطع لگاریتم منفی درست‌نمایی است، پس هر دو فرایند یک هدف را بهینه می‌کنند و آن هدف یک بهینه دارد. شبکه چیزی شبیه شمارش یاد نگرفت. کند و آهسته به شمارش همگرا شد.

که سؤال منصفانه‌ای ایجاد می‌کند: پس چرا کسی باید زحمتش را بکشد؟ چون جدول شمارش از اینجا به بعد جایی برای رفتن ندارد، اما شبکه دارد.

مدل را گسترش دهید تا بیش از یک کاراکتر قبلی را ببیند. این معماری Bengio در 2003 است، نیای مستقیم هر مدلی در ادامهٔ این دوره:4 سه کاراکتر آخر را بگیرید، هرکدام را از طریق یک جدول embedding به یک ردیف 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 در ابتدا و یک لایهٔ خروجی به پهنای واژگان فصل 7 هستند — و دومی بخش پرهزینهٔ هر مدل زبانی‌ای است که تاکنون ساخته شده، چون واژگان واقعی 100,000 ورودی دارد و این ضرب ماتریسی در هر جایگاه اجرا می‌شود.

همان کد، با آموزش کاملاً یکسان، و فقط با تغییر اندازهٔ context window:

contextپارامترهازیان validationvalidation perplexity
شمارش، 1 کاراکتر7292.454611.642
عصبی، 1 کاراکتر7,8972.457711.678
عصبی، 3 کاراکتر11,8972.11458.285
عصبی، 8 کاراکتر21,8972.05067.773

ردیف دوم جالب است. شبکه‌ای با یک لایهٔ پنهان 200واحدی و یازده برابر پارامتر بیشتر از جدول شمارش، دقیقاً به‌خوبی جدول شمارش عمل می‌کند و نه بهتر. ظرفیت هرگز محدودیت نبود. یک کاراکتر context مقدار مشخصی زیان را ممکن می‌کند و هرچه هم به آن بچسبانید نمی‌تواند پایین‌تر برود، چون اطلاعات آنجا نیست.

سه کاراکتر به آن بدهید و perplexity از 11.68 به 8.29 می‌افتد — کاهش 29 %، با 4,000 پارامتر اضافه. اینجا دقیقاً به همان دلیلی شمارش را شکست می‌دهد که پیش‌تر تشخیص دادیم: یک مدل شمارشی روی contextهای سه‌کاراکتری به 273=19,68327^3 = 19{,}683 ردیف نیاز دارد، که بیشترشان خالی‌اند یا فقط یک مشاهده دارند، و هرکدام را تنها می‌آموزد. شبکه به‌اشتراک می‌گذارد. اگر a، e و i در نهایت ردیف‌های embedding مشابهی داشته باشند، آنچه پس از bra یاد می‌گیرد به bre منتقل می‌شود، بی‌آنکه هرگز bre را دیده باشد. این انتقال کل ارزش جدول embedding است، و همان شکاف میان ردیف‌های دوم و سوم.

نمونه‌ها نیز متناسب با آن بهتر می‌شوند:

TEXT
deliah   nellara   joce     kael      quintis
salayson  reety    khyrmin  mahnen    madiaryxia

هنوز فهرستی از نام‌های واقعی نیست. اما deliah، nellara و kael در چنین فهرستی نامأنوس به نظر نمی‌رسند، و هیولاهای کش‌دار ناپدید شده‌اند: بلندترینِ بیست نمونه از مدل شمارشی نوزده حرف داشت، بلندترینِ بیست نمونه از این مدل سیزده حرف دارد.

واقعاً داخل جدول embedding چیست

لینک به بخش: واقعاً داخل جدول embedding چیست

جدول 27×1027 \times 10 است: برای هر کاراکتر یک ردیف ده‌عددی، همگی تصادفی مقداردهی اولیه شده‌اند و فقط با gradient زیان کاراکتر بعدی جابه‌جا شده‌اند. هیچ‌کس چیزی داخل آن نگذاشته است. پس چه چیزی در آن شکل گرفت؟

ابزار پرسیدن این سؤال شباهت کسینوسی است، یعنی ضرب داخلیِ فصل 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 نرمال کنید — همان‌طور که سیستم‌های واقعی یک‌بار هنگام index کردن انجام می‌دهند — و شباهت کسینوسی صرفاً ضرب داخلی می‌شود.

اینجا نزدیک‌ترین همسایه‌های چند کاراکتر در جدول آموزش‌دیده را می‌بینید:

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. پس واقعی است، اما هیچ شباهتی به جزیرهٔ هندسیِ واضحی ندارد که روایت‌های عامه‌پسند دربارهٔ embeddingها القا می‌کنند.

این توصیف صادقانهٔ یک جدول embedding است و ارزش دارد آن را برای باقی دوره نگه دارید. نقشهٔ معنا نیست. یک تغییر مختصات است، آموخته‌شده نه طراحی‌شده، که تنها کارش آسان‌کردن کار لایهٔ بعدی است — همان جمله‌ای که فصل 5 برای لایهٔ پنهانی به کار برد که صفحه را تا کرد تا XOR را حل کند. هر ساختاری که در آن پیدا می‌کنید آنجاست چون زیان را پایین آورده، و ساختاری که زیان را پایین نمی‌آورد اصلاً آنجا نیست.

word2vec، GloVe، و حسابی که همه نقل می‌کنند

لینک به بخش: word2vec، GloVe، و حسابی که همه نقل می‌کنند

اگر بخش مفید همان جدول است، می‌توانید مستقیم سراغش بروید. این word2vec است: lookup مربوط به embedding را نگه دارید، مدل زبانی را دور بیندازید.5

هدف skip-gram with negative sampling یک خط است. برای یک جفت واقعی (مرکز، context) که از 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 % امتیاز معنایی را نگه می‌دارید. بیشتر چیزی که شبیه استدلال قیاسی به نظر می‌رسد، نزدیکی به‌علاوهٔ قاعده‌ای است که پاسخ‌های بدیهی را ممنوع می‌کند؛ همان چیزی که Linzen روی بردارهای درست‌آموزش‌دیده اندازه گرفت و خط پایه‌های بالا بازتولیدش می‌کنند.8 این بردارهای خاص کوچک‌اند — 17 میلیون واژه در برابر میلیاردهایی که پشت مدل‌های منتشرشده‌اند — پس درصدها را به‌عنوان شکل بخوانید، نه وضعیت پیشرفتهٔ روز. شکل همان چیزی است که در هر مقیاسی باقی می‌ماند: حساب واقعی است، و بسیار ضعیف‌تر از همان نمایشی که همه نقل می‌کنند.

ایستا و contextual: یک بردار برای هر واژه، یا یکی برای هر رخداد

لینک به بخش: ایستا و 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

ردیف اول دقیق است، نه تقریبی: بردار ایستای bank در هر دو جمله همان 768 عدد است، پس کسینوس بنا به تعریف 1 است. نه لایه بعد، دو رخداد روی 0.43 می‌نشینند، در حالی که bank در دو جملهٔ متفاوت دربارهٔ رودخانه روی 0.87 می‌ماند. هیچ‌کس در هیچ جای این فرایند معنایی را برچسب نزد؛ معناها جدا شدند چون جداکردنشان هدف آموزشی — حدس‌زدن یک token پنهان از همسایه‌هایش — را آسان‌تر می‌کند.

دو جزئیات ارزش توجه دارند. لایهٔ 0 از قبل 0.9512 است نه 1.0، چون position embeddingها اضافه شده‌اند و واژه در هر جمله جای متفاوتی نشسته است. و شباهت در لایه‌های 11 و 12 دوباره بالا می‌رود: لایه‌های نهایی یک مدل pretrained به هدف آموزشی‌اش تخصصی شده‌اند، و اغلب بهترین جای گرفتن representation نیستند.

نمایش جزئیات

اختیاری: weight tying.

در bert-base-uncased جدول embedding برابر 30,522×76830{,}522 \times 768 است — 23,440,896 عدد، 21.4 % از 109,482,240 پارامتر مدل. در یک مدل زبانی کوچک، این کسر حتی بزرگ‌تر است؛ برای همین یک ترفند تقریباً همه‌جا به کار می‌رود: جدول ورودی و لایهٔ خروجی که logits را تولید می‌کند همان ماتریس هستند، یک‌بار با lookup ردیفی و یک‌بار به‌صورت ترانهاده استفاده می‌شوند.11 لایهٔ خروجی همین حالا هم به هر ورودی واژگان یک بردار نسبت می‌دهد — با هرکدام ضرب داخلی می‌گیرد — و tying می‌گوید برداری که برای خواندن یک token استفاده می‌شود و برداری که برای نوشتن آن استفاده می‌شود باید یک شیء واحد باشد. هم پارامترها را کم می‌کند و هم perplexity را بهتر می‌کند، ترکیبی آن‌قدر نادر که ارزش توجه دارد.

یک embedding model مدل زبانی نیست

لینک به بخش: یک embedding model مدل زبانی نیست

برای جست‌وجوی یک corpus بر اساس معنا، به یک بردار برای هر جمله نیاز دارید. با داشتن آن‌ها، جست‌وجو پیش‌پاافتاده است — این کل بازیابی معنایی است، و فصل 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 را بگیرید. این روش را در برابر چهار جایگزین می‌بینید، با دو امتیاز: همبستگی رتبه‌ای میان کسینوس و قضاوت‌های شباهت انسانی روی 1,379 جفت benchmark STS، و بازیابی top-1 روی index ساخته‌شده از 200 جفتِ بیشترین paraphrase — یک سمت هر جفت index شده، سمت دیگر به‌عنوان query استفاده شده است.

روش embedded کردن جملههمبستگی رتبه‌ایtop-1 روی index با 200 جمله
هم‌پوشانی واژهٔ دودویی (بدون هیچ مدلی)0.550089.0 %
میانگین بردارهای ایستای آموزش‌داده‌شدهٔ بالا0.526385.5 %
BERT، token [CLS]0.203067.0 %
BERT، میانگین بردارهای token0.472984.0 %
MiniLM، آموزش‌دیده به‌صورت contrastive0.820392.0 %

سه ردیف میانی را در برابر دو ردیف اول بخوانید. یک transformer pretrained با 109 میلیون پارامتر، وقتی به شکل بدیهی استفاده شود، در قضاوت شباهت جمله‌ها از شمردن اینکه دو جمله چند واژهٔ مشترک دارند بدتر است — و از میانگین‌گرفتن بردارهای 100بعدی text8 که همین چند لحظه پیش آموزش دادیم هم بدتر. token [CLS] که آموزش‌های اینترنتی هنوز توصیه‌اش می‌کنند چون BERT با یک هدف جمله‌سطحی متصل به آن pretrained شده بود، از نصف آن هم بدتر است.

این نقص BERT نیست. مسئله هدف است. یک مدل زبانی طوری آموزش می‌بیند که حالت‌های پنهانش یک token را پیش‌بینی کنند؛ هیچ‌چیز در آنجا نمی‌خواهد دو paraphrase نزدیک هم قرار بگیرند، و هیچ‌چیز به هندسه‌ای پاداش نمی‌دهد که در آن کسینوس یعنی «معنای یکسان». ردیف آخر مدلی است با یک‌پنجم اندازه (22,713,216 پارامتر) که روی زیانی کاملاً متفاوت آموزش دیده است: contrastive learning، که در آن نمونه‌ها جفت‌اند — یک پرسش و پاسخ آن، یک جمله و paraphrase آن — و هدف جفت‌های درست را به هم می‌کشد و negativeهای نمونه‌گیری‌شده را از هم دور می‌کند. این سهم Sentence-BERT و خاستگاه کل صنعت embedding modelهاست.12 Dense Passage Retrieval همین دستور را مستقیماً برای جست‌وجو به کار می‌برد، با یک encoder برای queryها و یکی برای passageها.13

پس قاعدهٔ عملی این است:

یک embedding model، مدل زبانی‌ای نیست که لایهٔ آخرش حذف شده باشد. مدلی متفاوت روی هدفی متفاوت است، معمولاً بسیار کوچک‌تر، که کسینوسش همان معنایی را دارد که می‌خواهید چون روی جفت‌هایی آموزش دیده که همان هدف بوده است. جدول بالا هزینهٔ جایگزین‌کردن یکی با دیگری است.

و این خانواده در ترتیب واژه‌ها شکست می‌خورد. «The dog bit the man» و «the man bit the dog» کیسهٔ واژگان یکسانی دارند، پس هم‌پوشانی واژه و میانگین بردار ایستا به آن‌ها کسینوس دقیقاً 1.000000 می‌دهد، و BERT میانگین‌گیری‌شده که جایگاه را می‌بیند، همچنان تقریباً همان‌جا فرود می‌آید — و MiniLM آموزش‌دیده به‌صورت contrastive هم آن‌ها را روی 0.979 می‌گذارد. اگر وظیفهٔ بازیابی شما به این وابسته است که چه کسی چه کاری با چه کسی کرده، هیچ آستانهٔ کسینوسی نجاتتان نمی‌دهد.

فصل 19 روی همین پایه یک سیستم بازیابی تولیدی می‌سازد و به یک cut-off کسینوسی مشخص می‌رسد. آخرین اندازه‌گیری این فصل همان چیزی است که چنین عددی را قابل دفاع می‌کند، نه جادویی.

embeddingهای واقعی صدها یا هزاران مؤلفه دارند، و فاصله‌ها آن بالا عجیب رفتار می‌کنند. 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 % از نزدیک‌ترین جفت دورتر است. همه‌چیز تقریباً از همه‌چیز به یک اندازه فاصله دارد، «نزدیک‌ترین همسایه» دیگر اطلاعات زیادی حمل نمی‌کند، و این همان نفرین بُعد است — و همچنین یکی از دلایلی که پایگاه‌داده‌های برداری بزرگ جست‌وجوی دقیق نزدیک‌ترین همسایه انجام نمی‌دهند. روی دیگر همین سکه چیزی است که آستانه‌های کسینوسی را قابل استفاده می‌کند: اگر روی هزار جفت بردار واحد تصادفی اندازه بگیریم، میانگین کسینوس در 100 بُعد روی 0.0052-0.0052 و در 768 بُعد روی +0.0003+0.0003 می‌نشیند، با انحراف معیارهای 0.0968 و 0.0357 — و در 768 بُعد فقط 0.2 % از جفت‌های تصادفی از 0.1 از نظر قدر مطلق بالاتر می‌روند. بنابراین شباهت اندازه‌گیری‌شدهٔ 0.4 یعنی «40 % شبیه» نیست؛ بسیار بیرون از هر چیزی است که تصادف تولید می‌کند، و برای همین آستانه‌های بین 0.3 و 0.7 سیگنال را از نویز جدا می‌کنند، نه اینکه وسط آن بنشینند.

بعد از این به کجا می‌رویم

لینک به بخش: بعد از این به کجا می‌رویم

مدل این فصل تعداد ثابتی از کاراکترهای قبلی را می‌خواند، هرکدام را lookup می‌کند و نتایج را به‌ترتیب به هم می‌چسباند. این طراحی دو مشکل دارد، و آن دو در واقع یک مشکل‌اند.

دوباره به جدول context نگاه کنید: رفتن از سه کاراکتر به هشت، پارامترها را تقریباً دو برابر کرد و فقط 0.06 نَت خرید. هزینه به‌صورت خطی با context رشد می‌کند — هر جایگاه اضافه به اسلب خودش از ماتریس وزن اول نیاز دارد — و فایده چنین نمی‌کند. آن را تا هزار token جلو ببرید و لایهٔ اول به‌تنهایی از بقیهٔ مدل سنگین‌تر می‌شود، بیشترش هم صرف جایگاه‌هایی می‌شود که برای پیش‌بینی مشخص اهمیتی ندارند.

و این همان مشکل دوم است: مدل هیچ راهی ندارد تصمیم بگیرد کدام tokenهای قبلی مهم‌اند. جایگاه دو وزن‌های خودش را دارد و جایگاه هفت وزن‌های خودش را، برای همیشه، هرچه داخلشان باشد. وقتی مدل دارد nell را هجی می‌کند، کاراکتر تعیین‌کننده همان قبلیِ بلافصل است. وقتی جمله ضمیری دارد، واژه‌ای که مرجع آن را مشخص می‌کند شاید چهل token عقب‌تر باشد — و هیچ slot ثابتی را نمی‌توان به «چهل تا عقب‌تر» اختصاص داد، چون دفعهٔ بعد شش تا عقب‌تر خواهد بود.

آنچه می‌خواهیم مدلی است که برای هر پیش‌بینی محاسبه کند هر token قبلی چقدر باید حساب شود — وزن‌هایی روی context که محتوا تولیدشان می‌کند، نه چیدمان ثابت. اگر این را دقیق بنویسید، به چیزی کاملاً معمولی آغاز می‌شود: میانگینی روی tokenهای قبلی. بعد بگذارید وزن‌های آن میانگین آموخته شوند، و بگذارید به اینکه کدام token سؤال می‌پرسد وابسته باشند.

این همان attention است، و موضوع فصل 9.


همچنین ارزش دارد هم‌زمان بخوانید: فصل 3 کتاب Speech and Language Processing نوشتهٔ Jurafsky و Martin، که مدل‌های n-gram، هموارسازی و perplexity را بسیار دقیق‌تر از فضایی که اینجا داریم بررسی می‌کند، از جمله اینکه چرا interpolation و back-off از اضافه‌کردن یک بهترند؛ یادداشت‌های Stanford CS229 بخش‌های §17.1–17.2 برای مدل‌سازی زبانی از سمت احتمالاتی؛ و مقالهٔ Linzen در بالا، که کوتاه است و ارزش خواندن کامل را دارد.

  1. مثال تولید نام، dataset و مسیر از جدول شمارش تا شبکه‌ای به سبک Bengio، از مجموعهٔ building makemore نوشتهٔ Andrej Karpathy پیروی می‌کند؛ دو بخش اول آن بهترین همراه این فصل‌اند.

  2. Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). آزمودنی‌های انسانی که حرف بعدی انگلیسی را حدس می‌زدند، و اندازه‌گیری اولیهٔ بیت به‌ازای هر کاراکتر.

  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، subsampling واژه‌های پرتکرار، و توزیع نویزی به توان 3/4 که در بالا استفاده شد.

  7. Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. بردارهای واژه از فاکتورگیری ماتریس هم‌رخدادی جهانی به‌جای پنجره‌های محلیِ جریان‌یافته.

  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 میانگین‌گیری‌شده در شباهت جمله‌ها از بردارهای ایستای میانگین‌گرفته‌شده ضعیف‌تر عمل می‌کند — همان چیزی است که جدول بالا بازتولید می‌کند.

  13. Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). آموزش contrastive یک بازیاب دو-encoder؛ نیای مستقیم stack بازیابی فصل 19.


تهیه‌شده توسط

David Vicente Campos

بنیان‌گذار NeuraLIA Labs و هم‌بنیان‌گذار MyRealFood

من مهندس کامپیوتر و فارغ‌التحصیل دانشگاه لئون هستم. هم‌بنیان‌گذار MyRealFood بودم، جایی که به‌عنوان مدیر ارشد فناوری اپلیکیشنی را ساختم که میلیون‌ها نفر برای سالم‌تر غذا خوردن از آن استفاده کرده‌اند، و NeuraLIA Labs را بنیان‌گذاری کردم؛ جایی که محصولات هوش مصنوعی می‌سازم. اینجا از چیزهایی می‌نویسم که در طول مسیر باید می‌فهمیدم، همان‌طور که دوست داشتم کسی برایم توضیح می‌داد.

بیشتر درباره نویسنده

منتشرشده توسط NeuraLIA Labs.

پست‌های جدید را در ایمیل خود دریافت کنید

اخبار AI، راهنماها و به‌روزرسانی‌های محصول — هر وقت چیزی ارزشمند منتشر کنیم، یک ایمیل کوتاه می‌فرستیم.

فهرست دوره

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev12 دقیقه مطالعه

مدل هوش مصنوعی Jev برای تصمیم ساخته شده، نه نثر

Jev از TypeSafe AI توجه‌ها را جلب کرده چون هوشمندی نرم‌افزار را مسئله‌ای احتمالاتی می‌بیند: شاخه درست را انتخاب کنید، میزان اطمینان را کنار آن بگذارید، و وقتی کد به یک تصمیم نیاز دارد برای نوشتن متن به یک LLM پول ندهید.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering13 دقیقه مطالعه

مهندسی کانتکست برای عامل‌های AI بلندافق

عامل‌های طولانی‌اجرا فقط به‌خاطر کوچک بودن پنجره شکست نمی‌خورند. وقتی فایل‌ها، خروجی ابزارها و تاریخچهٔ کهنه وظیفه‌ای را که عامل قرار بود تمام کند کنار می‌زنند، شکست رخ می‌دهد.

آماده‌اید انتخاب مدل را به LIA بسپارید؟

با همه مدل‌های هوش مصنوعی در یک جا بسازید — همین امروز رایگان شروع کنید.