ข้ามไปยังเนื้อหา
9/30บทที่ 9 จาก 30

Attention และบล็อก Transformer อนุมานจากค่าเฉลี่ย

เริ่มจากสรุป context ที่ถูกที่สุดคือค่าเฉลี่ย วัดว่ามันพลาดอย่างไร แล้วปล่อยให้สูตร attention เกิดจากการซ่อมมัน

ในหน้านี้

คุณมาถึงตรงนี้พร้อม tokenizer จาก บทที่ 7, ตาราง embedding จาก บทที่ 8, และ objective ที่มากับมัน: เมื่อมี tokens ก่อนหน้าแล้ว ให้ใส่ความน่าจะเป็นให้ token ถัดไป

สิ่งที่หายไปคือส่วนกลาง เพื่อทำนาย token tt model ต้องมี vector หนึ่งตัว ที่สรุปทุกอย่างก่อนหน้า และสิ่งที่คุณสร้างมายังไม่มีอะไรผลิตสิ่งนั้นได้ embedding ของ token t1t-1 ไม่ใช่มัน — นั่นคือ bigram model และมันไม่มีทางรู้ว่าประโยคเริ่มด้วยคำถาม การต่อ embeddings ก่อนหน้าทั้งหมดเข้าด้วยกันก็ไม่ใช่เหมือนกัน: จำนวนของมันเปลี่ยนทุก step และเมทริกซ์น้ำหนักขนาดคงที่รับอินพุตความยาวแปรผันไม่ได้

ดังนั้น: vector ขนาดคงที่หนึ่งตัว ที่สรุป vectors จำนวนแปรผัน นั่นคือปัญหาทั้งหมด และ attention คือสิ่งที่ได้จากการแก้มันด้วยวิธีขี้เกียจที่สุดเท่าที่เป็นไปได้ แล้วซ่อมสองอย่างที่พัง

คำตอบที่วงการเคยมี และทำไมเราจะไม่สร้างมัน

ลิงก์ไปยังส่วน: คำตอบที่วงการเคยมี และทำไมเราจะไม่สร้างมัน

ตั้งแต่ปี 1997 ถึงประมาณ 2017 สรุปคือ recurrent state: เก็บ vector h\mathbf{h} แล้วอัปเดตมันทุก token, ht=f(ht1,xt)\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t) ขนาดคงที่ อินพุตแปรผัน รูปร่างถูกต้องพอดี

มันล้มเหลวสามทาง และสถาปัตยกรรมของบทนี้ตอบทั้งสามทาง Backpropagating ผ่าน TT steps คูณ Jacobians TT ตัวเข้าด้วยกัน ทำให้ gradient หายไปหรือระเบิด — โรคที่ บทที่ 5 วัดภายใน node tanh\tanh เดียว LSTM1 ถูกออกแบบมาเพื่อรับมือสิ่งนั้นโดยตรง และดันช่วงที่ใช้งานได้จากหลักสิบ steps ไปเป็นหลักร้อย โดยไม่เปลี่ยนข้อเท็จจริงที่ว่าข้อมูลจาก token 5 ไปถึง token 500 ได้ก็ต่อเมื่อรอดผ่านการอัปเดตแบบลำดับ 495 ครั้ง แหล่งข้อมูลทั้งหมดต้องยัดลงใน vector เดียว: ในการแปลแบบ sequence-to-sequence2 encoder บีบอัดอินพุตลงใน state สุดท้าย Bahdanau, Cho และ Bengio ตั้งชื่อคอขวดนั้นและแก้มันในปี 2014 สามปีก่อน transformer โดยให้ decoder รับผลรวมถ่วงน้ำหนักของ encoder states ทั้งหมด ด้วยน้ำหนักที่มันคำนวณเอง3 ทุกอย่างด้านล่างคือแนวคิดนั้น นำมาใช้กับ sequence ที่มองตัวเอง พร้อมลบ recurrence ออก และ การอัปเดตเป็นแบบลำดับโดยโครงสร้าง: ht\mathbf{h}_t ต้องมี ht1\mathbf{h}_{t-1} และ GPU ที่มีคอร์หมื่นตัวก็ทำอะไรกับเรื่องนั้นไม่ได้ สถาปัตยกรรมที่ชนะไม่ได้ฉลาดกว่าอย่างเห็นได้ชัด แต่มันคือสถาปัตยกรรมที่ step แพงเป็นการคูณเมทริกซ์

inductive bias แบบคลาสสิกอีกอย่างคือ convolution — เลื่อนฟิลเตอร์เล็กตัวหนึ่งไปทั่วอินพุต เพื่อให้ feature ที่ตรวจพบที่ไหนก็ตรวจพบได้ทุกที่ — ก็ไม่ได้สร้างที่นี่เช่นกัน มันเกือบถูกต้องพอดีสำหรับภาพ และถูกมอบให้คอร์ส vision ไป หลังหน้านี้ทั้ง recurrence และ convolution จะไม่กลับมาอีก นั่นคือเหตุผลที่ทั้งสองไม่มีบทของตัวเอง: บทที่ 1 สัญญาว่าสิ่งที่ละไว้จะถูกประกาศ ไม่ใช่เงียบหาย

ฟังก์ชันที่ชัดเจนที่สุดของ vectors จำนวนแปรผันที่คืน vector หนึ่งตัวคือ ค่าเฉลี่ย:

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

อินพุตกี่ตัวก็ได้ เอาต์พุตขนาดคงที่ differentiable ฟรี ตาราง embedding บวกค่าเฉลี่ยนี้ บวก linear layer ไปยัง vocabulary คือ language model ที่สมบูรณ์ในสิบห้าบรรทัด มันยังแย่มากด้วย และวิธีที่มันแย่คือที่มาของการอนุมานทั้งหมด

corpus ด้านล่างคือ Shakespeare หนึ่งเมกะไบต์ 1,115,394 characters ผ่าน byte-level BPE tokenizer แบบที่สร้างในบทที่ 7 ด้วย vocabulary 1024: 459,760 tokens ที่ 2.43 characters ต่อ token แบ่ง 90/10 ทุก model กว้าง 128 เห็น 128 tokens และฝึก 3000 steps ของ AdamW ที่ 10310^{-3} ด้วย batch 64 Perplexity อยู่บน split ที่กันไว้4

