1 คะแนน โดย GN⁺ 2024-09-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • WordLlama คือชุดเครื่องมือ NLP ที่รวดเร็วและเบา ซึ่งนำ token embeddings ของ LLM มาใช้ซ้ำเพื่อทำ fuzzy deduplication, คำนวณความคล้ายคลึง, จัดอันดับ, clustering และ semantic text splitting
  • การ inference ทำงานโดยเน้น การ lookup token และ average pooling พร้อมชูจุดเด่นเรื่อง pipeline ขนาดเบาที่รันได้ด้วย NumPy เท่านั้น และการปรับแต่งให้เหมาะกับ CPU
  • โมเดลพื้นฐานมีขนาด 256 มิติ 16MB สามารถลดมิติด้วย Matryoshka representation ได้ และ binary embeddings รองรับการคำนวณที่เร็วขึ้นด้วย Hamming similarity
  • ในตาราง MTEB, WL64~WL1024 ทำคะแนนได้สูงกว่า GloVe 300d และ Komninos ในหลาย metric แต่โดยรวมยังต่ำกว่า all-MiniLM-L6-v2
  • หลัง pip install wordllama สามารถใช้งานได้ด้วย WordLlama.load() และ .key(query) จะคืน callable function ที่ใส่เข้าไปในฟังก์ชัน standard library อย่าง sorted, min, max ได้

WordLlama ทำอะไร

  • WordLlama คือชุดเครื่องมือน้ำหนักเบาสำหรับงาน utility ด้าน NLP เช่น fuzzy deduplication, การคำนวณความคล้ายคลึง, การจัดอันดับ, clustering และ semantic text splitting
  • สกัด token embedding codebook จาก LLM รุ่นใหม่อย่าง LLaMA 2 และ LLaMA 3 70B เพื่อสร้าง compact word representation ที่คล้ายกับ GloVe, Word2Vec และ FastText
  • ระหว่าง inference มี dependency น้อยและถูกปรับให้เหมาะกับฮาร์ดแวร์ CPU จึงเหมาะกับการ deploy ใน สภาพแวดล้อมที่มีข้อจำกัดด้านทรัพยากร
  • ด้วยความเร็วและขนาดเล็ก จึงใช้เป็น utility ได้ เช่น exploratory analysis, evaluator สำหรับผลลัพธ์จาก LLM, งานเตรียมข้อมูลของ multi-hop หรือ agentic workflow

การติดตั้งและการใช้งานพื้นฐาน

  • ติดตั้งด้วย pip
pip install wordllama
  • โหลด โมเดล 256 มิติ พื้นฐานด้วย WordLlama.load()
from wordllama import WordLlama

wl = WordLlama.load()
  • .key(query) จะคืน Callable[[str], float] เพื่อใช้จัดเรียง candidate strings ตามความคล้ายกับ query หรือเลือกค่าที่มากที่สุดได้
query = "Machine learning methods"
candidates = [
    "Foundations of neural science",
    "Introduction to neural networks",
    "Cooking delicious pasta at home",
    "Introduction to philosophy: logic",
]

sim_key = wl.key(query)

sorted_candidates = sorted(candidates, key=sim_key, reverse=True)
best_candidate = max(candidates, key=sim_key)
  • ในผลลัพธ์ตัวอย่าง "Introduction to neural networks" เป็น candidate ที่มีคะแนนสูงสุดที่ 0.3414

ฟีเจอร์หลัก

  • สร้าง embedding: สร้าง text embeddings ได้รวดเร็วด้วยการ lookup token แบบง่ายและ average pooling
  • คำนวณความคล้ายคลึง: คำนวณ cosine similarity ระหว่างข้อความสองชุด
  • จัดอันดับเอกสาร: จัดอันดับตามความคล้ายระหว่าง query กับเอกสาร candidate
  • fuzzy deduplication: ลบข้อความซ้ำตาม threshold ของความคล้ายคลึง
  • clustering: จัดกลุ่มเอกสารด้วย KMeans
  • filtering: เหลือไว้เฉพาะเอกสารที่มีความคล้ายกับ query เกินเกณฑ์
  • Top-K search: คืนเอกสาร K รายการที่คล้ายกับ query มากที่สุด
  • semantic text splitting: แบ่งข้อความเป็น chunk ที่เกาะกลุ่มกันเชิงความหมาย
  • binary embeddings: รองรับการคำนวณที่เร็วขึ้นด้วย Hamming similarity
  • Matryoshka representation: ตัดมิติของ embedding ตามต้องการเพื่อปรับขนาดโมเดลและประสิทธิภาพ

