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

Attention و بلوک transformer، از دلِ یک میانگین

از ساده‌ترین خلاصهٔ context شروع کنید: میانگین؛ ببینید کجا شکست می‌خورد و فرمول attention را از تعمیر آن به دست آورید.

در این صفحه

شما با یک tokenizer از فصل 7، یک جدول embedding از فصل 8، و objective همراه آن‌ها به اینجا می‌رسید: با داشتن tokenهای تا اینجا، روی token بعدی یک احتمال بگذارید.

چیزی که کم است میانهٔ کار است. برای پیش‌بینی token tt، model به یک بردار نیاز دارد که همه‌چیز پیش از آن را خلاصه کند، و هیچ‌کدام از چیزهایی که ساخته‌اید چنین برداری تولید نمی‌کند. embedding مربوط به token t1t-1 آن نیست — آن یک bigram model است و نمی‌تواند بداند جمله با یک پرسش شروع شده است. الحاق همهٔ embeddingهای قبلی هم آن نیست: تعدادشان در هر گام تغییر می‌کند، و یک ماتریس وزن ثابت نمی‌تواند ورودی با طول متغیر بگیرد.

پس: یک بردار با اندازهٔ ثابت، که تعداد متغیری از بردارها را خلاصه می‌کند. کل مسئله همین است، و attention چیزی است که وقتی این مسئله را به تنبلانه‌ترین شکل ممکن حل کنید و بعد دو چیزی را که می‌شکند تعمیر کنید، به دست می‌آورید.

پاسخی که این حوزه داشت، و چرا ما آن را نمی‌سازیم

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

از 1997 تا حدود 2017، خلاصه یک حالت بازگشتی بود: برداری h\mathbf{h} را نگه دارید و در هر token آن را به‌روزرسانی کنید، ht=f(ht1,xt)\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t). اندازهٔ ثابت، ورودی متغیر، دقیقاً شکل درست.

این روش از سه جهت شکست خورد، و معماری این فصل به هر سه پاسخ می‌دهد. backpropagation از میان TT گام، TT ژاکوبین را در هم ضرب می‌کند، پس gradient محو یا منفجر می‌شود — همان بیماری‌ای که فصل 5 داخل یک گرهٔ tanh\tanh اندازه گرفت. LSTM1 دقیقاً برای مقابله با همین طراحی شد و بازهٔ قابل استفاده را از ده‌ها گام به صدها رساند، بی‌آنکه این واقعیت را تغییر دهد که اطلاعات token 5 فقط با دوام آوردن در 495 به‌روزرسانی ترتیبی به token 500 می‌رسد. کل منبع باید در یک بردار جا می‌شد: در ترجمهٔ sequence-to-sequence2، یک encoder ورودی را در حالت نهایی‌اش فشرده می‌کند. Bahdanau، Cho و Bengio این گلوگاه را نام‌گذاری کردند و در 2014، سه سال پیش از transformer، با این کار آن را رفع کردند که decoder بتواند از همهٔ حالت‌های encoder یک جمع وزن‌دار بگیرد، با وزن‌هایی که خودش محاسبه می‌کرد.3 همهٔ آنچه در ادامه می‌آید همان ایده است، اعمال‌شده توسط یک دنباله به خودش، با حذف بازگشت. و به‌روزرسانی ذاتاً ترتیبی است: ht\mathbf{h}_t به ht1\mathbf{h}_{t-1} نیاز دارد، و یک GPU با ده‌هزار هسته نمی‌تواند کاری با آن بکند. معماری برنده لزوماً باهوش‌تر نیست؛ همان معماری‌ای است که گام پرهزینه‌اش ضرب ماتریسی است.

سوگیری استقرایی کلاسیک دیگر، convolution — یک فیلتر کوچک را روی کل ورودی بلغزانید، تا ویژگی‌ای که هرجا تشخیص داده شد همه‌جا تشخیص داده شود — اینجا هم ساخته نمی‌شود؛ برای تصویرها تقریباً دقیقاً درست است و به درس بینایی سپرده می‌شود. نه recurrence و نه convolution پس از این صفحه دوباره ظاهر نمی‌شوند، و به همین دلیل هیچ‌کدام فصل ندارند: فصل 1 قول داده بود حذف‌ها اعلام شوند، نه اینکه بی‌سروصدا بگذرند.

ارزان‌ترین خلاصه‌ای که وجود دارد

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

بدیهی‌ترین تابعی که تعداد متغیری از بردارها را می‌گیرد و یک بردار برمی‌گرداند، میانگین است:

ct=1ti=1txi\mathbf{c}_t = \frac{1}{t}\sum_{i=1}^{t} \mathbf{x}_i

هر تعداد ورودی، اندازهٔ خروجی ثابت، مشتق‌پذیر، رایگان. جدول embedding به‌علاوهٔ این میانگین به‌علاوهٔ یک لایهٔ خطی به vocabulary، در پانزده خط یک language model کامل است. و در عین حال وحشتناک است؛ و اینکه چگونه وحشتناک است، کل استنتاج را می‌سازد.

corpus زیر یک مگابایت از Shakespeare است، 1,115,394 کاراکتر، از طریق یک tokenizer نوع byte-level BPE از همان جنسی که در فصل 7 ساخته شد، با vocabulary برابر 1024: در مجموع 459,760 token با میانگین 2.43 کاراکتر برای هرکدام، با split 90/10. همهٔ modelها پهنای 128 دارند، 128 token می‌بینند، و برای 3000 گام AdamW با 10310^{-3} و batch برابر 64 آموزش می‌بینند. Perplexity روی split نگه‌داشته‌شده است.4

modelparametersvalidation perplexity
فقط token فعلی، بدون هیچ context263,16859.71
به‌علاوهٔ میانگین یکنواختِ همه‌چیز پیش از آن263,168248.07
به‌علاوهٔ position embeddingهای آموخته‌شده279,552245.93
میانگین یکنواخت اضافه‌شده به token به‌جای جایگزین‌کردن آن263,16860.45

سطر دوم را دوبار بخوانید. میانگین‌گرفتن از context کمی کمک نمی‌کند؛ model را چهار برابر بدتر از نادیده‌گرفتن کامل context می‌کند. دو دلیل دارد، و هر دو قابل اثبات‌اند نه صرفاً تجربی.

میانگین order را نمی‌بیند. جمع جابه‌جایی‌پذیر است، پس shuffle کردن window خلاصه را بی‌تغییر می‌گذارد — نه تقریباً:

