StreamingLLM - ใช้ Attention Sink เพื่อสร้างโมเดลภาษาแบบสตรีมมิงอย่างมีประสิทธิภาพ
(github.com/mit-han-lab)- StreamingLLM เป็น เฟรมเวิร์กสำหรับนำ LLM ไปใช้งานในแอปพลิเคชันสตรีมมิงอินพุตความยาวไม่จำกัด โดยไม่ต้องแลกมาด้วยประสิทธิภาพหรือสมรรถนะ
- แก้ปัญหาในการสนทนาหลายรอบที่ต้องมีการโต้ตอบยาว ๆ ซึ่งการแคชสถานะ Key/Value ของโทเค็นก่อนหน้าใช้หน่วยความจำมาก และ LLM ทั่วไปไม่สามารถ generalize กับข้อความที่ยาวกว่าความยาวลำดับที่ใช้ตอนเทรนได้
- window attention ที่แคชเฉพาะ KV ล่าสุดจะล้มเหลวเมื่อความยาวข้อความเกินขนาดแคช ขณะที่ StreamingLLM กู้คืนสมรรถนะของ window attention ได้อย่างมากด้วย attention sink ที่คง KV ของโทเค็นเริ่มต้นไว้
- ทำให้ LLM ที่เทรนด้วย attention window ความยาวจำกัดสามารถ generalize ไปยังความยาวลำดับไม่จำกัดได้โดยไม่ต้อง fine-tuning และทำ language modeling ได้อย่างเสถียรและมีประสิทธิภาพบน Llama-2, MPT, Falcon, Pythia ที่ความยาวสูงสุดมากกว่า 4 ล้านโทเค็น
- ในการตั้งค่าแบบสตรีมมิง แสดง speedup สูงสุด 22.2 เท่า เมื่อเทียบกับ baseline แบบ sliding window recomputation
- ไม่ได้ขยาย context window แต่คงไว้เฉพาะโทเค็นล่าสุดกับ attention sink และทิ้งโทเค็นช่วงกลาง
- หาก Llama-2 ถูก pretrain ด้วย context window 4096 โทเค็น ขนาดแคชสูงสุดของ Llama-2 ใน StreamingLLM ก็เป็น 4096 เช่นกัน
- หากป้อนหนังสือยาว ๆ โมเดลจะรับรู้เฉพาะโทเค็นล่าสุด จึงสรุปได้เพียงส่วนบทสรุปท้าย ๆ เท่านั้น
- กรณีใช้งานที่เหมาะสมคือ แอปพลิเคชันสตรีมมิง ที่ต้องทำงานต่อเนื่อง และต้องหลีกเลี่ยงการพึ่งพาข้อมูลในอดีตหรือการใช้หน่วยความจำขนาดใหญ่ โดยมีตัวอย่างคือการสนทนาหลายรอบและผู้ช่วยรายวันบนพื้นฐาน LLM
- เป็นแนวทางที่ orthogonal กับวิธีขยาย context ล่าสุดและสามารถผสานรวมกันได้ โดย context extension ในบริบทของ StreamingLLM หมายถึงความเป็นไปได้ในการเก็บโทเค็นล่าสุดได้มากขึ้นด้วยขนาดแคชที่ใหญ่ขึ้น
- ตัวอย่างการรันคือ
examples/run_streaming_llama.py --enable_streamingและการตั้งค่าสภาพแวดล้อมใช้ Python 3.8,torch,transformers==4.33.0,accelerate,datasets,evaluate,wandb,scikit-learn,scipy,sentencepiece - โค้ดหลักรวมถึง Llama-2, MPT, Falcon, Pythia เปิดเผยแล้ว รวมทั้งโค้ดประเมิน perplexity และเดโม Streaming Llama Chatbot ก็เปิดเผยแล้วเช่นกัน ส่วนชุดข้อมูล StreamEval และโค้ดประเมินยังไม่เปิดเผย
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ดูเหมือนว่ามีคนเข้าใจงานนี้ผิดว่าเป็นอะไรแบบเดียวกับ full dense attention
สิ่งที่พูดถึงตรงนี้ไม่ใช่การทำให้มองเห็นเนื้อหาที่อยู่ไกลออกไปได้ แต่เป็นการปรับปรุงประสิทธิภาพในแง่ที่นำแคชกลับมาใช้ซ้ำเพื่อรักษา perplexity แทนที่จะคำนวณ sliding window ใหม่ทุกครั้งและเสียต้นทุน L² จำนวน T ครั้ง
การทดสอบก็วัดโดยการต่อกันแบบ
Q A Q A Q A Q A...ไม่ใช่ให้หาเฉลยที่อยู่ไกลออกไปมากแบบQ Q Q Q A A A A...การวัด perplexity หมายถึงการสร้าง “ข้อความที่อ่านได้” หรือประโยคที่ดูสมเหตุสมผลในระดับท้องถิ่น ไม่ใช่หลักฐานว่า attention สามารถ “ดึง” อะไรบางอย่างออกมาจากช่องว่างสามเหลี่ยมขนาดใหญ่ที่ attention ไปไม่ถึง
ถ้าให้หนังสือแล้วสั่งให้เขียนคำแรกของแต่ละย่อหน้า หรือให้สรุปแต่ละบทเป็นหนึ่งประโยค ก็น่าจะล้มเหลว
ลองทดสอบเองแล้ว ดูเหมือนว่ามันไม่ได้ช่วย ขยายความยาว context และรันได้ค่อนข้างเร็ว
ใช้หน่วยความจำบน A100 ประมาณ 35GB และปริมาณการใช้คงที่ตลอดการรัน
ผมเอาหนังสือจาก Project Gutenberg มาแบ่งเป็นย่อหน้า ป้อนเข้าไปทีละย่อหน้า แล้วให้ตอบ “okay” ทุกย่อหน้า จากนั้นถามคำถามตอนท้าย ปรากฏว่าคำตอบ hallucinate ไปเต็ม ๆ
อีกอย่าง ระหว่างลองเล่นอยู่ราว 10 นาที แม้แต่การทำให้โมเดลพื้นฐาน
lmsys/vicuna-13b-v1.3ตอบเป็นภาษาอังกฤษก็ยังทำได้ไม่ค่อยดีhttps://gist.github.com/bluecoconut/9cae9e91fe3b1616ed650a96...
ถึงอย่างนั้นก็เป็นงานที่น่าสนใจ และแก่นหลักดูเหมือนจะเป็นการค้นพบใน Figure 2
สองเลเยอร์แรกแสดงแพตเทิร์นเฉพาะที่ที่ให้ความสนใจกับโทเค็นล่าสุดมากกว่า แต่หลังจากผ่านลงไปด้านล่างแล้ว โมเดลจะให้ความสนใจกับ โทเค็นเริ่มต้น อย่างมากในทุกเลเยอร์และทุก head
ผู้เขียนเรียกสิ่งนี้ว่า “attention sinks” และมองว่าแม้จะไม่ได้สำคัญในเชิงความหมาย แต่เพราะ Softmax บังคับให้ผลรวมของคะแนน attention เป็น 1 attention ที่เหลือจึงต้องไหลไปที่ไหนสักแห่ง
คำอธิบายคือ ในโมเดลภาษาแบบ autoregressive โทเค็นเริ่มต้นมักถูกมองเห็นได้จากโทเค็นถัดมาทั้งหมด จึงเรียนรู้ให้ทำหน้าที่เป็น sink แบบนี้ได้ง่าย
StreamingLLM ค่อนข้างเหมือน “แฮ็ก” ที่ชดเชยพฤติกรรมแปลก ๆ นี้เมื่อเราตัด attention window ของ LLM มาใช้ และเป็นกรณีที่เผยให้เห็นรอยร้าวของการใช้ Softmax ทำให้คิดว่าถ้าอยากได้ LLM ที่ยืดหยุ่นกับความยาว context ฟังก์ชันอื่นอาจเหมาะกว่าก็ได้
ตอนแรกที่กวาดตาดู มันดีเกินไปจนชวนสงสัยว่าเป็นจริงไหม แต่คุณภาพของงานดูใช้ได้ และเทคนิคก็เรียบง่ายอย่างน่าประหลาด
ไอเดียคือในแต่ละเลเยอร์ ให้ใช้ attention เฉพาะกับ โทเค็นแรก และ sliding context window เท่านั้น แล้วละเลยโทเค็นที่อยู่ระหว่างกลาง
นั่นดูเหมือนหมายความว่าแต่ละเลเยอร์จะค่อย ๆ ดันข้อมูลที่เกี่ยวข้องไปทางท้ายลำดับ เพื่อให้ sliding attention window ตรงปลายของเลเยอร์บนสุดมองเห็นมันได้
แต่ถ้าช่วงที่ sliding window ทั้งหมดครอบคลุมไม่ยาวพอจะเชื่อมทั้ง sequence เข้าด้วยกัน ก็อาจส่งต่อข้อมูลสำคัญทั้งหมดไปข้างหน้าไม่ได้
เช่น ถ้าทุก window มีความยาวเท่ากัน เมื่อ
ความลึกของโมเดล × ความยาว window < ความยาว sequenceก็จะเกิดข้อจำกัดดูเหมือนว่าสิ่งนี้เป็นไปได้เพราะการสังเกตว่า Softmax ต้องทำให้ผลรวมเป็น 1
ดูแบบเร็ว ๆ แล้ว โมเดลมีแนวโน้มใช้ โทเค็นแรกเป็น placeholder เมื่อไม่จำเป็นต้องสนใจโทเค็นก่อนหน้า
ครั้งแรกที่เห็นประเด็นนี้คือโพสต์ HN ของ Evan Miller ซึ่งบอกว่าการบังคับให้ attention head ต้องกระจาย attention ทั้งหมดไปยังโทเค็นก่อนหน้านั้นเป็นเรื่องผิด และควรอนุญาตให้ “ไม่สนใจอะไร” โดยบวก 1 เข้าไปในตัวส่วนของ Softmax
ชอบตรงที่งานนี้ใช้ประโยชน์จากข้อสังเกตนี้โดยไม่ต้องฝึกใหม่ และก็สงสัยเหมือนกันว่าโมเดลจะต่างไปอย่างไรถ้าทำตามข้อเสนอของ Evan
[2] https://news.ycombinator.com/item?id=36851494
พวกเขาฝึกโมเดลโดยใส่ โทเค็น sink เฉพาะ ที่ค่าทั้งหมดเป็น 0 แต่ถึงอย่างนั้นโทเค็นเริ่มต้นอื่น ๆ ก็ยังถูกใช้เป็น sink อยู่ดี ดังนั้นข้อสรุปดูเหมือนว่าการมีโทเค็น sink เฉพาะนั้นดีกว่า
เท่าที่ผมรู้ มันไม่เคยทำให้ประสิทธิภาพจริงดีขึ้น
เมื่อปรับแต่ง attention window หลังฝึกเสร็จ Softmax + 1 อาจเข้ากันได้ดีกว่า แต่ไม่รู้ว่ามีใครทดลองในสเกลใหญ่หรือยัง
การเพิ่ม หน่วยความจำแคชของ attention เป็นแนวทางแก้ปัญหานี้ที่น่าสนใจมาก
ไม่กี่วันก่อนก็มีเปเปอร์ที่สังเกตประเด็นเกี่ยวข้องกันใน Vision Transformer ออกมา
โมเดล Transformer ดูเหมือนจะเลือกโทเค็นบางตัวเพื่อเก็บข้อมูลระดับโกลบอล และดูเหมือนต้องการ “โทเค็นสำหรับคิด” บางประเภท
หากให้โทเค็นเฉพาะสำหรับจุดประสงค์นี้ ประสิทธิภาพจะดีขึ้นเล็กน้อย และ visualization เพื่ออธิบายก็ค่อนข้างน่าสนใจ
[0] https://arxiv.org/pdf/2309.16588.pdf
ในการ fine-tune อาจตรึงพารามิเตอร์ของโมเดลเดิมไว้ แล้วปรับเฉพาะพารามิเตอร์ที่เข้าและออกจากยูนิตแคช “สำหรับจูน” ใหม่
แบบนั้นก็สามารถสลับหรือใช้ชุดยูนิตสำหรับจูนหลายชุดร่วมกันได้
เหมือนการผสม super prompt บางแบบ เช่น ยูนิตหลีกเลี่ยงคำหยาบ + ยูนิตคำศัพท์เฉพาะ + ยูนิตเขียนให้กระชับ
หากจำนวนพารามิเตอร์ใหม่มีน้อยพอ แม้จะใช้หน่วยความจำมากขึ้น แต่ก็อาจจูนได้รวดเร็วและมีประสิทธิภาพด้วย higher-order optimization
อาจคิดถึงวิธีเพิ่มความยาว sequence และจำนวนยูนิตไปพร้อมกันระหว่างการฝึกได้ด้วย
เช่น ใช้ยูนิตเพียงไม่กี่ตัวกับ sequence สั้น ๆ แล้วเมื่อเพิ่มความยาว sequence ในการฝึก ก็เพิ่มยูนิตและฝึกต่อ
แทนที่จะใช้ schedule แบบกำหนดเอง อาจควบคุมการขยายแคชด้วยการวิเคราะห์ประสิทธิภาพหรือ gradient ก็ได้
ผู้เขียนได้โพสต์ FAQ ไว้ ซึ่งอาจช่วยคลี่คลายความสับสนได้ระดับหนึ่ง: https://github.com/mit-han-lab/streaming-llm/blob/main/READM...
สำหรับคำถามว่า “สามารถป้อนข้อความยาวอย่างหนังสือเข้า StreamingLLM เพื่อสรุปได้ไหม?” คำตอบคือ แม้จะป้อนข้อความยาวได้ แต่โมเดลจะรับรู้ได้เฉพาะ โทเคนล่าสุด ดังนั้นถ้าป้อนหนังสือเข้าไป ก็อาจสรุปได้แค่ย่อหน้าท้าย ๆ และอาจไม่ค่อยมีประโยชน์
กล่าวคือ นี่ไม่ใช่การขยาย context window ของ LLM หรือการเสริมความจำระยะยาว จุดแข็งของ StreamingLLM อยู่ที่การสร้างข้อความที่ลื่นไหลจากโทเคนล่าสุดโดยไม่ต้องรีเฟรชแคช
ผมอาจเข้าใจผิดก็ได้ แต่ดูเหมือนว่านี่ไม่ใช่เทคโนโลยีที่ทำให้ LLM อ้างอิงเนื้อหาที่เกินความยาวที่ฝึกมาได้อย่างที่หลายคนคิด
น่าจะเป็นปัญหาเรื่องการรักษาประสิทธิภาพของโมเดลบนข้อความยาว ๆ หรือพูดให้ชัดคือประสิทธิภาพต่อเนื้อหาที่ยังอยู่ภายใน context window มากกว่า
คำอธิบายคือโมเดลเรียนรู้ที่จะใส่ภาระบางอย่างไว้ใน attention ของโทเคนช่วงต้นของข้อความ และเมื่อสิ่งนั้นหลุดออกไปนอก window ก็พัง แต่ผมก็ไม่แน่ใจว่าทำไมถึงเป็นแบบนั้น
ถ้าไม่ใช่อินพุตคำสั่ง ผมรู้สึกว่าข้อความตรงกลางก็น่าจะดีพอ ๆ กับข้อความช่วงต้นไม่ใช่หรือ
ผมสงสัยว่า เทคนิค sliding window แบบนี้รับมืออย่างไรในกรณีที่มีคำสั่งที่ไม่คาดคิดโผล่มาเฉพาะตอนท้าย
เช่น ถ้าป้อนหนังสือให้โมเดล แล้วประโยคสุดท้ายมีคำสั่งว่า “จงคืนค่าจำนวนตัวอักษร m ในอินพุตก่อนหน้า” มนุษย์คงถอนหายใจแล้วกลับไปอ่านใหม่เพื่อนับ แต่ LLM ไม่มีความสามารถในการย้อนกลับไปอ่านอินพุตซ้ำ
ในตัวอย่างนี้ ต่อให้มองข้ามข้อจำกัดของ LLM เรื่องการนับตัวอักษรเอง ถ้าจะแก้จริง ๆ ก็ดูเหมือนว่า LLM ต้องสามารถวนลูปและกระโดดไปมาได้ตามใจ
แน่นอนว่าถ้าเป็นแบบนั้นก็จะเกิดปัญหาใหม่ทั้งหมด และอาจต้องใช้อาร์คิเทกเจอร์ใหม่เลยก็ได้
วิธีคือแปลงคำถามเป็นคีย์เวิร์ดที่เกี่ยวข้อง ค้นหา แล้วไล่อ่านเนื้อหาอีกรอบเพื่อหาข้อมูลที่เกี่ยวข้อง
ถ้ามีการประมวลผลล่วงหน้าที่จำเป็น LLM ที่ “ไปค้นคว้าให้พอแล้วค่อยตอบ” ได้จะทรงพลังมาก
ตลอดราว 10,000 ปีที่ผ่านมา เราพัฒนาเทคโนโลยีการจัดการความรู้เพื่อให้ก้าวพ้นความจุและเวลาของสมองส่วนบุคคล ดังนั้นโมเดลภาษาก็ควรใช้วิธีวิจัยจริงและการย่อยความรู้ล่วงหน้า ไม่ใช่แค่ค้นหา Bing แบบง่าย ๆ
ความจำระยะสั้นไม่จำเป็นต้องจำว่าโค้ดชิ้นไหนทำอะไร แค่ติดแท็กตอนอ่าน แล้วพึ่งพาดัชนีแท็กแบบแชร์ที่ขยายได้ก็พอ
แต่ยิ่งคิดก็ยิ่งรู้สึกว่ามันคล้ายการ pretraining ของ LLM ทั่วไป และดัชนีความรู้ก็เหมือนเป็นก้อนน้ำหนัก LLM ขนาดมหึมา
มันใกล้เคียงกับชั้นที่วางอยู่บน LLM มากกว่าการเปลี่ยนพฤติกรรมของตัว LLM เอง
ผมอาจเข้าใจผิดก็ได้ แต่ในกรณีนี้ hidden state ไม่ได้แก้ปัญหาการค้นคืนข้อมูลอยู่แล้วหรือ?
ก่อนตอบก็ต้องดูดซับอินพุตทั้งหมดอยู่ดี ดังนั้นไม่ว่าคำสั่งจะอยู่ด้านหน้าหรือท้าย นอกจาก attention แล้วดูเหมือนจะไม่ได้มีผลมากนัก
Claude 100K ขอให้ผู้ใช้ใส่คำสั่งไว้ตอนท้าย
หรือไม่ก็ใช้โมเดลที่เร็วกว่าเพื่อตรวจว่ามีคำสั่งอยู่ท้ายหรือไม่ แล้วดึงมันมาไว้ด้านหน้าก็ได้
ผมยังไม่แน่ใจว่าโมเดลปัจจุบันทำสิ่งนี้ได้แม้กับอินพุตสั้น ๆ หรือเปล่า
พูดแบบติดตลกนิด ๆ คือ LLM กำลังพยายามอย่างหนักมากที่จะประดิษฐ์ RNN ขึ้นมาใหม่ และถ้าให้เครื่องมือมันพอ สุดท้ายก็น่าจะไปถึงจุดนั้น
มองอีกแบบ โมเดล Transformer คือความพยายามคาดการณ์ว่า เมื่อมีข้อจำกัดด้านทรัพยากร ส่วนใดของเครือข่าย RNN ที่ “ควรค่าแก่การเก็บรักษา”
Transformer ปัจจุบันใช้ heuristic แบบง่าย ๆ และผลลัพธ์นี้ทำให้ heuristic นั้นดีขึ้น
เช่นเดียวกับปัญหา NP-complete จำนวนมาก แม้จะหาคำตอบสมบูรณ์แบบไม่ได้ ก็อาจมีการประมาณที่เป็นประโยชน์ได้ และ Transformer แสดงให้เห็นว่าสิ่งนั้นเป็นไปได้ในเครือข่ายประสาทด้วย
มันเคยอยู่ระดับกลาง ๆ บนลีดเดอร์บอร์ดโอเพนซอร์สมาพักหนึ่ง จึงเป็นแนวทางที่ค่อนข้างสมเหตุสมผล เพียงแต่ไม่เป็นกระแสเท่านั้น
[1]: https://huggingface.co/blog/rwkv
ข้อได้เปรียบหลักของ Transformer เหนือ RNN คือ การทำ parallelization ระหว่างการฝึก
RNN มีปัญหา gradient หายไประหว่างฝึก และยังทำให้ utilization โดยรวมสูงได้ยาก จึงต้องใช้ batch ขนาดใหญ่ ทำให้ยุ่งยาก
การมีอยู่ของโมเดลอย่าง RWKV แสดงให้เห็นว่าอาจมีอนาคตที่ฝึกเหมือน Transformer และ infer เหมือน RNN
ที่เกี่ยวข้องกัน ศาสตราจารย์ Han จาก MIT กำลังเปิดสอน คอร์ส TinyML แบบสาธารณะ
https://news.ycombinator.com/item?id=37620507
https://efficientml.ai