การค้นหาเชิงความหมายด้วย NumPy
สร้างระบบค้นหาเชิงความหมายด้วย Python ล้วน โดยใช้ NumPy คำนวณความคล้ายคลึงแบบโคไซน์ระหว่างเวกเตอร์ฝังตัวของคำค้นกับกลุ่มเวกเตอร์ฝังตัวของเอกสาร
การค้นหาเชิงความหมายด้วย NumPy เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
การค้นหาเชิงความหมายโดยไม่ใช้ฐานข้อมูล
การค้นหาเชิงความหมายค้นหาเอกสารที่เกี่ยวข้องกับคำค้นมากที่สุดโดยพิจารณาจากความหมาย ไม่ใช่เพียงการมีคำสำคัญตรงกัน การใช้งานที่ง่ายที่สุดคือใช้ NumPy คำนวณความคล้ายคลึงแบบโคไซน์ระหว่างเวกเตอร์ฝังตัวของคำค้นกับเวกเตอร์ฝังตัวของเอกสารทั้งหมดในหน่วยความจำ โดยไม่ต้องใช้ฐานข้อมูลภายนอก
แนวทางนี้ทำงานได้ดีสำหรับเอกสารจำนวนไม่เกินหลักหมื่นรายการ และเหมาะอย่างยิ่งสำหรับการสร้างต้นแบบก่อนลงทุนใช้ฐานข้อมูลเวกเตอร์
การสร้างคลังเอกสาร
เริ่มด้วยการรวบรวมเอกสารและสร้างเวกเตอร์ฝังตัวหนึ่งรายการต่อเอกสารโดยใช้ OpenAI API จัดเก็บเวกเตอร์ฝังตัวเป็นอาร์เรย์ NumPy สองมิติ โดยแต่ละแถวแทนเวกเตอร์ของเอกสารหนึ่งรายการ เก็บรายการข้อความเอกสารแยกไว้อีกชุดหนึ่งในลำดับเดียวกัน เพื่อให้เรียกคืนเนื้อหาต้นฉบับได้หลังจากพบรายการที่ตรงกันมากที่สุด
import numpy as np
from openai import OpenAI
client = OpenAI()
documents = [
'Python is a high-level programming language.',
'NumPy provides fast numerical computing for Python.',
'Embeddings represent text as dense vectors.',
'Cosine similarity measures angle between vectors.',
'RAG combines retrieval with language generation.'
]
response = client.embeddings.create(
model='text-embedding-3-small',
input=documents
)
corpus_embeddings = np.array([item.embedding for item in response.data])
print(f'Corpus shape: {corpus_embeddings.shape}') # (5, 1536)การสร้างเวกเตอร์ฝังตัวจากคำค้นของผู้ใช้
เมื่อผู้ใช้ส่งคำค้น ให้สร้างเวกเตอร์ฝังตัวโดยใช้โมเดลเดียวกันกับที่ใช้สร้างเวกเตอร์ฝังตัวของเอกสาร การผสมโมเดลเข้าด้วยกัน เช่น ใช้ text-embedding-3-small กับเอกสารและใช้ text-embedding-3-large กับคำค้น จะทำให้เวกเตอร์อยู่คนละปริภูมิและทำให้ค่าความคล้ายคลึงไม่มีความหมาย
from openai import OpenAI
import numpy as np
client = OpenAI()
query = 'How do I compute similarity between text?'
response = client.embeddings.create(
model='text-embedding-3-small', # must match corpus model
input=query
)
query_embedding = np.array(response.data[0].embedding)
print(f'Query vector shape: {query_embedding.shape}') # (1536,)การคำนวณความคล้ายคลึงแบบโคไซน์ด้วย NumPy
หากต้องการหาความคล้ายคลึงระหว่างคำค้นกับเอกสารทุกฉบับในขั้นตอนเดียว ให้คำนวณผลคูณจุดของเวกเตอร์คำค้นกับเมทริกซ์เวกเตอร์เอกสาร เนื่องจากเวกเตอร์ฝังตัวของ OpenAI ทั้งสองแบบผ่านการทำให้เป็นมาตรฐานแบบ L2 แล้ว ค่านี้จึงเท่ากับความคล้ายคลึงแบบโคไซน์ของเอกสารทั้งหมดในครั้งเดียว ใช้เวลา O(n * d) เมื่อ n คือจำนวนเอกสาร และ d คือมิติ
import numpy as np
# corpus_embeddings: (n_docs, 1536)
# query_embedding: (1536,)
def semantic_search(query_vec, corpus_vecs):
# Matrix-vector dot product: shape (n_docs,)
similarities = corpus_vecs @ query_vec
return similarities
# Example call (assuming pre-computed embeddings)
# sims = semantic_search(query_embedding, corpus_embeddings)
# print(sims) # array of similarity scores, one per documentการจัดอันดับและเรียกคืนผลลัพธ์ k อันดับแรก
ใช้ np.argsort เพื่อจัดอันดับเอกสารตามค่าความคล้ายคลึงจากมากไปน้อย จากนั้นตัดเลือกดัชนี k รายการแรก วิธีนี้จะให้ดัชนีของเอกสารที่เกี่ยวข้องมากที่สุด ซึ่งคุณสามารถใช้ค้นหาข้อความต้นฉบับจากรายการที่จัดเก็บไว้คู่กัน
import numpy as np
def get_top_k(query_vec, corpus_vecs, documents, k=3):
similarities = corpus_vecs @ query_vec
# argsort gives ascending order; [::-1] reverses to descending
ranked_indices = np.argsort(similarities)[::-1]
top_k_indices = ranked_indices[:k]
return [
{'text': documents[i], 'score': float(similarities[i])}
for i in top_k_indices
]
# results = get_top_k(query_embedding, corpus_embeddings, documents, k=3)
# for r in results:
# print(f'{r["score"]:.4f}: {r["text"]}')ตัวอย่างการค้นหาเชิงความหมายแบบครบถ้วน
เมื่อนำทุกอย่างมารวมกัน ให้สร้างเวกเตอร์ฝังตัวของคลังเอกสาร สร้างเวกเตอร์ฝังตัวของคำค้น คำนวณค่าความคล้ายคลึง และส่งคืนผลลัพธ์ที่จัดอันดับแล้ว รูปแบบที่ครบถ้วนนี้เป็นแกนหลักของขั้นตอนการค้นคืน RAG ทุกแบบ แม้ภายใต้การทำงานจริงจะใช้ฐานข้อมูลเวกเตอร์แทน NumPy ก็ตาม
import numpy as np
from openai import OpenAI
client = OpenAI()
docs = [
'Embeddings map text to numerical vectors.',
'Python lists store ordered collections.',
'Cosine similarity compares vector directions.',
'RAG retrieves documents to ground LLM answers.',
'Dictionaries store key-value pairs in Python.'
]
corpus_resp = client.embeddings.create(model='text-embedding-3-small', input=docs)
corpus = np.array([d.embedding for d in corpus_resp.data])
query = 'finding similar text using angles'
q_resp = client.embeddings.create(model='text-embedding-3-small', input=query)
q_vec = np.array(q_resp.data[0].embedding)
scores = corpus @ q_vec
for i in np.argsort(scores)[::-1][:3]:
print(f'{scores[i]:.3f}: {docs[i]}')การกำหนดเกณฑ์ค่าคะแนน
ผลลัพธ์ k อันดับแรกไม่ได้เกี่ยวข้องเสมอไป บางครั้งผลลัพธ์ที่ตรงกันมากที่สุดก็ยังไม่สอดคล้องทางความหมายมากพอ ให้เพิ่มเกณฑ์ค่าคะแนนเพื่อกรองผลลัพธ์ที่มีความคล้ายคลึงต่ำออกไป โดยทั่วไปเกณฑ์สำหรับความคล้ายคลึงแบบโคไซน์จะอยู่ที่ 0.70–0.80 แต่คุณควรปรับเทียบค่าให้เหมาะกับโดเมนเฉพาะของคุณโดยใช้คำค้นจริง
import numpy as np
def search_with_threshold(query_vec, corpus_vecs, documents, k=5, threshold=0.75):
similarities = corpus_vecs @ query_vec
ranked = np.argsort(similarities)[::-1][:k]
results = []
for i in ranked:
if similarities[i] >= threshold:
results.append({'text': documents[i], 'score': float(similarities[i])})
return results
# Only returns documents above the minimum similarity thresholdลักษณะด้านประสิทธิภาพของการค้นหาด้วย NumPy
การค้นหาความคล้ายคลึงด้วย NumPy มีความซับซ้อนด้านเวลา O(n * d) ต่อคำค้น โดย n คือจำนวนเอกสาร และ d คือมิติของเวกเตอร์ฝังตัว สำหรับเวกเตอร์ฝังตัวขนาด 1536 มิติ:
- เอกสาร 10,000 รายการ: ประมาณ 5 มิลลิวินาทีต่อคำค้นบน CPU รุ่นใหม่
- เอกสาร 100,000 รายการ: ประมาณ 50 มิลลิวินาทีต่อคำค้น
- เอกสาร 1,000,000 รายการ: ประมาณ 500 มิลลิวินาที ซึ่งช้าเกินไป ควรเปลี่ยนไปใช้ฐานข้อมูลเวกเตอร์
NumPy เหมาะอย่างยิ่งสำหรับการสร้างต้นแบบ แต่ไม่มีการค้นหาโดยประมาณ การกรอง หรือการคงอยู่ของข้อมูลในตัว
การบันทึกเวกเตอร์ฝังตัวลงดิสก์
การคำนวณเวกเตอร์ฝังตัวใหม่ทุกครั้งที่เรียกใช้โปรแกรมทำให้เสียทั้งการเรียก API และเงิน ให้บันทึกเวกเตอร์ฝังตัวของคลังเอกสารและข้อความเอกสารลงดิสก์ เพื่อสร้างเวกเตอร์ฝังตัวใหม่เฉพาะเมื่อคลังเอกสารเปลี่ยนแปลง
np.save จัดเก็บเมทริกซ์เวกเตอร์ฝังตัวได้อย่างมีประสิทธิภาพ และคุณสามารถบันทึกรายการเอกสารเป็น JSON ได้ เมื่อเริ่มโปรแกรม ให้โหลดไฟล์ทั้งสองแทนการเรียก API
import numpy as np
import json
# Save
np.save('/tmp/corpus_embeddings.npy', corpus_embeddings)
with open('/tmp/corpus_docs.json', 'w') as f:
json.dump(documents, f)
# Load
corpus_embeddings = np.load('/tmp/corpus_embeddings.npy')
with open('/tmp/corpus_docs.json') as f:
documents = json.load(f)
print(f'Loaded {len(documents)} docs, shape {corpus_embeddings.shape}')การจัดการเอกสารใหม่แบบเพิ่มทีละส่วน
เมื่อมีเอกสารใหม่เข้ามา คุณไม่จำเป็นต้องสร้างเวกเตอร์ฝังตัวของคลังเอกสารทั้งหมดใหม่ ให้สร้างเวกเตอร์ฝังตัวเฉพาะเอกสารใหม่ แล้วใช้ np.vstack ต่อเวกเตอร์เหล่านั้นเข้ากับเมทริกซ์เดิม อย่าลืมต่อข้อความใหม่เข้ากับรายการเอกสารตามลำดับเดียวกัน
import numpy as np
from openai import OpenAI
client = OpenAI()
# Assume these exist from a previous session:
# corpus_embeddings: (n, 1536)
# documents: list of strings
new_docs = ['New document about vector search.']
resp = client.embeddings.create(model='text-embedding-3-small', input=new_docs)
new_vecs = np.array([item.embedding for item in resp.data])
corpus_embeddings = np.vstack([corpus_embeddings, new_vecs])
documents.extend(new_docs)
print(f'Corpus now has {len(documents)} documents')ข้อจำกัดของการค้นหาในหน่วยความจำ
การค้นหาเชิงความหมายด้วย NumPy มีข้อจำกัดสำคัญเมื่อเทียบกับฐานข้อมูลเวกเตอร์ที่สร้างมาโดยเฉพาะ:
- ไม่มีการคงอยู่ของข้อมูล — ทุกอย่างอยู่ใน RAM และสูญหายเมื่อเริ่มระบบใหม่
- ไม่มีการกรองข้อมูลกำกับ — ไม่สามารถกรองผลลัพธ์ตามวันที่ หมวดหมู่ หรือผู้เขียนได้
- ค้นหาแบบไล่ตรวจตามลำดับเท่านั้น — ไม่มีดัชนีค้นหาเพื่อนบ้านใกล้เคียงโดยประมาณ
- ไม่รองรับการเข้าถึงพร้อมกัน — ไม่เหมาะสำหรับระบบใช้งานจริงที่มีผู้ใช้หลายคน
ข้อจำกัดเหล่านี้เป็นเหตุผลให้ควรใช้ฐานข้อมูลเวกเตอร์โดยเฉพาะสำหรับระบบ RAG ที่ใช้งานจริง
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดด้านวิศวกรรม AI จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า การคำนวณผลคูณจุดของเมทริกซ์กับเวกเตอร์ฝังตัวที่ทำให้เป็นมาตรฐานแบบ L2 จะคำนวณความคล้ายคลึงแบบโคไซน์ของคลังเอกสารทั้งหมดได้ในขั้นตอนเดียว การใช้ np.argsort ร่วมกับการย้อนลำดับจะเรียกคืนเอกสารที่คล้ายคลึงมากที่สุด k รายการ และ การค้นหาด้วย NumPy เหมาะสำหรับต้นแบบ แต่ไม่มีการคงอยู่ของข้อมูลและการกรองข้อมูลกำกับ บทถัดไป เราจะใช้การจัดกลุ่มและ UMAP เพื่อค้นหาโครงสร้างหัวข้อในชุดเวกเตอร์ฝังตัว
คำถามที่พบบ่อย
บทเรียน “การค้นหาเชิงความหมายด้วย NumPy” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การค้นหาเชิงความหมายด้วย NumPy” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การค้นหาเชิงความหมายด้วย NumPy”
สร้างระบบค้นหาเชิงความหมายด้วย Python ล้วน โดยใช้ NumPy คำนวณความคล้ายคลึงแบบโคไซน์ระหว่างเวกเตอร์ฝังตัวของคำค้นกับกลุ่มเวกเตอร์ฝังตัวของเอกสาร คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การค้นหาเชิงความหมายด้วย NumPy” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เวกเตอร์ฝังตัวคืออะไร
- การสร้างเวกเตอร์ฝังตัวด้วย OpenAI
- การค้นหาเชิงความหมายด้วย NumPy
- การจัดกลุ่มและแสดงภาพเวกเตอร์ฝังตัว