แนวคิด AI ด้วย Python

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 โฟกัสมากขึ้น

โค้ดตัวอย่าง

รันโค้ด →
main.py
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 และทดสอบกรณีขอบก่อนใช้ชุดข้อมูลที่ใหญ่ขึ้น

  1. เปลี่ยนอินพุตหรือน้ำหนัก แล้วลองทายผลลัพธ์ก่อนรัน
  2. พิมพ์ค่าระหว่างทางออกมาเพื่อดูการคำนวณทีละขั้น
  3. แก้โจทย์ที่ลิงก์ไว้ด้านล่างเพื่อเขียนแนวคิดนี้ด้วยตัวเอง
รันใน Python IDE →

ฝึกด้วยโจทย์

ใช้สิ่งที่เรียนในบทนี้แก้ปัญหาจริง ทุกโจทย์รันในเบราว์เซอร์ พร้อมการทดสอบทันทีและรีวิวจาก AI

โจทย์ทั้งหมด