modelparametersvalidation perplexity
token ปัจจุบันเท่านั้น ไม่มี context เลย263,16859.71
บวกค่าเฉลี่ยแบบสม่ำเสมอของทุกอย่างก่อนหน้า263,168248.07
บวก position embeddings ที่เรียนรู้ได้279,552245.93
ค่าเฉลี่ยแบบสม่ำเสมอ บวก เข้ากับ token แทนที่จะแทนที่มัน263,16860.45

อ่านแถวที่สองสองครั้ง การเฉลี่ย context ไม่ได้ช่วยเล็กน้อย แต่มันทำให้ model แย่กว่าการไม่สนใจ context เลยถึงสี่เท่า มีสองเหตุผล ทั้งคู่พิสูจน์ได้ ไม่ใช่แค่เชิงประจักษ์

ค่าเฉลี่ยมองไม่เห็นลำดับ การบวกสลับที่ได้ ดังนั้นการสับหน้าต่างไม่ทำให้สรุปเปลี่ยน — ไม่ใช่แค่ประมาณ:

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

noise แบบ floating-point จากผลรวมที่เรียงใหม่: สรุปทั้งสองเป็น vector เดียวกัน model ที่มอง context ได้แค่ค่าเฉลี่ย แยก the dog bit the man ออกจาก the man bit the dog ไม่ได้ แถวที่สามพิสูจน์ว่าแก้ไม่ได้ด้วยการเพิ่มตำแหน่งให้กับอินพุต — learned position embedding บนทุก token ก่อนเฉลี่ย ซื้อมาได้ 2.14 จุดจาก 188 ตำแหน่งเข้าไปในผลรวม แล้วผลรวมก็ลืมมัน

และค่าเฉลี่ยกลบปัจจุบัน ที่ตำแหน่ง 100 token ปัจจุบันเป็นหนึ่งในร้อยของสรุป เรื่องนี้มีวิธีแก้ถูก ๆ ที่คุณมีอยู่แล้ว: เก็บ token ไว้แล้ว บวก สรุปเข้าไป — residual connection จาก บทที่ 6 และแถวที่สี่คือสิ่งที่มันทำ เมื่อซ่อมการเจือจางแล้ว ค่าเฉลี่ยแบบสม่ำเสมอไม่ช่วย อะไรเลย: 60.45 เทียบกับ baseline 59.71 ทุก token อยู่ในนั้น ถ่วงน้ำหนักเท่ากัน และการถ่วงเท่ากันก็เหมือนกับไม่มีข้อมูล

ปัญหาไม่ใช่การเฉลี่ย แต่คือ น้ำหนัก

ค่าเฉลี่ยคือการคูณเมทริกซ์ และ mask คือ softmax

ลิงก์ไปยังส่วน: ค่าเฉลี่ยคือการคูณเมทริกซ์ และ mask คือ softmax

การเฉลี่ยบน prefix ที่โตขึ้นดูเหมือน loop แต่มันคือการคูณหนึ่งครั้งด้วยเมทริกซ์ lower-triangular ที่แต่ละแถวรวมกันได้หนึ่ง — และยังเป็น 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: ถ้าตำแหน่ง tt มองเห็นตำแหน่ง t+1t{+}1 ได้ คำตอบก็อยู่ในอินพุต — leak ที่บทที่ 6 บอกให้คุณ audit เพียงแต่มันอยู่ในสถาปัตยกรรม softmax คือวิธี implement mask: การตั้งค่า entries ที่ห้ามเป็น -\infty ส่งมันไปเป็นศูนย์พอดีและ normalise ส่วนที่เหลือ ดังนั้น masking และ normalising จึงเป็น operation เดียวกัน (ใช้ -\infty ไม่ใช่ -1e9: มันคือค่าที่ masking หมายถึง มันรอดจากการ cast เป็น float16 ในรูป -\infty และช่วยให้คุณไม่ต้องตัดสินว่าค่าคงที่ที่เลือกใหญ่พอสำหรับ range ที่บังเอิญอยู่หรือไม่ — ซึ่งคือกล่อง floating-point ของ บทที่ 2 ที่ถามคำถามซึ่งคุณไม่จำเป็นต้องตอบ) และ scores คือ free parameter ค่าเฉลี่ยแบบสม่ำเสมอคือสิ่งที่ได้เมื่อทุก allowed score เป็นเลขเดียวกัน ใส่เลขอะไรก็ได้ตรงนั้น แล้ว softmax จะเปลี่ยนมันเป็นน้ำหนักที่ถูกต้อง

ส่วนที่เหลือของบทนี้คือคำถามเดียว: เลขเหล่านั้นมาจากไหน

มันเป็น parameters ธรรมดาไม่ได้ เมทริกซ์ T×TT \times T ที่เรียนรู้ได้จะเหมือนกันทุกประโยค — มันเข้ารหัสได้ว่า “มองย้อนกลับไปสี่ tokens” แต่ไม่มีวันเข้ารหัสได้ว่า “มองคำนามที่สรรพนามนี้อ้างถึง” น้ำหนักที่เชื่อมตำแหน่ง tt กับตำแหน่ง ii ต้องขึ้นกับสิ่งที่อยู่ที่ ทั้งสอง ตำแหน่ง เพราะความเกี่ยวข้องเป็นความสัมพันธ์ ไม่ใช่คุณสมบัติ: คำว่า it ไม่ได้เกี่ยวข้องในตัวเอง แต่มันเกี่ยวข้อง กับ บางอย่าง

ฟังก์ชันที่ถูกที่สุดของ vectors สองตัวที่คืนตัวเลขคือ dot product จากบทที่ 1 ให้ score ตำแหน่ง ii สำหรับตำแหน่ง tt เป็น xtxi\mathbf{x}_t \cdot \mathbf{x}_i แล้วกลไกก็ทำงาน — แย่ ในสองทางที่บังคับทุกอย่างที่เหลือ dot product ของ vector กับตัวเองคือ norm กำลังสอง ดังนั้นทุก token จะ attend ส่วนใหญ่ไปที่ตัวเอง และความสัมพันธ์จะ สมมาตร: ถ้า it attend ไปที่ animal อย่างแรง animal ก็ attend ไปที่ it อย่างแรง ซึ่งไม่จริงสำหรับภาษา ที่ adjective ต้องการ noun ของมันมากกว่า noun ต้องการ adjective มาก