order.pyPYTHON
A = torch.tril(torch.ones(T, T))
A = A / A.sum(1, keepdim=True)          # rows of the averaging matrix
y = x[torch.randperm(T)]                # the same tokens, shuffled
print((A[-1] @ x - A[-1] @ y).abs().max().item())
TEXT
2.9802322387695312e-08

نویز floating-point روی جمعِ بازچیده‌شده: دو خلاصه همان بردارند. modelای که تنها نگاهش به context یک میانگین است، نمی‌تواند the dog bit the man را از the man bit the dog تشخیص دهد. سطر سوم ثابت می‌کند این با افزودن position به ورودی‌ها درست نمی‌شود — یک position embedding آموخته‌شده روی هر token پیش از میانگین‌گیری فقط 2.14 امتیاز از 188 امتیاز را پس گرفت. positionها وارد جمع می‌شوند، و جمع آن‌ها را فراموش می‌کند.

و میانگین، حال را غرق می‌کند. در position 100، token فعلی یک‌صدمِ خلاصه است. این یک تعمیر ارزان دارد که از قبل دارید: token را نگه دارید و خلاصه را به آن اضافه کنید — یک اتصال residual، از فصل 6، و سطر چهارم نشان می‌دهد چه می‌کند. با تعمیر رقیق‌شدن، میانگین یکنواخت هیچ چیزی اضافه نمی‌کند: 60.45 در برابر baseline برابر 59.71. هر token آنجاست، با وزن برابر، و وزن‌دهی برابر همان بی‌اطلاعی است.

مسئله خودِ میانگین‌گیری نیست. مسئله وزن‌ها هستند.

میانگین یک ضرب ماتریسی است، و mask یک softmax است

لینک به بخش: میانگین یک ضرب ماتریسی است، و mask یک softmax است

میانگین‌گیری روی prefix رو‌به‌رشد شبیه یک loop است. اما یک ضرب در یک ماتریس پایین‌مثلثی است که جمع سطرهایش یک می‌شود — و همچنین، دقیقاً، یک softmax:

mechanics.pyPYTHON
loop = torch.stack([x[:t + 1].mean(0) for t in range(T)])   # the obvious version

A = torch.tril(torch.ones(T, T))
A = A / A.sum(1, keepdim=True)
mat = A @ x                                                  # the same thing

S = torch.zeros(T, T).masked_fill(torch.tril(torch.ones(T, T)) == 0, float("-inf"))
soft = F.softmax(S, dim=-1) @ x                              # and the same thing again
TEXT
loop vs matmul   max |diff| = 5.960464477539063e-08
loop vs softmax  max |diff| = 5.960464477539063e-08

the averaging matrix A (rows sum to 1, upper triangle is zero):
  1.000 0.000 0.000 0.000 0.000 0.000
  0.500 0.500 0.000 0.000 0.000 0.000
  0.333 0.333 0.333 0.000 0.000 0.000
  0.250 0.250 0.250 0.250 0.000 0.000
  0.200 0.200 0.200 0.200 0.200 0.000
  0.167 0.167 0.167 0.167 0.167 0.167

سه جزء نام‌دارِ transformer حالا روی صفحه‌اند. مثلث همان causal mask است، که objective آن را تحمیل می‌کند: اگر position tt می‌توانست position t+1t{+}1 را ببیند، پاسخ داخل ورودی بود — همان نشتی‌ای که فصل 6 به شما گفت audit کنید، فقط این بار داخل معماری. softmax روش پیاده‌سازی mask است: گذاشتن -\infty در ورودی‌های ممنوع آن‌ها را دقیقاً به صفر می‌فرستد و آنچه می‌ماند را نرمال می‌کند، پس masking و normalizing یک عملیات‌اند. (از -\infty استفاده کنید، نه -1e9: این همان مقداری است که masking معنا می‌دهد، در cast به float16 به‌صورت -\infty دوام می‌آورد، و شما را از تصمیم‌گیری دربارهٔ اینکه ثابت انتخابی‌تان برای بازه‌ای که اتفاقاً در آن هستید به‌اندازهٔ کافی بزرگ هست یا نه نجات می‌دهد — یعنی همان جعبهٔ floating-point در فصل 2 که سوالی می‌پرسد که لازم نیست جواب دهید.) و scoreها پارامتر آزادند. میانگین یکنواخت چیزی است که وقتی همهٔ scoreهای مجاز یک عدد یکسان باشند به دست می‌آورید؛ هر عددی آنجا بگذارید و softmax آن‌ها را به وزن‌های معتبر تبدیل می‌کند.

بقیهٔ این فصل یک سوال است: این عددها از کجا می‌آیند؟

نمی‌توانند پارامترهای ساده باشند. یک ماتریس آموخته‌شدهٔ T×TT \times T برای هر جمله یکسان می‌بود — می‌توانست «چهار token قبل را نگاه کن» را encode کند، اما هرگز «به اسمی نگاه کن که این ضمیر به آن اشاره دارد» را. وزنی که position tt را به position ii وصل می‌کند باید به آنچه در هر دو position است وابسته باشد، چون ارتباط یک رابطه است، نه یک ویژگی: واژهٔ it ذاتاً relevant نیست، نسبت به چیزی relevant است.

ارزان‌ترین تابعی که دو بردار می‌گیرد و یک عدد برمی‌گرداند، dot product فصل 1 است. position ii را برای position tt به‌صورت xtxi\mathbf{x}_t \cdot \mathbf{x}_i score کنید و سازوکار کار می‌کند — بد کار می‌کند، به دو شکل که بقیهٔ اجزا را تحمیل می‌کنند. dot product یک بردار با خودش برابر نرمِ به‌توان‌دو آن است، پس هر token عمدتاً به خودش attention می‌دهد. و رابطه متقارن خواهد بود: اگر it با قدرت به animal attention بدهد، آنگاه animal هم با قدرت به it attention می‌دهد، که دربارهٔ زبان نادرست است؛ یک صفت بسیار بیشتر به اسمش نیاز دارد تا اسم به صفت.