โครงสร้างโมเดลและประสิทธิภาพ

  • WordLlama ฝึก โมเดลขนาดเล็กแบบ context-less ภายใน embedding framework อเนกประสงค์
  • โมเดลพื้นฐานมีขนาด 256 มิติ 16MB
  • ตาราง MTEB ใน README เปรียบเทียบ WL64, WL128, WL256, WL512, WL1024 กับ GloVe 300d, Komninos และ all-MiniLM-L6-v2
    • WL256 ทำคะแนน Clustering 33.25, Reranking 52.03, Classification 58.21, Pair Classification 78.22, STS 67.91, CQA DupStack 24.12, SummEval 30.99
    • GloVe 300d ทำคะแนนในรายการเดียวกันตามลำดับคือ 27.73, 43.29, 57.29, 70.92, 61.85, 15.47, 28.87
    • all-MiniLM-L6-v2 ทำคะแนน Clustering 42.35, Reranking 58.04, Classification 63.05, Pair Classification 82.37, STS 78.90, CQA DupStack 41.32, SummEval 30.81
  • l2_supercat เป็นโมเดล vocabulary ของ LLaMA 2
    • ฝึกโดยนำ codebook จากหลายโมเดล เช่น LLaMA 2 70B และ phi 3 medium มาต่อกัน หลังลบ special token เพิ่มเติมออกแล้ว
    • สามารถฝึกโดยนำ codebook ของหลายโมเดลที่ใช้ LLaMA 2 tokenizer มาต่อรวมกันได้
    • ให้ประสิทธิภาพใกล้เคียงกับการฝึก codebook ของ LLaMA 3 70B แต่ vocabulary เล็กกว่า 4 เท่า คือ 32k เทียบกับ 128k
  • มีโมเดลที่ใช้ LLaMA 3 คือ l3_supercat
  • ผลลัพธ์เพิ่มเติมอยู่ที่ Results

Semantic text splitting

  • .split() แบ่งข้อความยาวเป็น semantic chunks
long_text = "Your very long text goes here... " * 100
chunks = wl.split(long_text, target_size=1536)

print(list(map(len, chunks)))

# Output: [1055, 1055, 1187]
  • target_size เป็นทั้งขนาดเป้าหมายและขนาดสูงสุด
  • กระบวนการแบ่งพยายามรักษาลำดับข้อความ โครงสร้างประโยค และโครงสร้างย่อหน้าเมื่อทำได้
  • ใช้ WordLlama embeddings เพื่อหา index สำหรับแบ่งที่เป็นธรรมชาติมากขึ้น
  • ขนาด chunk ที่ได้อาจแตกต่างกัน แต่จะไม่เกิน target_size
  • target size ที่แนะนำคือ 512~2048 ตัวอักษร และค่าเริ่มต้นคือ 1536
  • หากต้องการ chunk ที่ใหญ่ขึ้น แนะนำให้แบ่งก่อนแล้วค่อยรวม semantic chunk หลายส่วนเป็น batch
  • รายละเอียดเพิ่มเติมอยู่ใน technical overview

Model2Vec และ direct inference

  • อัปเดต 2025-01-04 เพิ่มการรองรับ Model2Vec static embeddings
  • สามารถโหลดโมเดล Model2Vec ด้วย WordLlama.load_m2v()
wl = WordLlama.list_configs()

wl = WordLlama.load_m2v("potion_base_8m")  # 256-dim model
wl = WordLlama.load_m2v("m2v_multilingual")  # multilingual model
  • Model2Vec เป็นอีกวิธีหนึ่งที่ใช้ PCA เพื่อสร้าง static embedding
  • ฝั่ง Model2Vec ระบุว่าได้สร้าง multilingual model และโมเดลที่ใช้ glove เป็นฐาน และทำคะแนนได้ดีใน word similarity task
  • ดูได้ที่ minishlab บน Hugging Face
  • WordLlamaInference สามารถใช้งานได้โดยใส่ static embedding array รูปแบบ (n_vocab, dim) และ tokenizer โดยตรง แทนการใช้ loader