ดังนั้นให้ token แต่ละตัวมีสองบทบาท เป็น linear maps ที่เรียนรู้ได้สองตัวของมัน: สิ่งที่ตำแหน่งนี้กำลัง มองหา, qt=Wqxt\mathbf{q}_t = W_q\mathbf{x}_t, คือ query; และสิ่งที่มัน เสนอให้ถูกพบด้วย, ki=Wkxi\mathbf{k}_i = W_k\mathbf{x}_i, คือ key ให้ score เป็น qtki\mathbf{q}_t \cdot \mathbf{k}_i แล้วความสมมาตรก็หายไป เพราะ WqWkW_q \neq W_k: token สามารถโฆษณาอย่างหนึ่งและค้นหาอีกอย่างได้

ยังมีอีกอย่างที่ผิด ผลรวมถ่วงน้ำหนักเดิมรวมบน xi\mathbf{x}_i เอง ซึ่งบังคับให้สิ่งที่ถูก คัดลอก เป็นสิ่งเดียวกับที่ถูก จับคู่ การจับคู่ต้องการ features ที่ระบุ token; การคัดลอกต้องการ features ที่มีประโยชน์ downstream ดังนั้นเรียนรู้ map ที่สาม 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 มันยาวสามสิบบรรทัด ซึ่งยี่สิบบรรทัดคือ shapes:

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 saturate” ซึ่งจริง แต่ไม่อธิบายอะไรเลย เหตุผลเป็น variance สองบรรทัดจากบทที่ 2 ถ้า entries ของ q\mathbf{q} และ k\mathbf{k} เป็นอิสระ มี mean ศูนย์และ variance หนึ่ง แต่ละผลคูณ qjkjq_j k_j มี variance หนึ่ง และ variances ของสิ่งที่เป็นอิสระบวกกัน:

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

ดังนั้น scores มี standard deviation 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 ไวต่อสเกลในแบบที่ linear layer ไม่เป็น การคูณอินพุตของ linear layer สองเท่าทำให้เอาต์พุตสองเท่า; การคูณ scores ด้วยสิบก่อน softmax เปลี่ยน soft blend เป็น hard choice หนึ่ง row ของ 64 scores พร้อมและไม่มีการหาร:

dkd_kน้ำหนักใหญ่สุด ไม่หารentropyeffective tokensน้ำหนักใหญ่สุด หารแล้วentropyeffective tokens
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

“Effective tokens” คือ exponential ของ entropy: row นั้นเฉลี่ยจริง ๆ เหนือกี่ตำแหน่ง เมื่อไม่หาร ที่ dk=256d_k = 256 head ที่เพิ่ง initialise attend ไปที่ token หนึ่ง ตัวพอดีจาก 64 โดยถูกเลือกจากการสุ่มล้วน ๆ

นั่นแย่ใน forward และแย่กว่าใน backward ในรูปร่างที่บทที่ 5 วัดบน tanh\tanh ไปแล้ว softmax ที่ปักใจกับ entry เดียวแทบไม่มี derivative: diagonal ของ Jacobian คือ wi(1wi)w_i(1-w_i) เป็นศูนย์ที่ปลายทั้งสอง จาก rows สุ่มสองพัน rows:

dkd_kiwi(1wi)\sum_i w_i(1-w_i) ไม่หารหารแล้วrows ที่ saturated (น้ำหนักใหญ่สุดมากกว่า 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 เจ็ดในสิบ rows ถูกแช่แข็งก่อนเริ่มฝึก และ head ที่เริ่มแบบแช่แข็งเรียนรู้ไม่ได้ว่าควรมองอะไร เมื่อหารแล้ว ค่านี้ราบที่ 0.96 ทุก width และไม่มีอะไร saturate

ต่อไปคือส่วนที่ไม่มีใครตีพิมพ์: มันเปลี่ยน perplexity สุดท้ายไหม ลบการหารแล้วฝึก ที่ head widths สี่แบบ:

head widthไม่หารหารด้วย dk\sqrt{d_k}หารด้วย dkd_k
สี่ heads, 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

สองแถวแรกมาจาก budget 3000-step ข้างต้น สามแถวสุดท้ายเป็น run ที่สั้นกว่า — 1500 steps, batch 32, หนึ่ง head, ไม่มี normalisation ก่อน projections — โดยทั้งสอง variants อยู่ใต้ settings เดียวกัน

ที่ dk=32d_k = 32 การหารไม่มีค่าอะไร และ run ที่ไม่มีมันนำหน้าเล็กน้อยมาก นั่นไม่ใช่ใบอนุญาตให้ทิ้งมัน เพราะที่ 256 มันมีค่า 18 จุด perplexity และที่ 1024 มีค่า 17 กลไกเห็นได้จาก scores เอง:

dkd_kscore std ตอน initหลัง 1500 steps ไม่หารหลัง 1500 steps หารแล้วrows saturated ไม่หารหารแล้ว
25610.49121.672.1391.9 %0.8 %
51215.13836.852.6698.7 %1.3 %
102421.155147.463.4499.9 %16.5 %

head ที่ไม่หารไม่ฟื้นตัว มัน หนีเตลิด: standard deviation ของ scores จาก 21 ตอน initialisation กลายเป็น 5147, attention entropy ลดเป็นศูนย์ และ 99.9 % ของ rows ใส่น้ำหนักมากกว่า 0.99 ไว้ที่ token เดียว เมื่อ head กลายเป็น hard selector แล้ว gradient แทบเป็นศูนย์และไม่มีอะไรดึงมันกลับ ดังนั้นการ collapse จึงเสถียร head ที่หารแล้วอยู่ที่ score standard deviation 3.44 หลังการฝึกเดียวกัน ซึ่งเป็น soft blend ที่ยังเปลี่ยนได้

Vaswani et al. พูดเช่นนี้พอดีและไม่มากกว่านั้น — พวกเขาสงสัยว่าผลคูณ “มี magnitude ใหญ่ขึ้นสำหรับค่ามากของ dkd_k” แล้วหาร5 คำว่า ใหญ่ รับน้ำหนักไว้มาก และตารางบอกว่าใหญ่เริ่มตรงไหน: ไม่มีอะไรที่ 32 และทุกอย่างที่ 256

มากกว่าหนึ่งความคิดเห็น และสองในสามที่ไม่มีใครพูดถึง

ลิงก์ไปยังส่วน: มากกว่าหนึ่งความคิดเห็น และสองในสามที่ไม่มีใครพูดถึง

หนึ่ง head คือ softmax row หนึ่งต่อหนึ่งตำแหน่ง ดังนั้นมันมีคำตอบเดียวต่อ “อะไรเกี่ยวข้องตรงนี้” การทำนายคำหลัง the ใน the animal that crossed the wet street ต้องการช่องวากยสัมพันธ์ subject และ token ก่อนหน้าพร้อมกัน และ probability distribution หนึ่งอันไม่สามารถกระจุกอยู่สามที่ได้ ดังนั้นรันหลาย heads ขนานกัน แต่ละ head กว้าง dmodel/hd_{\text{model}}/h ต่อเข้าด้วยกัน แล้วผสมด้วยเมทริกซ์อีกตัว WoW_o: คุณแบ่ง width เป็นส่วน ๆ ไม่ได้เพิ่มมัน

Attention ยังทำสิ่งเดียวพอดี — มันย้ายข้อมูล ระหว่าง ตำแหน่ง operation ทุกตัวใน code ข้างต้นเป็น linear ตามแกน feature และบทที่ 5 พิสูจน์แล้วว่า stack ของ linear maps คืออะไร ดังนั้นแต่ละ block จึงมี MLP เล็ก ๆ ที่ใช้กับ แต่ละตำแหน่งแยกกัน ขยาย width สี่เท่าแล้วกลับมา โดยมี GELU ตรงกลาง การแบ่งงานนี้ควรจำให้ขึ้นใจ: attention ผสมข้ามตำแหน่ง feed-forward network คำนวณภายในตำแหน่ง

บันไดเต็ม แต่ละแถวเพิ่มหนึ่งชิ้นจากแถวเหนือมัน:

modelparametersvalidation perplexity
ค่าเฉลี่ยแบบสม่ำเสมอ บวกเข้าไป279,55260.45
attention head หนึ่งตัว แทนที่ token328,70455.47
attention head หนึ่งตัว บวกเข้าไป328,70446.10
สี่ heads แทนหนึ่ง345,21643.21
บวก feed-forward network476,92839.87
บวก LayerNorm — block สมบูรณ์477,69638.07

น้ำหนักที่เรียนรู้ได้ชนะน้ำหนักแบบสม่ำเสมอ 14 จุด perplexity ซึ่งเป็นข้อโต้แย้งทั้งหมดของบทนี้ในหนึ่งแถว สี่ heads ซื้อเพิ่มอีก 3 ด้วย parameters เพิ่ม 16,512 และ head เดียวกันมีค่ามากกว่า 9 จุดเมื่อ บวก มากกว่า แทนที่: attention นำข้อมูลเข้ามา มันไม่ได้ตัดสินว่าตำแหน่งหนึ่งคืออะไร

ทีนี้ parameters อยู่ตรงไหนจริง ๆ ซึ่งมักทำให้คนที่เคยเห็นแต่ diagram แปลกใจ:

widthheadsattentionfeed-forwardtotal per 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 network ในทุกสเกล เพราะ attention มีเมทริกซ์ d×dd \times d สี่ตัว และ MLP มีเทียบเท่าแปดตัว ไม่ว่า model จะรู้อะไร parameters ส่วนใหญ่ที่ถือมันไว้ก็อยู่ใน MLP ต่อหนึ่งตำแหน่ง

LayerNorm ถูกสร้างและวัดในบทที่ 6 และบทนี้ใช้มันตามที่ทิ้งไว้ตรงนั้น residual connections ถูกตั้งชื่อและ ablate ไว้ตรงนั้น และถูกสร้างที่นี่ แถว “บวก ไม่ใช่แทนที่” ด้านบนคือ residual connections มีค่า 188 จุด perplexity สำหรับค่าเฉลี่ย และ 9 สำหรับหนึ่ง head LayerNorm7 normalise แต่ละตัวอย่างข้าม features ของมัน และบทที่ 6 ให้เหตุผลว่าทำไมมัน ไม่ใช่ BatchNorm ที่รอดมาที่นี่ — ไม่พึ่ง batch, ไม่มี running statistics, เหมือนกันใน training และ inference, ไม่สนใจความยาว sequence — ทุกข้อกลายเป็น requirement เมื่อคุณ generate ทีละ token ให้ผู้ใช้หนึ่งคน ซึ่งคือจุดที่บทที่ 13 ไปถึง มันมีต้นทุน 768 parameters และซื้อ 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 path จาก input ไป output ไม่เคยถูก normalise นั่นคือ pre-norm paper ปี 2017 ทำตรงข้าม x = LayerNorm(x + Att(x))post-norm ซึ่งวาง LayerNorm บน residual path เอง

Xiong et al. อธิบายความต่างผ่าน gradient ตอน initialisation ซึ่งใน post-norm network ถูกสเกลกับ depth แย่มาก — เหตุผลที่ transformer ต้นฉบับต้องมี learning-rate warmup จึงจะฝึกได้เลย8 สิบสอง blocks, 1000 steps, 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 ไม่ใช่ best practice ทั่วไปตรงนี้ มันคือ patch สำหรับการจัดวาง normalisation แบบเฉพาะ และการย้าย LayerNorm เอาความจำเป็นของมันออก นั่นคือเหตุผลที่แทบทุก model ตั้งแต่ 2019 เป็น pre-norm และเหตุผลที่ diagram ปี 2017 ควรถูกอ่านเป็นประวัติศาสตร์ ไม่ใช่ specification

ลบ position embeddings แล้ว model ยังฝึกได้ มันแค่บอกไม่ได้ว่าอะไรอยู่ตรงไหน และนั่นเป็น symmetry ไม่ใช่ training failure ไม่มีอะไรใน attention score กล่าวถึง tt หรือ ii เอง ดังนั้นการสลับอินพุตจะสลับเอาต์พุต: self-attention เป็น permutation-equivariant มันคือความมองไม่เห็นลำดับของค่าเฉลี่ยในหน้ากากที่ดีกว่า — causal mask คืนลำดับบางส่วน เพราะแต่ละตำแหน่งเห็น prefix ต่างกัน แต่ภายใน prefix การเรียงทุกรูปแบบเหมือนกัน

สี่วิธีในการฉีดตำแหน่ง ฝึกบนหน้าต่าง 64-token และประเมินที่ 64, 128 และ 256 — เลยความยาวใด ๆ ที่มันเคยเห็น:

positionsperplexity ที่ 64ที่ 128ที่ 256
ไม่มีเลย48.7952.6357.52
learned absolute embeddings38.63108.47181.94
fixed sinusoids42.9695.26152.25
RoPE44.1250.5284.84
ALiBi44.9543.5142.49

Learned absolute embeddings — vector หนึ่งตัวต่อตำแหน่ง บวกเข้ากับ token — ชนะที่ความยาวที่ฝึก แล้วตกหน้าผา เพราะตำแหน่ง 100 ไม่เคยอยู่ใน batch และ embedding ของมันยังเป็น random vector ที่เริ่มต้นมา Sinusoids ตัวเลือกดั้งเดิม คำนวณแทนการเรียนรู้ จาก sines และ cosines ที่ความถี่เว้นแบบเรขาคณิต paper ปี 2017 หวังว่านั่นจะ extrapolate และตารางบอกว่าไม่ — ฟังก์ชันนิยามที่ตำแหน่ง 200 แต่ model ไม่เคยเรียนรู้ที่จะอ่านมันตรงนั้น RoPE9 ไม่เพิ่มอะไร แต่ หมุน query และ key ด้วยมุมที่แปรตามตำแหน่ง ในชิ้นสองมิติ; เพราะการหมุนทั้งสองฝั่งของ dot product เท่ากันทำให้มันไม่เปลี่ยน score จึงลงเอยว่าขึ้นกับ tit - i เท่านั้น ดังนั้นตำแหน่งกลายเป็น relative ฟรี ๆ และไม่มีตารางให้ใช้หมด มัน degrade แต่ก็เป็นการ degrade ALiBi10 คือผลลัพธ์ที่ง่ายที่สุดและประหลาดที่สุดที่นี่: linear penalty บน score แปรตามระยะทาง โดยมี slope ต่างกันต่อ head Perplexity ของมัน ดีขึ้น เมื่อหน้าต่างโตเกินความยาวฝึก จาก 44.95 เป็น 42.49 เพราะ penalty นิยามได้ทุกระยะและทุก head ทำสิ่งที่มันถูกฝึกให้ทำต่อไป

บทเรียนอยู่ยาวกว่าตาราง: สถาปัตยกรรมที่ represent บางอย่างไม่ได้ เป็นคนละปัญหากับสถาปัตยกรรมที่ไม่เคย learned range นั้น และอย่างหลังคือสิ่งที่กัดคุณ นี่ยังเป็นกลไกเบื้องหลังประกาศทุกครั้งว่า “เราขยาย context เป็น 128K” — เกือบทั้งหมดคือการ re-scale rotary encoding และนั่นคือเหตุผลที่ บทที่ 16 บอกว่า context limit เคลื่อนที่ ไม่ใช่หายไป

Dropout รับมาด้วยวิธีเดียวกัน: มันปรากฏบน attention weights หลัง softmax, บนเอาต์พุตของแต่ละ sub-layer ก่อน residual addition, และบน embedding sum ทำสิ่งที่บทที่ 6 อธิบายพอดี ใน runs pretraining ขนาดใหญ่ มักตั้งเป็นศูนย์ เพราะ model ที่เห็นแต่ละ token ครั้งเดียวไม่ได้อยู่ในสภาพที่จะ overfit

มี tensors สองตัวใน layer ที่มี shape n×nn \times n โดย nn คือจำนวน tokens: scores และ weights หลัง softmax อย่างอื่นทั้งหมด — ทุก projection, MLP ทั้งหมด — เป็น linear ใน nn

หนึ่ง attention layer กว้าง 512, 8 heads, batch หนึ่ง, float32 บน laptop GPU อ่านสองคอลัมน์มิลลิวินาทีเพื่อดู อัตราส่วน เท่านั้น: มันคือ wall clock บนการ์ด laptop 8 GB ที่ throttle จาก 1,785 MHz ลงต่ำกว่า 300 MHz เมื่อร้อน ดังนั้น cold run ของ code เดียวกันนี้จะกลับมาเร็วกว่าเจ็ดถึงสิบเท่า และ run ตอนยุ่งจะช้ากว่านั้นอีก คอลัมน์เมกะไบต์คือ allocator byte counts และไม่ขยับ

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 เป็นสองเท่าลู่เข้า 4 พอดีทั้งเวลาและหน่วยความจำ — 3.91 ที่ step สุดท้ายเทียบกับทฤษฎี 4 คอลัมน์ projections คือ control: 4.0 ms ที่ 1024 tokens ไป 40.1 ms ที่ 8192 เป็นปัจจัยสิบสำหรับปัจจัยแปด Linear ตามที่โฆษณา

แล้วดูแถวสุดท้าย หนึ่ง attention layer, หนึ่ง sequence, ไม่มี model รอบมัน หน่วยความจำหมดบน GPU 8 GB ที่ 16,384 tokens — แค่ score matrix อย่างเดียวก็เป็น 8 GB แล้ว เพราะเป็น 8 heads คูณ 16,384 คูณ 16,384 คูณ 4 bytes ไม่ใช่ model; เป็น intermediate tensor ตัวเดียวใน layer เดียว

นั่นคือข้อเท็จจริงทางกายภาพใต้สามบทถัดไป มันคือเหตุผลที่ context window มีขีดจำกัดเลย ซึ่งบทที่ 16 เปลี่ยนเป็นราคา มันคือเหตุผลที่ FlashAttention มีอยู่ โดยคำนวณผลลัพธ์เดียวกันเป็น tiles โดยไม่เคยเก็บเมทริกซ์ — เป็น memory optimisation ก่อนจะเป็น speed optimisation11 และมันคือเลขคณิตเบื้องหลังราคาของ prompt ยาว ซึ่งบทที่ 24 จ่ายใน agent loop — เป็นคนละเรื่องกับข้อค้นพบอีกอย่างของบทนั้น ว่า model ยัง ใช้ context ยาวได้แย่ลงด้วย ซึ่งบทนั้นวัดและปฏิเสธที่จะโทษสูตรนี้

แสดงรายละเอียด

สอง variants ที่ทำให้ cache เล็กลง ตั้งชื่อไว้ที่นี่และจ่ายบัญชีในบทที่ 13

Generation cache keys และ values ของ tokens ที่ประมวลผลแล้ว — หนึ่ง key และหนึ่ง value ต่อ token, ต่อ head ต่อ layer Multi-query attention12 เก็บ query projections hh ตัว แต่มี key และ value projection เดียวที่ heads ทั้งหมดแชร์กัน หาร cache นั้นด้วย hh Grouped-query attention13 อยู่กึ่งกลาง: heads ถูกจัดกลุ่ม แต่ละกลุ่มแชร์ key และ value หนึ่งชุด ดังนั้น g=hg = h คือ attention ธรรมดา และ g=1g = 1 คือ multi-query แทบทุก open model ตั้งแต่ 2023 ใช้มันกับ 4 หรือ 8 groups ทั้งสองอย่างไม่ได้มีอยู่เพื่อคุณภาพ ทั้งสองมีอยู่เพื่อขนาดของ cache นั้น และบทที่ 13 ทำเลขคณิตที่เปลี่ยนมันเป็น “model ไหน fit ใน GPU ของคุณ”

สองรูปร่าง และขนาดของหนึ่งรูปร่าง

ลิงก์ไปยังส่วน: สองรูปร่าง และขนาดของหนึ่งรูปร่าง

paper ปี 2017 อธิบาย encoder-decoder: stack หนึ่งอ่าน source ด้วย unmasked attention, stack ที่สอง generate target แบบ causal, และ attention ชนิดที่สามตรงกลางที่ queries ของ decoder พบ keys ของ encoder นั่นถูกต้องสำหรับการแปล ที่อินพุตและเอาต์พุตเป็นสอง sequences

สิ่งที่ชนะคือครึ่งแบบ decoder-only — stack เดียว causal ทั้งหมด อินพุตและเอาต์พุตอยู่ใน sequence เดียวกัน — และเหตุผลไม่ใช่ความงาม “ทำนาย token ถัดไป” รันได้บน text ใดก็ได้ ดังนั้น training set คืออินเทอร์เน็ต ไม่ใช่ parallel corpus และทุกอย่างกลายเป็นงานเดียวกันนั้น: การแปลคือ document ที่มี source แล้ว target, คำถามและคำตอบของมันคือ document, บทสนทนาที่มี tool call กลางทางคือ document บทที่ 11 ว่าด้วยการผลิตอย่างหลัง Encoders ไม่ได้หายไป — ตัวหนึ่งเห็นอินพุตทั้งหมดพร้อมกัน ซึ่งคือสิ่งที่ต้องการเมื่องานคือการ represent text ไม่ใช่ต่อมัน และนั่นคือเหตุผลที่ retrieval embeddings ของบทที่ 19 มาจาก encoders ไม่ใช่จาก model ที่กำลัง chat

เมื่อกำหนด block แล้ว ขนาด model คือเลขคณิต ต่อ block ด้วย width dd และการขยายสี่เท่า: 4d2+4d4d^2 + 4d สำหรับ Wq,Wk,Wv,WoW_q, W_k, W_v, W_o พร้อม biases บนทั้งสี่ เหมือน GPT-2 มี — ตารางด้านบนละ bias ออกสามตัว จึงน้อยกว่า 2,304 ต่อ block ที่ d=768d = 768; 8d2+5d8d^2 + 5d สำหรับ MLP; 4d4d สำหรับ LayerNorms สองตัว — 12d2+13d12d^2 + 13d บวก token table V×dV \times d และสำหรับ absolute positions, nctx×dn_{\text{ctx}} \times d สำหรับรูปร่างของ GPT-2 small — d=768d = 768, 12 blocks, vocabulary 50,257, context 1024, output layer แชร์ embedding weights:

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 โปรดสังเกตด้วยว่าเกือบหนึ่งในสามของ small model คือ embedding table นั่นคือเหตุผลที่ vocabulary size เป็นการตัดสินใจทางสถาปัตยกรรม ไม่ใช่ preprocessing — trade-off ที่บทที่ 7 วางไว้

Perplexity เป็นตัวเลขเกี่ยวกับ corpus สิ่งที่ head หนึ่งทำเป็นคำถามอีกแบบ และ model ที่ฝึกบน Shakespeare หนึ่งเมกะไบต์เป็นเครื่องมือผิดสำหรับมัน: สิ่งที่ซื่อสัตย์คือการพูดว่า attention map ของ model 500,000-parameter ส่วนใหญ่ตีความไม่ได้ ดังนั้น: ใช้ภาษาที่คำถามมีคำตอบถูก

ภาพประกอบคลาสสิกคือ the animal did not cross the street because it was too tired ที่ it คือ animal เทียบกับ …because it was too wet ที่คำเดียวขยับ referent ไปที่ street นี่คือ Winograd schemas14 — คู่ประโยคที่เหมือนกันทุกอย่างยกเว้นคำเดียว และคำนั้นตัดสินว่าสรรพนามอ้างถึงอะไร

มันยัง แก้ได้ด้วยการโกง ซึ่งเป็นส่วนที่ tutorials ข้าม ถ้าผู้สมัครสองตัวเป็นสัตว์และสถานที่ tired และ wet ระบุ referent ด้วย หมวดหมู่ และ model ที่รู้แค่ว่ามีคำไหนอยู่ก็ทำถูกได้โดยไม่รู้อะไรเกี่ยวกับลำดับ วัดบน version นั้นของงาน ด้วยคู่ 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

ดังนั้นปิดช่องโหว่: เลือกผู้สมัคร ทั้งสอง จาก pool เดียวกันของ nouns สิบหกคำ ซึ่งตัวใดก็ปรากฏใน slot ใดก็ได้ และแบ่ง adjectives ตาม บทบาท แทนหมวดหมู่ — สี่คำทำให้ it เป็นผู้ข้าม (tired, scared, slow, weak) สี่คำทำให้มันเป็นสิ่งที่ถูกข้าม (wet, wide, busy, steep)

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

ฝึกเป็น next-token predictor ธรรมดา ให้ score หนึ่งตำแหน่ง — คำหลัง so the — และสร้าง held-out set จากคู่ nouns ที่ลำดับ กลับกัน อยู่ใน training ดังนั้นอะไรก็ตามที่รู้ว่าสอง nouns ไหนอยู่ แต่ไม่รู้ว่าอะไรมาก่อน ต้องตอบกลับด้าน

modelparametersheld-outตั้งชื่อ noun อีกตัว
token ปัจจุบันเท่านั้น5,7965.2 %5.2 %
ค่าเฉลี่ย causal แบบสม่ำเสมอ5,79627.9 %50.0 %
learned attention หนึ่ง head18,08435.4 %64.6 %
สี่ heads22,24475.0 %15.6 %
transformer block หนึ่ง55,71692.7 %4.2 %
transformer blocks สอง105,508100.0 %0.0 %

โอกาสสุ่มในสอง nouns ที่มีอยู่คือ 50 % ค่าเฉลี่ยแบบสม่ำเสมอจบที่ 27.9 % และตอบด้วย noun ผิดของคู่นั้นครึ่งหนึ่งพอดี — ลายเซ็นของสิ่งที่รู้ว่ามีคำอะไรอยู่ แต่ไม่รู้อะไรเกี่ยวกับลำดับ ตามที่ shuffle test ทำนายไว้สาม sections ก่อน

ทีนี้ดู map: attention ที่ตำแหน่งซึ่งต้องตั้งชื่อ referent เฉลี่ยเหนือสี่ heads ของแต่ละ block สำหรับสองประโยคที่ต่างกันหนึ่งคำ ค่าเฉลี่ยสม่ำเสมอจะใส่ 0.067 บนแต่ละ token จากสิบห้า token ที่มองเห็น

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 บน noun แรก ไม่ว่า adjective คืออะไร นั่นไม่ใช่ความล้มเหลวแต่เป็นหลักฐาน: ใน layer แรก query ที่ตำแหน่งหนึ่งเป็นฟังก์ชันของ token และ index ของตำแหน่งนั้นเอง และ the ที่ตำแหน่ง 14 เป็น token เดียวกันในทั้งสองประโยค head ชั้นแรก condition บนคำที่มันยังไม่ได้ fetch ไม่ได้ ดังนั้น block 1 ทำสิ่งเดียวที่มีประโยชน์ที่ทำได้ และลาก noun แรกไปข้างหน้า

Block 2 คือที่ที่ประโยคแยกทางกัน และ row เดียวกันข้าม adjectives ทั้งแปดแสดงกฎที่ model พบ:

adjectiveblock 2 บน animalบน streetบน adjectiveคำตอบ
tired, scared, slow, weak0.0000.0001.000animal
wet, wide, busy, steep0.0000.4910.00–0.03street

สำหรับ crosser-adjective block ที่สองใช้ weight ทั้งหมดบน adjective เพราะคำตอบอยู่ใน residual stream แล้ว — block 1 ใส่มันไว้ตรงนั้น — และสิ่งที่ต้องการมีแค่การยืนยัน สำหรับ crossed-adjective มันไป fetch noun อีกตัวแทน นั่นคือ two-hop circuit: head หนึ่งย้าย candidate ไปข้างหน้า head ใน layer ถัดมาอ่าน token ที่ตัดสินว่าจะเก็บมันหรือไม่ Composition ข้าม layers คือกลไก และนั่นคือเหตุผลที่หนึ่ง block ถึง 92.7 % และสอง block ถึง 100 %

มันยังเป็นรูปร่างของ circuit ที่มีเอกสารดีที่สุดใน models จริง Induction heads — previous-token head ที่ป้อน head ใน layer ถัดไปซึ่งเติม pattern [A][B] … [A] → [B] — คือสิ่งที่งาน interpretability ของ Anthropic ระบุว่าอยู่เบื้องหลังส่วนใหญ่ของ in-context learning และมันก่อตัวในช่วงเวลาที่ระบุได้ระหว่าง pretraining บทนี้ไม่พยายามทำ analysis นั้น: มันถูกมอบหมายต่อ พร้อม papers ทั้งสองใน references เพราะการอ่าน circuits ออกจาก model จริงเป็นสาขาวิจัย ไม่ใช่ section หนึ่ง

สุดท้าย implementation สามสิบบรรทัดข้างต้น พร้อม weights ที่คัดลอกจาก 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} บนเอาต์พุตที่ mean magnitude คือ 0.159: เลขคณิตเดียวกันในลำดับที่ต่างกัน ที่ precision float32

