Attention Is All You Need
น้ำหนัก 0.70 มาจากไหน: แกะสูตร Self-Attention ทีละขั้นด้วยมือ (ตอนที่ 2)
ตอนที่ 1 กำหนดทั้งน้ำหนักกับ value มาให้ เราเลยเห็นแล้วว่ามันผสมออกมาอย่างไร แต่ยังไม่ได้ให้ query กับ key ที่ใช้คิดน้ำหนัก 0.70 บทนี้จะเติมกลไกส่วนนั้นด้วยเวกเตอร์ชุดใหม่ ไม่ได้แกะย้อนว่าค่า 0.70 เดิมเกิดจากคู่ไหน
Attention(Q, K, V) = softmax(QKᵀ / √d_k) V
เริ่มจาก RNN seq2seq ที่ส่งสถานะทีละตำแหน่ง งาน Bahdanau ปี 2014 เพิ่ม additive attention ให้ decoder เลือกดูสถานะของ encoder ได้ แต่ทั้งคู่ยังเป็น RNN จากนั้น Transformer ปี 2017 จึงแทน recurrence ด้วย attention โดยยังมี feed-forward, residual และ layer norm อยู่ สี่ท่อนในสูตรคือวัดว่าเข้ากัน ปรับสเกล แปลงเป็นสัดส่วน แล้วผสมตามสัดส่วน
แวะนิดหนึ่ง — หน้า Self-Attention คืออะไร ใช้ประโยค “แมว มอง หนู บน พรม” ให้เลื่อน T เอง ตัวเลขคนละชุดกับของเล่นในบทนี้
1. คำถามตั้งต้น
ในสูตร softmax(QKᵀ / √d_k) V น้ำหนักที่แต่ละคำให้กับคำอื่นคำนวณมาอย่างไร ถูกนำไปใช้อย่างไร และทำไมภายในลำดับเดียวทั้งหมดนี้ถึงทำพร้อมกันได้ โดยไม่ต้องส่งบันทึกทีละตำแหน่งแบบ RNN?
ถ้าอ่านจบแล้วอธิบายได้ว่า Q, K, V แต่ละตัวทำอะไร ทำไมต้องหารด้วย √d_k และทำไมน้ำหนักในแต่ละแถวรวมกันได้ 1 ก็ได้แกนของบทนี้แล้ว ของเล่นสามคำเป็น encoder ไม่มี mask ที่ค่าเริ่มต้น query ของแมวคือ (1, 0) น้ำหนักมากสุดของแถวนั้นตกที่ตัวเอง ไม่ใช่ 0.70 รูปด้านล่างเริ่มที่ค่านี้ แล้วเลขในรูปตามแถบที่เลื่อน
2. ปูพื้นฐานทีละขั้น
ขั้นที่ 0: เส้นทางขากลับ
ตอนที่ 1 มองความจางของข้อมูลจากทางที่เดินไปข้างหน้า คำต้น ๆ ต้องถูกส่งต่อผ่านบันทึกทีละขั้นกว่าจะถึงคำท้าย ในส่วน Why Self-Attention ผู้เขียนเขียนว่าสิ่งที่สำคัญต่อการเรียนรู้ความสัมพันธ์ระยะไกลคือความยาวของเส้นทางที่สัญญาณทั้งขาไปและขากลับต้องเดิน การจางนี้เป็นการถูกผสมไปตามเส้นทางยาว LSTM มี forget gate ส่วน GRU ใช้ update gate กับ reset gate RNN ธรรมดาไม่มีประตูพวกนั้น
ขากลับคือสัญญาณที่ใช้สอน ถ้าคำสุดท้ายของประโยคยาว 50 คำแปลผิดเพราะไม่ได้ใช้ข้อมูลจากคำที่ 2 สัญญาณแก้ต้องย้อนเกือบ 50 ช่วง และระหว่างทางมันถูกผสมกับเรื่องของคำอื่น สิ่งที่ไปถึงต้นทางจึงอาจอ่อนหรือเพี้ยนจนแทบใช้สอนไม่ได้ ปัญหาจึงไม่จบที่ “ข้อมูลเก่าจาง” มันรวมถึง “บทเรียนจากความผิดพลาดส่งไปไม่ถึงต้นเหตุ” ทั้งสองอย่างมาจากเส้นทางที่ยาวตามระยะห่าง
paper อ้างงานของ Hochreiter และคณะ เป็นอ้างอิง [12] ในฉบับ arXiv เรื่อง gradient flow ใน recurrent nets บทนี้ไม่ได้อ่านงานนั้นเอง จึงถือตามที่ Vaswani และคณะเขียนอ้าง ไม่ได้ตรวจหลักฐานต้นทาง
ถ้าทุกคู่ตำแหน่งเหลือเส้นทางหนึ่งก้าว ทั้งข้อมูลขาไปและสัญญาณสอนขากลับถึงกันได้ในก้าวเดียว นั่นคือสิ่งที่ self-attention ทำ หัวข้อต่อจากนี้คือหนึ่งก้าวหน้าตาเป็นตัวเลขอย่างไร
ขั้นที่ 1: vector คือรายการตัวเลข
ตอนที่ 1 บอกแล้วว่าแต่ละ token ถูกแปลงเป็น vector คือรายการตัวเลข รุ่น base ใน paper ยาว 512 ตัว บทนี้ย่อเหลือ 2 ตัวเพื่อให้คิดในหัวได้ เช่น (1, 0) หรือ (0.5, 0.5) สิ่งที่ต้องใช้มีแค่ว่าเอามันมาบวก คูณ และเปรียบเทียบกันได้
ขั้นที่ 2: dot product คือคะแนนความเข้ากัน
dot product ของสอง vector คือเอาตัวเลขตำแหน่งเดียวกันมาคูณกัน แล้วบวก ตัวอย่างนี้เป็นนิยามของการคูณ ไม่ใช่น้ำหนัก attention และยังไม่มี softmax:
- (1, 2) · (3, 1) = 1×3 + 2×1 = 5
- (1, 0) · (0, 1) = 0
- (1, 0) · (−1, 0) = −1
ถ้าสอง vector ชี้ทางเดียวกัน ผลเป็นบวกมาก ถ้าตั้งฉาก ผลใกล้ 0 ถ้าชี้สวน ผลติดลบ มันจึงใช้เป็นคะแนนความเข้ากันแบบหยาบได้ และมันมีแค่คูณกับบวก จึงเขียนเป็นการคูณเมทริกซ์ได้ ล็อก q = (1, 0) ไว้ k = (1, 0) ได้คะแนน 1 แต่ k = (3, 0) ได้ 3 ทั้งที่ชี้ทางเดียวกัน vector ที่ยาวกว่าให้คะแนนสูงกว่า ข้อนี้กลับมาตอนหารด้วย √d_k
ขั้นที่ 3: Query, Key, Value
ในส่วน 3.2 paper นิยาม attention ว่าเป็นการแปลง query หนึ่งตัวกับชุดของคู่ key–value ให้เป็น output ทั้งหมดเป็น vector และ output คือผลรวมถ่วงน้ำหนักของ value น้ำหนักของแต่ละ value มาจากฟังก์ชันวัดความเข้ากันระหว่าง query กับ key ที่คู่กับ value นั้น
ทุก token สวมสามบทบาทพร้อมกัน
- Query (Q) ใช้ตอน token นั้นเป็นฝ่ายถาม เช่นคำว่า “มัน” อาจกำลังมองหาคำนามที่มันอ้างถึง คำว่า “ฉันกำลังมองหาอะไร” ในที่นี้คือปากของ token
- Key (K) คือป้ายที่เอาไปเทียบกับ query ของคนอื่น
- Value (V) คือเนื้อหาที่จะถูกส่งต่อเมื่อ token นั้นได้น้ำหนัก
หัวข้ออีเมลช่วยให้เราตัดสินใจว่าจะเปิดไหม แต่สิ่งที่ได้หลังเปิดคือเนื้อหาข้างใน key กับ value ก็แยกหน้าที่กันแบบนี้ ป้ายที่ใช้เลือกไม่จำเป็นต้องเหมือนของที่ส่งต่อ
แล้ว Q, K, V มาจากไหน? ในส่วน 3.2.2 มีการฉายด้วยเมทริกซ์ที่เรียนรู้ได้ W^Q, W^K, W^V token เดียวกันถูกคูณสามชุด ได้ q, k, v สามตัว ตัวเลขในเมทริกซ์ไม่มีใครตั้งมือ โมเดลเรียนรู้ระหว่างเทรน ในส่วน 3.2.3 self-attention ของ encoder ใช้ key, value และ query จากที่เดียวกัน คือ output ของ layer ก่อนหน้า การฉายหลายชุดพร้อมกันเป็นเรื่อง multi-head ของตอนถัดไป ของเล่นในบทนี้เริ่มหลังการฉายแล้ว คือให้ q, k, v มาเลย
น้ำหนักใหญ่ได้เมื่อ query ของฝ่ายถามเข้ากับ key ของอีกคำ และความเข้ากันวัดด้วย dot product ตอนที่ 1 มีน้ำหนักกับ value แล้ว แต่ยังไม่มี query กับ key ของเลข 0.70 บทนี้จึงไม่แกะย้อนคู่นั้น
ขั้นที่ 4: คะแนนทุกคู่ใน QKᵀ
ถ้ามี n token คะแนนที่ต้องคิดคือ query ของคำที่ i กับ key ของคำที่ j ครบ n × n คู่ paper แพ็ก query ทุกตัวเป็นเมทริกซ์ Q แต่ละแถวคือ query ของหนึ่ง token แล้วแพ็ก key กับ value เป็น K กับ V จากนั้นคำนวณ QKᵀ ช่องแถว i คอลัมน์ j คือคะแนนระหว่าง query i กับ key j การคูณเมทริกซ์ครั้งเดียวจึงเท่ากับ dot product ครบทุกคู่
ขั้นที่ 5: หารด้วย √d_k
d_k คือจำนวนตัวเลขใน query และใน key แต่ละตัว รุ่น base ของ paper ใช้ d_k = 64 ต่อ head ก่อนส่งคะแนนเข้า softmax ให้หารทุกช่องด้วย √d_k รูปคณิตเหมือน softmax ที่ตั้ง T = √d_k แต่ในสูตรนี้ค่าถูกกำหนดจากมิติของ key ไม่ใช่ปุ่มอุณหภูมิที่เลือกได้อิสระ ส่วนหน้า Self-Attention คืออะไร ให้ลองเปลี่ยน T เองและใช้ตัวเลขคนละชุด
เหตุผลในส่วน 3.2.1 มีสองชั้น
- ผู้เขียนอ้างข้อสังเกตจากงานของ Britz และคณะ อ้างอิง [3] ว่าเมื่อ d_k เล็ก dot-product attention กับ additive attention ทำงานได้ใกล้กัน แต่เมื่อ d_k ใหญ่ additive attention ทำได้ดีกว่า dot-product แบบไม่ปรับสเกล บทนี้ไม่ได้อ่านงานของ Britz เอง
- คำอธิบายที่ผู้เขียนสงสัยว่าเป็นสาเหตุ ผู้เขียนใช้คำว่า “We suspect” เมื่อ d_k ใหญ่ dot product จะมีขนาดใหญ่ ซึ่งดัน softmax เข้าไปในบริเวณที่ gradient เล็กมาก จึงหารด้วย √d_k เพื่อหักล้าง นี่เป็นข้อเสนอ ไม่ใช่บทพิสูจน์
ทำไม dot product ถึงโตตาม d_k? footnote ที่ 4 บอกไว้ตรง ๆ ว่า ถ้าแต่ละมิติของ q และของ k เป็นอิสระกันและแจกเหมือนกัน ค่าเฉลี่ย 0 ความแปรปรวน 1 แล้ว q · k มีค่าเฉลี่ย 0 และ Var(q · k) = d_k ส่วนเบี่ยงเบนมาตรฐานคือ √d_k การหารด้วย √d_k ทำให้ความแปรปรวนของคะแนนเป็น 1 ภายใต้ข้อสมมตินี้ ไม่ได้รับประกันว่าเวกเตอร์จริงในโมเดลจะเป็นแบบนี้ทุกครั้ง การสุ่มแต่ละชุดแกว่งรอบ d_k และรอบ 1 หลังหาร
ความแปรปรวน ของ q · k
แต่ละช่องของ q และ k สุ่มแบบอิสระ ค่าเฉลี่ย 0 ความแปรปรวน 1 ด้วย mulberry32 ที่ seed ด้านล่าง 4000 คู่ต่อหนึ่งค่า d_k ความแปรปรวนของตัวอย่างคือค่าเฉลี่ยของ (x − ค่าเฉลี่ย)2 ปุ่มสุ่มใหม่บวก seed ทีละ 1 แล้วคำนวณใหม่
ตัวเลขในรูปเป็นการสุ่มจากข้อสมมติของ footnote ไม่ใช่ตัวเลขจาก paper
-
d_k = 2 · ทฤษฎี 2 · หลังหารทฤษฎี 1
- ไม่หาร วัดได้ 1.9705
- ไม่หาร ทฤษฎี 2
- หาร √d_k วัดได้ 0.9853
- หาร √d_k ทฤษฎี 1
-
d_k = 64 · ทฤษฎี 64 · หลังหารทฤษฎี 1
- ไม่หาร วัดได้ 63.3198
- ไม่หาร ทฤษฎี 64
- หาร √d_k วัดได้ 0.9894
- หาร √d_k ทฤษฎี 1
-
d_k = 512 · ทฤษฎี 512 · หลังหารทฤษฎี 1
- ไม่หาร วัดได้ 496.5016
- ไม่หาร ทฤษฎี 512
- หาร √d_k วัดได้ 0.9697
- หาร √d_k ทฤษฎี 1
seed 1 · N = 4000 · d_k 2 วัดได้ 1.9705 ทฤษฎี 2 · หลังหาร วัดได้ 0.9853 ทฤษฎี 1 · d_k 64 วัดได้ 63.3198 ทฤษฎี 64 · หลังหาร วัดได้ 0.9894 ทฤษฎี 1 · d_k 512 วัดได้ 496.5016 ทฤษฎี 512 · หลังหาร วัดได้ 0.9697 ทฤษฎี 1 · แกว่งรอบ d_k
รูปที่ 1. ทฤษฎีคือ Var(q · k) = d_k และหลังหาร √d_k ความแปรปรวนเป็น 1 เลขที่วัดได้ตาม seed ที่โชว์เหนือตาราง กดสุ่มใหม่แล้วทั้ง seed และเลขขยับรอบค่าทฤษฎี
ลองเดาก่อนลาก ฝั่งซ้ายช่องแรกนำอยู่เยอะ ฝั่งขวายังสูสีกัน ถ้าเราเติมให้ช่องสองเท่ากัน ฝั่งไหนจะขยับแรงกว่า ตั้งแถบที่ 0.5 แล้วดูน้ำหนักช่องสองจาก 0.0180 เป็น 0.0293 เทียบกับ 0.3072 เป็น 0.4223 ตัวอย่างนี้เลือกหารคะแนนด้วย 8 เพื่อเทียบความไวของ softmax ไม่ได้ใช้ d_k = 2 ของของเล่นสามคำ การหารนี้เทียบได้กับตั้ง T = 8 แต่ไม่ใช่การเปลี่ยนมิติของเวกเตอร์ในรูปที่ 3 ของเล่นนี้มีแค่คะแนน ไม่มีคำและไม่มี V เลยหยุดที่น้ำหนัก
คะแนนชุดเดียวกัน คนละสเกล
ฝั่งซ้ายคือ (8, 4, 0) ฝั่งขวาคือคะแนนนั้นหาร 8 แถบเลื่อนบวกจำนวนเดียวกันเข้าช่องสองของทั้งสองฝั่ง แล้ว softmax คำนวณใหม่ทั้งคู่ ไม่มี value ในของเล่นนี้ จึงยังไม่มี output
ตัวเลขตัวอย่าง คนละชุดกับแมว กิน ปลา หารด้วย 8 เทียบได้กับ T = 8
คะแนนใหญ่
(8, 4, 0)
หาร 8 แล้ว
(1, 0.5, 0)
คนละชุดกับแมว กิน ปลา · ไม่มี V จึงหยุดที่น้ำหนัก · บวกช่องสอง +0 · ซ้ายช่องสอง 0.0180 → 0.0180 · ขวาช่องสอง 0.3072 → 0.3072 · มากสุดซ้าย “ช่อง 1” (0.9817) · มากสุดขวา “ช่อง 1” (0.5065) · การหารด้วย 8 เทียบได้กับ T = 8 แต่ไม่ใช่การเปลี่ยนมิติของเวกเตอร์ในรูปที่ 3
รูปที่ 2. ของเล่นคนละชุดกับประโยคสามคำ น้ำหนักตามแถบที่เลื่อนอยู่
เมื่อคะแนนช่องหนึ่งทิ้งห่างช่องอื่นมาก softmax จะเกือบเลือกช่องเดียว การขยับคะแนนเล็กน้อยจึงแทบไม่เปลี่ยนน้ำหนัก อนุพันธ์ของน้ำหนักต่อคะแนนในบริเวณนี้เล็ก นี่คือจุดที่ paper สงสัยว่าจะทำให้ส่งสัญญาณผ่าน attention เรียนรู้ได้ยากขึ้น ไม่ได้หมายความว่า gradient ทุกส่วนของโมเดลหายไป
ขั้นที่ 6: softmax ทำให้แถวรวมได้ 1
คะแนนหลังปรับสเกลยังเป็นอะไรก็ได้ ติดลบก็ได้ จึงยังไม่สะดวกที่จะเอาไปผสม value softmax ทำสองขั้นกับหนึ่งแถว ยก e (ค่าคงที่ประมาณ 2.718) กำลังคะแนนแต่ละช่อง ทุกค่ากลายเป็นบวก และช่องที่คะแนนสูงจะโดดมากกว่าแบบเส้นตรง จากนั้นหารทุกช่องด้วยผลรวมของแถว ทุกช่องอยู่ระหว่าง 0 กับ 1 และรวมกันได้ 1
softmax(s)_j = e^{s_j} / Σ_m e^{s_m}
ทำไมต้องรวมได้ 1? เพราะอยากให้น้ำหนักเป็นสัดส่วนของความสนใจในแถวนั้น ถ้าให้คำหนึ่งมากขึ้น ต้องลดคำที่เหลือ ผลคือ output เป็นค่าเฉลี่ยถ่วงน้ำหนักของ value เสมอ ขนาดของผลจึงไม่พองตามจำนวนคำ งบ 100% นี้เป็นของแต่ละแถว ไม่ใช่งบก้อนเดียวของทั้งประโยค และไม่ใช่เวลาหรืองบคำนวณ paper เรียกขั้นนี้ว่าการใส่ softmax เพื่อให้ได้น้ำหนักของ value
ขั้นที่ 7: ผลรวมถ่วงน้ำหนักของ V
เอาน้ำหนักแถว i ไปคูณ value ของแต่ละคำ แล้วบวก ได้ vector ใหม่ของคำ i ในรูปเมทริกซ์คือคูณตารางน้ำหนัก n × n กับ V ขนาด n × d_v ได้ output n แถว
Figure 2 ฝั่งซ้ายใน paper เรียงจากล่างขึ้นบนว่า Q กับ K เข้า MatMul แล้ว Scale แล้ว Mask (opt.) แล้ว SoftMax แล้ว MatMul กับ V ตรงกับขั้นที่ 4 ถึง 7 กล่อง Mask ที่เขียนว่า opt. เป็นทางเลือก จะเปิดในหัวข้อที่ 6 ของเล่นหลักของบทนี้ปิดกล่องนั้นไว้ คือ encoder ไม่มี mask
3. ของเล่นสามคำ ที่กำหนดครบ
ขั้น A–E บนค่าในตาราง
แถวคือฝ่ายถาม คอลัมน์คือฝ่ายถูกถาม คะแนนดิบคือ q ของแถวจุดกับ k ของคอลัมน์
| คะแนนดิบ | แมว | กิน | ปลา |
|---|---|---|---|
| แมว ถาม | 2 | 0 | 1 |
| กิน ถาม | 0 | 1 | 1 |
| ปลา ถาม | 2 | 1 | 2 |
ตารางไม่สมมาตร ในค่าเริ่มต้น “แมวถามปลา” ได้ 1 แต่ “ปลาถามแมว” ได้ 2 เพราะใช้ q ของฝ่ายถามกับ k ของฝ่ายถูกถาม คนละ vector ช่องไม่เท่ากันเป็นผลของเวกเตอร์ในตารางนี้ ไม่ได้แปลว่าแมวกับปลาในภาษาคนสนใจกันไม่เท่า รูปที่ 3 ถ้าเลื่อนแถบจะใช้คนละค่า
หารด้วย √2 ซึ่งปัดสามตำแหน่งเป็น 1.414 ได้ 2 → 1.414, 1 → 0.707, 0 → 0 e ยกกำลัง √2 ที่ยังไม่ปัดได้ 4.113 ส่วน e ยกกำลัง 1.414 ที่ปัดแล้วได้ 4.112 รูปใช้ √2 เต็มจึงโชว์ 4.113
| หลังหาร √2 | แมว | กิน | ปลา |
|---|---|---|---|
| แมว ถาม | 1.414 | 0 | 0.707 |
| กิน ถาม | 0 | 0.707 | 0.707 |
| ปลา ถาม | 1.414 | 0.707 | 1.414 |
softmax ทีละแถวจากคะแนนเต็มไม่ปัด e^0 = 1, e^{√2/2} ปัดเป็น 2.028, e^{√2} ปัดเป็น 4.113
- แถวแมว e เป็น (4.113, 1, 2.028) รวมของค่าเต็มปัดเป็น 7.141 น้ำหนัก 0.576, 0.140, 0.284
- แถวกิน รวมปัดเป็น 5.056 น้ำหนัก 0.198, 0.401, 0.401
- แถวปลา ค่า e ที่ปัดแล้วบวกกันได้ 4.113 + 2.028 + 4.113 = 10.254 แต่ผลรวมก่อนปัดแต่ละพจน์ปัดสามตำแหน่งได้ 10.255 น้ำหนักยังเป็น 0.401, 0.198, 0.401
| น้ำหนัก | แมว | กิน | ปลา |
|---|---|---|---|
| แมว ถาม | 0.576 | 0.140 | 0.284 |
| กิน ถาม | 0.198 | 0.401 | 0.401 |
| ปลา ถาม | 0.401 | 0.198 | 0.401 |
วิธีอ่านตารางนี้บนของเล่นชุดนี้เท่านั้น
- อ่านตามแถว คือคำนั้นแบ่งน้ำหนักไปที่ไหน ที่ query แมว = (1, 0) แมวให้ตัวเอง 0.576 ให้ปลา 0.284 ให้กิน 0.140 มากสุดคือแมวเอง ไม่ได้ข้ามตัวเอง รูปที่ 3 เริ่มที่แถวนี้ แล้วเปลี่ยนตามแถบ
- ทุกแถวรวมได้ 1 เพราะ softmax ทำทีละแถว คอลัมน์ไม่ต้องรวมได้ 1 คอลัมน์แมวจากน้ำหนักที่แสดงบวกได้ 1.175 คอลัมน์กินได้ 0.739 คอลัมน์ปลาได้ 1.086
- ช่องทแยงไม่ได้ถูกห้าม ที่ค่าเริ่มต้นแมวให้น้ำหนักตัวเองมากสุด เพราะเวกเตอร์ในตารางเป็นแบบนั้น ไม่ใช่เพราะโมเดลจริงมองตัวเอง
- ไม่มีช่องเป็น 0 เป๊ะเมื่อไม่ใส่ mask softmax ให้ค่าบวกเสมอ
จากนั้นคูณน้ำหนักด้วย V ที่กำหนดไว้ v แมว (1, 0), v กิน (0, 1), v ปลา (0.5, 0.5) output ที่ปัดจากค่าเต็มเป็นสามตำแหน่งคือแมว (0.718, 0.282), กิน (0.398, 0.602), ปลา (0.602, 0.398) ถ้าเอาแต่น้ำหนักที่ปัดแล้วมาบวกมือ แถวกินได้ 0.198 + 0.2005 = 0.3985 ซึ่งอยู่คนละจุดปัดกับ 0.398 ตารางกับรูปใช้ค่าเต็มแล้วค่อยปัด จึงตรงกับ 0.398
แต่ละ token ได้ vector ใหม่ที่ยังมีร่องรอยของ value เดิมปนกับ value อื่นตามน้ำหนัก vector ใหม่ของกินเป็นผลบวกของ value ตามน้ำหนัก ไม่ได้แปลว่าคำนั้นเข้าใจแมวแล้ว เลขในรูปที่ 3 ตามแถบที่เลื่อน
สูตรทั้งเส้น บนเวกเตอร์ชุดนี้
เลือกคำที่ถาม แล้วเดินจาก q, k ไปคะแนน ไปการหาร ไป softmax ไปผลรวมของ v แถบเลื่อนขยับเลขตัวที่สองของ query แมว จาก 0 ซึ่งเป็นค่าในตาราง รูปที่ 4 ใช้สถานะเดียวกัน
ตัวเลขตัวอย่าง ของเล่นที่กำหนดครบด้านบน ไม่ใช่ค่าจากโมเดลจริง
q, k, v ตรงกับตารางของเล่นที่กำหนดครบในบทนี้
แมวถาม → น้ำหนัก (0.576, 0.140, 0.284) → output (0.718, 0.282)
softmax(QKᵀ / √d_k) V · d_k = 2 · √d_k = 1.414 · หารด้วย √d_k เทียบเท่า T = √d_k ที่ล็อกตาม d_k · encoder · ไม่มี mask · ทุกตำแหน่งเห็นทุกตำแหน่ง รวมตัวเอง
q ของแมว = (1, 0)
k แมว = (2, 0) · k กิน = (0, 1) · k ปลา = (1, 1)
v แมว = (1, 0) · v กิน = (0, 1) · v ปลา = (0.5, 0.5)
encoder · ไม่มี mask · ทุกตำแหน่งเห็นทุกตำแหน่ง รวมตัวเอง
คะแนนดิบ
- แมว ถาม
- แมว 2
- กิน 0
- ปลา 1
- กิน ถาม
- แมว 0
- กิน 1
- ปลา 1
- ปลา ถาม
- แมว 2
- กิน 1
- ปลา 2
หลังหาร √d_k และหลัง mask
- แมว ถาม
- แมว 1.414
- กิน 0
- ปลา 0.707
- กิน ถาม
- แมว 0
- กิน 0.707
- ปลา 0.707
- ปลา ถาม
- แมว 1.414
- กิน 0.707
- ปลา 1.414
softmax ทีละแถว
e ยกกำลังคะแนนหลังหารและหลัง mask = 4.113, 1.000, 2.028 · รวม 7.141
น้ำหนักแถวนี้รวม 1.000
- แมว ถาม
- แมว 0.576
- กิน 0.140
- ปลา 0.284
- กิน ถาม
- แมว 0.198
- กิน 0.401
- ปลา 0.401
- ปลา ถาม
- แมว 0.401
- กิน 0.198
- ปลา 0.401
output = น้ำหนัก × V
- แมว: 0.576 × (1, 0) = (0.576, 0.000)
- กิน: 0.140 × (0, 1) = (0.000, 0.140)
- ปลา: 0.284 × (0.5, 0.5) = (0.142, 0.142)
- รวม output ของแมว = (0.718, 0.282)
- แมว (0.718, 0.282)
- กิน (0.398, 0.602)
- ปลา (0.602, 0.398)
ถาม “แมว” · q = (1, 0) · ให้น้ำหนักมากสุด “แมว” (0.576) · ให้ตัวเอง 0.576 · output (0.718, 0.282) · encoder · ไม่มี mask · ทุกตำแหน่งเห็นทุกตำแหน่ง รวมตัวเอง · ตัวเลขตัวอย่าง
รูปที่ 3. มากสุดนับรวมตัวเอง เลขในรูปตามแถบและปุ่มที่กดอยู่ ตอนแถบอยู่ที่ 0 และยังมองได้ทุกคำ แถวแมวจึงให้น้ำหนักตัวเองมากสุด
ชุดเดียวกัน หารกับไม่หาร
q, k, v, คำที่ถาม, และ mask เป็นชุดเดียวกับรูปที่ 3 ฝั่งซ้ายหารด้วย √d_k ก่อน softmax ฝั่งขวาเอาคะแนนดิบเข้า softmax เลย งานคือหา output ของสูตร เมตริกคือน้ำหนักที่รวมได้ 1 กับเวกเตอร์ output
ตัวเลขตัวอย่าง ฝั่งไม่หารคำนวณจากเวกเตอร์ชุดเดียวกัน
q, k, v ตรงกับตารางของเล่นที่กำหนดครบในบทนี้
แมวถาม → น้ำหนัก (0.576, 0.140, 0.284) → output (0.718, 0.282)
q ของแมว = (1, 0)
หาร √d_k
softmax([1.414, 0, 0.707]) V = (0.718, 0.282)
- แมว ถาม
- แมว 0.576
- กิน 0.140
- ปลา 0.284
- กิน ถาม
- แมว 0.198
- กิน 0.401
- ปลา 0.401
- ปลา ถาม
- แมว 0.401
- กิน 0.198
- ปลา 0.401
- แมว (0.718, 0.282)
- กิน (0.398, 0.602)
- ปลา (0.602, 0.398)
ไม่หาร
softmax([2, 0, 1]) V = (0.788, 0.212) · ไม่ได้หาร √d_k
- แมว ถาม
- แมว 0.665
- กิน 0.090
- ปลา 0.245
- กิน ถาม
- แมว 0.155
- กิน 0.422
- ปลา 0.422
- ปลา ถาม
- แมว 0.422
- กิน 0.155
- ปลา 0.422
- แมว (0.788, 0.212)
- กิน (0.367, 0.633)
- ปลา (0.633, 0.367)
ชุดเดียวกัน · ถาม “แมว” · q แมว = (1, 0) · หาร √d_k มากสุด “แมว” (0.576) ให้ตัวเอง 0.576 output (0.718, 0.282) · ไม่หาร มากสุด “แมว” (0.665) ให้ตัวเอง 0.665 output (0.788, 0.212) · หารด้วย √d_k เทียบเท่า T = √d_k ที่ล็อกตาม d_k · encoder · ไม่มี mask · ทุกตำแหน่งเห็นทุกตำแหน่ง รวมตัวเอง
รูปที่ 4. เทียบบน q, k, v ชุดเดียว งานเดียว เมตริกเดียว สิ่งที่ต่างคือหารด้วย √d_k หรือไม่หาร ฝั่งไม่หารคำนวณจากเวกเตอร์ชุดเดียวกัน
ทำไมทุกแถวคิดพร้อมกันได้
การคิดแถวปลาไม่ต้องรอผลของแถวแมว ทุกแถวใช้แค่ q ของตัวเองกับ K และ V ชุดเดียวกันที่มีอยู่แล้ว เทียบกับ RNN ที่ภายในลำดับเดียวต้องได้บันทึกของตำแหน่งก่อนหน้าก่อนจึงจะเริ่มตำแหน่งถัดไปได้ paper บอกว่าธรรมชาตินี้ขัดขวางการทำงานแบบขนานภายในตัวอย่างเดียวกัน หลายประโยคในแบตช์ยังเดินพร้อมกันที่ดัชนีเวลาเดียวกันได้ สิ่งที่เรียงคือตำแหน่งภายในลำดับเดียว
เพราะไม่มีแถวไหนพึ่งผลของอีกแถว งานทั้งก้อนเขียนเป็นการคูณเมทริกซ์สองครั้ง คือ QKᵀ แล้วตามด้วยน้ำหนักคูณ V โดยมีการหารและ softmax คั่นกลาง ในส่วน 3.2.1 ผู้เขียนบอกว่า dot-product attention ใช้โค้ดคูณเมทริกซ์ที่ปรับแต่งมาได้ จึงเร็วและประหยัดหน่วยความจำกว่า additive attention ในทางปฏิบัติ ส่วนที่อ่านไม่มีตารางจับเวลา ข้อนี้คนละอย่างกับ Table 1 Table 1 ไม่ได้นับวินาที มันบอกว่าปริมาณงานต่อเลเยอร์โตตามอะไร self-attention โตแบบ O(n² · d) ส่วน recurrent โตแบบ O(n · d²) จำนวนขั้นที่ต้องเรียงในเลเยอร์เป็น O(1) เทียบ O(n) และนั่นคือตอน token ของลำดับนั้นมีครบแล้ว เลเยอร์ถัดไปยังรอ output ของเลเยอร์นี้ ตอนสร้างคำแปลฝั่ง decoder ยังออกทีละ token ตามที่ตอนที่ 1 เขียนไว้
ทำไมเส้นทางเหลือหนึ่งก้าว
ในตารางที่ล็อก query แมว = (1, 0) ช่อง “แมวถามปลา” คือ 0.284 ข้อมูลจาก value ของปลาไหลเข้า output ของแมวผ่านการคูณครั้งเดียว ไม่ได้ผ่านกินก่อน ถ้าเลื่อนแถบในรูปที่ 3 ช่องนั้นในรูปเปลี่ยน แต่ทางผ่านยังเป็นการคูณครั้งเดียว ถ้าประโยคยาว 50 คำ คำที่ 1 กับคำที่ 50 ก็มีช่องของตัวเองในตาราง 50 × 50
ในเลเยอร์นี้ output ของแมวใช้ query ของแมว แต่ใช้ key กับ value ของปลาได้โดยตรง ตอนย้อนสัญญาณจึงไปถึง k และ v ของปลา รวมถึง q ของแมวได้ โดยไม่ต้องผ่านคำว่ากินก่อน ไม่ใช่ไปถึง q ของปลาจาก output แถวนี้ เส้นทางจาก value ของปลาถึง output ของแมวจึงยาวหนึ่งก้าว นี่คือ maximum path length O(1) ใน Table 1 เทียบกับ O(n) ของ recurrent layer ราคาในตารางเดียวกันคือปริมาณงานต่อเลเยอร์ O(n² · d) เทียบ recurrent ที่ O(n · d²) ไม่ใช่นาฬิกาจับวินาที
4. ศัพท์
- ผลคูณจุด (dot product)
- คูณตัวเลขตำแหน่งเดียวกันของสอง vector แล้วบวก ใช้เป็นคะแนนว่าชี้ทางเดียวกันแค่ไหน และดูความยาวด้วย
- คิวรี (query, Q)
- vector ที่ใช้ตอน token เป็นฝ่ายถาม
- คีย์ (key, K)
- vector ป้ายที่ query อื่นมาเทียบ
- แวลู (value, V)
- vector เนื้อหาที่ถูกส่งต่อเมื่อได้รับน้ำหนัก
- d_k
- จำนวนตัวเลขใน query และ key แต่ละตัว รุ่น base ใช้ 64 ต่อ head ของเล่นบทนี้ใช้ 2
- เมทริกซ์
- ตารางตัวเลข ที่นี่ใช้แพ็ก vector ของทุก token เป็นแถว เพื่อคำนวณพร้อมกัน
- Kᵀ
- พลิกแถวของ K เป็นคอลัมน์ ทำให้ QKᵀ เป็นตารางคะแนนทุกคู่
- ซอฟต์แม็กซ์ (softmax)
- ยก e กำลังคะแนนหนึ่งแถว แล้วหารด้วยผลรวม ได้ค่าบวกที่รวมกันเป็น 1
- attention weights
- น้ำหนักจาก softmax บอกสัดส่วนที่แถวนั้นดึง value จากแต่ละตำแหน่ง รวมตัวเองด้วย
- ผลรวมถ่วงน้ำหนัก
- คูณแต่ละ value ด้วยน้ำหนักแล้วบวก เมื่อน้ำหนักรวมได้ 1 ก็คือค่าเฉลี่ยถ่วงน้ำหนัก
- เกรเดียนต์
- สัญญาณว่าควรปรับตัวเลขภายในไปทางไหนเท่าไรจึงจะผิดน้อยลง ถ้าเล็กมาก การเรียนรู้นิ่ง
- ความแปรปรวน
- ตัววัดว่าค่าสุ่มแกว่งห่างจากค่าเฉลี่ยแค่ไหน รากที่สองของมันคือส่วนเบี่ยงเบนมาตรฐาน
- additive attention
- อีกแบบที่ใช้เครือข่ายชั้นซ่อนหนึ่งชั้นวัดความเข้ากัน แทน dot product ตามที่ Vaswani และคณะอ้างถึงงานของ Bahdanau และคณะ
- mask
- ปิดบางช่องก่อน softmax โดยตั้งคะแนนเป็น −∞ แล้ว e ยกกำลังช่องนั้นเป็น 0 น้ำหนักช่องนั้นจึงเป็น 0 ของเล่นหลักของบทนี้ไม่ใส่ mask
5. อุปมา พร้อมขอบเขต
แต่ละภาพจับคนละจุด และใช้ได้ไม่สุดทาง
อุปมา 1: ห้องสมุด
คนค้นมีคำถามในใจ (query) หนังสือแต่ละเล่มมีป้ายสัน (key) เทียบคำถามกับป้ายทุกเล่ม (dot product) แล้วหยิบเนื้อหาข้างใน (value) ของเล่มที่เข้ากัน สิ่งที่ได้ผสมจากหลายเล่ม โดยเล่มที่ตรงที่สุดมีส่วนมาก
อุปมา 2: งบ 100% ของแถว
ทุกคำได้งบความสนใจ 100% ของแถวตัวเอง ต้องแบ่งให้ทุกตำแหน่งในประโยค รวมตัวเอง คะแนนบอกว่าใครควรได้มาก แต่ยกกำลัง e ทำให้คะแนนสูงได้ส่วนแบ่งเพิ่มแบบทวีคูณ ไม่ใช่เพิ่มตามสัดส่วนตรง
อุปมา 3: ปุ่มลดเกนก่อนลำโพง
ในภาพลำโพง ให้คะแนนก่อน softmax เป็นสัญญาณเข้า และให้เกนเป็น 1/√d_k เราลดความต่างระหว่างคะแนนก่อนเข้าช่วงไม่เป็นเส้นตรงของ softmax ภาพนี้ช่วยคิดเรื่องความไวของน้ำหนัก ไม่ได้บอกว่าเสียงดังเท่ากันทุกช่องแล้ว softmax จะอิ่ม
อุปมา 4: จดหมายทอด กับกลุ่มที่เห็นทุกข้อความ
ใน RNN ถ้าตำแหน่งที่ 50 อยากรู้ว่าตำแหน่งที่ 2 ถืออะไรอยู่ ต้องอาศัยบันทึกที่ส่งต่อมา และสัญญาณสอนก็ย้อนกลับตามเส้นเดิม ใน self-attention ที่ไม่มี mask ทุกตำแหน่งมีช่องตรงถึงกันในเลเยอร์นั้น
6. เชื่อมกลับไปที่ paper
ส่วนไหนพูดถึงอะไร
- ส่วน 3.2 นิยาม attention ว่าแปลง query กับคู่ key–value เป็นผลรวมถ่วงน้ำหนักของ value
- ส่วน 3.2.1 และ Figure 2 ซ้าย คือ Scaled Dot-Product Attention สมการที่ 1 คือ softmax(QKᵀ / √d_k) V พร้อมเหตุผลของการหารและ footnote 4
- ส่วน 3.2.3 ใช้ attention สามแบบ encoder-decoder attention ที่ query มาจาก decoder และ key/value มาจาก encoder, self-attention ใน encoder ที่ Q, K, V มาจากที่เดียวกันและทุกตำแหน่งมองได้ทุกตำแหน่งของ layer ก่อนหน้า, และ self-attention ใน decoder ที่แต่ละตำแหน่งมองได้เฉพาะตำแหน่งก่อนหน้าและตัวเอง
- ส่วน 4 กับ Table 1 เทียบ self-attention กับ recurrent และ convolutional layer ด้วยความซับซ้อนต่อ layer จำนวนขั้นตามลำดับ และความยาวเส้นทางสูงสุด
mask ใน decoder
ตอนสร้างคำแปล decoder เดาคำถัดไปจากคำที่สร้างไปแล้ว จะดูคำในอนาคตไม่ได้ paper ตั้งคะแนนของช่องที่ไม่อนุญาตเป็น −∞ ก่อน softmax เพราะ e ยกกำลัง −∞ เป็น 0 น้ำหนักช่องนั้นจึงเป็น 0 ตำแหน่งปัจจุบันยังเห็นตัวเอง ของเล่นสามคำเดิม ถ้าใส่ mask แบบนี้หลังหารสเกล แถวกินเหลือคะแนน (0, 0.707, −∞) น้ำหนักปัดเป็น (0.330, 0.670, 0) แถวแมวซึ่งเป็นคำแรกเหลือให้มองแค่ตัวเอง จึงได้ 1 ที่ตัวเอง แถวปลาอยู่ท้ายสุด ไม่มีตำแหน่งให้ปิด แถวจึงเป็นแถวเดิม รูปที่ 3 มีปุ่ม “ปิดคำถัดไป” ที่ตั้ง −∞ ก่อน softmax จริง ไม่ได้คำนวณเสร็จแล้วค่อยซ่อนเส้น
ยกมาเพื่อให้เห็นกล่อง Mask เท่านั้น โครงสร้าง encoder–decoder ทั้งก้อนเป็นเรื่องของตอนถัดไป ของเล่นเริ่มต้นของบทนี้เป็น encoder ไม่มี mask
ผลที่เกี่ยวกับกลไกนี้
- ผู้เขียนอ้างว่า dot-product กับ additive attention มีความซับซ้อนทางทฤษฎีใกล้กัน แต่ dot-product ใช้โค้ดคูณเมทริกซ์ที่ดีได้ จึงเร็วและประหยัดหน่วยความจำกว่าในทางปฏิบัติ เป็นข้ออ้างเชิงวิศวกรรม ไม่มีตารางจับเวลาในส่วนที่อ่าน และไม่ใช่แถวของ Table 1
- Table 3 แถว (B) วัดบนชุด development (newstest2013) งานแปลอังกฤษ→เยอรมัน ลด d_k จาก 64 ซึ่งเป็นรุ่น base ที่ 25.8 BLEU เหลือ 32 ได้ 25.4 BLEU และเหลือ 16 ได้ 25.1 BLEU ผู้เขียนตีความว่าการตัดสินความเข้ากันไม่ใช่เรื่องง่าย และฟังก์ชันที่ซับซ้อนกว่า dot product อาจให้ผลดีกว่า สามแถวนี้คืองานเดียวกัน ชุดเดียวกัน เปลี่ยน d_k ผล BLEU ของชุดทดสอบเป็นคนละตาราง อยู่ในตอนที่ 1 ซึ่งใช้ 41.8 ตาม abstract และ Table 2 ของ arXiv v7 ส่วน §6.1 ในฉบับเดียวกันยังพิมพ์ 41.0 และฉบับ NeurIPS 2017 ก็รายงาน 41.0 บทนี้ไม่ลงตารางนั้น
- Table 3 แถว (A) attention หัวเดียว (h = 1, d_k = 512) แย่กว่าค่าที่ดีที่สุดราว 0.9 BLEU หัวมากไปก็ลดคุณภาพ รายละเอียดของ multi-head อยู่ในตอนถัดไป
- Table 1 เทียบการโตของปริมาณงาน ไม่ใช่วินาที self-attention ต่อเลเยอร์เป็น O(n² · d) recurrent เป็น O(n · d²) เมื่อ n น้อยกว่า d นิพจน์แรกเล็กกว่า ซึ่งผู้เขียนบอกว่าเป็นกรณีปกติของการแทนประโยคในงานแปล ขั้นที่ต้องเรียงเป็น O(1) เทียบ O(n) และเส้นทางสูงสุดเป็น O(1) เทียบ O(n)
ข้อจำกัดที่ผู้เขียนยอมรับ เฉพาะกลไกนี้
- เหตุผลเรื่อง √d_k เป็นข้อสันนิษฐาน คำว่า “We suspect” และข้อสังเกตว่า additive ชนะ dot-product ที่ไม่ปรับสเกลเมื่อ d_k ใหญ่ มาจากงานที่อ้าง ใน Table 3 ไม่พบแถวที่ทดลองเอาการหาร √d_k ออก
- ผู้เขียนเขียนเองจาก Table 3 แถว (B) ว่าฟังก์ชันวัดความเข้ากันที่ซับซ้อนกว่าอาจดีกว่า
- การเฉลี่ยตามน้ำหนักภายในหัวเดียวทำให้ความละเอียดลดลง ผู้เขียนพูดไว้ในส่วน 2 และ 3.2.2 การชดเชยคือ multi-head: ฉาย h ชุด ต่อผลเข้าด้วยกัน แล้วคูณ W^O ไม่ใช่การโหวตหรือการเฉลี่ยหัว
- สำหรับข้อความยาวมาก ผู้เขียนเสนอ restricted self-attention ที่มองเฉพาะบริเวณขนาด r รอบตัวเอง เส้นทางยาวขึ้นเป็น O(n/r) และระบุว่าเป็นงานในอนาคต
สิ่งที่ paper ยังไม่ได้พิสูจน์
- ยังไม่ได้พิสูจน์ว่า attention weights คือคำอธิบายเหตุผลของโมเดล ในส่วน 4 ผู้เขียนเขียนว่า self-attention could yield more interpretable models คืออาจทำให้ตีความได้ง่ายขึ้น และบอกว่าตรวจดูการกระจายของ attention แล้วนำตัวอย่างไปไว้ในภาคผนวก โดยกล่าวว่า head ต่าง ๆ เรียนรู้ทำงานต่างกันอย่างชัดเจน และหลาย head appear to แสดงพฤติกรรมที่เกี่ยวกับโครงสร้างประโยค คำบรรยายในภาคผนวกของฉบับ arXiv ใช้ apparently กับ Figure 4 และ seems related กับ Figure 5 ทั้งหมดนี้เป็นการดูตัวอย่างด้วยตา paper ไม่ได้ทดสอบว่าถ้าเปลี่ยนน้ำหนักแล้วคำแปลเปลี่ยนตาม และไม่ได้อ้างว่าน้ำหนักคือเหตุผลของการตัดสินใจ ตารางในหัวข้อที่ 3 จึงบอกได้แค่ว่าของเล่นนี้ผสม value มาจากไหน ไม่ใช่โมเดลคิดอะไร
- ยังไม่ได้พิสูจน์ว่าเส้นทางสั้นทำให้เรียนรู้ความสัมพันธ์ระยะไกลได้ดีขึ้นจริงในงานนี้ ข้อในส่วน 4 เป็นการวิเคราะห์เชิงโครงสร้างโดยอ้างงานก่อนหน้า ไม่ได้มีการทดลองแยกที่วัดความสามารถนี้ในส่วนที่อ่าน
- ยังไม่ได้พิสูจน์ว่าเหตุผลเรื่อง gradient ถูกต้อง footnote แสดงว่า dot product โตตาม d_k ภายใต้ข้อสมมติความเป็นอิสระ ส่วนการเชื่อมไปถึง gradient เล็กเป็นข้อสงสัย ไม่ได้วัด gradient ให้ดู
7. สรุป
กลับมาที่คำว่า “มัน” ในตอนที่ 1 น้ำหนัก 0.70 กับ value ที่ใช้ผสมมีให้แล้ว สิ่งที่ยังไม่มีคือ query กับ key บนของเล่นแมว กิน ปลา เมื่อ query ของแมวเป็น (1, 0) และยังมองได้ทุกคำ น้ำหนักมากสุดคือ 0.576 ที่แมวเอง และ output คือ (0.718, 0.282)
8. แหล่งอ้างอิง
- Vaswani et al. 2017, Attention Is All You Need — arXiv 1706.03762 (v7) · PDF ประเภท preprint อ่านลึกแค่ไหน อ่านละเอียดส่วน 3.2–3.2.3 รวม footnote 4, ส่วน 4 และ Table 1, Figure 2 ซ้าย, ข้อความ Table 3 แถว (A)(B), คำบรรยายภาพในภาคผนวก งาน Britz และ Hochreiter ที่ paper อ้างไม่ได้อ่านต้นฉบับ
- Vaswani et al. 2017 — NeurIPS (NIPS 2017) proceedings · PDF ประเภท peer-reviewed (conference proceedings) อ่านลึกแค่ไหน ตรวจเทียบเฉพาะจุด: ส่วน 3.2.1, สมการที่ 1, footnote 4, ส่วน 3.2.3, Table 1, ย่อหน้า interpretability ในส่วน 4 ตรงกับ preprint ทุกจุดที่ตรวจ PDF ไม่มีภาคผนวกภาพ attention
- Luong, Pham, Manning 2015, Effective Approaches to Attention-based Neural Machine Translation — arXiv 1508.04025 ประเภท preprint บน arXiv หน้า arXiv ระบุว่าเป็น EMNLP 2015 camera-ready version (peer-reviewed) อ่านลึกแค่ไหน อ่านบางส่วน: ส่วน 3.1 เรื่อง global attention และฟังก์ชันคะแนน dot / general / concat และย่อหน้าผลใน 5.3
- Bahdanau, Cho, Bengio 2014 — arXiv 1409.0473 ประเภท preprint บน arXiv PDF ระบุ Published as a conference paper at ICLR 2015 (peer-reviewed) อ่านลึกแค่ไหน ไม่ได้อ่านเพิ่มในรอบนี้ อ่านบางส่วนไว้ในตอนที่ 1 กล่าวถึงในฐานะงานต้นแบบของ additive attention ตามที่ Vaswani และคณะอ้าง
บริบทจากส่วนที่อ่านของ Luong และคณะ งานนั้นเสนอฟังก์ชันคะแนนระหว่าง hidden state ของ decoder กับของ encoder สามแบบ คือ dot ซึ่งเป็น dot product ตรง ๆ, general ซึ่งคั่นด้วยเมทริกซ์ที่เรียนรู้ได้, และ concat ซึ่งใช้เครือข่ายชั้นเดียวคล้ายแนวของ Bahdanau แล้วใช้ softmax แปลงคะแนนเป็นน้ำหนักเหมือนกัน ผู้เขียนงานนั้นรายงานว่า dot ทำงานได้ดีกับ global attention ในงานนั้น ส่วน general ดีกว่าสำหรับ local attention scaled dot-product ของ Transformer จึงอยู่ใกล้แบบ dot ที่เพิ่มการหาร √d_k และเปลี่ยนจาก hidden state ของ RNN มาเป็น q, k, v ที่ฉายจาก token เดียวกัน
9. ตอนถัดไป
ตอนนี้เห็นแล้วว่า attention หนึ่งชุดคิดน้ำหนักและผสม value อย่างไร ยังมีสองเรื่องที่ของเล่นนี้ตอบไม่ได้
- multi-head attention ถ้าใช้ attention ชุดเดียว แต่ละตำแหน่งได้ผลรวมถ่วงน้ำหนักของ value ชุดเดียว paper จึงรัน h ชุดพร้อมกัน h = 8 ในรุ่น base แต่ละชุดมี W^Q, W^K, W^V ของตัวเอง เอาผล h ก้อนมาต่อกัน แล้วคูณด้วย W^O ไม่ได้โหวต และไม่ได้เฉลี่ยหัวเข้าหากัน ไม่ได้สั่งไว้ล่วงหน้าว่าหัวไหนต้องดูกรรม
- ลำดับคำ ถ้าสลับเป็น “ปลา กิน แมว” โดย q, k, v ของแต่ละคำเหมือนเดิม และไม่มี mask ไม่มีข้อมูลตำแหน่ง output ของแต่ละคำไม่เปลี่ยน แค่สลับแถวตาม ตัว attention นี้จึงยังไม่รู้ว่า “หมากัดคน” ต่างจาก “คนกัดหมา” ใน paper นี้ positional encoding ถูกบวกครั้งเดียวเข้ากับ input embedding ที่ก้นสแตกของ encoder และก้นสแตกของ decoder ไม่ได้บวกซ้ำทุกเลเยอร์ โมเดลอื่นอาจใส่ตำแหน่งคนละแบบ
ตอนที่ 3 จะเปิดสองเรื่องนี้ บทนั้นยังไม่มีหน้าใน logbook หน้า Self-Attention คืออะไร ยังเป็นรูปอีกประโยคหนึ่ง ตัวเลขคนละชุดกับตารางค่าเริ่มต้นที่ query แมวเป็น (1, 0)
ถามอธิบายกลับ
สองข้อนี้อยู่นอกเนื้อเรื่อง ใช้เช็กว่าเล่าต่อได้ด้วยคำของตัวเอง
- Q, K, V แต่ละตัวทำอะไร และทำไมน้ำหนักในแต่ละแถวรวมกันได้ 1 (ใบ้: ห้องสมุด และงบ 100% ของแถวนั้น)
- ทำไมต้องหาร QKᵀ ด้วย √d_k ก่อน softmax และทำไมภายในลำดับเดียว self-attention ไม่ต้องรอทีละตำแหน่ง ขณะที่ RNN ต้องรอ ทั้งที่แบตช์ของหลายลำดับยังเดินพร้อมกันได้
ลองตอบในหัวก็พอ