پس به هر token دو نقش بدهید، به‌صورت دو نگاشت خطیِ آموخته‌شده از آن: اینکه این position دنبال چه می‌گردد، qt=Wqxt\mathbf{q}_t = W_q\mathbf{x}_t، یعنی query؛ و اینکه چه چیزی عرضه می‌کند تا با آن پیدا شود، ki=Wkxi\mathbf{k}_i = W_k\mathbf{x}_i، یعنی key. امتیاز را qtki\mathbf{q}_t \cdot \mathbf{k}_i بگیرید و تقارن از بین می‌رود، چون WqWkW_q \neq W_k: یک token می‌تواند چیزی را تبلیغ کند و دنبال چیز دیگری بگردد.

یک چیز هنوز غلط است. جمع وزن‌دار روی خودِ xi\mathbf{x}_iها بود، که اجبار می‌کند چیزی که کپی می‌شود همان چیزی باشد که match می‌شود. Matching ویژگی‌هایی را می‌خواهد که یک token را شناسایی می‌کنند؛ copying ویژگی‌هایی را می‌خواهد که downstream مفیدند. پس نگاشت سومی بیاموزید، vi=Wvxi\mathbf{v}_i = W_v\mathbf{x}_i، یعنی value، و آن‌ها را جمع کنید.

فرمول حالا حسابداری است:

Attention(Q,K,V)=softmax ⁣(QKdk+M)V\mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}} + M\right)V

که در آن MM causal mask است، صفر روی قطر و زیر آن و -\infty بالای آن. در code سی خط است، که بیست خطش shapeها هستند:

attention.pyPYTHON
class Head(nn.Module):
    """One head of causal self-attention."""

    def __init__(self, d_model, d_head, block):
        super().__init__()
        self.q = nn.Linear(d_model, d_head, bias=False)      
        self.k = nn.Linear(d_model, d_head, bias=False)      
        self.v = nn.Linear(d_model, d_head, bias=False)      
        self.d_head = d_head
        self.register_buffer("mask", torch.tril(torch.ones(block, block)).bool())

    def forward(self, x):
        T = x.shape[1]
        q, k, v = self.q(x), self.k(x), self.v(x)
        s = q @ k.transpose(-2, -1) / math.sqrt(self.d_head)          
        s = s.masked_fill(~self.mask[:T, :T], float("-inf"))          
        w = F.softmax(s, dim=-1)                                      
        return w @ v                                                  

Score، mask، normalise، mix. بقیه projection است.

تقسیم بر ریشهٔ دوم، و چیزی که در برابرش دفاع می‌کند

لینک به بخش: تقسیم بر ریشهٔ دوم، و چیزی که در برابرش دفاع می‌کند

تقریباً هر توضیحی دربارهٔ dk\sqrt{d_k} می‌گوید «برای اینکه softmax اشباع نشود»، که درست است و هیچ‌چیز را توضیح نمی‌دهد. استدلال دو خط از واریانسِ فصل 2 است. اگر ورودی‌های q\mathbf{q} و k\mathbf{k} مستقل، با میانگین صفر و واریانس یک باشند، هر حاصل‌ضرب qjkjq_j k_j واریانس یک دارد، و واریانسِ چیزهای مستقل جمع می‌شود:

Var(qk)=j=1dkVar(qjkj)=dk\mathrm{Var}(\mathbf{q}\cdot\mathbf{k}) = \sum_{j=1}^{d_k}\mathrm{Var}(q_j k_j) = d_k

پس scoreها انحراف معیار dk\sqrt{d_k} دارند. اندازه‌گیری روی بیست‌هزار جفت تصادفی:

TEXT
     d     Var(q.k)         std   sqrt(d)
     4        3.975       1.994     2.000
    16       16.071       4.009     4.000
    64       64.249       8.016     8.000
   256      253.065      15.908    16.000
  1024     1015.562      31.868    32.000

چرا مهم است: softmax نسبت به scale حساس است، به شکلی که یک لایهٔ خطی نیست. دو برابر کردن ورودی یک لایهٔ خطی خروجی‌اش را دو برابر می‌کند؛ ضرب‌کردن scoreها در ده پیش از softmax یک ترکیب نرم را به یک انتخاب سخت تبدیل می‌کند. یک سطر از 64 score، با تقسیم و بدون تقسیم:

dkd_kبزرگ‌ترین وزن، تقسیم‌نشدهentropytokenهای مؤثربزرگ‌ترین وزن، تقسیم‌شدهentropytokenهای مؤثر
40.2052.94419.00.0813.75842.9
160.4381.6925.40.0753.84946.9
640.4890.8742.40.0853.67339.4
2560.99990.00071.00.1433.54734.7
10241.00000.00001.00.1323.64438.3

«tokenهای مؤثر» نماییِ entropy است: اینکه سطر واقعاً روی چند position میانگین می‌گیرد. بدون تقسیم، در dk=256d_k = 256، یک head تازه initialised دقیقاً به یک token از 64 attention می‌دهد، آن هم با انتخابی که هیچ‌چیز جز نمونه‌گیری تصادفی تعیینش نکرده است.

این در مسیر forward بد است و در backward بدتر، با شکلی که فصل 5 روی یک tanh\tanh اندازه گرفته بود. softmaxای که به یک ورودی متعهد شده تقریباً هیچ مشتقی ندارد: قطر ژاکوبین آن wi(1wi)w_i(1-w_i) است، که در هر دو انتها صفر می‌شود. روی دوهزار سطر تصادفی:

dkd_kiwi(1wi)\sum_i w_i(1-w_i) تقسیم‌نشدهتقسیم‌شدهسطرهای اشباع‌شده (بزرگ‌ترین وزن بالای 0.99)
40.84270.95680.2 % → 0.0 %
640.29400.960917.9 % → 0.0 %
2560.14060.960949.1 % → 0.0 %
10240.06810.961170.4 % → 0.0 %

در dk=1024d_k = 1024، هفت سطر از ده سطر پیش از شروع آموزش frozen شده‌اند، و headای که frozen شروع کند نمی‌تواند یاد بگیرد به چه چیزی نگاه کند. با تقسیم، این کمیت در همهٔ پهناها روی 0.96 صاف می‌ماند و هیچ‌چیز اشباع نمی‌شود.

حالا بخشی که هیچ‌کس منتشر نمی‌کند: آیا perplexity نهایی را تغییر می‌دهد؟ تقسیم را حذف کنید و در چهار پهنای head آموزش دهید:

پهنای headتقسیم‌نشدهتقسیم بر dk\sqrt{d_k}تقسیم بر dkd_k
چهار head، dk=32d_k = 3237.2938.0737.89
یک head، dk=128d_k = 12848.5146.1045.99
یک head، dk=256d_k = 25665.3747.53
یک head، dk=512d_k = 51267.0649.15
یک head، dk=1024d_k = 102476.6959.17