คุณมีสถาปัตยกรรมที่ทุก model ในส่วนที่เหลือของคอร์สสร้างขึ้นจากมันแล้ว และมันเล็กกว่าชื่อเสียงของมัน: ค่าเฉลี่ยถ่วงน้ำหนักที่น้ำหนักถูกเรียนรู้, MLP ต่อหนึ่งตำแหน่งที่ถือ parameters สองในสาม, normalisations สองตัวและ additions สองครั้ง วางซ้อนกัน

สิ่งที่คุณยังไม่มีคือ model ที่รู้อะไร และการ stack ด้วยตัวมันเองจะไม่แก้เรื่องนั้น สอง blocks บน corpus นี้ถึง training perplexity 14.49 และ validation perplexity 40.57 เทียบกับหนึ่ง block ที่ 18.77 และ 38.07 — capacity มากขึ้น ดีขึ้นบนสิ่งที่มันเคยเห็น แย่ลงบนสิ่งที่ไม่เคยเห็น ซึ่งคือตารางของบทที่ 6 ที่มี transformer อยู่ในนั้น ระยะห่างระหว่าง model นี้กับ models ที่บทที่ 14 ถึง 30 คุยด้วย ไม่ใช่สถาปัตยกรรม มันคือ block เดียวกัน ทำซ้ำมากกว่าหลายครั้ง บน text มากกว่ามหาศาล