from wordllama import WordLlamaInference
from tokenizers import Tokenizer

tokenizer = Tokenizer.from_pretrained(...)
wl = WordLlamaInference(np_embeddings_ar, tokenizer)

การฝึกและการสกัด embeddings

  • โมเดล binary embedding มีการปรับปรุงชัดเจนกว่าในมิติสูง และแนะนำให้ใช้ 512 หรือ 1024 มิติ สำหรับ binary embeddings
  • โมเดล L2 Supercat ฝึกบน GPU A100 ตัวเดียวด้วย batch size 512 เป็นเวลา 12 ชั่วโมง
  • หากต้องการสกัด token embeddings จากโมเดล LLaMA ต้องยอมรับข้อตกลงผู้ใช้และล็อกอิน Hugging Face CLI
from wordllama.extract.extract_safetensors import extract_safetensors

extract_safetensors("llama3_70B", "path/to/saved/model-0001-of-00XX.safetensors")
  • โดยทั่วไป embeddings อยู่ในไฟล์ safetensors ไฟล์แรก แต่ไม่เสมอไป
    • อาจมี manifest
    • อาจต้องตรวจดูและค้นหาด้วยตนเอง
  • การฝึกใช้สคริปต์ใน repository และต้องคัดลอกหรือแก้ไขการตั้งค่าที่มีอยู่เพื่อเพิ่ม configuration file
pip install wordllama[train]
python train.py train --config your_new_config
python train.py save --config your_new_config --checkpoint ... --outdir /path/to/weights/
  • ขั้นตอนการบันทึกจะบันทึกโมเดลทีละตัวตามมิติของ Matryoshka

อัปเดต, roadmap และ license

  • อัปเดต 2025-02-01 เพิ่มการรองรับ callable ที่ใช้กับฟังก์ชัน standard library อย่าง sorted, min, max
  • อัปเดต 2024-10-04 เพิ่ม semantic splitting inference algorithm
  • roadmap มีการเพิ่ม notebook ตัวอย่างสำหรับ DSPy evaluator และ Retrieval-Augmented Generation หรือ RAG pipeline
  • โปรเจกต์จากชุมชนมี Gradio Demo HF Space และ CPU-ish RAG
  • license ของโปรเจกต์คือ MIT License

