Attention và khối Transformer, suy ra từ phép trung bình
Bắt đầu từ bản tóm tắt rẻ nhất của ngữ cảnh — phép trung bình — đo lỗi của nó và để công thức attention tự xuất hiện.
Trên trang này
Bạn đến đây với một tokenizer từ Chương 7, một bảng embedding từ Chương 8, và objective đi kèm với chúng: với các token đã có, gán một xác suất cho token tiếp theo.
Phần còn thiếu là phần giữa. Để dự đoán token , model cần một vector tóm tắt mọi thứ trước nó, và không thứ gì bạn đã xây dựng tạo ra vector đó. embedding của token không phải là nó — đó là model bigram, và nó không thể biết câu đã bắt đầu bằng một câu hỏi. Nối tất cả embedding trước đó cũng không phải: số lượng của chúng thay đổi ở mỗi bước, và một ma trận trọng số cố định không thể nhận đầu vào có độ dài biến thiên.
Vậy: một vector có kích thước cố định, tóm tắt một số lượng vector biến thiên. Đó là toàn bộ vấn đề, và attention là thứ bạn nhận được khi giải nó theo cách lười nhất có thể rồi sửa hai thứ bị hỏng.
Câu trả lời mà lĩnh vực này từng có, và vì sao chúng ta không xây dựng nó
Liên kết đến mục: Câu trả lời mà lĩnh vực này từng có, và vì sao chúng ta không xây dựng nóTừ năm 1997 đến khoảng 2017, bản tóm tắt là một trạng thái hồi quy: giữ một vector và cập nhật nó ở mỗi token, . Kích thước cố định, đầu vào biến thiên, đúng chính xác về hình dạng.
Nó thất bại theo ba cách, và kiến trúc của chương này trả lời cả ba. Backpropagation qua bước nhân Jacobian, nên gradient biến mất hoặc bùng nổ — căn bệnh mà Chương 5 đã đo bên trong một node duy nhất. LSTM1 được thiết kế chính xác để chống lại điều đó và đã đẩy phạm vi dùng được từ vài chục bước lên vài trăm, nhưng không thay đổi sự thật rằng thông tin từ token 5 đến token 500 chỉ bằng cách sống sót qua 495 lần cập nhật tuần tự. Toàn bộ nguồn phải vừa trong một vector: trong dịch sequence-to-sequence2, một encoder nén đầu vào vào trạng thái cuối cùng của nó. Bahdanau, Cho và Bengio đã đặt tên cho nút thắt đó và sửa nó vào năm 2014, ba năm trước transformer, bằng cách cho decoder lấy tổng có trọng số của tất cả trạng thái encoder với các trọng số do chính nó tính.3 Mọi thứ bên dưới là ý tưởng đó, được một sequence áp dụng lên chính nó, với recurrence bị xóa. Và cập nhật là tuần tự theo thiết kế: cần , và một GPU có mười nghìn lõi cũng chẳng làm được gì với điều đó. Kiến trúc chiến thắng không hiển nhiên là thông minh hơn; nó là kiến trúc có bước tốn kém là phép nhân ma trận.
Inductive bias cổ điển còn lại, convolution — trượt một bộ lọc nhỏ trên toàn bộ đầu vào, để một feature được phát hiện ở đâu cũng được phát hiện ở mọi nơi — cũng không được xây ở đây; nó gần như đúng hoàn hảo cho ảnh và được giao cho một khóa thị giác. Cả recurrence lẫn convolution đều không xuất hiện lại sau trang này, đó là lý do không thứ nào có một chương riêng: Chương 1 đã hứa rằng những gì bị bỏ qua sẽ được nói rõ thay vì im lặng.
Bản tóm tắt rẻ nhất có thể
Liên kết đến mục: Bản tóm tắt rẻ nhất có thểHàm hiển nhiên nhất nhận một số lượng vector biến thiên và trả về một vector là trung bình:
Bao nhiêu đầu vào cũng được, kích thước đầu ra cố định, khả vi, miễn phí. Bảng embedding cộng phép trung bình này cộng một lớp tuyến tính ra vocabulary là một language model hoàn chỉnh trong mười lăm dòng. Nó cũng rất tệ, và nó tệ như thế nào chính là toàn bộ suy luận.
Corpus bên dưới là một megabyte Shakespeare, 1.115.394 ký tự, qua một byte-level BPE tokenizer kiểu đã xây trong Chương 7 với vocabulary 1024: 459.760 token ở mức 2,43 ký tự mỗi token, chia 90/10. Mọi model rộng 128, nhìn 128 token, và train 3000 bước AdamW tại với batch 64. Perplexity được đo trên phần held-out.4
| model | tham số | validation perplexity |
|---|---|---|
| chỉ token hiện tại, hoàn toàn không có ngữ cảnh | 263.168 | 59,71 |
| cộng trung bình đồng đều của mọi thứ trước nó | 263.168 | 248,07 |
| cộng learned position embeddings | 279.552 | 245,93 |
| trung bình đồng đều được cộng vào token thay vì thay thế nó | 263.168 | 60,45 |
Đọc hàng thứ hai hai lần. Trung bình hóa ngữ cảnh không giúp thêm một chút; nó làm model tệ hơn bốn lần so với việc hoàn toàn bỏ qua ngữ cảnh. Có hai lý do, cả hai đều chứng minh được chứ không chỉ là thực nghiệm.
Phép trung bình không thấy được thứ tự. Phép cộng giao hoán, nên xáo trộn cửa sổ vẫn để bản tóm tắt không đổi — không phải xấp xỉ:
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())2.9802322387695312e-08Nhiễu floating-point trên một tổng được sắp lại: hai bản tóm tắt là cùng một vector. Một model mà góc nhìn duy nhất về ngữ cảnh là phép trung bình không thể phân biệt the dog bit the man với the man bit the dog. Hàng ba chứng minh việc này không sửa được bằng cách thêm vị trí vào đầu vào — một learned position embedding trên mỗi token trước khi lấy trung bình chỉ mua được 2,14 điểm trên 188. Các vị trí đi vào tổng, và tổng quên chúng.
Và phép trung bình nhấn chìm hiện tại. Ở vị trí 100, token hiện tại chỉ là một phần trăm của bản tóm tắt. Điều đó có một cách sửa rẻ mà bạn đã có: giữ token và cộng bản tóm tắt vào nó — một residual connection, từ Chương 6, và hàng bốn cho thấy nó làm gì. Khi việc pha loãng được sửa, trung bình đồng đều chẳng đóng góp gì cả: 60,45 so với baseline 59,71. Mọi token đều ở đó, được gán trọng số bằng nhau, và trọng số bằng nhau cũng như không có thông tin.
Vấn đề không phải là phép trung bình. Nó là trọng số.
Phép trung bình là phép nhân ma trận, và mask là một softmax
Liên kết đến mục: Phép trung bình là phép nhân ma trận, và mask là một softmaxLấy trung bình trên một prefix đang lớn dần trông giống một vòng lặp. Nó là một phép nhân với ma trận tam giác dưới có các hàng cộng lại bằng một — và cũng, chính xác, là một softmax:
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 againloop 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.167Ba thành phần được đặt tên của một transformer giờ đã ở trên màn hình. Tam giác là causal mask, bị ép bởi objective: nếu vị trí có thể nhìn thấy vị trí thì câu trả lời đã nằm trong đầu vào — rò rỉ mà Chương 6 bảo bạn audit, chỉ là lần này nằm bên trong kiến trúc. softmax là cách mask được triển khai: đặt các entry bị cấm thành đưa chúng về đúng zero và chuẩn hóa phần còn lại, nên masking và chuẩn hóa là một thao tác. (Dùng , không phải -1e9: đó là giá trị mà masking có nghĩa, nó sống sót qua cast sang float16 dưới dạng , và nó tránh cho bạn phải quyết định hằng số mình chọn có đủ lớn cho miền giá trị hiện tại hay không — chính là chiếc hộp floating-point của Chương 2 đang hỏi một câu bạn không cần trả lời.) Và scores là tham số tự do. Trung bình đồng đều là thứ bạn có khi mọi score được phép đều là cùng một số; đặt bất kỳ số nào vào đó và softmax biến chúng thành trọng số hợp lệ.
Phần còn lại của chương này là một câu hỏi: những con số đó đến từ đâu?
Query, key, value
Liên kết đến mục: Query, key, valueChúng không thể là các tham số trần. Một ma trận được học sẽ giống hệt nhau cho mọi câu — nó có thể mã hóa “nhìn lùi bốn token” nhưng không bao giờ mã hóa “nhìn vào danh từ mà đại từ này tham chiếu”. Trọng số nối vị trí với vị trí phải phụ thuộc vào thứ ở cả hai vị trí, vì relevance là một quan hệ, không phải một thuộc tính: từ it không tự thân liên quan, nó liên quan đến thứ gì đó.
Hàm rẻ nhất của hai vector trả về một số là tích vô hướng từ Chương 1. Chấm điểm vị trí cho vị trí là và cơ chế hoạt động — nhưng tệ, theo hai cách buộc mọi thứ còn lại. Tích vô hướng của một vector với chính nó là norm bình phương của nó, nên mọi token sẽ attention chủ yếu đến chính nó. Và quan hệ sẽ đối xứng: nếu it attention mạnh đến animal, thì animal cũng attention mạnh đến it, điều này sai với ngôn ngữ, nơi một tính từ cần danh từ của nó hơn rất nhiều so với danh từ cần tính từ.
Vì vậy hãy cho mỗi token hai vai trò, như hai ánh xạ tuyến tính được học từ nó: vị trí này đang tìm kiếm gì, , tức query; và nó đưa ra gì để được tìm thấy bởi, , tức key. Chấm điểm và tính đối xứng biến mất, vì : một token có thể quảng cáo một thứ và tìm kiếm một thứ khác.
Vẫn còn một thứ sai. Tổng có trọng số đang lấy trên chính các , buộc thứ được copy phải là thứ được match. Matching muốn các feature nhận diện token; copying muốn các feature hữu ích ở downstream. Vì vậy học một ánh xạ thứ ba, , tức value, và lấy tổng trên những thứ đó.
Công thức giờ chỉ là bookkeeping:
với là causal mask, zero trên và dưới đường chéo, và phía trên. Trong code, nó là ba mươi dòng, hai mươi dòng trong đó là shapes:
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, chuẩn hóa, trộn. Mọi thứ khác là một projection.
Phép chia cho căn bậc hai, và nó chống lại điều gì
Liên kết đến mục: Phép chia cho căn bậc hai, và nó chống lại điều gìGần như mọi giải thích về đều nói “để giữ softmax khỏi bão hòa”, điều đó đúng và chẳng giải thích gì. Lập luận là hai dòng phương sai từ Chương 2. Nếu các entry của và độc lập, có mean zero và variance one, mỗi tích có variance one, và phương sai của các thứ độc lập thì cộng lại:
Vì vậy scores có độ lệch chuẩn . Đo trên hai mươi nghìn cặp ngẫu nhiên:
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.000Vì sao điều đó quan trọng: softmax nhạy với scale theo cách một lớp tuyến tính thì không. Nhân đôi đầu vào của một lớp tuyến tính thì nhân đôi đầu ra; nhân scores với mười trước softmax biến một hỗn hợp mềm thành một lựa chọn cứng. Một hàng gồm 64 scores, có và không có phép chia:
| trọng số lớn nhất, chưa chia | entropy | token hiệu dụng | trọng số lớn nhất, đã chia | entropy | token hiệu dụng | |
|---|---|---|---|---|---|---|
| 4 | 0,205 | 2,944 | 19,0 | 0,081 | 3,758 | 42,9 |
| 16 | 0,438 | 1,692 | 5,4 | 0,075 | 3,849 | 46,9 |
| 64 | 0,489 | 0,874 | 2,4 | 0,085 | 3,673 | 39,4 |
| 256 | 0,9999 | 0,0007 | 1,0 | 0,143 | 3,547 | 34,7 |
| 1024 | 1,0000 | 0,0000 | 1,0 | 0,132 | 3,644 | 38,3 |
“Token hiệu dụng” là exponential của entropy: hàng đó thật sự đang trung bình trên bao nhiêu vị trí. Không chia, tại , một head vừa khởi tạo attention đúng một token trong 64, được chọn không bởi gì ngoài mẫu ngẫu nhiên.
Điều đó tệ ở forward và còn tệ hơn ở backward, theo một hình dạng Chương 5 đã đo trên một . Một softmax đã cam kết vào một entry gần như không có đạo hàm: đường chéo Jacobian của nó là , bằng zero ở cả hai đầu. Trên hai nghìn hàng ngẫu nhiên:
| chưa chia | đã chia | hàng bão hòa (trọng số lớn nhất trên 0,99) | |
|---|---|---|---|
| 4 | 0,8427 | 0,9568 | 0,2 % → 0,0 % |
| 64 | 0,2940 | 0,9609 | 17,9 % → 0,0 % |
| 256 | 0,1406 | 0,9609 | 49,1 % → 0,0 % |
| 1024 | 0,0681 | 0,9611 | 70,4 % → 0,0 % |
Tại , bảy trong mười hàng đã bị đóng băng trước khi training bắt đầu, và một head bắt đầu ở trạng thái đóng băng không thể học nên nhìn vào đâu. Khi chia, đại lượng này phẳng ở 0,96 tại mọi width và không thứ gì bão hòa.
Giờ đến phần không ai publish: nó có thay đổi perplexity cuối cùng không? Xóa phép chia và train, ở bốn head width:
| head width | chưa chia | chia cho | chia cho |
|---|---|---|---|
| bốn heads, | 37,29 | 38,07 | 37,89 |
| một head, | 48,51 | 46,10 | 45,99 |
| một head, | 65,37 | 47,53 | — |
| một head, | 67,06 | 49,15 | — |
| một head, | 76,69 | 59,17 | — |
Hai hàng đầu đến từ budget 3000 bước ở trên; ba hàng cuối là một run ngắn hơn — 1500 bước, batch 32, một head, không normalization trước các projection — với cả hai biến thể dưới cùng setting.
Tại phép chia chẳng đáng gì và run không có nó còn nhỉnh hơn rất nhẹ. Đó không phải giấy phép để bỏ nó, vì tại 256 nó đáng 18 điểm perplexity và tại 1024 đáng 17. Cơ chế hiện rõ trong chính scores:
| score std khi init | sau 1500 bước, chưa chia | sau 1500 bước, đã chia | hàng bão hòa, chưa chia | đã chia | |
|---|---|---|---|---|---|
| 256 | 10,49 | 121,67 | 2,13 | 91,9 % | 0,8 % |
| 512 | 15,13 | 836,85 | 2,66 | 98,7 % | 1,3 % |
| 1024 | 21,15 | 5147,46 | 3,44 | 99,9 % | 16,5 % |
Head không chia không phục hồi. Nó chạy mất kiểm soát: độ lệch chuẩn của scores đi từ 21 khi khởi tạo lên 5147, attention entropy rơi về zero, và 99,9 % hàng đặt hơn 0,99 trọng số của chúng lên một token duy nhất. Khi một head đã là bộ chọn cứng, gradient của nó gần như zero và không có gì kéo nó lại, nên sụp đổ là ổn định. Head đã chia nằm ở độ lệch chuẩn score 3,44 sau cùng training, tức một hỗn hợp mềm vẫn có thể thay đổi.
Vaswani và cộng sự nói đúng điều này và không hơn — họ nghi rằng các tích “trở nên lớn về độ lớn với các giá trị lớn” và chia.5 Từ lớn gánh trọng lượng, và các bảng cho biết lớn bắt đầu ở đâu: không gì tại 32, mọi thứ tại 256.
Nhiều hơn một ý kiến, và hai phần ba không ai nói tới
Liên kết đến mục: Nhiều hơn một ý kiến, và hai phần ba không ai nói tớiMột head là một hàng softmax cho mỗi vị trí, nên nó giữ một câu trả lời cho “cái gì liên quan ở đây”. Dự đoán từ sau the trong the animal that crossed the wet street cần slot cú pháp, chủ ngữ và token trước đó cùng lúc, và một phân phối xác suất không thể tập trung ở ba nơi. Vì vậy chạy nhiều head song song, mỗi head có width , nối lại, và trộn bằng một ma trận nữa : bạn đã chia nhỏ width, không thêm vào nó.
Attention cũng làm đúng một việc — nó di chuyển thông tin giữa các vị trí. Mọi thao tác trong code phía trên là tuyến tính dọc theo trục feature, và Chương 5 đã chứng minh một chồng các ánh xạ tuyến tính là gì. Vì vậy mỗi block cũng mang một MLP nhỏ áp dụng độc lập cho từng vị trí, mở rộng width lên bốn lần rồi quay lại, với GELU ở giữa. Sự phân công này đáng ghi nhớ: attention trộn qua các vị trí, feed-forward network tính toán bên trong một vị trí.
Cái thang đầy đủ, mỗi hàng thêm một mảnh vào hàng phía trên:
| model | tham số | validation perplexity |
|---|---|---|
| trung bình đồng đều, được cộng | 279.552 | 60,45 |
| một attention head, thay thế token | 328.704 | 55,47 |
| một attention head, được cộng | 328.704 | 46,10 |
| bốn heads thay vì một | 345.216 | 43,21 |
| cộng feed-forward network | 476.928 | 39,87 |
| cộng LayerNorm — block hoàn chỉnh | 477.696 | 38,07 |
Trọng số được học thắng trọng số đồng đều 14 điểm perplexity, chính là toàn bộ lập luận của chương này trong một hàng. Bốn heads mua thêm 3 điểm với 16.512 tham số bổ sung. Và cùng một head đáng giá thêm 9 điểm khi được cộng hơn là thay thế: attention đưa thông tin vào, nó không quyết định một vị trí là gì.
Giờ là các tham số thật sự nằm ở đâu, điều thường gây ngạc nhiên cho những người chỉ từng nhìn sơ đồ:
| width | heads | attention | feed-forward | tổng mỗi block |
|---|---|---|---|---|
| 128 | 4 | 65.664 (33,2 %) | 131.712 (66,6 %) | 197.888 |
| 768 | 12 | 2.360.064 (33,3 %) | 4.722.432 (66,6 %) | 7.085.568 |
| 4096 | 32 | 67.112.960 (33,3 %) | 134.238.208 (66,7 %) | 201.367.552 |
Hai phần ba của mỗi transformer block là feed-forward network, ở mọi scale, vì attention có bốn ma trận và MLP có tương đương tám. Dù một model biết gì, phần lớn tham số giữ tri thức đó nằm trong MLP per-position.
Residuals và LayerNorm, thừa hưởng từ Chương 6
Liên kết đến mục: Residuals và LayerNorm, thừa hưởng từ Chương 6LayerNorm đã được xây và đo trong Chương 6, và chương này dùng nó đúng như đã để lại ở đó; residual connections đã được đặt tên và ablate ở đó, và được xây ở đây. Các hàng “được cộng, không thay thế” phía trên là residual connections, đáng 188 điểm perplexity cho phép trung bình và 9 cho một head. LayerNorm7 chuẩn hóa từng ví dụ theo các feature của nó, và Chương 6 đã đưa ra lý do vì sao nó chứ không phải BatchNorm sống sót ở đây — không phụ thuộc batch, không running statistics, giống hệt trong training và inference, không quan tâm sequence length — mỗi điểm trong đó trở thành yêu cầu khi bạn generate từng token một cho một người dùng, chính là nơi Chương 13 đi tới. Nó tốn 768 tham số và mua được 1,8 điểm perplexity.
class Block(nn.Module):
def forward(self, x):
x = x + self.att(self.ln1(x))
x = x + self.ff(self.ln2(x))
return xNhìn xem normalization nằm ở đâu: trên đầu vào của mỗi sub-layer, với residual path từ đầu vào đến đầu ra không bao giờ bị normalize. Đó là pre-norm. Paper năm 2017 làm ngược lại, x = LayerNorm(x + Att(x)) — post-norm, đặt một LayerNorm lên chính residual path.
Xiong và cộng sự giải thích khác biệt qua gradient lúc khởi tạo, thứ trong mạng post-norm bị scale rất tệ theo độ sâu — lý do transformer gốc cần learning-rate warmup mới train được.8 Mười hai block, 1000 bước, learning rate :
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.88Post-norm không có warmup tệ hơn tám lần, và post-norm có warmup khớp đúng pre-norm. Warmup không phải một best practice chung ở đây; nó là bản vá cho một cách bố trí normalization cụ thể, và di chuyển LayerNorm loại bỏ nhu cầu đó. Đó là lý do hầu như mọi model từ 2019 là pre-norm, và vì sao sơ đồ 2017 nên được đọc như lịch sử chứ không phải như specification.
Một token ở đâu?
Liên kết đến mục: Một token ở đâu?Xóa position embeddings và model vẫn train; nó chỉ đơn giản không thể biết thứ gì ở đâu, và đó là một đối xứng chứ không phải lỗi training. Không có gì trong attention score nhắc đến chính hay , nên hoán vị đầu vào sẽ hoán vị đầu ra: self-attention là permutation-equivariant. Đó là sự mù thứ tự của phép trung bình trong một lớp ngụy trang tốt hơn — causal mask khôi phục một phần thứ tự, vì mỗi vị trí thấy một prefix khác nhau, nhưng bên trong một prefix mọi thứ tự đều như nhau.
Bốn cách đưa vị trí vào, train trên cửa sổ 64-token và đánh giá tại 64, 128 và 256 — vượt quá mọi độ dài chúng đã thấy:
| positions | perplexity tại 64 | tại 128 | tại 256 |
|---|---|---|---|
| hoàn toàn không có | 48,79 | 52,63 | 57,52 |
| learned absolute embeddings | 38,63 | 108,47 | 181,94 |
| fixed sinusoids | 42,96 | 95,26 | 152,25 |
| RoPE | 44,12 | 50,52 | 84,84 |
| ALiBi | 44,95 | 43,51 | 42,49 |
Learned absolute embeddings — một vector cho mỗi vị trí, cộng vào token — thắng ở độ dài đã train rồi rơi khỏi vách đá, vì vị trí 100 chưa từng có trong batch và embedding của nó vẫn là vector ngẫu nhiên ban đầu. Sinusoids, lựa chọn gốc, được tính chứ không học, từ sine và cosine ở các tần số cách nhau theo cấp số nhân; paper 2017 hy vọng điều đó extrapolate, và bảng cho thấy không — hàm được định nghĩa tại vị trí 200, nhưng model chưa từng học cách đọc nó ở đó. RoPE9 không thêm gì mà thay vào đó xoay query và key theo một góc tỷ lệ với vị trí, trong các lát hai chiều; vì xoay cả hai vế của một tích vô hướng như nhau sẽ để nó không đổi, score cuối cùng chỉ phụ thuộc vào , nên vị trí trở thành relative miễn phí và không có bảng nào để dùng hết. Nó suy giảm, nhưng nó vẫn suy giảm một cách có kiểm soát. ALiBi10 là kết quả đơn giản nhất và kỳ lạ nhất ở đây: một linear penalty trên score tỷ lệ với khoảng cách, với độ dốc khác nhau cho mỗi head. Perplexity của nó cải thiện khi cửa sổ vượt quá độ dài training, từ 44,95 xuống 42,49, vì penalty được định nghĩa ở mọi khoảng cách và mỗi head tiếp tục làm thứ nó đã được train để làm.
Bài học sống lâu hơn bảng: một kiến trúc không thể biểu diễn một thứ là vấn đề khác với một kiến trúc chưa từng học miền đó, và vấn đề thứ hai mới là thứ cắn bạn. Nó cũng là bộ máy đằng sau mọi thông báo “chúng tôi đã mở rộng context lên 128K” — gần như luôn là các phép rescale của một rotary encoding, và đó là lý do Chương 16 nói giới hạn context dịch chuyển thay vì biến mất.
Dropout được thừa hưởng theo cùng cách: nó xuất hiện trên attention weights sau softmax, trên đầu ra của mỗi sub-layer trước residual addition, và trên tổng embedding, làm đúng thứ Chương 6 đã mô tả. Trong các run pretraining lớn, nó thường được đặt về zero, vì một model thấy mỗi token một lần không ở vị thế để overfit.
Nó tốn gì
Liên kết đến mục: Nó tốn gìHai tensor trong layer có shape , trong đó là số token: scores và weights sau softmax. Mọi thứ khác — mọi projection, toàn bộ MLP — tuyến tính theo .
Một attention layer, rộng 512, 8 heads, batch một, float32, trên GPU laptop. Chỉ đọc hai cột millisecond theo tỷ lệ của chúng: đó là wall clock trên một card laptop 8 GB bị throttle từ 1.785 MHz xuống dưới 300 MHz khi nóng, nên một cold run của cùng code này trả về nhanh hơn bảy đến mười lần và một run khi máy bận còn chậm hơn. Các cột megabyte là byte count của allocator và không dịch chuyển.
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.87Các cột x4 là tỷ lệ so với hàng phía trên, và việc nhân đôi hội tụ đúng về 4 cho cả thời gian và bộ nhớ — 3,91 ở bước cuối so với lý thuyết 4. Cột projections là đối chứng: 4,0 ms tại 1024 token đến 40,1 ms tại 8192, hệ số mười cho hệ số tám. Tuyến tính, đúng như quảng cáo.
Rồi đến hàng cuối. Một attention layer, một sequence, không có model xung quanh nó, hết bộ nhớ trên GPU 8 GB tại 16.384 token — riêng score matrix đã là 8 GB, vì 8 heads nhân 16.384 nhân 16.384 nhân 4 byte. Không phải model; một tensor trung gian trong một layer.
Đó là sự thật vật lý nằm dưới ba chương sau. Nó là lý do context window có giới hạn ngay từ đầu, thứ Chương 16 biến thành một mức giá. Nó là lý do FlashAttention tồn tại, tính cùng kết quả theo tiles mà không bao giờ lưu ma trận — một tối ưu bộ nhớ trước khi là tối ưu tốc độ.11 Và nó là phép tính đằng sau giá của một prompt dài, thứ Chương 24 trả trong một agent loop — một vấn đề tách biệt với phát hiện khác của chương đó, rằng model cũng sử dụng context dài tệ hơn, điều nó đo và từ chối đổ lỗi cho công thức này.
Hiện chi tiết
Hai biến thể thu nhỏ cache, được đặt tên ở đây và tính tiền ở Chương 13.
Generation cache các keys và values của các token đã xử lý — một key và một value cho mỗi token, mỗi head mỗi layer. Multi-query attention12 giữ query projections nhưng một key projection và value projection duy nhất dùng chung cho mọi head, chia cache đó cho . Grouped-query attention13 nội suy: các head được gom nhóm, mỗi nhóm dùng chung một key và value, nên là attention thường và là multi-query. Gần như mọi open model từ 2023 dùng nó với 4 hoặc 8 groups. Không thứ nào tồn tại vì chất lượng; cả hai tồn tại vì kích thước cache đó, và Chương 13 làm phép tính biến nó thành “model nào vừa trong GPU của bạn”.
Hai hình dạng, và kích thước của một hình
Liên kết đến mục: Hai hình dạng, và kích thước của một hìnhPaper năm 2017 mô tả một encoder-decoder: một stack đọc nguồn bằng attention không mask, stack thứ hai generate đích theo causal, và một loại attention thứ ba ở giữa nơi queries của decoder gặp keys của encoder. Điều đó đúng cho dịch thuật, nơi đầu vào và đầu ra là hai sequence.
Thứ chiến thắng là nửa decoder-only — một stack, causal xuyên suốt, đầu vào và đầu ra trong cùng một sequence — và lý do không phải là thanh lịch. “Dự đoán token tiếp theo” chạy trên bất kỳ văn bản nào, nên tập training là internet thay vì parallel corpus, và mọi thứ trở thành đúng một task đó: một bản dịch là một document chứa nguồn rồi đích, một câu hỏi và câu trả lời của nó là một document, một cuộc hội thoại với tool call ở giữa là một document. Chương 11 nói về cách thứ cuối cùng đó được chế tạo. Encoders không biến mất — một encoder thấy toàn bộ đầu vào cùng lúc, điều bạn muốn khi công việc là biểu diễn một văn bản thay vì tiếp tục nó, và đó là lý do retrieval embeddings của Chương 19 đến từ encoders chứ không phải từ model đang chat.
Với block đã định nghĩa, kích thước model là số học. Mỗi block, với width và mở rộng bốn lần: cho với bias trên cả bốn, như GPT-2 có — bảng phía trên bỏ bias khỏi ba trong số chúng, nên ít hơn 2.304 mỗi block tại ; cho MLP; cho hai LayerNorm — , cộng một bảng token và, với absolute positions, . Với hình dạng của GPT-2 small — , 12 block, vocabulary 50.257, context 1024, output layer dùng chung trọng số với embedding:
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Đó chính là kích thước đã publish của model đó. Công thức không phải xấp xỉ; nó là model. Cũng lưu ý rằng gần một phần ba model nhỏ là bảng embedding, đó là lý do kích thước vocabulary là một quyết định kiến trúc chứ không phải tiền xử lý — trade-off mà Chương 7 đã dựng lên.
Một head thật sự nhìn vào gì
Liên kết đến mục: Một head thật sự nhìn vào gìPerplexity là một con số về corpus. Một head làm gì là câu hỏi khác, và một model train trên một megabyte Shakespeare là công cụ sai cho việc đó: điều trung thực cần nói về attention map của một model 500.000 tham số là nó hầu như không diễn giải được. Vậy: một ngôn ngữ nơi câu hỏi có đáp án đúng.
Minh họa kinh điển là the animal did not cross the street because it was too tired, trong đó it là animal, đối lại với …because it was too wet, nơi một từ chuyển referent sang street. Đây là Winograd schemas14 — các cặp câu giống hệt nhau trừ một từ, và từ đó quyết định đại từ tham chiếu đến gì.
Chúng cũng có thể giải bằng cách gian lận, phần mà các tutorial bỏ qua. Nếu hai ứng viên là một con vật và một địa điểm, tired và wet nhận diện referent theo category, và một model chỉ biết những từ nào xuất hiện cũng trả lời đúng mà không biết gì về thứ tự. Đo trên phiên bản task đó, với các cặp animal/place held-out:
uniform causal average held-out referent accuracy 100.0 %
one transformer block held-out referent accuracy 91.7 %Bag of words thắng transformer. Bất kỳ demonstration nào xây trên câu đó đều không chứng minh gì về attention.
Vậy hãy bịt lỗ hổng: rút cả hai ứng viên từ một pool mười sáu danh từ, bất kỳ danh từ nào cũng có thể xuất hiện ở bất kỳ slot nào, và chia tính từ theo role thay vì category — bốn từ làm it là crosser (tired, scared, slow, weak), bốn từ làm nó là crossed (wet, wide, busy, steep).
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .Train như một next-token predictor thông thường, chấm điểm một vị trí — từ sau so the — và xây held-out set từ các cặp danh từ mà thứ tự đảo ngược đã có trong training, nên bất kỳ thứ gì biết hai danh từ nào hiện diện nhưng không biết cái nào đến trước sẽ phải trả lời ngược.
| model | tham số | held-out | gọi tên danh từ kia |
|---|---|---|---|
| chỉ token hiện tại | 5.796 | 5,2 % | 5,2 % |
| trung bình causal đồng đều | 5.796 | 27,9 % | 50,0 % |
| một head learned attention | 18.084 | 35,4 % | 64,6 % |
| bốn heads | 22.244 | 75,0 % | 15,6 % |
| một transformer block | 55.716 | 92,7 % | 4,2 % |
| hai transformer blocks | 105.508 | 100,0 % | 0,0 % |
Ngẫu nhiên giữa hai danh từ hiện diện là 50 %. Trung bình đồng đều đạt 27,9 % và trả lời bằng danh từ sai của cặp đúng một nửa số lần — dấu hiệu của thứ biết những từ nào ở đó và không biết gì về thứ tự của chúng, đúng như shuffle test đã dự đoán ba phần trước.
Giờ đến map: attention tại vị trí phải gọi tên referent, trung bình trên bốn heads của mỗi block, cho hai câu chỉ khác nhau một từ. Một trung bình đồng đều sẽ đặt 0,067 lên mỗi token trong mười lăm token nhìn thấy được.
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.25Block 1 giống hệt trong cả hai câu — 0,70 lên danh từ đầu tiên, bất kể tính từ là gì. Đó không phải thất bại mà là một chứng minh: trong layer đầu tiên, query tại một vị trí là hàm của chính token và index của vị trí đó, và the ở vị trí 14 là cùng token trong cả hai câu. Một head ở layer đầu không thể condition trên một từ nó chưa fetch. Vì vậy block 1 làm thứ hữu ích duy nhất có thể và kéo danh từ đầu tiên về phía trước.
Block 2 là nơi các câu tách ra, và cùng một hàng trên toàn bộ tám tính từ cho thấy quy tắc model đã tìm ra:
| tính từ | block 2 trên animal | trên street | trên tính từ | đáp án |
|---|---|---|---|---|
| tired, scared, slow, weak | 0,000 | 0,000 | 1,000 | animal |
| wet, wide, busy, steep | 0,000 | 0,491 | 0,00–0,03 | street |
Với crosser-adjective, block thứ hai dành toàn bộ trọng số cho tính từ, vì đáp án đã nằm trong residual stream — block 1 đã đặt nó ở đó — và nó chỉ cần xác nhận. Với crossed-adjective, nó đi fetch danh từ kia thay vào đó. Đó là một circuit hai bước: một head đẩy một ứng viên về phía trước, một head ở layer sau đọc một token quyết định có giữ nó hay không. Composition qua các layer là cơ chế, và đó là lý do một block đạt 92,7 % còn hai block đạt 100 %.
Nó cũng là hình dạng của circuit được ghi chép tốt nhất trong các model thật. Induction heads — một previous-token head cấp dữ liệu cho một head ở layer kế tiếp để hoàn tất pattern [A][B] … [A] → [B] — là thứ công trình interpretability của Anthropic xác định đứng sau một phần lớn in-context learning, và chúng hình thành tại một thời điểm có thể nhận diện trong pretraining. Chương này không cố phân tích điều đó: nó được giao cho tài liệu tham khảo, với cả hai paper trong phần nguồn, vì đọc circuits ra khỏi một model thật là một lĩnh vực nghiên cứu chứ không phải một mục.
Cuối cùng là phần triển khai. Ba mươi dòng phía trên, với weights được copy từ chính PyTorch:
ours vs nn.MultiheadAttention max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention max |diff| = 1.7881393432617188e-07trên outputs có mean magnitude 0,159: cùng một phép tính theo thứ tự khác, ở độ chính xác float32.
Điều này dẫn tới đâu tiếp theo
Liên kết đến mục: Điều này dẫn tới đâu tiếp theoBạn đã có kiến trúc mà mọi model trong phần còn lại của khóa học được xây từ đó, và nó nhỏ hơn danh tiếng của mình: một phép trung bình có trọng số với trọng số được học, một MLP per-position giữ hai phần ba tham số, hai normalization và hai addition, được xếp chồng.
Thứ bạn chưa có là một model biết bất kỳ điều gì, và chỉ xếp chồng sẽ không tự sửa được. Hai block trên corpus này đạt training perplexity 14,49 và validation perplexity 40,57, so với 18,77 và 38,07 của một block — nhiều capacity hơn, tốt hơn trên thứ nó đã thấy, tệ hơn trên thứ nó chưa thấy, chính là bảng của Chương 6 với một transformer trong đó. Khoảng cách giữa model này và những model mà Chương 14 đến 30 nói chuyện không nằm ở kiến trúc. Nó là cùng block đó, lặp nhiều lần hơn, trên lượng văn bản lớn hơn rất nhiều.
Điều đó biến nó thành một bài toán kế toán, và việc kế toán kỳ lạ hơn vẻ ngoài. Bao nhiêu văn bản, và mọi người lấy nó ở đâu? Bao nhiêu số học, và bạn ước tính nó trước khi tiền được tiêu như thế nào? Với một ngân sách cố định, tốt hơn là làm model lớn hơn hay cho nó xem nhiều dữ liệu hơn — và có câu trả lời đúng không, hay chỉ là mốt? Chương 10 trả lời cả ba bằng đo lường, và đặt giá lên dạng hữu ích rẻ nhất của câu hỏi: hôm nay tốn bao nhiêu để train một model như GPT-2 từ con số không?
Nguồn và phương pháp
Liên kết đến mục: Nguồn và phương phápBa cách giải thích về tài liệu này tốt hơn phần này ở đúng mục đích của chúng, và chương này được viết để đọc song song với chúng. The Illustrated Transformer của Jay Alammar là bức tranh đẹp nhất về luồng dữ liệu từng được vẽ. The Annotated Transformer của Harvard NLP là paper 2017 với code chạy được xen kẽ từng dòng. Let's build GPT: from scratch, in code, spelled out của Andrej Karpathy xây cùng model trực tiếp trong hai giờ, và cái thang ablation phía trên là cùng một xương sống được đo trên một corpus khác. Với câu hỏi interpretability mà chương này chỉ chạm tới, các nguồn chính là Elhage và cộng sự, A Mathematical Framework for Transformer Circuits (2021) và Olsson và cộng sự, In-context Learning and Induction Heads (2022), đều từ nhóm interpretability của Anthropic.
Tài liệu tham khảo
Liên kết đến mục: Tài liệu tham khảo-
Hochreiter, S. và Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), tr. 1735–1780 (1997). ↩
-
Sutskever, I., Vinyals, O. và Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). Encoder-decoder có context vector duy nhất là nút thắt. ↩
-
Bahdanau, D., Cho, K. và Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, ba năm trước transformer. ↩
-
Perplexity là exponential của mean cross-entropy trên mỗi token, từ Chương 8. Mọi con số ở đây dùng cùng tokenizer và cùng validation split, đó là điều kiện duy nhất để hai perplexity có thể được so sánh. ↩
-
Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł. và Polosukhin, I. Attention Is All You Need. arXiv:1706.03762 (2017). Mục 3.2.1 là một câu về mà chương này dành cả một phần để đo. ↩
-
Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G. và Dean, J. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538 (2017). ↩
-
Ba, J. L., Kiros, J. R. và Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). Được giới thiệu và đo trong Chương 6; dùng ở đây không đổi. ↩
-
Xiong, R., Yang, Y., He, D., Zheng, K., Zheng, S., Xing, C., Zhang, H., Lan, Y., Wang, L. và Liu, T.-Y. On Layer Normalization in the Transformer Architecture. arXiv:2002.04745 (2020). Phân tích gradient phía sau pre-norm, và lập luận rằng warmup là một triệu chứng. ↩
-
Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. và Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021). ↩
-
Press, O., Smith, N. A. và Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). Kết quả extrapolation được tái hiện phía trên. ↩
-
Dao, T., Fu, D. Y., Ermon, S., Rudra, A. và Ré, C. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. arXiv:2205.14135 (2022). ↩
-
Shazeer, N. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150 (2019). ↩
-
Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F. và Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023). ↩
-
Levesque, H. J., Davis, E. và Morgenstern, L. The Winograd Schema Challenge. KR (2012). Cấu trúc phía sau câu animal / street mà mọi attention tutorial đều dùng. ↩