ซึ่งทำให้มันเป็นปัญหาบัญชี และบัญชีนั้นประหลาดกว่าที่เห็น text เท่าไร และใครเอามาจากไหน เลขคณิตเท่าไร และคุณประมาณมัน ก่อน ใช้เงินได้อย่างไร ถ้ามี budget คงที่ ทำให้ model ใหญ่ขึ้นดีกว่า หรือให้มันเห็นข้อมูลมากขึ้นดีกว่า — และมีคำตอบที่ถูกต้องไหม หรือมีแค่กระแส บทที่ 10 ตอบทั้งสามด้วยการวัด และติดราคาให้รูปแบบที่ถูกที่สุดและมีประโยชน์ของคำถาม: วันนี้ต้องใช้เงินเท่าไรในการฝึก model แบบ GPT-2 จากศูนย์


คำอธิบายสามชิ้นของเนื้อหานี้ทำหน้าที่ของมันได้ดีกว่าชิ้นนี้ และบทนี้เขียนมาให้อ่านคู่กับพวกมัน The Illustrated Transformer ของ Jay Alammar คือภาพ data flow ที่ดีที่สุดเท่าที่เคยวาด The Annotated Transformer ของ Harvard NLP คือ paper ปี 2017 ที่สอดแทรก code ที่รันได้ทีละบรรทัด Let’s build GPT: from scratch, in code, spelled out ของ Andrej Karpathy สร้าง model เดียวกันสด ๆ ในสองชั่วโมง และบันได ablations ด้านบนคือแกนเดียวกันที่วัดบน corpus อีกชุด สำหรับคำถาม interpretability ที่บทนี้แตะแค่บางส่วน แหล่งหลักคือ Elhage et al., A Mathematical Framework for Transformer Circuits (2021) และ Olsson et al., 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 vector เดียวเป็นคอขวด

  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 คือ exponential ของ mean cross-entropy ต่อ token จากบทที่ 8 ตัวเลขทุกตัวที่นี่ใช้ tokenizer เดียวกันและ validation split เดียวกัน ซึ่งเป็นเงื่อนไขเดียวที่ทำให้ perplexities สองค่าเปรียบเทียบกันได้

  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). Section 3.2.1 คือหนึ่งประโยคเกี่ยวกับ dk\sqrt{d_k} ที่บทนี้ใช้หนึ่ง section ในการวัด

  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 เป็นอาการ

  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 ที่ทุก attention tutorial ใช้


