Hugging Face เปิดตัว Tokenizers v1 เร็วขึ้นสูงสุด 30 เท่า

· By: TanasakP

ปกติแล้ว Tokenizer มักไม่ค่อยเป็นคอขวดในเวิร์กโฟลว์ของ ML เมื่อเทียบกับการทำ Modeling ที่ต้องใช้ทรัพยากรสูงกว่ามาก อย่างไรก็ตาม เมื่อโมเดลทำงานเร็วขึ้นและปริมาณงานขยายตัวขึ้นเรื่อยๆ การทำ Tokenization ก็อาจกลายเป็นตัวถ่วงสำคัญที่ทำให้โมเดลต้องหยุดรอข้อมูล (Starve)

นี่คือเหตุผลที่เรามุ่งเน้นพัฒนาประสิทธิภาพอย่างหนักสำหรับ tokenizers v1 เพื่อให้การทำงานเบาและปรับขยาย (Scale) ได้ตามเวิร์กโฟลว์จริง โดยไม่ปล่อยให้ GPU ต้องนั่งรอ CPU ทำการ Tokenization ให้เสร็จสิ้น

ในบทความนี้ เราจะเจาะลึกสิ่งที่ทำให้ v1 เร็วกว่า v0.23 หลายสิบเท่า ซึ่งเป็นผลมาจากความเคลื่อนไหวในระบบนิเวศโอเพนซอร์สของไลบรารีต่างๆ เช่น gigatoken, tiktoken และโปรเจกต์อื่นๆ ที่ร่วมกันผลักดันขีดจำกัดด้านความเร็ว

เราขอขอบคุณ IBM, NVIDIA และทีม ExecuTorch สำหรับการสนับสนุนและช่วยทดสอบบนฮาร์ดแวร์ที่หลากหลาย เพื่อขยายการรองรับแพลตฟอร์มให้กว้างขึ้นกว่าเดิม

ผลลัพธ์ (Results)

เราได้แสดงผลการทดสอบของ tokenizers v1 (Release Candidate) เปรียบเทียบกับตัวเลือกยอดนิยมอื่นๆ โดยครอบคลุมตั้งแต่การทำงานแบบ Single-threaded, Multi-threaded, การปรับขยายข้ามเธรด ไปจนถึง Latency และ Throughput ในการถอดรหัส

ผู้ที่สนใจสามารถรันเบนช์มาร์กซ้ำบนฮาร์ดแวร์ของตัวเองได้ผ่านทาง repository tokbench

V1 คืออะไร

v1 จะสร้าง Token ID ชุดเดิมเหมือนกับ v0.23 โดยมีเป้าหมายคือการรักษาผลลัพธ์ (Output), API, Vocabulary และ Merge Ranks ไว้เช่นเดิม แต่ปรับปรุงทุกส่วนที่สามารถเพิ่มประสิทธิภาพได้ ตัวไลบรารียังคงความเป็นทั่วไป (General) ทำให้สามารถโหลดทุกอย่างที่เวอร์ชันเก่ารองรับได้

ขั้นตอนการทำงานของ Tokenizer ประกอบด้วย 4 ขั้นตอนหลัก ได้แก่ Normalization, Pre-tokenization, Model Stage และ Post-processing โดยขั้นตอนของโมเดลคือจุดที่มีการเปลี่ยนแปลงมากที่สุด โดยเฉพาะในตระกูล BPE (Byte Pair Encoding) ซึ่งถูกใช้งานในโมเดลส่วนใหญ่ 8 ใน 10 รุ่นที่นำมาทดสอบ

รายละเอียดเพิ่มเติมสามารถอ่านได้ที่หน้า tokenization pipeline และ Tokenization algorithms

การเปลี่ยนแปลงที่สำคัญมีดังนี้:

การเปลี่ยนแปลงหน้าที่
workspace splitแยกเป็นหลาย crate: tk-encode สำหรับ runtime, ส่วนอื่นๆ จะเชื่อมโยงเมื่อจำเป็นเท่านั้น
no-alloc modelใช้ scratch buffer แทนการแตะ allocator ในลูปการทำงาน
bitcannonใช้คำสั่ง SIMD และ Boolean operations บน bitstreams แทน regex engine ในการแยกข้อความ
merge-loop rewriteใช้ intrusive doubly-linked list ภายในบัฟเฟอร์เดียวเพื่อลดการย้ายข้อมูล
word cacheบันทึกผลลัพธ์คำที่ซ้ำในระดับเธรด ทำให้ไม่ต้องรวมคำเดิมซ้ำ
native parallelismรองรับการ encode จากหลายเธรดพร้อมกันโดยไม่ติดคิวใน lock ตัวเดียว (#2365)

The Split: Bitstreams แทนที่จะเป็น Regex

โมเดล BPE มักใช้ Regular Expression ในการแยกข้อความอินพุต แต่ v1 ได้เปลี่ยนมาใช้ฟังก์ชันที่เขียนขึ้นด้วยมือ (Handwritten) ซึ่งรองรับคำสั่ง SIMD ของ CPU สมัยใหม่

เทคโนโลยี bitcannon จะมองอินพุตเป็นกระแสบิตขนานกัน ทำให้ตัดสินใจได้ถึง 64 ไบต์ต่อหนึ่งการทำงานของ Register ซึ่งเป็นแนวคิดเดียวกับ Parabix และ simdjson

The Word Cache เนื่องจากข้อความจริงมักมีคำซ้ำ v1 จึงใช้ Cache ระดับเธรดเพื่อบันทึกผลลัพธ์ของ pre-token ที่เคยประมวลผลแล้ว เมื่อเจอคำเดิมซ้ำอีกครั้ง ระบบจะข้ามขั้นตอนการรวม (Merge) ไปได้ทันที ช่วยเพิ่มประสิทธิภาพอย่างมากโดยเฉพาะในอินพุตที่มีความยาวสูง

คุณสามารถทดสอบประสิทธิภาพการทำ prefix-sharing ได้ด้วยคำสั่ง:

tokbench measure prefix-sharing \
  --engine pipeline \
  --engine hf-tokenizers \
  --compare-to pipeline-no-cache \
  --corpus agentic_swe

The Merge Loop

v1 กำจัดการจองหน่วยความจำซ้ำซ้อนด้วยการนำ scratch buffer กลับมาใช้ใหม่ และเก็บสัญลักษณ์ไว้ใน Array แบบแบนที่เชื่อมโยงกัน ทำให้การอัปเดตระหว่างรวมคู่มีราคาถูกลง นอกจากนี้ยังใช้การเปรียบเทียบเลขจำนวนเต็ม 64-bit แทนการใช้ Branch ในลูปการรวม

วิธีการ (Method) เพื่อให้การเปรียบเทียบเป็นธรรม เรากำหนดกฎเกณฑ์ที่เข้มงวด เช่น การรันลูปที่เหมือนกันทุกเอนจิน, แยกเวลาโหลด Vocabulary ออกจากการ Encode, ตรวจสอบความถูกต้องของ Output ID ด้วย FNV-1a และการล็อกโปรเซสเซอร์ไว้กับ Physical Core แปดคอร์ที่แยกกัน เป็นต้น

ผลลัพธ์โดยรวม

จากการทดสอบ v1 สามารถ Encode ข้อความได้ เร็วกว่าเดิม 3 ถึง 30 เท่า บน Apple M4 Max เมื่อเทียบกับ v0.23 โดยรุ่นที่เห็นผลชัดเจนที่สุดคือ gpt2 และยังสามารถปรับขยายประสิทธิภาพได้ถึง 76% ของแบบเชิงเส้นเมื่อใช้ 8 worker โดยให้ผลลัพธ์ Token ID เหมือนเดิมทุกประการ

เป้าหมายถัดไปคือการรองรับตระกูลโมเดลให้มากขึ้นก่อนปล่อยเวอร์ชัน 1.0.0 และนำการปรับปรุงเหล่านี้เข้าสู่ไลบรารี Transformers และระบบนิเวศอื่นๆ ต่อไป

การติดตั้ง

คุณสามารถติดตั้ง Release candidate สำหรับ v1 ได้ผ่าน crates.io:

cargo add tokenizers --pre

หากต้องการใช้งานเฉพาะการ Encode โดยไม่รวมส่วนการ Training:

cargo add tokenizers --pre --no-default-features --features http

ตัวอย่างการใช้งานภาษา Rust:

use tokenizers::tokenizer::{Result, Tokenizer};
 
fn main() -> Result<()> {
    let tokenizer = Tokenizer::from_pretrained("deepseek-ai/DeepSeek-V4-Flash", None)?;
 
let encoding = tokenizer.encode("The tokenizer is no longer the bottleneck.", false)?;
    println!("{:?}", encoding.get_ids());
    println!("{:?}", encoding.get_tokens());
 
Ok(())
}

สำหรับการประมวลผลแบบกลุ่ม (Batch) เพื่อขยายขนาดข้ามคอร์ ให้ใช้คำสั่ง:

let encodings = tokenizer.encode_batch(documents, false)?;

ความคืบหน้าสู่ V1

ขณะนี้งานในส่วนของ Rust pre-release เสร็จสิ้นแล้วในหลายส่วน เช่น workspace split, bitcannon และ WordCache ส่วนแผนงานสำหรับเวอร์ชัน 1.0.0 จะรวมถึงการปรับปรุง Normalizers และการสร้าง C/C++ bindings แบบ inference-only

หลังจากเวอร์ชัน 1.0.0 เป็นต้นไป ทีมงานจะสำรวจการทำ GPU encoding และการถอดรหัสแบบกลุ่มบนอุปกรณ์โดยตรง เพื่อรองรับการประมวลผลข้อมูลขนาดใหญ่ที่มีประสิทธิภาพสูงขึ้นไปอีกขั้น

Source: Hugging Face Blog
ดูแลงานแปลและเรียบเรียงโดย TanasakP

ความคิดเห็น (0)

เข้าสู่ระบบเพื่อร่วมแสดงความเห็น

สมัครสมาชิก

มาเป็นคนแรกที่แสดงความเห็นกันเลยโบร