دو سطر اول از بودجهٔ 3000 گامی بالا می‌آیند؛ سه سطر آخر یک اجرای کوتاه‌ترند — 1500 گام، batch برابر 32، یک head، بدون normalization پیش از projectionها — با هر دو variant در تنظیمات یکسان.

در dk=32d_k = 32 تقسیم هیچ ارزشی ندارد و اجرای بدون آن اندکی جلوتر است. این مجوزی برای حذفش نیست، چون در 256 به‌اندازهٔ 18 امتیاز perplexity ارزش دارد و در 1024 به‌اندازهٔ 17. مکانیزم در خود scoreها پیداست:

dkd_kانحراف معیار score در initپس از 1500 گام، تقسیم‌نشدهپس از 1500 گام، تقسیم‌شدهسطرهای اشباع‌شده، تقسیم‌نشدهتقسیم‌شده
25610.49121.672.1391.9 %0.8 %
51215.13836.852.6698.7 %1.3 %
102421.155147.463.4499.9 %16.5 %

head تقسیم‌نشده recover نمی‌کند. فرار می‌کند: انحراف معیار scoreهایش از 21 در initialisation به 5147 می‌رسد، entropy مربوط به attention به صفر می‌افتد، و 99.9 % سطرها بیش از 0.99 وزن خود را روی یک token می‌گذارند. وقتی یک head به selector سخت تبدیل شود، gradient آن تقریباً صفر است و هیچ‌چیز آن را عقب نمی‌کشد، پس collapse پایدار است. head تقسیم‌شده پس از همان آموزش روی انحراف معیار score برابر 3.44 می‌نشیند، یعنی ترکیبی نرم که هنوز می‌توان تغییرش داد.

Vaswani و همکاران دقیقاً همین را می‌گویند و نه بیشتر — آن‌ها گمان می‌کنند حاصل‌ضرب‌ها برای مقادیر بزرگ dkd_k «از نظر magnitude بزرگ می‌شوند» و تقسیم می‌کنند.5 واژهٔ بزرگ بار اصلی را به دوش می‌کشد، و جدول‌ها نشان می‌دهند بزرگی از کجا شروع می‌شود: هیچ‌چیز در 32، همه‌چیز تا 256.

بیش از یک نظر، و دو سومی که کسی درباره‌اش حرف نمی‌زند

لینک به بخش: بیش از یک نظر، و دو سومی که کسی درباره‌اش حرف نمی‌زند

یک head یعنی یک سطر softmax برای هر position، پس یک پاسخ به «اینجا چه چیزی relevant است» دارد. پیش‌بینی واژهٔ بعد از the در the animal that crossed the wet street هم‌زمان به جایگاه نحوی، subject و token قبلی نیاز دارد، و یک توزیع احتمال نمی‌تواند در سه جا متمرکز باشد. پس چند head را موازی اجرا کنید، هرکدام با پهنای dmodel/hd_{\text{model}}/h، concatenate کنید، و با یک ماتریس دیگر WoW_o mix کنید: پهنا را بخش‌بندی کرده‌اید، نه اینکه به آن اضافه کرده باشید.

Attention همچنین دقیقاً یک کار می‌کند — اطلاعات را بین positionها جابه‌جا می‌کند. هر عملیات در code بالا در امتداد محور feature خطی است، و فصل 5 ثابت کرد پشته‌ای از نگاشت‌های خطی چیست. پس هر block یک MLP کوچک هم دارد که روی هر position مستقل اعمال می‌شود، پهنا را چهار برابر می‌کند و برمی‌گرداند، با یک GELU در میانه. تقسیم کار ارزش حفظ‌کردن دارد: attention بین positionها mix می‌کند، شبکهٔ feed-forward داخل یک position محاسبه می‌کند.

نردبان کامل، هر سطر یک قطعه به سطر بالایی اضافه می‌کند:

modelparametersvalidation perplexity
میانگین یکنواخت، اضافه‌شده279,55260.45
یک attention head، جایگزین token328,70455.47
یک attention head، اضافه‌شده328,70446.10
چهار head به‌جای یکی345,21643.21
به‌علاوهٔ شبکهٔ feed-forward476,92839.87
به‌علاوهٔ LayerNorm — block کامل477,69638.07

وزن‌های آموخته‌شده 14 امتیاز perplexity بهتر از وزن‌های یکنواخت‌اند، که کل استدلال این فصل در یک سطر است. چهار head با 16,512 پارامتر اضافی، 3 امتیاز دیگر می‌خرد. و همان head وقتی اضافه شود 9 امتیاز بیشتر از وقتی جایگزین شود ارزش دارد: attention اطلاعات را وارد می‌کند، تصمیم نمی‌گیرد یک position چیست.

حالا پارامترها واقعاً کجا نشسته‌اند؛ چیزی که برای کسانی که فقط diagram را دیده‌اند غافلگیرکننده است:

پهناheadهاattentionfeed-forwardکل برای هر block
128465,664 (33.2 %)131,712 (66.6 %)197,888
768122,360,064 (33.3 %)4,722,432 (66.6 %)7,085,568
40963267,112,960 (33.3 %)134,238,208 (66.7 %)201,367,552

دو سوم هر transformer block شبکهٔ feed-forward است، در هر scale، چون attention چهار ماتریس d×dd \times d دارد و MLP معادل هشت‌تا. هرچه یک model بداند، بیشتر پارامترهایی که آن را نگه می‌دارند در MLP per-position هستند.

Residualها و LayerNorm، به ارث رسیده از فصل 6

لینک به بخش: Residualها و LayerNorm، به ارث رسیده از فصل 6

LayerNorm در فصل 6 ساخته و اندازه‌گیری شد، و این فصل همان‌طور که آنجا باقی ماند از آن استفاده می‌کند؛ اتصال‌های residual آنجا نام‌گذاری و ablate شدند، و اینجا ساخته می‌شوند. سطرهای «اضافه‌شده، نه جایگزین» بالا اتصال‌های residual هستند، که برای میانگین 188 امتیاز perplexity و برای یک head 9 امتیاز ارزش دارند. LayerNorm7 هر example را در سراسر featureهایش normalise می‌کند، و فصل 6 دلیل‌هایی را داد که چرا این و نه BatchNorm اینجا دوام آورد — بی‌وابستگی به batch، نبود آمار running، یکسان بودن در training و inference، بی‌تفاوتی به طول sequence — که هرکدام وقتی یک token در هر لحظه برای یک user تولید می‌کنید به یک requirement تبدیل می‌شود؛ همان‌جایی که فصل 13 به آن می‌رسد. 768 پارامتر هزینه دارد و 1.8 امتیاز perplexity می‌خرد.