สร้างโดย

David Vicente Campos

ผู้ก่อตั้ง NeuraLIA Labs และผู้ร่วมก่อตั้ง MyRealFood

ผมเป็นวิศวกรคอมพิวเตอร์ที่จบจากมหาวิทยาลัยเลออน ผมร่วมก่อตั้ง MyRealFood ที่ที่ผมในฐานะ CTO ได้สร้างแอปซึ่งผู้คนหลายล้านคนใช้เพื่อกินให้ดีขึ้น และผมก่อตั้ง NeuraLIA Labs ที่ที่ผมสร้างผลิตภัณฑ์ AI ที่นี่ผมเขียนถึงสิ่งที่ผมต้องทำความเข้าใจระหว่างทาง ในแบบที่ผมเคยหวังว่าจะมีใครสักคนอธิบายให้ผมฟัง

เพิ่มเติมเกี่ยวกับผู้เขียน

เผยแพร่โดย NeuraLIA Labs

รับโพสต์ใหม่ในกล่องจดหมาย

ข่าว AI คู่มือ และอัปเดตผลิตภัณฑ์ — อีเมลสั้น ๆ เมื่อเรามีสิ่งที่คุ้มเวลาของคุณ

ชอบแบบข้อความมากกว่าไหม รับเนื้อหาเดียวกันได้ที่นี่:คอมมูนิตี้ WhatsApp (เปิดในแท็บใหม่)ช่อง Telegram (เปิดในแท็บใหม่)