1 ความคิดเห็น

 
GN⁺ 2024-09-16
ความเห็นจาก Hacker News
  • ชอบที่ขนาดเล็กมาก มีข้อดีเหนือกว่า โมเดลที่เล็กที่สุดของ SBERT อยู่แล้ว
    แต่ในเชิงเทคนิคมันก็ดูเป็นแนวทางที่ค่อนข้างเก่า และก็เข้าใจได้ว่าเป็นการแลกกับประสิทธิภาพ ถึงอย่างนั้นก็ยังสงสัยว่าจะรองรับ การสลับประเภทความคล้ายคลึง อย่าง semantic similarity, natural language inference (NLI) หรือ noun abstraction ได้ไหม
    ตัวอย่างเช่น ถ้าจะจัดกลุ่มบทความข่าวเป็นหมวดอย่าง “เหตุการณ์สภาพแวดล้อมสุดขั้ว” ก็อยากให้ “Freezing” กับ “Burning” ออกมาคล้ายกันมาก กรณีนี้เหมือน MTEB/Sentence-Similarity หรือ Word2Vec/GloVe แบบดั้งเดิม แต่ถ้าเป็นบทความเคมี ทั้งสองคำก็ควรออกมาใกล้เคียงกับความตรงข้าม และบางครั้งก็อยากดูความสัมพันธ์เชิงเหตุและผลระหว่างสองสิ่งด้วย embedding สำหรับ natural language inference
    embedding สองประเภทหลังนี้เป็นแนวทางที่ค่อนข้างใหม่หลังปี 2019 เลยคิดว่ายังมีโอกาสทางเทคนิคอีกมาก ส่วนสาย MTEB/semantic similarity แบบเก่านั้นก็ดีพอสำหรับหลายงานมาตั้งแต่ปี 2014 แล้ว และดีขึ้นมากในปี 2019 ด้วย mini-lm-v2 เป็นต้น
    embedding ทั้งสามประเภทนี้ทำได้ด้วย SBERT เหมือนกัน แต่มีมิติสูงและตัวโมเดลก็ใหญ่ ถ้าต้องโหลดหลายโมเดลตามแต่ละประเภทก็เปลืองทรัพยากรพอสมควร ส่วนโมเดล generative embedding, E5 หรือโมเดล natural language inference ก็มีขนาดใหญ่จนมักต้องใช้ราว 6GB

    • เป็นไอเดียที่ดี เดี๋ยวจะลองทำการทดลองบางอย่างและดูว่าทำได้จริงแค่ไหน
      อยากเห็นเหมือนกันว่าถ้าเทรนด้วยประเภทความคล้ายคลึงแบบเดียว ประสิทธิภาพจะเป็นอย่างไร ยังไม่แน่ใจว่าจะมีวิธีอื่นจัดการเรื่องนี้ได้โดยไม่คำนวณบริบทหรือไม่ อาจต้องสลับโมเดล แต่ตัวมันเองก็ไม่ใช่ปัญหาใหญ่
    • อันนี้เป็น โมเดล 17MB และจาก benchmark ก็แน่นอนว่าต่ำกว่า MiniLM v2 หรือ SBERT ผมเองกำลังรัน V3 บน ONNX ด้วยโมเดล 23MB ได้แทบทุกแพลตฟอร์ม
      ไม่ได้จะดูแคลนอะไรนะ แค่อยากบอกว่าสำคัญที่จะต้องเข้าใจงานนี้ในบริบท ที่นี่คือพอคนเข้าใจ LLM ลึกขึ้น ก็พบว่า LLM เองก็มี embedding เหมือนกัน และจากมุมมองนั้น การลองเล่นกับ embedding แบบนี้เพื่อก้าวต่อไปอีกขั้นมันเป็นเรื่องธรรมชาติกว่าการย้อนกลับไปสำรวจภาพรวมทั้งวงการ embedding ใหม่ทั้งหมด
    • ถ้า “ChatGPT embedding” หมายถึง โมเดล embedding ของ OpenAI แล้ว “burning” กับ “freezing” ก็ไม่ได้ตรงข้ามกันเลย ถ้ารันด้วย text-embedding-large-3 แบบ 1024 มิติ จะได้ cosine similarity ประมาณ 0.46 ถ้าเป็น embedding ที่ตรงข้ามกันจริง ความคล้ายควรเป็น -1
      การคิดว่าคำที่มีความหมายตรงข้ามกันจะต้องมี embedding ตรงข้ามกันด้วย เป็นความเข้าใจผิดที่พบได้บ่อย ในความเป็นจริง คำที่มีความหมายตรงข้ามกันก็มักมีคุณสมบัติร่วมกันมาก “burning” กับ “freezing” ต่างก็เกี่ยวกับอุณหภูมิและฟิสิกส์ เป็นคำภาษาอังกฤษ ใช้ได้ทั้งเป็นกริยา คำนาม และคำคุณศัพท์ และสะกดถูกต้อง คุณลักษณะเหล่านี้ทั้งหมดล้วนถูกรวมอยู่ใน embedding
  • embedding สามารถบรรจุ ข้อมูลความหมาย ได้มาก ขึ้นอยู่กับข้อมูลที่ใช้ฝึกและ objective function และนำไปใช้กับงานที่มีประโยชน์หลายอย่างได้โดยอิสระ
    เมื่อก่อนผมเคยใช้ embedding ของ text encoder ในโมเดล CLIP เพื่อเสริม prompt ให้เข้ากับภาพเป้าหมายได้ดีขึ้น ตัวอย่างเช่น ถ้าใน prompt มีคำว่า “building” ก็จะหา nearest neighbors อย่าง “concrete”, “underground” จาก embedding matrix แล้วแทนที่หรือเติมต่อท้ายคำนั้น ในการทดลองแบบจำกัด ผลคือ recall สูงขึ้นสำหรับคำค้นส่วนใหญ่

    • ใช่แล้ว สามารถสอนให้โมเดล embedding เรียนรู้ ความสัมพันธ์ของบริบทภายในโดเมน แบบนี้ได้
      https://www.marqo.ai/blog/generalized-contrastive-learning-f...
    • เป็นไอเดียที่เจ๋งมาก ดูแล้วก็น่าจะทำได้กับ implementation นี้เหมือนกัน เดี๋ยวจะลองคิดต่อ
      ถ้าดูขนาดของ token embedding ใน wordllama ก็น่าจะช่วยระบุ token สำคัญที่ควรเอาไปเสริมได้ด้วย แต่ถ้าเทรนด้วยข้อมูลที่คัดมาให้เหมาะกับงานนี้โดยเฉพาะ ก็น่าจะทำงานได้ดีกว่ามาก
  • สงสัยว่ามีแผนสำหรับภาษาอื่นนอกจากอังกฤษไหม ดูเหมือนจะเป็นเครื่องมือที่เหมาะมากสำหรับ ภาษาฝรั่งเศส

    • เป็นไปได้แน่นอน แค่ต้องจัดชุดคอร์ปัสสำหรับการฝึกก่อน ซึ่งผมเองก็ไม่ค่อยรู้ว่าภาษาฝรั่งเศสมีข้อมูลอะไรให้ใช้บ้าง
      เคยลองเทรนกับโมเดลตระกูล Mistral มาบ้าง ดังนั้นถ้าเป็นคอร์ปัสภาษาฝรั่งเศสก็น่าจะลองแนวนั้นก่อน
      ถ้าเปิด issue ไว้ เดี๋ยวพอมีเวลาก็จะลองทำดู
  • ถ้าใช้กับคอร์ปัสขนาดใหญ่ เช่น มากกว่า 10,000 ประโยค โดยมองแต่ละประโยคเป็นเอกสาร ก็อาจได้ผลคล้ายกันด้วยการทำ clustering แบบ k-means บน เวกเตอร์ sparse matrix ของ TF-IDF
    แต่ดูเหมือนว่าเครื่องมือนี้จะมี utility อยู่พอสมควรสำหรับทำส่วน k-means ให้เร็วขึ้นด้วยวิธีอย่างการทำให้เป็นไบนารี ผมว่าจะลอง benchmark ดูในอีกไม่กี่สัปดาห์ข้างหน้า

  • เมื่อหลายปีก่อนผมเคยทำชุด เกมภาษา ที่ใช้ฟังก์ชันคล้ายกันไว้: https://github.com/Hellisotherpeople/Language-games

  • สงสัยว่ามีใครเคยคิดจะใช้ embedding มาแก้ Little Alchemy ไหม #sample-use

  • ดูเจ๋งดี สงสัยว่ามันมีข้อได้เปรียบอะไรเมื่อเทียบกับโมเดล mini-lm เพราะใน งาน MTEB ส่วนใหญ่ mini-lm ดูจะดีกว่า เลยอยากรู้ว่ามีด้านไหนที่ดีกว่า เช่น ความเร็วในการอนุมาน

    • Mini-lm เป็นโมเดล embedding ที่ดีกว่า โมเดลนี้ไม่ได้ทำ การคำนวณ attention และหลังการฝึกก็ไม่ใช้ deep learning framework ด้วย ดังนั้นจึงไม่ได้ประโยชน์ด้านบริบทแบบโมเดล transformer
      มันไม่ได้ถูกออกแบบมาเพื่อไล่ตามประสิทธิภาพสูงสุดล่าสุดอยู่แล้ว แต่ตั้งเงื่อนไขค่อนข้างจำกัดเพื่อให้ลด dependency, ขนาด, ความต้องการฮาร์ดแวร์ และเพิ่มความเร็ว
      ต่อให้มองว่าเป็นโมเดล word embedding ก็นับว่าเบามาก เพราะปกติโมเดลแนวนี้มักมี vocabulary ใหญ่กว่ามากและมีขนาดเป็นหลาย GB
    • น่าจะมาจากความต่างของขนาดโมเดลเอง เบากว่าและเร็วกว่า mini-lm มีขนาด 80MB ส่วนโมเดลที่เล็กที่สุดที่นี่มีขนาด 16MB
  • ดูมีประโยชน์มากสำหรับการทำเกม

  • แสดงให้เห็นชัดเลยว่าใน token เองมี เนื้อหาทางความหมาย อยู่มากแค่ไหน

  • พอจะทำเป็น ส่วนขยาย PostgreSQL ได้ไหม?