block.pyPYTHON
class Block(nn.Module):
    def forward(self, x):
        x = x + self.att(self.ln1(x))     
        x = x + self.ff(self.ln2(x))      
        return x

به محل normalisation نگاه کنید: روی ورودی هر sub-layer، با مسیر residual از ورودی تا خروجی که هرگز normalise نمی‌شود. این pre-norm است. مقالهٔ 2017 برعکس عمل می‌کند، x = LayerNorm(x + Att(x)) — یعنی post-norm، که LayerNorm را روی خود مسیر residual می‌گذارد.

Xiong و همکاران تفاوت را از طریق gradient در initialisation توضیح دادند، که در شبکهٔ post-norm با عمق به‌بدی scale می‌شود — همان دلیلی که transformer اصلی اصلاً برای آموزش به warmup در learning rate نیاز داشت.8 دوازده block، 1000 گام، learning rate برابر 3×1033 \times 10^{-3}:

TEXT
gradient norm per block at initialisation, before any step
  pre-norm    block 1 0.0498 ... block 12 0.0657   ratio last/first  1.32
  post-norm   block 1 0.0977 ... block 12 0.1613   ratio last/first  1.65

  pre-norm,  no warmup          perplexity   37.82
  pre-norm,  200-step warmup    perplexity   37.62
  post-norm, no warmup          perplexity  308.05
  post-norm, 200-step warmup    perplexity   37.88

Post-norm بدون warmup هشت برابر بدتر است، و post-norm با warmup دقیقاً با pre-norm برابر می‌شود. Warmup اینجا یک practice خوب عمومی نیست؛ وصله‌ای برای چیدمان خاصی از normalisation است، و جابه‌جا کردن LayerNorm نیاز به آن را حذف می‌کند. به همین دلیل تقریباً هر model از 2019 به بعد pre-norm است، و به همین دلیل diagram سال 2017 باید به‌عنوان تاریخ خوانده شود، نه specification.

position embeddingها را حذف کنید و model همچنان train می‌شود؛ فقط نمی‌تواند بفهمد چیزی کجاست، و این یک تقارن است نه شکست آموزش. هیچ‌چیز در score مربوط به attention خودِ tt یا ii را ذکر نمی‌کند، پس permute کردن ورودی خروجی را permute می‌کند: self-attention permutation-equivariant است. این همان نابیناییِ میانگین نسبت به order است در لباسی بهتر — causal mask مقداری order را بازمی‌گرداند، چون هر position prefix متفاوتی می‌بیند، اما درون یک prefix همهٔ orderها یکسان‌اند.

چهار راه برای تزریق position، آموزش‌دیده روی windowهای 64-token و ارزیابی‌شده در 64، 128 و 256 — فراتر از هر طولی که دیده بودند:

positionهاperplexity در 64در 128در 256
هیچ‌کدام48.7952.6357.52
embeddingهای absolute آموخته‌شده38.63108.47181.94
sinusoidهای ثابت42.9695.26152.25
RoPE44.1250.5284.84
ALiBi44.9543.5142.49

embeddingهای absolute آموخته‌شده — یک بردار برای هر position، افزوده‌شده به token — در طول آموزش‌دیده برنده می‌شوند و بعد از پرتگاه می‌افتند، چون position 100 هرگز در batch نبوده و embedding آن هنوز همان بردار تصادفیِ شروع کار است. Sinusoidها، انتخاب اولیه، به‌جای آموخته‌شدن محاسبه می‌شوند، از سینوس و کسینوس با فرکانس‌های هندسی فاصله‌گذاری‌شده؛ مقالهٔ 2017 امیدوار بود این extrapolate کند، و جدول می‌گوید نمی‌کند — تابع در position 200 تعریف شده، اما model هرگز یاد نگرفته آن را آنجا بخواند. RoPE9 چیزی اضافه نمی‌کند و در عوض query و key را با زاویه‌ای متناسب با position، در برش‌های دو‌بعدی می‌چرخاند؛ چون چرخاندن هر دو طرف یک dot product به یک اندازه آن را بی‌تغییر می‌گذارد، score در نهایت فقط به tit - i وابسته می‌شود، پس position رایگان relative می‌شود و جدولی وجود ندارد که تمام شود. افت می‌کند، اما افت‌کردنش تدریجی است. ALiBi10 ساده‌ترین و عجیب‌ترین نتیجهٔ اینجاست: یک جریمهٔ خطی روی score متناسب با فاصله، با شیب متفاوت برای هر head. Perplexity آن وقتی window از طول آموزش‌دیده می‌گذرد بهتر می‌شود، از 44.95 به 42.49، چون جریمه در هر فاصله‌ای تعریف شده و هر head همان کاری را ادامه می‌دهد که برایش آموزش دیده بود.

درس، بیشتر از جدول دوام می‌آورد: معماری‌ای که نمی‌تواند چیزی را بازنمایی کند مسئله‌ای متفاوت از معماری‌ای است که هرگز آن بازه را یاد نگرفته، و دومی همان چیزی است که گاز می‌گیرد. این همچنین machinery پشت هر اعلامیهٔ «context را به 128K گسترش دادیم» است — آن‌ها تقریباً همیشه rescalingهای یک encoding چرخشی‌اند، و به همین دلیل فصل 16 می‌گوید محدودیت context جابه‌جا می‌شود، نه اینکه ناپدید شود.

Dropout هم به همان شکل به ارث می‌رسد: روی وزن‌های attention پس از softmax، روی خروجی هر sub-layer پیش از جمع residual، و روی جمع embedding ظاهر می‌شود، و دقیقاً همان کاری را می‌کند که فصل 6 توصیف کرد. در pretrainingهای بزرگ اغلب روی صفر تنظیم می‌شود، چون modelای که هر token را یک‌بار می‌بیند در موقعیتی نیست که overfit کند.

دو tensor در لایه شکل n×nn \times n دارند، که در آن nn تعداد tokenهاست: scoreها و وزن‌های پس از softmax. همهٔ چیزهای دیگر — هر projection، کل MLP — نسبت به nn خطی است.