ดัชนีคอร์ส

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jevอ่าน 5 นาที

โมเดล AI Jev สร้างมาเพื่อการตัดสินใจ ไม่ใช่การเขียนความเรียง

Jev ของ TypeSafe AI กำลังได้รับความสนใจ เพราะมองความฉลาดของซอฟต์แวร์เป็นปัญหาความน่าจะเป็น: เลือกกิ่งที่ถูกต้อง แนบความมั่นใจ และหลีกเลี่ยงการจ่ายเงินให้ LLM เขียนข้อความเมื่อโค้ดต้องการการตัดสินใจ

Abstract legal research workspace with documents, search nodes and governance controls.
openaiอ่าน 4 นาที

Astra for Law ของ OpenAI คือระบบ AI ด้านกฎหมาย ไม่ใช่โมเดลใหม่

การเปิดตัวด้านกฎหมายของ OpenAI ไม่ได้เน้นโมเดลฐานรากใหม่เท่ากับระบบที่ล้อมรอบโมเดลนั้น: การค้นคืนเฉพาะโดเมน เครื่องมือที่เชื่อถือได้ สิทธิ์ เบนช์มาร์ก และเส้นทางการตรวจทาน

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineeringอ่าน 4 นาที

วิศวกรรมบริบทสำหรับเอเจนต์ AI ที่ทำงานระยะยาว

เอเจนต์ที่ทำงานต่อเนื่องไม่ได้ล้มเหลวเพียงเพราะหน้าต่างบริบทเล็กเกินไป แต่ล้มเหลวเมื่อไฟล์ ผลลัพธ์จากเครื่องมือ และประวัติที่ค้างเก่าบดบังงานที่เอเจนต์ควรทำให้เสร็จ

พร้อมให้ LIA เลือกโมเดลให้แล้วหรือยัง?

สร้างงานด้วยโมเดล AI ทุกตัวในที่เดียว เริ่มฟรีวันนี้