Llama2.c: รันการอนุมาน Llama 2 จากไฟล์ C ล้วน
(github.com/karpathy)- llama2.c คือโซลูชันการฝึกและการอนุมานแบบ “fullstack” ที่ฝึกสถาปัตยกรรม Llama 2 LLM ด้วย PyTorch และรันการอนุมานด้วยไฟล์ C แบบเรียบง่าย
run.c - จุดโฟกัสหลักคือ ความมินิมอลและความเรียบง่าย โดยเป็น implementation เชิงการศึกษาที่ฮาร์ดโค้ดสถาปัตยกรรม Llama 2 และประกอบด้วยไฟล์อนุมาน C ล้วนไฟล์เดียวที่ไม่มี dependency
- มีโมเดลตัวอย่างบนพื้นฐาน TinyStories โดยยึดแนวคิดว่าแม้แต่ LLM ขนาดเล็กมากก็ยังให้ประสิทธิภาพที่ดีได้ หากจำกัดโดเมนให้แคบพอ
- โมเดล 15M พารามิเตอร์มีขนาดดาวน์โหลดราว 60MB และสามารถรันได้ด้วย
make runแล้วตามด้วย./run stories15M.bin - ยังมีโมเดล 42M และ 110M พารามิเตอร์ให้ด้วย โดยระบุว่าโมเดล 110M มีขนาดเท่ากับ GPT-1
- โมเดล 15M พารามิเตอร์มีขนาดดาวน์โหลดราว 60MB และสามารถรันได้ด้วย
- โมเดล Llama 2 ของ Meta ก็สามารถรันการอนุมานได้เช่นกันเพราะใช้สถาปัตยกรรมโครงข่ายประสาทแบบเดียวกัน แต่ต้องรับ checkpoint ตามแนวทางของ Meta ก่อน แล้วแปลงเป็นฟอร์แมตของ llama2.c ด้วย
export.py- ปัจจุบัน
run.cรองรับเฉพาะการอนุมานแบบ fp32 ดังนั้นโมเดลที่ใหญ่กว่า 7B อาจโหลดมาใช้งานจริงได้ยาก - รุ่น 13B ขึ้นไปยังไม่ทำงานในตอนนี้เพราะ integer overflow ใน pointer arithmetic และยังไม่ได้แก้ไข
- ปัจจุบัน
- การอนุมานแบบ int8 quantization ถูก implement ไว้ใน
runq.cโดยใช้วิธี Q8_0 เพื่อ quantize น้ำหนักที่เข้าร่วม matmul และยัง quantize/dequantize ค่า activation แบบไดนามิกในรันไทม์- การ export แบบ fp32 ของ Llama 2 7B จะสร้างไฟล์ขนาด 26GB ส่วน quantized export version 2 จะสร้างไฟล์ขนาด 6.7GB
- ในสภาพแวดล้อมของผู้เขียน เมื่อใช้ OpenMP 64 เธรด fp32 ทำได้ 4.6 tok/s และ int8 ทำได้ 14 tok/s ทำให้ checkpoint มีขนาดเล็กลง 4 เท่าและเร็วขึ้นราว 3 เท่า
- วิธีใช้งานครอบคลุมการรัน C inference, การป้อนพรอมป์ต์, การควบคุม sampling แบบ temperature และ top-p, การรันโหมด chat และการระบุ tokenizer แบบกำหนดเอง
- ตัวอย่างการรันคือ
./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth" - โมเดล chat รันด้วยแฟลก
-m chatเช่น./run llama2_7b_chat.bin -m chat - tokenizer แบบกำหนดเองสามารถ export เป็นฟอร์แมต
.binด้วยtokenizer.pyแล้วระบุผ่านแฟลก-z
- ตัวอย่างการรันคือ
- โมเดลบน Hugging Face ที่ใช้สถาปัตยกรรม Llama 2 สามารถ export เป็นไฟล์
.binได้ด้วยแฟลก--hfของexport.py - เวิร์กโฟลว์การฝึกเริ่มจากดาวน์โหลดและ pre-tokenize TinyStories จากนั้นรัน
train.pyแล้ว export โมเดลเพื่อนำไปอนุมานต่อใน C- ขณะนี้ตัวอย่าง TinyStories พื้นฐานเป็นตัวอย่างชุดข้อมูลเดียวที่มีให้
- การฝึก tokenizer แบบกำหนดเองใช้
sentencepieceโดยในตัวอย่างใช้การตั้งค่า--vocab_size=4096
- การ build ด้านประสิทธิภาพแบ่งเป็น
make run,make runfastและmake runompโดย build แบบ OpenMP จะเปิดใช้#pragma omp parallel forภายใน matmul และ attention เพื่อกระจายงานในลูปไปยังหลายโปรเซสเซอร์ - มีคำแนะนำการ build สำหรับ Windows, Centos 7, Amazon Linux 2018 และ Mac
- Windows ใช้
build_msvc.batหรือmake win64 - Centos 7 และ Amazon Linux 2018 ใช้
make rungnuหรือmake runompgnu - OpenMP build บน Mac ใช้
make runomp CC=/opt/homebrew/opt/llvm/bin/clangหลังติดตั้ง clang จาก brew
- Windows ใช้
- มีการทดสอบด้วย
pytestและ C testmake testccโดยtest_all.pyจะรัน forward 200 สเต็ปทั้งใน C และ Python แล้วเปรียบเทียบกับผลลัพธ์คาดหมายที่ทราบอยู่แล้ว - เป้าหมายของโปรเจ็กต์คือคงความเป็น reference implementation แบบเรียบง่ายที่ประกอบด้วยไฟล์
.pyสำหรับการฝึก 2 ไฟล์ที่อ่านง่าย และโค้ดอนุมาน C โดยไม่มุ่งไปทางเฟรมเวิร์กซับซ้อนหรือออปชันจำนวนมาก - ไลเซนส์คือ MIT
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
เห็นโพสต์นี้บน HN แล้วน่าสนใจดี :) เดิมทีเช็กพอยต์นี้เมื่อคอมไพล์ด้วย
-O3บน MacBook Air M1 จะรันได้เร็วถึง 100 tok/s ซึ่งเร็วกว่าที่คาดมาก ตอนนี้เลยกำลังฝึกโมเดล 44M ที่ใหญ่ขึ้นอยู่ถึงอย่างนั้นก็น่าจะยังรันแบบโต้ตอบได้ และก็รู้สึกว่าอาจเอื้อมถึงโมเดล 7B ของ Llama ได้เหมือนกัน
nanoGPTนิดหน่อยแล้วพรีเทรนโมเดล 12M ด้วยข้อมูล 2GB ที่ GPT-4 สร้างจาก TinyStories ผลลัพธ์ออกมาน่าประหลาดใจทีเดียวหลังจากนั้นพอปรับให้เข้ากับ Wikipedia อีกเล็กน้อย มันก็กลายเป็นตัวสร้างเรื่องเพ้อเจ้อที่ดูน่าเชื่อถือ ซึ่งฉลาดกว่าและเล็กกว่าระบบ n-gram แบบทำ smoothing มาก ดูเหมือนว่า LLM ขนาดเล็กจะกลายเป็นกระแสหลักในหลายด้าน และเป้าหมายถัดไปคือย่อ Llama2 7B ให้เหลือ 10~100M โดยไม่ให้มันโง่ลงมากเกินไป
การเช่า GPU instance จากที่อย่าง Linode แพงกว่าการเช่าเซิร์ฟเวอร์เว็บแอปทั่วไปมาก เลยอยากรู้ว่านี่เป็นพื้นที่ที่เป็นไปไม่ได้เลยหรือเปล่า หรือแนวทางแบบนี้รวมถึงวิธีอื่น ๆ ยังพอเป็นทางที่ใช้งานได้จริง
Georgi Gerganov ผู้โด่งดังจาก llama.cpp มีเวอร์ชันที่รันบนเบราว์เซอร์ด้วย Emscripten: https://ggerganov.com/llama2.c/
Twitter thread ที่กำลังดำเนินอยู่คือ https://twitter.com/ggerganov/status/1683174252990660610
ทั้งต้นฉบับและงานนี้ยอดเยี่ยมมาก และแม้จะใกล้เคียงกับการพิสูจน์แนวคิดที่ใช้โมเดลเล็กมาก แต่ LLM แบบ local-first ก็น่าสนใจเป็นพิเศษ ชอบแนวคิดที่ว่าสามารถสร้างเว็บแอปด้วย local inference ได้
ถ้าต่อยอดไปถึงการปรับแต่งประสิทธิภาพ งานวิจัยโมเดลที่เล็กลง การดาวน์โหลดบางส่วน และการใช้ WebGPU ก็อาจเป็นจุดเริ่มของแนวทางใหม่ในการสร้างแอปส่วนตัวที่อิงกับ LLM ในเครื่อง แม้อาจยากที่จะมีความสามารถเทียบเท่า LLM ที่โฮสต์บนคลัสเตอร์ GPU ระดับสูงขนาดใหญ่ แต่แนวทางนี้ก็น่าจะเปิด use case ได้อีกมาก
ตัวอย่างเช่นเริ่มด้วย “Once upon a time...” แล้วดูเหมือนจะเป็นเรื่องของ Lily กับ Timmy แต่จากนั้นก็กลายเป็นข้อความเพี้ยน ๆ อย่าง “Butterfly would pauseWhy”, “TextField”,
querySelector,HttpRequestและเศษข้อความจากหลายภาษาที่ปนกันจนเละสำหรับคนที่สงสัย มี เวอร์ชัน Rust ด้วย ในโหมด release ได้ประมาณ 106 tokens/second
https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...
เวอร์ชันที่ไม่ใช่เว็บรองรับ GPU อย่างเต็มที่ แต่ไม่ได้มินิมอลเลยแม้แต่น้อย
บางครั้งยังทำให้ความพยายามของชุมชนในการ กระจาย การปรับปรุงโปรเจกต์ด้วย
ดูเหมือนจะมีไม่มากนักที่เข้าใจว่านี่เป็นก้าวเดินที่กล้าหาญแค่ไหน
Andrej ได้ค่าตอบแทนก้อนโตจาก OpenAI(MSFT) แต่ก็ยังช่วย Apple, Facebook และที่สำคัญกว่านั้นคือ ขบวนการโอเพนซอร์ส ด้วย ถึงอย่างนั้นก็คงยากที่จะกันเขาออกไปได้ เพราะถ้าเป็นแบบนั้นเขาก็อาจย้ายไป Tesla หรือ xAI ได้ทันที
รู้สึกว่า Llama-2 มี การกรองความปลอดภัย หนักเกินไปจนเอาไปใช้กับงานสร้างสรรค์ไม่ได้: https://i.imgur.com/GFY0wSL.png
อย่างไรก็ตาม ปรากฏการณ์นี้พอจะทำซ้ำได้เฉพาะตอนส่งเป็นข้อความที่สองบน Llama2-70b-chat TGI ของ Hugging Face และอาจเป็นไปได้ว่ามีอะไรแปลก ๆ ในวิธีพรอมป์ต์จนทำให้เกิดพฤติกรรมแบบนี้ ตอนนี้ยังไม่ได้รันโมเดลเองเพื่อตรวจสอบเพิ่มเติม
Chat/instruct มีข้อดีตรงที่ปล่อยให้ผู้ใช้ภายนอกใช้งานได้ง่าย พรอมป์ต์ไม่ซับซ้อน และมีราวกันความปลอดภัย แต่ถ้าใช้เอง มันด้อยกว่าโมเดลพรีเทรนอย่างมาก ตรงนี้ Llama 2 อาจได้เปรียบ OpenAI เพราะ OpenAI ดูเหมือนจะเลิกใช้โมเดลพรีเทรน GPT-3 และมุ่งไปทางให้บริการเฉพาะ chat model ต่อไป
ไม่ต้องการกรรไกรเซฟตี้ จะจำกัดสิ่งที่รันบนเซิร์ฟเวอร์ของตัวเองก็เรื่องหนึ่ง แต่อย่าเอาโมเดลที่ฉันแก้ไขและใช้ตามต้องการบนคอมพิวเตอร์ของตัวเองไม่ได้มาให้
Andrej โพสต์รายละเอียดเพิ่มเติมไว้ที่นี่: https://twitter.com/karpathy/status/1683143097604243456?s=46...
อนึ่ง ถ้าสนใจเรื่องแนวนี้ โค้ดนี้สามารถบิลด์ด้วย WASI SDK ได้อย่างเรียบร้อย และรันบน Wasm runtime ได้โดยไม่ต้องแก้ไข
สงสัยว่าถ้าจะรันโครงข่ายประสาทเทียมต้องใช้หน่วยความจำเท่าไร
แค่อ่านสองเลเยอร์แรกจากดิสก์ คำนวณค่า activation ของทุกโหนด จากนั้นทิ้งเลเยอร์แรก แล้วอ่านเลเยอร์ที่สามมาคำนวณต่อ แล้วทิ้งเลเยอร์ที่สอง แบบนี้ก็พอหรือไม่? ถ้าใช่ ก็สงสัยว่ามีหน่วยความจำพอแค่เก็บสองเลเยอร์ก็พอหรือเปล่า
สรุปคือ RAM สูงสุดขึ้นอยู่กับวิธีควอนไทซ์ โดยคร่าว ๆ โมเดล 7B อยู่ที่ 4~8GB, 13B อยู่ที่ 8~15GB, 30B อยู่ที่ 13~33GB และ 70B อยู่ที่ 31~75GB
มีความคิดแวบขึ้นมาว่า ตอนนี้ LLM คืนค่าการกระจายความน่าจะเป็นออกมา แล้วตัวสุ่มก็เลือกหนึ่งค่าไปต่อท้ายผลลัพธ์แล้วทำซ้ำ
ถ้าเปลี่ยนเป็นให้ตัวสุ่มเลือกโทเค็น N ตัวที่ประมาณการกระจายนั้น แล้วให้ LLM สร้างการกระจายใหม่ N ชุด จากนั้นรวมมันด้วยวิธีใดวิธีหนึ่ง แล้วเลือกโทเค็น N ตัวอีกครั้งจากการกระจายที่รวมกัน แบบนี้จะเป็นไปได้ไหม?
ดูตัวอย่างได้ที่ https://huggingface.co/docs/transformers/internal/generation...
แต่ก็ไม่รู้ว่าจะทำอย่างไร
แน่นอนว่าแต่ละการสร้างโทเค็นจะต้องใช้ การคำนวณเพิ่ม N เท่า อาจเลือก N อันดับแรก หรือถ้าจำเป็นก็ปรับอุณหภูมิที่ logits แล้วสุ่ม N ตัวออกมาได้
อันนี้มีไว้เพื่อการศึกษาหรือ? เมื่อดูความสำเร็จของ llama.cpp และโปรเจกต์นี้ ก็เหมือนว่าอุตสาหกรรมกำลังไปในทางมี ซอร์สโค้ดแยกเฉพาะ สำหรับแต่ละโมเดลที่ออกมา แทนการใช้เฟรมเวิร์กอเนกประสงค์อย่าง PyTorch, TensorFlow, ONNX Runtime
และไม่ใช่แบบนั้นทั้งหมด ตามชื่อแล้ว llama.cpp ก็ไม่ได้รองรับแค่ llama และก็ไม่ได้เฉพาะทางเต็มตัว เพราะสร้างอยู่บนไลบรารี/เฟรมเวิร์กเทนเซอร์
ggmlที่มีความทั่วไปมากกว่าแต่เมื่อเจอโมเดลที่ใช้งานได้ดีแล้ว ความก้าวหน้าเหล่านั้นก็มักถูกรวมเข้าไปในเฟรมเวิร์กเวอร์ชันถัดไป นั่นจึงเป็นเหตุผลที่ TensorFlow มีบล็อกพื้นฐานอย่าง CNN, GRU, TransformerEncoder และในขณะเดียวกันก็มีการทำ implementation สำหรับฮาร์ดแวร์เฉพาะที่แลกความทั่วไปเพื่อให้ได้ความเร็ว