یک لایهٔ attention، پهنای 512، هشت head، batch یک، float32، روی GPU لپ‌تاپ. دو ستون میلی‌ثانیه را فقط برای نسبت‌هایشان بخوانید: زمان wall clock روی کارت لپ‌تاپ 8 GB است که وقتی داغ می‌شود از 1,785 MHz به زیر 300 MHz throttling می‌کند، پس یک اجرای سرد از همین code هفت تا ده برابر سریع‌تر برمی‌گردد و اجرای مشغول هنوز کندتر. ستون‌های مگابایت شمارش byteهای allocator هستند و جابه‌جا نمی‌شوند.

TEXT
  tokens   ms total    ms x4   ms projections   attn matrix MB    peak MB    MB x4
     128      2.246        -            1.324              0.5       14.6        -
     256      2.855     1.27            2.113              2.0       19.2     1.31
     512      5.761     2.02            3.105              8.0       34.4     1.79
    1024     16.414     2.85            4.008             32.0       89.1     2.59
    2048     51.573     3.14            9.989            128.0      296.1     3.32
    4096    225.432     4.37           20.176            512.0     1100.1     3.72
    8192    832.838     3.69           40.106           2048.0     4300.1     3.91
   16384   OUT OF MEMORY                                 8192.0

fitted exponent (log-log slope, last four rows):  time ~ n^1.91   memory ~ n^1.87

ستون‌های x4 نسبت به سطر بالایی هستند، و دو برابر کردن nn برای زمان و memory دقیقاً به 4 همگرا می‌شود — 3.91 در گام آخر در برابر 4 نظری. ستون projectionها کنترل است: از 4.0 ms در 1024 token تا 40.1 ms در 8192، ضریب ده برای ضریب هشت. خطی، همان‌طور که وعده داده شد.

بعد سطر آخر. یک لایهٔ attention، یک sequence، بدون هیچ modelی اطراف آن، روی GPU هشت‌گیگابایتی در 16,384 token از memory خارج می‌شود — فقط ماتریس score برابر 8 GB خواهد بود، یعنی 8 head ضربدر 16,384 ضربدر 16,384 ضربدر 4 byte. نه model؛ یک tensor میانی در یک لایه.

این واقعیت فیزیکی زیرِ سه فصل بعدی است. دلیل این است که context window اصلاً limit دارد، چیزی که فصل 16 آن را به price تبدیل می‌کند. دلیل وجود FlashAttention است، که همان نتیجه را در tileها محاسبه می‌کند بی‌آنکه هرگز ماتریس را ذخیره کند — پیش از آنکه بهینه‌سازی سرعت باشد، بهینه‌سازی memory است.11 و arithmetic پشت قیمت یک prompt طولانی است، که فصل 24 آن را در یک loop مربوط به agent می‌پردازد — مسئله‌ای جدا از یافتهٔ دیگر آن فصل، یعنی اینکه model همچنین از context طولانی بدتر استفاده می‌کند، که آن را اندازه می‌گیرد و سرزنشش را به گردن این فرمول نمی‌اندازد.

نمایش جزئیات

دو variant کوچک‌کنندهٔ cache، اینجا نام‌گذاری‌شده و در فصل 13 هزینه‌شان پرداخت می‌شود.

Generation کلیدها و مقدارهای tokenهای قبلاً پردازش‌شده را cache می‌کند — یک key و یک value برای هر token، برای هر head در هر layer. Multi-query attention12 تعداد hh projection مربوط به query را نگه می‌دارد، اما یک projection یکتای key و value را میان همهٔ headها مشترک می‌کند، و آن cache را بر hh تقسیم می‌کند. Grouped-query attention13 میان این‌ها interpolates می‌کند: headها گروه‌بندی می‌شوند، هر گروه یک key و value مشترک دارد، پس g=hg = h attention معمولی است و g=1g = 1 multi-query. تقریباً هر open model از 2023 به بعد از آن با 4 یا 8 گروه استفاده می‌کند. هیچ‌کدام برای quality وجود ندارد؛ هر دو برای اندازهٔ آن cache وجود دارند، و فصل 13 حسابی را انجام می‌دهد که آن را به «کدام model در GPU شما جا می‌شود» تبدیل می‌کند.

مقالهٔ 2017 یک encoder-decoder را توصیف می‌کند: یک stack که منبع را با attention بدون mask می‌خواند، دومی که هدف را causally تولید می‌کند، و نوع سومی از attention در میانه که queryهای decoder با keyهای encoder روبه‌رو می‌شوند. این برای ترجمه درست است، جایی که input و output دو sequence هستند.

چیزی که برنده شد نیمهٔ decoder-only بود — یک stack، سراسر causal، input و output در همان sequence — و دلیلش elegance نیست. «token بعدی را پیش‌بینی کن» روی هر متنی اجرا می‌شود، پس training set اینترنت است نه corpus موازی، و همه‌چیز همان یک task می‌شود: ترجمه سندی است که source و سپس target را در خود دارد، پرسش و پاسخش یک سندند، گفت‌وگویی با tool call در میانه یک سند است. فصل 11 دربارهٔ این است که آخری چگونه ساخته می‌شود. Encoderها ناپدید نشدند — یکی کل input را یک‌جا می‌بیند، که وقتی کار بازنمایی یک متن است نه ادامه‌دادنش، همان چیزی است که می‌خواهید، و به همین دلیل embeddingهای retrieval در فصل 19 از encoderها می‌آیند نه از modelای که chat می‌کند.

با تعریف block، اندازهٔ model حساب است. برای هر block، با پهنای dd و expansion چهاربرابر: 4d2+4d4d^2 + 4d برای Wq,Wk,Wv,WoW_q, W_k, W_v, W_o با bias روی هر چهار، همان‌طور که GPT-2 دارد — جدول بالا bias را از سه‌تای آن‌ها حذف می‌کند، بنابراین در d=768d = 768 برای هر block تعداد 2,304 کمتر دارد؛ 8d2+5d8d^2 + 5d برای MLP؛ 4d4d برای دو LayerNorm — 12d2+13d12d^2 + 13d، به‌علاوهٔ جدول token برابر V×dV \times d و، برای positionهای absolute، nctx×dn_{\text{ctx}} \times d. برای شکل GPT-2 small — d=768d = 768، 12 block، vocabulary برابر 50,257، context برابر 1024، و output layer که وزن‌های embedding را share می‌کند:

