Attention และ self-attention ใน Python
Attention ช่วยให้แต่ละ token มองไปยัง token อื่น ๆ แล้วตัดสินว่าตัวไหนสำคัญ ทุก token มี query (สิ่งที่มันมองหา) key (สิ่งที่มันเสนอ) และ value (ข้อมูลที่มันส่งต่อ)
แนวคิดแบบเข้าใจง่าย
Attention ช่วยให้แต่ละ token มองไปยัง token อื่น ๆ แล้วตัดสินว่าตัวไหนสำคัญ ทุก token มี query (สิ่งที่มันมองหา) key (สิ่งที่มันเสนอ) และ value (ข้อมูลที่มันส่งต่อ)
คำนวณ scaled dot-product attention ด้วยมือจาก query, key และ value แล้วเพิ่ม causal mask แบบ GPT
ประเด็นสำคัญ
- น้ำหนัก attention มาจาก softmax แต่ละแถวจึงรวมกันได้ 1
- การหารด้วย √d ช่วยไม่ให้คะแนนใหญ่เกินไปเมื่อเวกเตอร์ยาว
- causal mask ป้องกันไม่ให้ token มองไปยัง token ในอนาคตระหว่างการสร้างข้อความ
- multi-head attention รัน attention หลายชุดพร้อมกัน ส่วน positional encoding เพิ่มข้อมูลลำดับคำ
ควรใช้เมื่อใด?
- เข้าใจสิ่งที่เกิดขึ้นภายในโครงข่ายประสาทเทียมและไลบรารี AI
- เข้าใจแนวคิดก่อนลงมือเขียนเองในโจทย์ที่เกี่ยวข้อง
- เตรียมตัวสำหรับคอร์สแมชชีนเลิร์นนิง การสัมภาษณ์งาน และโปรเจกต์
ลองดูการทำงานจริง
คลิกแถวของแผนที่ความร้อนเพื่อดูว่า token นั้นมองไปที่ใด เปิด causal mask เพื่อซ่อน token ในอนาคต และปรับความคมเพื่อให้ attention โฟกัสมากขึ้น
โค้ดตัวอย่าง
import math
def softmax(row):
exps = [math.exp(v - max(row)) for v in row]
return [e / sum(exps) for e in exps]
# Three tokens, each with a query, key and value vector of size 2.
Q = [[1, 0], [0, 1], [1, 1]]
K = [[1, 0], [0, 1], [1, 1]]
V = [[10, 0], [0, 10], [5, 5]]
d = len(K[0])
def attention(causal=False):
out = []
for i, q in enumerate(Q):
# Score: how well this query matches every key, scaled by sqrt(d).
scores = [sum(a * b for a, b in zip(q, k)) / math.sqrt(d) for k in K]
if causal: # a token may only look at itself and earlier tokens
scores = [s if j <= i else -1e9 for j, s in enumerate(scores)]
weights = softmax(scores)
out.append([round(sum(w * v[c] for w, v in zip(weights, V)), 2) for c in range(2)])
return out
print("attention:", attention())
print("causal attention:", attention(causal=True))
ผลลัพธ์ที่คาดหวัง
attention: [[6.02, 3.98], [3.98, 6.02], [5.0, 5.0]]
causal attention: [[10.0, 0.0], [3.3, 6.7], [5.0, 5.0]]
หลักการทำงาน
สำหรับแต่ละ query คะแนนคือผลคูณจุดกับ key ทุกตัว หารด้วย √d แล้ว softmax จะแปลงคะแนนเป็นน้ำหนัก และเอาต์พุตคือค่าเฉลี่ยถ่วงน้ำหนักของ value เมื่อใช้ causal mask token แรกมองเห็นแค่ตัวเอง เอาต์พุตจึงเท่ากับ value ของมันเองคือ [10, 0] พอดี
เปลี่ยนค่าและรันโปรแกรมด้วย คอมไพเลอร์ Python ออนไลน์ของ CodeUtility โดยไม่ต้องติดตั้ง Python
แบบฝึกหัด
ลองเปลี่ยน input และทดสอบกรณีขอบก่อนใช้ชุดข้อมูลที่ใหญ่ขึ้น
- เปลี่ยนอินพุตหรือน้ำหนัก แล้วลองทายผลลัพธ์ก่อนรัน
- พิมพ์ค่าระหว่างทางออกมาเพื่อดูการคำนวณทีละขั้น
- แก้โจทย์ที่ลิงก์ไว้ด้านล่างเพื่อเขียนแนวคิดนี้ด้วยตัวเอง
ฝึกด้วยโจทย์
ใช้สิ่งที่เรียนในบทนี้แก้ปัญหาจริง ทุกโจทย์รันในเบราว์เซอร์ พร้อมการทดสอบทันทีและรีวิวจาก AI
- การเข้ารหัสตำแหน่งแบบไซน์ คำนวณเวกเตอร์ตำแหน่งแบบไซน์และโคไซน์ที่ Transformer บวกเข้ากับ embedding ของ token ปานกลาง
- Scaled dot-product attention เขียนการคำนวณ attention ซึ่งเป็นหัวใจของ Transformer และโมเดลภาษาขนาดใหญ่ ยาก
- Self-attention แบบ causal (มีมาสก์) Implement attention แบบมีมาสก์ของโมเดล GPT ซึ่งแต่ละ token มองเห็นได้เฉพาะตัวเองและ token ก่อนหน้า ปานกลาง
- Multi-head self-attention ฉายอินพุตเป็น query, key และ value รัน attention ในหลาย head พร้อมกัน แล้วรวมผลเข้าด้วยกัน ยาก