- ระหว่างช่วยพัฒนาแอป AI ที่จัดการข้อมูล e-commerce พบปัญหาว่า Retrieval-augmented generation (RAG) ทำงานได้ดีกับบางคิวรี แต่ไม่ดีนักกับบางคิวรี
- เมื่อต้องแก้ปัญหาแบบนี้ การตรวจดูข้อมูลนำเข้า (ข้อความต้นฉบับที่ถูกทำดัชนี, คิวรีของผู้ใช้ที่ใช้ในการค้นหา) เป็นสิ่งสำคัญ
- โดยเฉพาะในมุมของ chunking และ tokenization ที่ดูเหมือนว่ายังต้องปรับให้เหมาะสม
[Tokenization]
- Tokenization คือกระบวนการแยกข้อความออกเป็นหน่วยย่อยที่เล็กลงซึ่งเรียกว่าโทเค็น โดยใช้ tokenizer
- โทเค็นเหล่านี้จะถูกแมปไปเป็น token ID ซึ่งเป็นค่าจำนวนเต็มที่ใช้ระบุโทเค็นแต่ละตัวอย่างไม่ซ้ำกันภายใน vocabulary ของ tokenizer
- vocabulary ของ tokenizer คือชุดของโทเค็นที่เป็นไปได้ทั้งหมดที่ใช้ในการฝึก tokenizer
- หากโทเค็นของข้อความไม่มีอยู่ใน vocabulary ของ tokenizer ที่ LLM ใช้ ก็อาจเกิดปัญหาได้
- LLM ส่วนใหญ่มี vocabulary ขนาดใหญ่ราว 30k~300k
- LLM ที่ใช้งานกันอย่างแพร่หลายส่วนมากพึ่งพา subword tokenizer (เช่น BPE, Wordpiece)
- ประเภทของ tokenizer
- word: แยกตามช่องว่าง เครื่องหมายวรรคตอน ฯลฯ
- character: แยกเป็นอักขระเดี่ยว ๆ (บางครั้งรวมถึงเครื่องหมายวรรคตอนด้วย)
- subword: แยกโทเค็นออกเป็นหน่วยย่อยของคำที่อาจดูไม่มีความหมาย
- LLM ส่วนใหญ่ใช้ subword tokenizer
- BPE (Byte-Pair Encoder): ไลบรารี
tiktoken ของ OpenAI
- Wordpiece: Cohere, MiniLM-L6-v2 เป็นต้น
เปรียบเทียบ MiniLM-L6-v2 กับ tiktoken
- tokenizer ของโมเดล MiniLM-L6-v2 มีขนาด vocabulary 30522 ซึ่งเล็กกว่า tiktoken (200019) มาก
- เมื่อนำประโยค "tokenizer tokenizes text into tokens" ไปทำ tokenization
- MiniLM-L6-v2: [CLS] token ##izer token ##izes text into token ##s [SEP]
- tiktoken: token, izer, token, izes, text, into, tokens
- ไลบรารี
tiktoken ของ OpenAI ใช้ BPE tokenizer และถูกใช้ในโมเดล LLM ของ ChatGPT
- vocabulary ของ MiniLM-L6-v2 ยังมีอักษรเยอรมันและญี่ปุ่นรวมอยู่ด้วย
การทำ tokenization กับอีโมจิ คำพิมพ์ผิด และคำเฉพาะโดเมน
- MiniLM-L6-v2 จะทำ tokenization ของอีโมจิเป็นโทเค็น [UNK]
tiktoken ได้เรียนรู้บางส่วนของโทเค็นอักขระ Unicode แต่ก็ยังอาจเป็นปัญหาสำหรับ RAG ได้
- ชื่อสินค้าที่เป็นคำเฉพาะโดเมน เช่น "Gucci Savoy Leathertrimmed Printed Coatedcanvas Suitcase" ก็ไม่ได้ถูกทำ tokenization อย่างเหมาะสมนัก
- ในกรณีของประโยคที่มีคำพิมพ์ผิด ("I hve received wrong pckage")
- MiniLM-L6-v2: i, h, ##ve, received, wrong, pc, ##ka, ##ge
- tiktoken: I, h, ve, received, wrong, p, ck, age
[Embeddings]
- ตัว tokenizer เองไม่ได้มีประโยชน์มากนักหากใช้เพียงลำพัง เดิมทีถูกพัฒนาขึ้นมาเพื่อการวิเคราะห์เชิงตัวเลขที่ซับซ้อน โดยอาศัยความถี่ของโทเค็นแต่ละตัวเป็นหลัก
- หากต้องการคงความหมายเชิงบริบทของข้อความไว้ จำเป็นต้องมีวิธีที่สามารถจับความสัมพันธ์ระหว่างโทเค็นได้
- embedding คือเวกเตอร์ที่แทนโทเค็น และสามารถจับความหมายกับความสัมพันธ์ระหว่างคำในข้อความได้ดี
- embedding เป็นผลพลอยได้จากการฝึก transformer และถูกเรียนรู้มาจากกองข้อมูลข้อความที่ผ่านการทำ tokenization แล้ว
- เวลาขอให้ LLM สร้างข้อความ สิ่งที่ป้อนเข้าไปเป็นอินพุตจริง ๆ ก็คือ embedding
- LLM ประกอบด้วยองค์ประกอบหลัก 2 ส่วนคือ encoder และ decoder
- ทั้ง encoder และ decoder รับ embedding เป็นอินพุต
- เอาต์พุตของ encoder ก็เป็น embedding เช่นกัน และจะถูกส่งต่อไปยัง cross-attention head ของ decoder ซึ่งมีบทบาทสำคัญต่อการสร้าง (ทำนาย) โทเค็นในเอาต์พุตของ decoder
- ใน RAG pipeline ข้อความจะถูกทำ tokenization ก่อน จากนั้นจึงทำ embedding แล้วจึงป้อนเข้า transformer
- token ID ทำหน้าที่เป็นดัชนีของ vocabulary ใน tokenizer และยังใช้ดึง embedding จาก embedding matrix ด้วย
- embedding ที่ดึงมาแล้วจะถูกประกอบเป็น tensor และป้อนเข้าเป็นอินพุตของ transformer
- ลำดับการทำงานของ encoder: tokenization ข้อความ -> ดึง embedding ของแต่ละโทเค็น -> ประกอบ embedding tensor -> ป้อนเข้าอินพุตของ transformer -> encoding -> ส่งเอาต์พุตของ encoder ไปยัง cross-attention ของ decoder -> สร้างเอาต์พุตของ decoder
ตัวอย่าง embedding
- "You can break it 😞" และ "You can not break it 😊" มีอารมณ์ตรงข้ามกัน แต่ใน MiniLM-L6-v2 กลับมีระยะห่างของ embedding ที่ใกล้กันมาก
- OpenAI ให้ผลดีกว่าเพราะ vocabulary ของโทเค็นจัดการอีโมจิได้ดีกว่า
- ในกรณีคำพิมพ์ผิด OpenAI ก็จัดการได้ดีกว่าเช่นกัน
- แต่แม้แต่ใน OpenAI หากเติมช่องว่างท้ายประโยค ระยะห่างระหว่าง embedding ก็อาจห่างออกไปมากกว่าที่คาด
- นักพัฒนายังพบความยากลำบากเมื่อต้องจัดการรูปแบบวันที่ โดยเฉพาะการแสดงเวลาแบบสัมพัทธ์ (เช่น "จัดส่งเมื่อวาน") อาจเป็นปัญหามากขึ้นไปอีก
- ความแตกต่างของรูปแบบการเขียนสกุลเงิน (£40, $50, 40£, 50¢ เป็นต้น) ก็อาจก่อให้เกิดปัญหาแปลก ๆ ได้
- สำหรับข้อมูลเฉพาะโดเมนอย่างกรณีกระเป๋า Gucci โดยทั่วไปมักแก้ด้วยการ fine-tuning แต่ก็ต้องตรวจสอบข้อมูลและตัวชี้วัดการประเมินเสมอ
บทสรุป
- บทความนี้ช่วยให้เข้าใจได้ดีขึ้นว่า tokenizer อาจส่งผลต่อแอป RAG อย่างไร และทำไมเราจึงควรใส่ใจกับ tokenizer
- ในแอปพลิเคชันแบบ agent หลัก garbage-in garbage-out อาจไม่ให้ผลลัพธ์ดีอย่างที่คาดเสมอไป
- การจัดระเบียบข้อความนำเข้าเพียงเล็กน้อยก็ช่วยได้มาก
- ทำรูปแบบวันที่ให้เป็นมาตรฐานเดียวกันอย่างสม่ำเสมอ
- ลบช่องว่างท้ายข้อความให้มากที่สุดเท่าที่ทำได้ (เพราะมีผลต่อ embedding)
- ใช้แนวทางเดียวกันกับข้อมูลตัวเลขอื่น ๆ เช่นราคาที่อยู่คนละสกุลเงิน
- หวังว่าสักวันหนึ่งเราจะไม่ต้องคิดเรื่อง tokenizer เลย และอาจเลิกใช้มันได้โดยสิ้นเชิง
- หากเป็นเช่นนั้น เราก็ไม่จำเป็นต้องรับมือกับคำพิมพ์ผิด อักขระช่องว่างแบบสุ่ม หรือการโจมตีเชิงปฏิปักษ์ที่อิงกับ word perplexity อีกต่อไป ความทุกข์ชนิดหนึ่งอาจหายไปในชั่วข้ามคืน
- จนกว่าจะถึงตอนนั้น ก็จงทำ tokenization อย่างมีความรับผิดชอบ
ความเห็นของ GN⁺
- บทความนี้แสดงให้เห็นได้ชัดว่า tokenizer และ embedding อาจส่งผลต่อประสิทธิภาพของแอป AI ที่อิงกับ RAG อย่างไร โดยเฉพาะเมื่อต้องจัดการกับอีโมจิ คำพิมพ์ผิด และคำเฉพาะโดเมน พร้อมอธิบายข้อควรระวังผ่านตัวอย่างจริง จึงน่าจะเป็นประโยชน์กับนักพัฒนาอย่างมาก
- อย่างไรก็ดี MiniLM-L6-v2 และ
tiktoken ของ OpenAI ที่กล่าวถึงในบทความนี้ต่างก็เป็นโมเดลที่ปรับให้เหมาะกับภาษาอังกฤษ ดังนั้นเมื่อจัดการกับภาษาอื่นอย่างภาษาเกาหลี ก็อาจมีประเด็นเพิ่มเติมที่ต้องพิจารณา สำหรับภาษาเกาหลีเอง มักมีการใช้ตัววิเคราะห์หน่วยคำในการทำ tokenization อยู่มาก จึงน่าจะต้องพิจารณาข้อดี ข้อเสีย และข้อจำกัดของแนวทางนี้เพิ่มเติมด้วย
- อีกทั้งบทความนี้มุ่งเน้นบทบาทของ tokenizer และ embedding ภายใน RAG pipeline แต่ในสภาพแวดล้อม production จริง ยังมีเรื่องที่ต้องคำนึงอีกมาก เช่น data preprocessing, hyperparameter tuning, model compression เป็นต้น ดังนั้นควรใช้เนื้อหาในบทความนี้เป็นจุดเริ่มต้น และในกระบวนการพัฒนาจริงควรค้นหาวิธีที่เหมาะสมที่สุดผ่านการทดลองและการประเมินที่หลากหลาย
- อีกมุมหนึ่งก็มีความเห็นว่าความสำคัญของ tokenizer กำลังลดลงจากการมาถึงของโมเดลภาษาขนาดใหญ่ เช่น GPT-4 เพราะโมเดลเหล่านี้ทำงานในระดับประโยคหรือย่อหน้า ไม่ได้อยู่ที่ระดับโทเค็นเพียงอย่างเดียว จึงอาจทำให้คุณภาพของโทเค็นแต่ละตัวส่งผลต่อประสิทธิภาพน้อยลงเมื่อเทียบกัน อย่างไรก็ตาม งานวิจัยในประเด็นนี้ยังมีไม่มากพอ จึงยังสรุปแบบฟันธงได้ยาก
- สุดท้าย ดังที่บทความกล่าวไว้ การทำความสะอาดและทำข้อมูลนำเข้าให้เป็นมาตรฐานล่วงหน้าเพียงเท่านี้ก็ช่วยยกระดับประสิทธิภาพของโมเดลได้มากแล้ว เมื่อต้องพัฒนาบริการจริง การสร้าง data preprocessing pipeline ที่แข็งแรงและทนทานโดยคำนึงถึงความหลากหลายและ noise ของอินพุตจากผู้ใช้จึงเป็นสิ่งสำคัญมาก นอกจากนี้ยังควรลงทุนทรัพยากรกับงาน data labeling และ annotation ให้เพียงพอ เพื่อให้ได้ข้อมูลฝึกที่มีคุณภาพสูง
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ตัวตัดโทเคนไม่ค่อยถูกมองว่าเป็นส่วนที่ "เซ็กซี่" ของ LLM แต่ก็มีคนที่มองว่านี่คือโอกาส งานวิจัยอย่าง xVal นำเสนอกลยุทธ์การทำ tokenization แบบเฉพาะทาง งานด้านการสะกดคำและการจัดการระดับอักขระก็เป็นอีกปัญหาหนึ่งที่อาจได้ประโยชน์จากนวัตกรรมด้าน tokenization
ต้องเข้าใจข้อมูลก่อนจึงจะทำงานที่มีความหมายได้ หลายคนใช้เครื่องมือประมวลผลข้อมูลอัตโนมัติเป็นหลักเพราะไม่อยากดูข้อมูลด้วยตัวเอง อยากให้คอมพิวเตอร์ดูข้อมูลและขอให้มีการรวบรวมข้อมูลเพิ่มเติมได้
ชอบส่วนที่พูดถึงคำสะกดผิดในบล็อกโพสต์เป็นพิเศษ กำลังช่วยโปรเจกต์ที่มีแอปพลิเคชันคล้าย RAG และกังวลว่าคำสะกดผิดเล็กน้อยหรือความแตกต่างด้านรูปแบบในคำค้นของผู้ใช้จะส่งผลต่อการคำนวณระยะห่างของ embedding อย่างไร
เคยทำงานกับแอปที่ใช้ Elasticsearch เพื่อจัดการความคล้ายคลึงกันระหว่างอินพุตยาว 1-2 ประโยคกับเอกสารที่ยาวกว่าหนึ่งย่อหน้าด้วยข้อความค้นหาข้อความขั้นสูง รู้สึกว่าน่าสนใจมากว่ากลยุทธ์ tokenization ส่งผลต่อบางคำค้นได้มากแค่ไหน
รู้สึกว่าบทความยังขาดการพูดถึงวิธีแก้สำหรับแต่ละปัญหา เสนอให้รันการตรวจสะกดก่อนทำ tokenizing หรือไม่ก็ทำ tokenization กับคำที่สะกดผิดและคำแก้ไขที่เป็นไปได้ควบคู่กันไป
นักพัฒนาจำนวนมากคุ้นเคยกับการพัฒนาในพื้นที่แบบดั้งเดิม (deterministic) แต่ยังปรับวิธีคิดให้มองปัญหาในพื้นที่เชิงสถิติไม่ได้ แอป LLM โดยแก่นแล้วคือพื้นที่เชิงสถิติ
คนส่วนใหญ่ที่ทำ RAG มักคิดเรื่อง embedding โดยไม่คิดเรื่อง tokenization
ไม่สามารถทำซ้ำตัวเลขบางส่วนจากบล็อกโพสต์ได้ ตัวอย่างเช่น ผลการคำนวณ cosine similarity ของสองประโยคจากโค้ดที่ใช้ SentenceTransformer ออกมาไม่ตรงกับที่คาดไว้
เห็นปัญหาในหลายการติดตั้งใช้งาน RAG ที่ตั้งสมมติฐานว่าเอกสารเป้าหมายจะเป็นคีย์ค้นหาที่ดีสำหรับคำค้นที่เข้ามา ในโปรเจกต์ล่าสุด ความเกี่ยวข้องของการค้นหาดีขึ้นมากจากการแยกคีย์ค้นหาออกจากค่าที่ส่งกลับ (เอกสารที่ถูกแบ่งเป็นชังก์) แล้วใช้ LM สร้างคีย์ที่เหมาะสมเพื่อนำไปทำ embedding
ถึงจะบอกว่าคลังคำศัพท์ของ LLM ขนาดใหญ่หลายตัวมีขนาดใหญ่พอสมควร แต่แค่อังกฤษภาษาเดียวก็มีคำมากกว่า 1 ล้านคำแล้ว 30k-300k โทเคนจึงดูเล็กไป