TEXT
  token embeddings     50,257 x 768 = 38,597,376
  position embeddings   1,024 x 768 =    786,432
  one block                             7,087,872
  12 blocks                            85,054,464
  final LayerNorm         2 x 768 =        1,536
  total (weights tied)                124,439,808

که همان اندازهٔ منتشرشدهٔ آن model است. فرمول تقریب نیست؛ خود model است. همچنین توجه کنید که تقریباً یک‌سوم یک model کوچک جدول embedding است، و به همین دلیل اندازهٔ vocabulary یک تصمیم معماری است نه یک تصمیم preprocessing — همان trade-offای که فصل 7 چید.

یک head واقعاً به چه چیزی نگاه می‌کند

لینک به بخش: یک head واقعاً به چه چیزی نگاه می‌کند

Perplexity عددی دربارهٔ یک corpus است. اینکه یک head چه می‌کند سوال دیگری است، و modelای که روی یک مگابایت Shakespeare آموزش دیده ابزار غلطی برای آن است: حرف صادقانه دربارهٔ attention map یک model با 500,000 پارامتر این است که عمدتاً قابل تفسیر نیست. پس: زبانی که در آن پرسش پاسخ درست دارد.

تصویر کلاسیک the animal did not cross the street because it was too tired است، که در آن it همان animal است، در برابر …because it was too wet، که یک واژه مرجع را به street منتقل می‌کند. این‌ها Winograd schemaها هستند14 — جفت‌جمله‌هایی که جز در یک واژه یکسان‌اند، و همان واژه تعیین می‌کند ضمیر به چه چیزی اشاره دارد.

آن‌ها همچنین با تقلب حل‌شدنی‌اند، و این همان بخشی است که tutorialها از قلم می‌اندازند. اگر دو candidate یکی animal و دیگری place باشند، tired و wet مرجع را بر اساس category مشخص می‌کنند، و modelای که فقط می‌داند کدام واژه‌ها حاضرند، بی‌آنکه چیزی دربارهٔ order بداند، درست جواب می‌دهد. اندازه‌گیری روی آن نسخهٔ task، با جفت‌های animal/place نگه‌داشته‌شده:

TEXT
uniform causal average           held-out referent accuracy 100.0 %
one transformer block            held-out referent accuracy  91.7 %

Bag of words از transformer بهتر است. هر نمایشی که روی آن جمله ساخته شود هیچ‌چیز دربارهٔ attention ثابت نمی‌کند.

پس شکاف را ببندید: هر دو candidate را از یک pool شانزده‌تایی اسم‌ها بکشید، که هرکدام می‌توانند در هر slot ظاهر شوند، و adjectiveها را نه بر اساس category بلکه بر اساس role split کنید — چهار مورد که it را crosser می‌کنند (tired, scared, slow, weak)، چهار مورد که آن را crossed می‌کنند (wet, wide, busy, steep).

TEXT
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .

مثل یک predictor معمولیِ next-token آموزش دهید، یک position را score کنید — واژهٔ پس از so the — و held-out set را از جفت‌اسم‌هایی بسازید که order معکوس آن‌ها در training بوده، پس هرچیزی که بداند کدام دو اسم حاضرند اما نداند کدام اول آمده، باید برعکس جواب دهد.

modelparametersheld-outاسم دیگر را نام می‌برد
فقط token فعلی5,7965.2 %5.2 %
میانگین causal یکنواخت5,79627.9 %50.0 %
یک head از attention آموخته‌شده18,08435.4 %64.6 %
چهار head22,24475.0 %15.6 %
یک transformer block55,71692.7 %4.2 %
دو transformer block105,508100.0 %0.0 %

شانس میان دو اسم حاضر 50 % است. میانگین یکنواخت روی 27.9 % می‌نشیند و دقیقاً نصف مواقع با اسم غلطِ آن جفت جواب می‌دهد — امضای چیزی که می‌داند کدام واژه‌ها آنجا هستند و هیچ‌چیز دربارهٔ orderشان نمی‌داند، همان‌طور که test مربوط به shuffle سه بخش پیش پیش‌بینی کرد.

حالا map: attention در positionای که باید مرجع را نام ببرد، میانگین‌گرفته‌شده روی چهار head هر block، برای دو جمله‌ای که با یک واژه فرق دارند. میانگین یکنواخت روی هرکدام از پانزده token قابل مشاهده 0.067 می‌گذاشت.

TEXT
the animal did not cross the street because it was too tired , so the animal waited .
  blk 1  the:0.00 animal:0.70 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.06
         because:0.00 it:0.00 was:0.00 too:0.00 tired:0.00 ,:0.05 so:0.00 the:0.19
  blk 2  the:0.00 animal:0.00 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.00
         because:0.00 it:0.00 was:0.00 too:0.00 tired:1.00 ,:0.00 so:0.00 the:0.00

the animal did not cross the street because it was too wet , so the street waited .
  blk 1  the:0.00 animal:0.70 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.06
         because:0.00 it:0.00 was:0.00 too:0.00   wet:0.00 ,:0.05 so:0.00 the:0.19
  blk 2  the:0.00 animal:0.00 did:0.00 not:0.00 cross:0.03 the:0.00 street:0.49
         because:0.00 it:0.00 was:0.00 too:0.20   wet:0.03 ,:0.00 so:0.00 the:0.25

Block 1 در هر دو جمله یکسان است — 0.70 روی اسم اول، هرچه adjective باشد. این شکست نیست بلکه اثبات است: در لایهٔ اول، query در یک position تابع token و index خودِ همان position است، و the در position 14 در هر دو جمله همان token است. head لایهٔ اول نمی‌تواند به واژه‌ای condition شود که هنوز fetch نکرده است. پس block 1 تنها کار مفید در دسترس را انجام می‌دهد و اسم اول را به جلو می‌کشد.

Block 2 جایی است که جمله‌ها از هم جدا می‌شوند، و همان سطر در همهٔ هشت adjective نشان می‌دهد model چه ruleای پیدا کرده است:

adjectiveblock 2 روی animalروی streetروی adjectiveپاسخ
tired, scared, slow, weak0.0000.0001.000animal
wet, wide, busy, steep0.0000.4910.00–0.03street

برای یک crosser-adjective، block دوم تمام وزنش را روی adjective می‌گذارد، چون پاسخ از قبل در residual stream است — block 1 آن را آنجا گذاشته — و تنها چیزی که لازم دارد confirmation است. برای یک crossed-adjective، می‌رود و اسم دیگر را fetch می‌کند. این یک مدار دو-hop است: یک head یک candidate را جلو می‌آورد، headای در لایهٔ بعدی tokenی را می‌خواند که تصمیم می‌گیرد آن را نگه دارد یا نه. Composition در میان لایه‌ها مکانیزم است، و به همین دلیل یک block به 92.7 % و دو block به 100 % رسیدند.

این همچنین شکل بهترین مدار مستندسازی‌شده در modelهای واقعی است. Induction headها — یک previous-token head که به headای در لایهٔ بعدی feed می‌دهد تا pattern [A][B] … [A] → [B] را کامل کند — همان چیزی‌اند که کار interpretability در Anthropic پشت بخش بزرگی از in-context learning شناسایی می‌کند، و در لحظه‌ای قابل شناسایی طی pretraining شکل می‌گیرند. این فصل آن تحلیل را انجام نمی‌دهد: با هر دو مقاله در references واگذار می‌شود، چون بیرون‌کشیدن circuitها از یک model واقعی یک میدان پژوهشی است نه یک بخش.

در نهایت، implementation. همان سی خط بالا، با weightهایی که از خود PyTorch کپی شده‌اند:

TEXT
ours vs nn.MultiheadAttention           max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention  max |diff| = 1.7881393432617188e-07

1.8×1071.8 \times 10^{-7} روی خروجی‌هایی که میانگین magnitudeشان 0.159 است: همان arithmetic در order متفاوت، با دقت float32.

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

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

شما معماری‌ای را دارید که هر model در بقیهٔ این دوره بر پایهٔ آن ساخته می‌شود، و از شهرتش کوچک‌تر است: یک میانگین وزن‌دار که وزن‌هایش آموخته می‌شوند، یک MLP per-position که دو سوم پارامترها را نگه می‌دارد، دو normalisation و دو addition، stack شده.

چیزی که ندارید modelای است که چیزی بداند، و stack کردن به‌تنهایی آن را درست نمی‌کند. دو block روی این corpus به training perplexity برابر 14.49 و validation perplexity برابر 40.57 می‌رسند، در برابر 18.77 و 38.07 برای یک block — ظرفیت بیشتر، بهتر روی آنچه دیده، بدتر روی آنچه ندیده، یعنی همان جدول فصل 6 با یک transformer داخل آن. فاصلهٔ این model با modelهایی که فصل‌های 14 تا 30 با آن‌ها حرف می‌زنند معماری نیست. همان block است، که دفعات بیشتری تکرار شده، روی متن بسیار بسیار بیشتر.

پس مسئله به حسابداری تبدیل می‌شود، و حسابداری عجیب‌تر از چیزی است که به نظر می‌رسد. چقدر متن، و اصلاً کسی از کجا آن را می‌آورد؟ چقدر arithmetic، و چگونه آن را پیش از خرج‌شدن پول estimate می‌کنید؟ با یک بودجهٔ ثابت، بهتر است model را بزرگ‌تر کنید یا دادهٔ بیشتری به آن نشان دهید — و آیا پاسخ درستی وجود دارد، یا فقط مد؟ فصل 10 هر سه را با اندازه‌گیری پاسخ می‌دهد، و روی ارزان‌ترین شکل مفیدِ پرسش قیمت می‌گذارد: امروز آموزش modelای مثل GPT-2 از صفر چقدر هزینه دارد؟


سه توضیح از این material در کاری که برایش نوشته شده‌اند بهتر از این یکی‌اند، و این فصل برای خواندن در کنار آن‌ها نوشته شده است. The Illustrated Transformer از Jay Alammar بهترین تصویر از data flow است که تا امروز کشیده شده. The Annotated Transformer از Harvard NLP مقالهٔ 2017 است با code اجرایی که خط‌به‌خط میان متن آمده. Let's build GPT: from scratch, in code, spelled out از Andrej Karpathy همان model را در دو ساعت، زنده و از صفر می‌سازد، و نردبان ablationهای بالا همان ستون فقرات است که روی corpus دیگری اندازه‌گیری شده. برای پرسش interpretability که این فصل فقط لمسش می‌کند، منابع اصلی Elhage و همکاران، A Mathematical Framework for Transformer Circuits (2021) و Olsson و همکاران، In-context Learning and Induction Heads (2022) هستند، هر دو از گروه interpretability در Anthropic.

  1. Hochreiter, S. and Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), pp. 1735–1780 (1997).

  2. Sutskever, I., Vinyals, O. and Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). همان encoder-decoder که بردار context یکتایش گلوگاه است.

  3. Bahdanau, D., Cho, K. and Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention، سه سال پیش از transformer.

  4. Perplexity نماییِ میانگین cross-entropy برای هر token است، از فصل 8. همهٔ عددهای اینجا از همان tokenizer و همان validation split استفاده می‌کنند، که تنها شرطی است که تحت آن اصلاً می‌توان دو perplexity را با هم مقایسه کرد.

  5. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł. and Polosukhin, I. Attention Is All You Need. arXiv:1706.03762 (2017). بخش 3.2.1 همان یک جمله دربارهٔ dk\sqrt{d_k} است که این فصل یک بخش را صرف اندازه‌گیری آن می‌کند.

  6. Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G. and Dean, J. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538 (2017).

  7. Ba, J. L., Kiros, J. R. and Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). در فصل 6 معرفی و اندازه‌گیری شد؛ اینجا بدون تغییر استفاده می‌شود.

  8. Xiong, R., Yang, Y., He, D., Zheng, K., Zheng, S., Xing, C., Zhang, H., Lan, Y., Wang, L. and Liu, T.-Y. On Layer Normalization in the Transformer Architecture. arXiv:2002.04745 (2020). تحلیل gradient پشت pre-norm، و استدلالی که warmup را یک symptom می‌داند.

  9. Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. and Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021).

  10. Press, O., Smith, N. A. and Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). نتیجهٔ extrapolation که بالا بازتولید شد.

  11. Dao, T., Fu, D. Y., Ermon, S., Rudra, A. and Ré, C. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. arXiv:2205.14135 (2022).

  12. Shazeer, N. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150 (2019).

  13. Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F. and Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023).

  14. Levesque, H. J., Davis, E. and Morgenstern, L. The Winograd Schema Challenge. KR (2012). سازهٔ پشت جملهٔ animal / street که هر tutorial مربوط به attention از آن استفاده می‌کند.


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

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 بسپارید؟

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