เจาะลึก SparseCore สำหรับโมเดลการฝังขนาดใหญ่ (LEM)

SparseCore เป็นโปรเซสเซอร์แบบไทล์เฉพาะที่ออกแบบมาเพื่อการเร่งความเร็วที่มีประสิทธิภาพสูง ของภาระงานที่เกี่ยวข้องกับการเข้าถึงหน่วยความจำแบบกระจัดกระจายและแบบไม่สม่ำเสมอ รวมถึงการ คำนวณ โดยเฉพาะอย่างยิ่งในชุดข้อมูลขนาดใหญ่ที่จัดเก็บไว้ในหน่วยความจำแบนด์วิดท์สูง (HBM) แม้ว่าโมเดลนี้จะทำงานได้ดีในงานต่างๆ เช่น การฝังการค้นหา แต่ความสามารถของโมเดลก็ครอบคลุมไปถึงการเร่งความเร็วของภาระงานแบบไดนามิกและแบบกระจัดกระจายอื่นๆ อีกมากมาย

1. ข้อมูลเบื้องต้นเกี่ยวกับ SparseCore

ฟีเจอร์สถาปัตยกรรมที่สำคัญ

  • สถาปัตยกรรมแบบไทล์: ประกอบด้วยไทล์การประมวลผลหลายรายการ (แต่ละไทล์เป็นหน่วยโฟลว์ข้อมูลที่สมบูรณ์พร้อมหน่วยความจำและการประมวลผลในเครื่องของตัวเอง) ซึ่งช่วยให้ประมวลผลแบบคู่ขนานได้
  • การดำเนินการแบบไดนามิก: รองรับโฟลว์การควบคุมและการเข้าถึงหน่วยความจำที่ขึ้นอยู่กับข้อมูลโดยกำเนิด ซึ่งมีความสำคัญอย่างยิ่งสำหรับข้อมูลแบบกระจัดกระจาย
  • การประมวลผลเวกเตอร์: ใช้ประโยชน์จากงานเวกเตอร์ขนาดเล็ก (8 หรือ 16 องค์ประกอบ ขึ้นอยู่กับเวอร์ชันฮาร์ดแวร์) เพื่อการคำนวณที่มีประสิทธิภาพ
  • การควบคุมจากส่วนกลาง: Sequencer ของ SparseCore ตัวเดียวจะจัดระเบียบงานในทุกไทล์เพื่อให้การทำงานซิงค์กัน
  • รองรับการสรุปข้อมูล: มีการดำเนินการข้ามเลนเฉพาะทางที่เป็นประโยชน์สำหรับงานต่างๆ เช่น การจัดเรียง การกรอง และผลรวมของคำนำหน้า
  • ลำดับชั้นของหน่วยความจำ: ใช้ประโยชน์จาก HBM อย่างมีกลยุทธ์เพื่อจัดเก็บชุดข้อมูลขนาดใหญ่และหน่วยความจำแบบ Scratchpad ในเครื่อง (SPMEM) เพื่อจัดเตรียมข้อมูลที่เข้าถึงบ่อย ซึ่งช่วยลดเวลาในการตอบสนองของ HBM ได้อย่างมาก

ข้อมูลจำเพาะโดยย่อ

แอตทริบิวต์ TPU v4 TPU v5p Trillium
SparseCores/Chip 4 4 2
Tiles/SparseCore 16 16 16
ความกว้างของ SIMD 8 8 8 (F32) 16 (BF16)
ความจุ HBM 32 GiB 96 GiB 32 GiB

2. การประมวลผลล่วงหน้าของโฮสต์ SparseCore

การเตรียมข้อมูลที่มีประสิทธิภาพเป็นสิ่งสำคัญอย่างยิ่งต่อประสิทธิภาพของ SparseCore และการประมวลผลล่วงหน้าของโฮสต์มีบทบาทสำคัญในเรื่องนี้ ซึ่งครอบคลุมฟังก์ชันหลักหลายอย่าง ดังนี้

  • การเปลี่ยนรูปแบบข้อมูล
    • ใช้การเปลี่ยนรูปแบบที่จำเป็นกับข้อมูลอินพุตดิบ
    • จัดการการเปลี่ยนรูปแบบรหัส ซึ่งมีความสำคัญอย่างยิ่งเมื่อต้องจัดการกับการซ้อนฟีเจอร์หรือตาราง
    • แปลงข้อมูลอินพุตเป็นรูปแบบ COO แบบกระจัดกระจาย ซึ่งมีรายละเอียดอยู่ในส่วนต่อไปนี้
    • แบ่งพาร์ติชันข้อมูลเพื่อการกระจายที่มีประสิทธิภาพใน SparseCore ต่างๆ ที่มีอยู่ในชิป
  • การตรวจสอบขีดจำกัด
    • ตรวจสอบว่าลักษณะของข้อมูลอินพุต (เช่น จำนวนรหัส) เป็นไปตามขีดจำกัดการทำงานที่กำหนดไว้ล่วงหน้าของ SparseCore เช่น max_ids_per_partition และ max_unique_ids_per_partition
    • หากข้อมูลอินพุตเกินขีดจำกัดเหล่านี้ เลเยอร์การประมวลผลล่วงหน้าของโฮสต์จะพยายามแบ่งกลุ่มข้อมูลออกเป็นมินิแบตช์ขนาดเล็กที่อยู่ในข้อจำกัด
  • การโอนข้อมูล
    • คัดลอกข้อมูลที่ประมวลผลและตรวจสอบแล้วไปยังหน่วยความจำแบนด์วิดท์สูง (HBM) ของ TPU อย่างมีประสิทธิภาพ เพื่อให้พร้อมสำหรับการดำเนินการ SparseCore

การทำความเข้าใจการซ้อนตาราง

การซ้อนตารางเป็นเทคนิคการเพิ่มประสิทธิภาพที่สำคัญ ซึ่งจะรวมตารางการฝังหลายตารางเข้าด้วยกันอย่างมีตรรกะเพื่อเพิ่มประสิทธิภาพการค้นหาการฝัง โดยปกติแล้วเฟรมเวิร์ก ML พื้นฐานจะจัดการกระบวนการนี้โดยอัตโนมัติ

  • การซ้อนฟีเจอร์: กรณีนี้จะเกิดขึ้นเมื่อฟีเจอร์ที่แตกต่างกันหลายรายการใช้ตารางการฝังพื้นฐานเดียวกัน ตัวอย่างที่พบบ่อยคือการใช้พจนานุกรมการฝังเดียวสำหรับฟีเจอร์เชิงหมวดหมู่ต่างๆ เช่น รหัสไปรษณีย์จากบริบทที่แตกต่างกัน
  • การซ้อนตาราง: ในสถานการณ์นี้ ตารางการฝังที่แตกต่างกันหลายตารางจะ ซ้อนกัน ระบบมักจะจัดกลุ่มตารางที่ใช้มิติข้อมูลการฝังและการกำหนดค่าเครื่องมือเพิ่มประสิทธิภาพเดียวกัน

ข้อได้เปรียบหลักของการซ้อนตารางคือการสร้างขนาดกลุ่มที่มีประสิทธิภาพมากขึ้น สำหรับการดำเนินการในตารางที่ซ้อนกันเหล่านี้ ซึ่งจะช่วยลดค่าใช้จ่ายในการคำนวณและอาจช่วยซ่อนเวลาในการตอบสนองของการสื่อสารระหว่างชิป (ICI) ขอแนะนำให้ใช้ตารางซ้อนกันในจำนวนปานกลาง (โดยทั่วไปอยู่ในช่วง 5 ถึง 100) เพื่อประสิทธิภาพสูงสุด

3. การแปลงเป็นเทนเซอร์ COO

ก่อนที่ SparseCore จะประมวลผลข้อมูลได้ โดยทั่วไปแล้วจะมีการแปลงข้อมูลเป็นรูปแบบเทนเซอร์แบบกระจัดกระจายของพิกัด (COO) รูปแบบ COO เป็นวิธีแสดงเมทริกซ์แบบกระจัดกระจายอย่างมีประสิทธิภาพ โดยปกติจะใช้ 3 อาร์เรย์ ได้แก่

  • row_ids: อาร์เรย์ที่มีดัชนีแถวสำหรับแต่ละองค์ประกอบที่ไม่ใช่ศูนย์ ใน บริบทของการประมวลผลแบบเป็นชุด มักจะสอดคล้องกับมิติข้อมูลชุด
  • col_ids: อาร์เรย์ที่มีดัชนีคอลัมน์สำหรับแต่ละองค์ประกอบที่ไม่ใช่ศูนย์ สําหรับการฝัง ค่าเหล่านี้มักจะเป็นค่าฟีเจอร์หรือค่ารหัส
  • values (ไม่บังคับ): อาร์เรย์ที่เก็บค่าจริงขององค์ประกอบที่ไม่ใช่ศูนย์ ที่พิกัด (row, col) ที่สอดคล้องกัน สําหรับการคํานวณขีดจํากัด (จะกล่าวถึงในภายหลัง) ที่เกี่ยวข้องกับจํานวนรหัส มักจะไม่นําค่าเหล่านี้ (กําไร) มาพิจารณา

ตัวอย่างที่แสดงให้เห็นภาพ

พิจารณาเมทริกซ์แบบกระจัดกระจายของอินพุตที่แสดงชุดรหัส

[
    [id_A],                 // Sample 0
    [id_A, id_B, id_C],     // Sample 1
    [id_B, id_B, id_D],     // Sample 2 (note duplicate id_B)
]

หลังจากแปลงเป็นรูปแบบ COO (และอาจหลังจากขจัดรหัสที่ซ้ำกันภายใน ตัวอย่างเดียวกัน)

row_ids = [0, 1, 1, 1, 2, 2]
col_ids = [id_A, id_A, id_B, id_C, id_B, id_D]

Conversion นี้เป็นพื้นฐานของวิธีที่ SparseCore ประมวลผลและกระจายงาน โดยเฉพาะอย่างยิ่ง col_ids มีความสําคัญอย่างยิ่งต่อการกําหนดว่ารหัสใดอยู่ในพาร์ติชัน SparseCore ใดโดยเฉพาะ ซึ่งช่วยให้การแบ่งข้อมูลและการค้นหามีประสิทธิภาพ

4. SparsecoreConfig: API ระดับสูง

API การฝังเฉพาะเฟรมเวิร์ก

SparsecoreConfig หรือกลไกที่เทียบเท่า เช่น แฟล็ก XLA ทำหน้าที่เป็นอินเทอร์เฟซระดับสูงสำหรับการควบคุมลักษณะการทำงานของ SparseCore ที่หลากหลาย การทําความเข้าใจพารามิเตอร์เหล่านี้อย่างละเอียดเป็นสิ่งสําคัญต่อการปรับประสิทธิภาพอย่างมีประสิทธิภาพ และรับประกันการทํางานที่ถูกต้องของโมเดล

  • disable_table_stacking: bool = False
    • คำอธิบาย: แฟล็กนี้ควบคุมว่าการซ้อนตารางอัตโนมัติจะ ป้องกันไม่ให้เฟรมเวิร์กซ้อนตาราง ซึ่งอาจส่งผลให้ ประสิทธิภาพลดลงเนื่องจากค่าใช้จ่ายที่เพิ่มขึ้นและความสามารถที่ลดลง ในการซ่อนเวลาในการตอบสนองของ Inter-Chip Interconnect (ICI)
    • ค่าเริ่มต้น: False (หมายความว่าโดยทั่วไปจะเปิดใช้การซ้อนตารางโดย ค่าเริ่มต้นในที่ที่เฟรมเวิร์กรองรับ)
  • max_ids_per_chip_per_sample: int = 64
    • คำอธิบาย: พารามิเตอร์นี้กำหนดขีดจำกัดสูงสุดส่วนกลางสำหรับ จำนวนรหัสการฝังทั้งหมดที่ชิปเดียวประมวลผลได้จาก ตัวอย่างเดียวในกลุ่มอินพุต ซึ่งรวบรวมไว้ในตารางทั้งหมด ซึ่งเป็นกลไกสำหรับจัดการทรัพยากรที่ระดับชิป ก่อนที่จะพิจารณาขีดจำกัดที่ละเอียดยิ่งขึ้นต่อตารางหรือต่อพาร์ติชัน โดยปกติแล้ว การปรับค่านี้จะขึ้นอยู่กับลักษณะเฉพาะของโมเดลและความจุโดยรวมของระบบ
    • ค่าเริ่มต้น: 64
  • max_ids_per_table: Optional[Dict[str, int]] = None
    • คำอธิบาย: พารามิเตอร์นี้ระบุจำนวนสูงสุดของ รหัสการฝัง (ซึ่งอาจรวมถึงรายการที่ซ้ำกัน) ที่สามารถประมวลผลได้สำหรับ แต่ละตารางเชิงตรรกะ โดยพิจารณาจากการแบ่งพาร์ติชันทั้งหมดใน SparseCore ทั้งหมด ซึ่งเป็นขีดจำกัดที่กว้างกว่า max_ids_per_partition หากตารางTแบ่งออกเป็นPพาร์ติชัน ขีดจำกัดนี้จะมีผลกับผลรวม ของรหัสที่ส่งไปยังพาร์ติชัน P ทั้งหมด ซึ่งมักเกี่ยวข้องกับ max_ids_per_partition_per_sampleและขนาดกลุ่มโดยรวม
    • การตั้งค่า: โดยปกติจะกำหนดค่าโดยใช้ไฟล์ขีดจำกัด (เช่น ใช้แฟล็ก xla_sparse_core_max_ids_file) ซึ่งมีการกำหนด max_ids_per_partition แนวคิดระดับตารางนี้เป็นวิธี ในการตั้งค่าขีดจํากัดระดับพาร์ติชันเหล่านั้น (max_ids และ max_uniques)
    • ค่าเริ่มต้น: None (ระบบอาจอนุมานค่าจากขีดจำกัดต่อพาร์ติชัน หรือการกำหนดค่าอื่นๆ หากไม่ได้ระบุอย่างชัดเจน)
  • max_unique_ids_per_table: Optional[Dict[str, int]] = None
    • คำอธิบาย: คล้ายกับ max_ids_per_table แต่พารามิเตอร์นี้ ระบุจำนวนสูงสุดของรหัสที่ไม่ซ้ำกันสำหรับตารางเชิงตรรกะแต่ละตาราง การตั้งค่านี้เป็น การตั้งค่าที่สำคัญสำหรับการกำหนดขนาดบัฟเฟอร์ในอุปกรณ์ที่ใช้ในการ ประมวลผลรหัสที่ไม่ซ้ำกันและการดำเนินการเวกเตอร์ที่ตามมาอย่างเหมาะสม
    • การตั้งค่า: มักกำหนดไว้ในไฟล์ขีดจำกัดหรือได้มาจาก max_unique_ids_per_partition_per_sample
    • ค่าเริ่มต้น: None
  • allow_id_dropping: bool = False
    • คำอธิบาย: แฟล็กบูลีนนี้จะควบคุมการทิ้งรหัสเมื่อจำนวนรหัสที่พบในข้อมูลอินพุต (ขีดจำกัดที่สังเกตได้) เกินขีดจำกัดที่ตั้งค่าไว้ระหว่างการคอมไพล์ (เช่น max_ids_per_partition)
      • หาก True: ระบบจะทิ้งรหัสที่จะทำให้เกินขีดจำกัดโดยไม่แจ้งให้ทราบ โดยปกติแล้ว ระบบจะประมวลผลรหัสภายในพาร์ติชันตามลำดับที่เรียงแล้ว และจะทิ้งรหัสใดก็ตามที่จะทำให้จำนวนที่กำลังนับเกินขีดจำกัดสำหรับมินิแบตช์ที่กำหนด ซึ่งจะช่วยให้โปรแกรมทำงานต่อไปได้ แต่อาจส่งผลเสียต่อความแม่นยำของโมเดล
      • หาก False: ระบบจะทริกเกอร์ข้อผิดพลาด และกระบวนการอาจ สิ้นสุดลงหากขีดจำกัดที่สังเกตได้เกินขีดจำกัดที่คอมไพล์ วิธีนี้ ช่วยให้มั่นใจได้ว่าระบบจะประมวลผลข้อมูลทั้งหมด แต่ต้องกำหนดค่าขีดจำกัด อย่างรอบคอบมากขึ้น
    • ค่าเริ่มต้น: False (ทำให้เกิดข้อผิดพลาดเมื่อข้อมูลเกินแทนที่จะทิ้งข้อมูลโดยไม่แจ้ง)
  • initialize_tables_on_host: bool = True

    • คำอธิบาย: แฟล็กนี้จะกำหนดว่าควรเริ่มต้นตารางการฝังใน CPU ของโฮสต์ก่อนที่จะโอนไปยังหน่วยความจำแบนด์วิดท์สูง (HBM) ของ TPU หรือไม่ แนวทางปฏิบัติมาตรฐานคือการเริ่มต้นตารางในโฮสต์ การตั้งค่านี้เป็น True จะเป็นไปตามรูปแบบนี้ หากตั้งค่าเป็น False จะหมายถึงกลไกการเริ่มต้นในอุปกรณ์ ซึ่งอาจมีผลต่อประสิทธิภาพที่แตกต่างกันหรือข้อกำหนดเบื้องต้นในการเริ่มต้นที่เฉพาะเจาะจง
  • enable_fast_table_initialization: bool = False

    • คำอธิบาย: เริ่มต้นตารางโดยตรงใน TPU ซึ่งจะช่วยลดเวลาเริ่มต้นของโมเดลได้

5. การไปป์ไลน์เพื่อประสิทธิภาพ

การไปป์ไลน์เป็นเทคนิคการเพิ่มประสิทธิภาพที่ช่วยให้ การดำเนินการบน TensorCore (TC) และ SparseCore (SC) ทำงานพร้อมกันได้ การทับซ้อนกันของการคำนวณเหล่านี้จะช่วยปรับปรุงปริมาณงานโดยรวมได้อย่างมาก

  • กลไก: ในขั้นตอนการฝึกมาตรฐานที่เกี่ยวข้องกับการค้นหา Embedding แบบกระจัดกระจาย (จัดการโดย SC) และการคำนวณเลเยอร์แบบหนาแน่น (จัดการโดย TC) การไปป์ไลน์ช่วยให้ SC ทำงานในส่วนของขั้นตอน i (เช่น การส่งต่อหรือส่งย้อนกลับ) ขณะที่ TC ประมวลผลส่วนอื่นของขั้นตอนเดียวกัน i หรือแม้แต่ส่วนของขั้นตอนที่อยู่ติดกัน เช่น i-1 หรือ i+1 พร้อมกัน
  • ผลกระทบต่อการไล่ระดับสี: SparseCore อาจทำงานกับการไล่ระดับสีที่ "ล้าสมัย" เช่น การไล่ระดับสีที่คำนวณในระยะการแพร่ย้อนกลับของ ขั้นตอน i อาจยังไม่อัปเดตและมองเห็นได้โดย SC จนกว่าจะถึงขั้นตอน i+2
  • การแลกเปลี่ยนประสิทธิภาพกับตัวเลข: การดำเนินการที่ทับซ้อนกันนี้อาจทำให้ความเร็วเพิ่มขึ้นอย่างมาก ซึ่งอาจช่วยปรับปรุงเวลาขั้นตอนของอุปกรณ์ได้ถึง 2 เท่า อย่างไรก็ตาม การเปลี่ยนแปลงเล็กน้อยในตัวเลข (embedding_weights) ที่เกิดจากการใช้การไล่ระดับสีที่ล้าสมัยอาจส่งผลต่อลักษณะการบรรจบกันของโมเดลหรือความแม่นยำสุดท้ายที่ได้รับ การยอมรับการแลกเปลี่ยนนี้ขึ้นอยู่กับโมเดลเป็นอย่างมาก และมักต้องมีการตรวจสอบเชิงประจักษ์
  • แฟล็กควบคุม: ควบคุมการไปป์ไลน์ได้โดย tf_xla_disable_full_embedding_pipelining การตั้งค่า Flag นี้เป็น true จะปิดใช้การไปป์ไลน์แบบเต็ม (การคำนวณ TensorCore และ SparseCore ที่ทับซ้อนกัน ) ในขณะที่การตั้งค่าเป็น false (หรือหากความหมายของ Flag หมายถึงการเปิดใช้เมื่อเป็นเท็จ) จะเปิดใช้งาน

โฟลว์การไปป์ไลน์เชิงแนวคิด

  • ไม่มีการไปป์ไลน์ (โฟลว์ตามลำดับแบบง่าย):

    Loop: SC/F_i -> TC/F_i -> TC/B_i -> SC/B_i

  • เมื่อใช้การไปป์ไลน์ (โฟลว์ที่ซ้อนทับกันแบบง่าย)

    Time ->
    Step i:   SC/F_i | TC/F_i | TC/B_i | SC/B_i
    Step i+1:          SC/F_i+1| TC/F_i+1| TC/B_i+1| SC/B_i+1
    

    หมายเหตุ: ขั้นตอนการไปป์ไลน์จริงที่ใช้ในฮาร์ดแวร์และ คอมไพเลอร์อาจซับซ้อนกว่านี้ โดยมักเกี่ยวข้องกับลูปก่อนหน้า ลูปการดำเนินการหลัก และลูปหลังเพื่อจัดการการขึ้นต่อกันของข้อมูลและรับประกันความถูกต้อง

6. บทบาทของ XLA

XLA (Accelerated Linear Algebra) เป็นคอมไพเลอร์เฉพาะโดเมนที่แปลกราฟการคำนวณระดับสูง ซึ่งโดยปกติมาจากเฟรมเวิร์ก เช่น TensorFlow เป็นโค้ดแมชชีนที่ได้รับการเพิ่มประสิทธิภาพสูงซึ่งปรับให้เหมาะกับ TPU ซึ่งรวมถึงการสร้าง วิธีการสำหรับการดำเนินการที่กำหนดไว้สำหรับ SparseCore

ฟังก์ชันหลักในบริบทของ SparseCore มีดังนี้

  • การคอมไพล์การดำเนินการแบบกระจัดกระจาย: XLA มีหน้าที่คอมไพล์ การดำเนินการค้นหาการฝัง (เช่น SparseDenseMatmulOp) และการคำนวณแบบกระจัดกระจายอื่นๆ ลงในโปรแกรม SparseCore ที่ดำเนินการได้ระดับต่ำ
  • การผสานรวมขีดจำกัด: ใช้ขีดจำกัดการทำงานที่กำหนดค่าไว้ (เช่น max_ids_per_partition, max_unique_ids_per_partition มักจะ ระบุผ่านไฟล์ขีดจำกัดที่ระบุโดยแฟล็ก เช่น xla_sparse_core_max_ids_file) เพื่อกำหนดขนาดแบบคงที่และ จัดสรรบัฟเฟอร์หน่วยความจำในอุปกรณ์ โดยเฉพาะภายใน SPMEM
  • การเพิ่มประสิทธิภาพที่ตรงเป้าหมาย: XLA ทำการเพิ่มประสิทธิภาพชุดหนึ่ง ที่ออกแบบมาสำหรับสถาปัตยกรรม SparseCore โดยเฉพาะ ซึ่งอาจรวมถึงการจัดกำหนดการคำสั่ง การแปลงเลย์เอาต์หน่วยความจำ และการรวมการดำเนินการเพื่อเพิ่มประสิทธิภาพสูงสุด
  • ควบคุมโดยใช้ Flag: ลักษณะการทำงานของ SparseCore, การปรับแต่งพารามิเตอร์ และกลยุทธ์การเพิ่มประสิทธิภาพหลายอย่างจะแสดงและควบคุมผ่าน Flag ของ XLA (เช่น xla_sparse_core_estimate_max_ids สำหรับการประมาณขีดจำกัด หรือ xla_sc_detect_nan สำหรับการแก้ไขข้อบกพร่อง)

สถานะโอเพนซอร์ส:

ปัจจุบันการติดตั้งใช้งาน Sparsecore เป็นการใช้งานภายในและให้บริการโดยใช้ libtpu.so

การรายงานข้อผิดพลาดและการวินิจฉัย:

ความล้มเหลวในการคอมไพล์ที่เกี่ยวข้องกับการกำหนดค่า SparseCore หรือข้อจำกัดของทรัพยากรมักจะแสดงเป็นXLA:TPUข้อผิดพลาดขณะคอมไพล์ ข้อความแสดงข้อผิดพลาดเหล่านี้อาจให้ข้อมูลเชิงลึกที่มีประโยชน์เกี่ยวกับปัญหาต่างๆ เช่น การตั้งค่าขีดจํากัดสูงเกินไปสําหรับ SPMEM ที่ใช้ได้ หรือการใช้การกําหนดค่าที่ไม่รองรับ

7. ขีดจำกัดในตารางบน SparseCore

ใน SparseCore "ขีดจํากัด" คือพารามิเตอร์การกําหนดค่าพื้นฐานที่อ้างอิงถึงการตั้งค่าต่อพาร์ติชัน 2 รายการสําหรับแต่ละตารางที่ทำการ Shard (กระจาย) ใน SparseCore ที่พร้อมใช้งานเป็นหลัก

  • max_ids_per_partition: กำหนดจำนวนสูงสุดของรหัสทั้งหมด (รวมถึงรหัสที่ซ้ำกัน) ที่คาดว่า SparseCore เดียวจะส่งไปยัง หรือ ประมวลผลสำหรับพาร์ติชันที่เฉพาะเจาะจงของตารางที่กำหนดภายในขั้นตอนการคำนวณเดียว
  • max_unique_ids_per_partition: กำหนดจำนวนสูงสุดของรหัสที่ไม่ซ้ำกันที่ SparseCore เดียวคาดว่าจะส่งหรือประมวลผลสำหรับ

การแปลเป็นเลย์เอาต์ตารางจริงและการประมวลผล

  • กลยุทธ์การแบ่งตาราง: โดยปกติแล้ว ตารางการฝังจะ "แบ่งตามมอด" ใน SparseCore ทั้งหมดในระบบ ซึ่งหมายความว่า SparseCore แต่ละรายการจะ รับผิดชอบชุดย่อยที่แตกต่างกันของคำศัพท์ (แถว) ของแต่ละตาราง โดยทั่วไป ระบบจะกำหนด รหัส j ให้กับ SparseCore_k ตามสูตร เช่น k = j % num_total_sparse_cores
  • คำจำกัดความของ "พาร์ติชัน": ในบริบทนี้ "พาร์ติชัน" หมายถึงกลุ่มเฉพาะของตารางการฝังที่ SparseCore เดียวจัดการการค้นหา
  • การจัดสรรบัฟเฟอร์ SPMEM: คอมไพเลอร์ XLA ใช้ขีดจำกัดเหล่านี้เพื่อกำหนดขนาดและจัดสรรบัฟเฟอร์แบบคงที่ภายในหน่วยความจำ Scratchpad บนอุปกรณ์ (SPMEM) บัฟเฟอร์ได้รับการกำหนดขนาดเพื่อให้โหลดข้อมูลที่จำเป็นทั้งหมดซึ่งเกี่ยวข้องกับ รหัสสำหรับพาร์ติชันที่กำหนด (สูงสุดตามขีดจำกัดที่ระบุของ max_ids และ max_unique_ids) ลงใน SPMEM เพื่อประมวลผลได้ ซึ่งมีความสําคัญอย่างยิ่งสําหรับการคํานวณที่ไม่ใช่การคํานวณแบบทีละองค์ประกอบ เช่น การลดรหัสที่ซ้ำกันภายในพาร์ติชัน (เช่น เมื่อสร้างการแสดงผลแบบแถวแบบกระจัดกระจายที่บีบอัด (CSR)) ซึ่งชุดข้อมูลที่เกี่ยวข้องทั้งหมดสําหรับรหัสของพาร์ติชันนั้นต้องพร้อมใช้งานในหน่วยความจําที่รวดเร็ว
  • ขีดจำกัดที่รวบรวมเทียบกับขีดจำกัดที่สังเกตได้:

    • ขีดจํากัดที่สังเกตได้: นี่คือจํานวนจริงของรหัสที่พบสําหรับแต่ละพาร์ติชันในระหว่างรันไทม์ โดยอิงตามข้อมูลอินพุตที่กําลังประมวลผล
    • หากขีดจำกัดที่สังเกตได้เกินขีดจำกัดที่คอมไพล์ อาจทำให้เกิดการทิ้งรหัส (หากเปิดใช้ allow_id_dropping) หรือข้อผิดพลาด
  • การคำนวณขีดจำกัด: กระบวนการกำหนดขีดจำกัดที่เหมาะสมต้องมีการวิเคราะห์การกระจายข้อมูลอินพุตอย่างรอบคอบ สำหรับตารางใดก็ตาม (สมมติว่าชื่อ T1 ซึ่งอาจเป็นส่วนหนึ่งของตารางที่ซ้อนกันขนาดใหญ่กว่า T)

    1. ระบบจะแยกกลุ่มอินพุต (เช่น SparseTensor แบบ 2 มิติที่มีรูปร่าง [BatchSize, MaxSequenceLength]) ใน SparseCore ที่พร้อมใช้งานในตอนแรก เช่น หาก TensorCore จับคู่กับ SparseCore 2 ตัว SparseCore แต่ละตัวอาจได้รับกลุ่มย่อยที่มีรูปร่าง [BatchSize/2, MaxSequenceLength]
    2. จากนั้นระบบจะแปลงกลุ่มย่อยนี้เป็นรูปแบบ COO ซึ่งให้ผลลัพธ์เป็น row_ids และ col_ids
    3. ระบบจะนำรหัสที่ซ้ำกันภายในตัวอย่างเดียวกัน (เช่น รายการที่มี row_id และ col_id เดียวกัน) ออก
    4. สำหรับ col_id ที่เหลือแต่ละรายการ (ภายในตัวอย่าง) ระบบจะกำหนด SparseCore เป้าหมายที่รับผิดชอบรหัสนี้โดยใช้กฎการแบ่งกลุ่มแบบโมดูโล: target_sc_id = col_id % num_total_sparse_cores
    5. ระบบจะนับจำนวนรหัสทั้งหมด (ids_per_sparse_core[target_sc_id]++) และจำนวนรหัสที่ไม่ซ้ำกัน (unique_ids_per_sparse_core[target_sc_id]++ หลังจากตรวจสอบว่าไม่ซ้ำกันสำหรับ target_sc_id นั้นๆ) ที่กำหนดไว้สำหรับ target_sc_id แต่ละรายการ
    6. จากนั้นระบบจะตั้งค่า max_ids_per_partition สำหรับตาราง T1 เป็น max(ids_per_sparse_core_array)
    7. ในทำนองเดียวกัน ระบบจะตั้งค่า max_unique_ids_per_partition สำหรับตาราง T1 เป็น max(unique_ids_per_sparse_core_array)
    8. หากตาราง T1 เป็นคอมโพเนนต์ของตารางแบบซ้อน ระบบอาจใช้การเปลี่ยนรูปแบบเพิ่มเติม เช่น การหมุนหรือการเลื่อน กับการกระจายรหัสก่อนที่จะรวมสถิติจากตารางที่เป็นส่วนประกอบทั้งหมด ซึ่งจะช่วยในการจัดสรรภาระงานในชิปต่างๆ

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

8. วิธีที่แต่ละ SparseCore สื่อสาร

การสื่อสารของ SparseCore โดยเฉพาะอย่างยิ่งในบริบทของการประมวลผลรายการรหัสสำหรับการค้นหาการฝัง จะขึ้นอยู่กับกลไกที่ประสานงานกันหลายอย่าง ดังนี้

  • การแบ่งส่วนโมดูลและการกำหนดเส้นทางโดยนัย
    • ระบบจะกระจายตารางการฝังในทุก SparseCore ในระบบ
    • เมื่อโฮสต์ระบุข้อมูลอินพุตเป็นชุด (ซึ่งจะได้รับการประมวลผลล่วงหน้าเป็นรูปแบบ COO รวมถึง col_ids ในภายหลัง) ระบบจะใช้ค่า col_id เพื่อพิจารณาว่า SparseCore ใดรับผิดชอบต่อรหัสที่เฉพาะเจาะจงนั้น target_sc_id = col_id % num_total_sparse_cores
    • SparseCore แต่ละรายการจะรับและประมวลผลเฉพาะชุดย่อยของรหัสที่แมปกับพาร์ติชันคำศัพท์ที่กำหนดเท่านั้น ขั้นตอนการประมวลผลล่วงหน้าของโฮสต์มีความสําคัญอย่างยิ่งในการเตรียมข้อมูลในลักษณะที่ SparseCore แต่ละรายการสามารถระบุและดําเนินการกับรหัสที่เกี่ยวข้องได้อย่างง่ายดาย
  • การกระจายข้อมูลตามโฮสต์
    • ตรรกะการประมวลผลล่วงหน้าของโฮสต์จะแบ่งกลุ่มอินพุตแบบกลุ่มโดยรวม และกระจายส่วนที่เกี่ยวข้องของ row_ids และ col_ids (พร้อมกับฟีเจอร์หรือน้ำหนักที่เกี่ยวข้อง หากมี) ไปยังหน่วยความจำ (HBM) ที่แต่ละ SparseCore เข้าถึงได้โดยตรง หรือไปยัง HBM ที่ใช้ร่วมกันซึ่ง SparseCore จะดึงข้อมูลที่ต้องการ
  • การประมวลผล Intra-SparseCore
    • เมื่อ SparseCore ได้รับชุดรหัสที่กำหนดไว้สำหรับพาร์ติชันตารางหนึ่งๆ แล้ว ก็จะดำเนินการต่างๆ เช่น การกรองรหัสที่ซ้ำกันออก และรวบรวมเวกเตอร์การฝังที่เกี่ยวข้อง การคำนวณเหล่านี้ส่วนใหญ่เป็นการคำนวณในเครื่องที่ดำเนินการภายในไทล์ของ SparseCore เองและใช้ SPMEM ในเครื่อง
  • การสื่อสารระหว่าง SparseCore (แบบทั้งหมดต่อทั้งหมด)
    • หลังจากระยะการประมวลผลเริ่มต้น (เช่น การค้นหาการฝัง) อาจใช้รูปแบบการสื่อสารแบบ "ทั้งหมดต่อทั้งหมด" เพื่อรวมหรือแจกจ่ายผลลัพธ์ใน SparseCore (เช่น ก่อนที่จะป้อนการเปิดใช้งานลงในเลเยอร์ TensorCore ที่คาดหวังอินพุตที่สอดคล้องกับตำแหน่งตัวอย่างเดิมทั้งหมด) ซึ่งมีความสําคัญอย่างยิ่งต่อการสร้างชุดการเปิดใช้งานที่สมบูรณ์ขึ้นใหม่ หากมีการกระจายชุดอินพุตเดิมเพื่อการประมวลผลแบบคู่ขนาน
  • การสื่อสารกับ TensorCore
    • SparseCore จะสื่อสารกับ TensorCore เพื่อส่งการเปิดใช้งานการฝัง (ระหว่างการส่งต่อ) และรับการไล่ระดับสี (ระหว่างการส่งย้อนกลับ) การโต้ตอบนี้ได้รับการจัดการโดยโปรแกรมที่คอมไพล์ XLA และมักเกี่ยวข้องกับ HBM ในฐานะบัฟเฟอร์ตัวกลาง กลยุทธ์การส่งข้อมูลแบบไปป์ไลน์ (ที่กล่าวถึงก่อนหน้านี้) มีอิทธิพลอย่างมากต่อเวลาและการซิงโครไนซ์ของการสื่อสาร SC-TC นี้

โดยพื้นฐานแล้ว รูปแบบการแบ่งข้อมูลและขั้นตอนการประมวลผลล่วงหน้าของโฮสต์จะจัดการ "การกระจาย" รหัสเริ่มต้นไปยัง SparseCore ที่เหมาะสมเป็นส่วนใหญ่ การสื่อสารในภายหลังเกี่ยวข้องกับ SparseCore ที่ทำงานกับข้อมูลในเครื่อง ซึ่งอาจตามด้วยการดำเนินการสื่อสารแบบกลุ่ม เช่น การสื่อสารแบบทั้งหมดต่อทั้งหมด หากจำเป็นต้องแลกเปลี่ยนข้อมูลทั่วโลกหรือจัดลำดับใหม่ใน SparseCore ก่อนที่ TensorCore จะประมวลผลเพิ่มเติม

9. การจัดการหน่วยความจำ SparseCore

SparseCore แต่ละรายการจัดการหน่วยความจำประเภทต่างๆ หลายรายการได้อย่างมีประสิทธิภาพเพื่อทำการคำนวณ

  • หน่วยความจำแบบ Scratchpad (SPMEM)
    • Nature: SRAM ในเครื่องขนาดค่อนข้างเล็กแต่เร็วมาก ซึ่งพร้อมใช้งานเฉพาะสำหรับ SparseCore แต่ละรายการ โปรดทราบว่า SPMEM ไม่ใช่แคช แต่การใช้งานจะได้รับการจัดการและจัดระเบียบอย่างชัดเจนโดยคอมไพเลอร์ XLA
    • วัตถุประสงค์: SPMEM ใช้เพื่อ "จัดเตรียมข้อมูลตามโอกาส" ซึ่งรวมถึงอินพุต เอาต์พุต และผลลัพธ์ระดับกลางที่จำเป็นสำหรับการคำนวณ SC อย่างต่อเนื่อง การจัดเตรียมข้อมูลใน SPMEM ช่วยลดเวลาในการตอบสนองที่สูงซึ่งมักเกี่ยวข้องกับการเข้าถึง HBM ได้อย่างมาก
    • การกำหนดขนาด: ตามที่ได้กล่าวไว้ในส่วน "ขีดจำกัด" บัฟเฟอร์ SPMEM จะได้รับการกำหนดขนาดแบบคงที่ในเวลาคอมไพล์ การกำหนดขนาดนี้อิงตามพารามิเตอร์ต่างๆ เช่น max_ids_per_partition และ max_unique_ids_per_partition การจัดสรรแบบคงที่นี้ช่วยให้มั่นใจได้ว่าสำหรับการดำเนินการใดๆ ในพาร์ติชันตาราง (เช่น การลด CSR) ข้อมูลที่จำเป็นทั้งหมดสำหรับรหัสของพาร์ติชันนั้น (สูงสุดตามขีดจำกัดที่กำหนด) จะพอดีกับ SPMEM
    • การเพิ่มประสิทธิภาพคอมไพเลอร์: คอมไพเลอร์ XLA มีการเพิ่มประสิทธิภาพที่ซับซ้อนเพื่อระบุจํานวนข้อมูลและองค์ประกอบข้อมูลที่เฉพาะเจาะจงซึ่งต้องจัดเตรียมใน SPMEM อย่างแม่นยํา เพื่อซ่อนเวลาในการตอบสนองของ HBM อย่างมีประสิทธิภาพและเพิ่มประสิทธิภาพสูงสุด
    • ข้อจํากัดการจัดสรรแบบไดนามิก: ปัจจุบันคอมไพเลอร์ SparseCore ยังไม่รองรับการจัดสรรพื้นที่พักข้อมูลแบบไดนามิก ซึ่งแสดงให้เห็นถึงความสำคัญอย่างยิ่งของการกำหนดขนาดแบบคงที่ผ่านการกำหนดค่าขีดจำกัดอย่างรอบคอบ
  • หน่วยความจำแบนด์วิดท์สูง (HBM)
    • Nature: แหล่งข้อมูลความทรงจำขนาดใหญ่ที่ใช้ร่วมกันซึ่งเข้าถึงได้โดย SparseCore, TensorCore และระบบโฮสต์ทั้งหมด ระบบจะจัดเก็บตารางการฝังหลักไว้ใน HBM
    • การใช้สแต็ก: การดำเนินการ SparseCore มักต้องใช้พื้นที่เก็บข้อมูลชั่วคราวใน HBM สำหรับผลลัพธ์ระดับกลางที่อาจไม่พอดีกับ SPMEM ที่มีจำกัด หรือต้องส่งผ่านระหว่างขั้นตอนที่ใหญ่กว่าของไปป์ไลน์การประมวลผล การใช้งานสแต็ก HBM ในระหว่างการส่งต่อและการส่งย้อนสามารถประมาณได้ดังนี้
      • Forward Pass HBM Stack (ตารางเดียว) ≈ (2 * feature_width + 1) * max_unique_nz_per_row * logical_replica_count * 4 ไบต์
      • การส่งต่อข้อมูลย้อนกลับของสแต็ก HBM (ตารางเดียว) ≈ 3 * feature_width * max_unique_nz_per_row * logical_replica_count * 4 ไบต์
    • การใช้งานฮีป: HBM ยังรองรับฮีปซึ่งโฮสต์เป็นผู้จัดการด้วย ฮีปจะจัดเก็บข้อมูล เช่น น้ำหนักของเลเยอร์แบบหนาแน่น ค่าคงที่ที่โมเดลใช้ และข้อมูลอินพุตที่ดึงข้อมูลล่วงหน้า การใช้งานฮีปมักจะเพิ่มขึ้นตามจำนวนขั้นตอนที่โฮสต์ดึงข้อมูลล่วงหน้า (ควบคุมโดยแฟล็ก maximum_parallel_iterations) แม้ว่าการดึงข้อมูลล่วงหน้าเพิ่มเติมจะช่วยปรับปรุงประสิทธิภาพได้โดยการทับซ้อนการโอนจากโฮสต์ไปยังอุปกรณ์กับการคำนวณของอุปกรณ์ แต่ก็ใช้ HBM มากขึ้นด้วย
    • การแปลงข้อมูลเป็นลำดับสำหรับการเพิ่มประสิทธิภาพ HBM: แฟล็ก xla_sc_num_serialized_tables_to_optimize_hbm มีกลไกในการควบคุมจำนวนข้อมูลของตารางที่เก็บไว้ "ใช้งานจริง" ในหน่วยความจำสแต็ก HBM ณ เวลาใดก็ตาม การเพิ่มจำนวนนี้จะทำให้การประมวลผลตารางต่างๆ เป็นแบบอนุกรม ซึ่งจะช่วยลดการใช้งานสแต็ก HBM สูงสุดได้ แต่ประสิทธิภาพอาจลดลงเนื่องจากความขนานลดลง
  • หน่วยความจำเวกเตอร์ (VMEM)
    • VMEM คือหน่วยความจำแบบกระดาษทดในเครื่องที่ TC (TensorCore) ใช้เท่านั้น แม้ว่า SparseCore จะไม่ได้จัดการ VMEM โดยตรง แต่ก็เป็นส่วนสำคัญของระบบนิเวศหน่วยความจำที่ SC โต้ตอบด้วย ซึ่งส่วนใหญ่จะผ่าน TensorCore

กลยุทธ์การจัดการหน่วยความจำโดยรวม

กลยุทธ์การจัดการหน่วยความจำหลักสำหรับ SparseCore นั้นมุ่งเน้นการใช้ SPMEM ขนาดเล็กที่รวดเร็วสำหรับข้อมูล "ยอดนิยม" ที่ไทล์ SparseCore กำลังประมวลผลอยู่ ซึ่งจะช่วยลดการเข้าถึง HBM ที่ช้ากว่า ขีดจำกัดที่กำหนดค่าไว้เป็นกลไกหลักในการตรวจสอบว่า SPMEM ไม่ล้น HBM ใช้สำหรับจัดเก็บตารางการฝังขนาดใหญ่และข้อมูลชั่วคราวที่เกินความจุของ SPMEM หรือต้องแชร์ในหน่วยประมวลผลหรือขั้นตอนไปป์ไลน์ต่างๆ คอมไพเลอร์ XLA มีหน้าที่จัดการการเคลื่อนย้ายข้อมูลและการจัดสรรบัฟเฟอร์ทั้งหมดตามหลักการด้านสถาปัตยกรรมเหล่านี้และขีดจํากัดที่ผู้ใช้กําหนดค่า

10. จุดคอขวดด้านประสิทธิภาพและหน่วยความจำ

การบรรลุประสิทธิภาพสูงสุดด้วย SparseCore จำเป็นต้องมีความเข้าใจที่ชัดเจนเกี่ยวกับคอขวดที่อาจเกิดขึ้นและวิธีแก้ไข ซึ่งอาจเกิดขึ้นในโฮสต์ ภายใน SparseCore เอง หรือในการโต้ตอบกับ TensorCore

จุดคอขวดของประสิทธิภาพที่พบบ่อย

  • คอขวดของโฮสต์
    • ปัญหา: CPU ของโฮสต์อาจประมวลผลข้อมูลล่วงหน้าไม่สำเร็จและป้อนข้อมูลไปยัง TPU ได้ไม่เร็วพอ ซึ่งจะส่งผลให้ SparseCore และ TensorCore ทำงานได้ไม่เต็มประสิทธิภาพ ซึ่งมักจะเป็นตัวจำกัดประสิทธิภาพ
    • การบรรเทา: ตรวจสอบการใช้งาน CPU ของโฮสต์และเมตริกไปป์ไลน์อินพุต เพิ่มประสิทธิภาพการโหลดข้อมูลฝั่งโฮสต์และกิจวัตรการประมวลผลล่วงหน้า (ดูเคล็ดลับ Conversion ของ COO) ปรับค่าสถานะ maximum_parallel_iterations เพื่อปรับแต่งการดึงข้อมูลล่วงหน้า
  • การซิงค์ TC/SC ที่ไม่เหมาะสม (ไม่มีการไปป์ไลน์):
    • ปัญหา: หากปิดใช้การไปป์ไลน์ระหว่าง TensorCore กับ SparseCore หรือการทำงานไม่มีประสิทธิภาพ หน่วยใดหน่วยหนึ่งอาจใช้เวลานานในการรออีกหน่วยหนึ่ง ซึ่งจะลดปริมาณงานโดยรวมของระบบ
    • การลดผลกระทบ: ตรวจสอบว่าได้เปิดใช้การส่งผ่านข้อมูลแบบไปป์ไลน์แล้ว (เช่น tf_xla_disable_full_embedding_pipelining = false หรือเทียบเท่า)
  • คอขวดที่เกิดจากขีดจำกัด
    • ปัญหา:
      • ขีดจำกัดต่ำเกินไป: อาจทำให้เกิดการแบ่งกลุ่มย่อยมากเกินไป (การแบ่งกลุ่มอินพุตออกเป็นกลุ่มย่อยเล็กๆ จำนวนมากเพื่อให้เป็นไปตามขีดจำกัดที่เข้มงวด) แม้ว่าวิธีนี้จะช่วยรักษาความถูกต้อง แต่แต่ละมินิแบทช์จะทำให้เกิดค่าใช้จ่ายในการประมวลผล ซึ่งอาจทำให้การดำเนินการโดยรวมช้าลง หาก allow_id_dropping เป็นจริง ขีดจำกัดที่ต่ำเกินไปอาจทำให้เกิดการทิ้งรหัส ซึ่งส่งผลต่อความแม่นยำของโมเดล
      • ขีดจำกัดสูงเกินไป (แต่ยังคงเหมาะสม): แม้ว่าขีดจำกัดที่สูงมากอาจป้องกันการประมวลผลแบบมินิแบทช์ แต่ก็อาจเพิ่มแรงกดดัน SPMEM โดยไม่จำเป็นหากลักษณะข้อมูลจริงแทบจะไม่ถึงค่าสูงสุดเหล่านี้ นอกจากนี้ยังอาจทำให้มีการใช้สแต็ก HBM มากกว่าที่จำเป็นอย่างเคร่งครัดอีกด้วย
      • การคอมไพล์ล้มเหลว: หากขีดจำกัดที่กำหนดค่าไว้ต้องใช้สแต็ก SPMEM หรือ HBM มากกว่าหน่วยความจำจริงที่มีอยู่ การคอมไพล์จะล้มเหลว
    • การลดผลกระทบ: ตรวจสอบว่าได้ตั้งค่าขีดจํากัดอย่างถูกต้อง
  • ความเบ้ของการกระจายข้อมูล
    • ปัญหา: หากพาร์ติชัน SparseCore บางรายการได้รับรหัสจำนวนมากอย่างสม่ำเสมอเมื่อเทียบกับพาร์ติชันอื่นๆ (ซึ่งบ่งบอกถึงการกระจายรหัสที่ไม่ดี) SparseCore ที่โอเวอร์โหลดเหล่านั้นจะกลายเป็นคอขวดด้านประสิทธิภาพ
    • การลดผลกระทบ: การสับเปลี่ยนรหัสระหว่างกระบวนการมินิแบตช์จะช่วยลดปัญหานี้สำหรับตารางที่ซ้อนกัน โดยเฉพาะตารางที่มีตารางผู้ใช้ "ยอดนิยม" วิเคราะห์การกระจายรหัสอย่างรอบคอบเพื่อกำหนดขีดจํากัดต่อตารางที่เหมาะสมและสมดุล
  • ปัญหาการซ้อนทับของตาราง
    • ปัญหา:
      • ซ้อนตารางน้อยเกินไป: อาจไม่เพียงพอที่จะซ่อนเวลาในการตอบสนองของ ICI อย่างมีประสิทธิภาพ หรือลดค่าใช้จ่ายในการประมวลผลได้อย่างเหมาะสม
      • ซ้อนตารางมากเกินไป: อาจส่งผลให้เกิดตารางเชิงตรรกะขนาดใหญ่มากซึ่งจัดการได้ยากหรืออาจเกินขีดจำกัดของทรัพยากรที่มีอยู่
    • การลดผลกระทบ
      • ตรวจสอบว่ามีจำนวนตารางที่เหมาะสมสำหรับการซ้อน หลักเกณฑ์ทั่วไปแนะนำให้ซ้อนตาราง 5-100 ตาราง
  • ตัวเลข/การหาปริมาณที่ไม่มีประสิทธิภาพ
    • ปัญหา: การใช้ความแม่นยำ FP32 แบบเต็มเมื่อรูปแบบความแม่นยำต่ำกว่า เช่น BF16 หรือจำนวนเต็มที่ผ่านการวัดปริมาณ จะเพียงพอ (และให้การคำนวณที่เร็วกว่า) อาจเป็นคอขวดด้านประสิทธิภาพ
    • การลดผลกระทบ: ลองใช้ตัวเลือกที่มีความแม่นยำต่ำกว่า อย่างไรก็ตาม โปรดทราบว่าการกำหนดปริมาณเองมีค่าใช้จ่ายบางอย่าง และอาจต้องปรับพารามิเตอร์การกำหนดปริมาณอย่างระมัดระวังเพื่อรักษาความแม่นยำของโมเดล
  • แบนด์วิดท์ HBM เต็ม
    • ปัญหา: การย้ายข้อมูลไปยังและจาก HBM มากเกินไป ซึ่งอาจเกิดจากความกว้างของฟีเจอร์ที่เล็กมาก (ทำให้มีค่าใช้จ่ายในการเพิ่มพื้นที่สูง) รูปแบบการเข้าถึงหน่วยความจำที่ไม่มีประสิทธิภาพ หรือการค้นหาจำนวนมากเกินไป อาจทำให้แบนด์วิดท์ HBM ที่มีอยู่เต็ม
    • การลดผลกระทบ: การปรับขนาดจำนวน TPU จะช่วยลดปัญหาแบนด์วิดท์ HBM เต็ม

ปัญหาคอขวดด้านหน่วยความจำที่พบบ่อย

  • SPMEM overflow (การคอมไพล์ล้มเหลว):
    • ปัญหา: หากตั้งค่า max_ids_per_partition และ max_unique_ids_per_partition สูงเกินไป คอมไพเลอร์ XLA อาจจัดสรร SPMEM ไม่เพียงพอ ซึ่งจะส่งผลให้เกิดข้อผิดพลาดในการคอมไพล์ เช่น "Fixed size allocations (...) do not fit in TileSpmem (...)" นอกจากนี้ หากเทอม (sample_count * feature_width) / kNumTiles (โดยที่ kNumTiles คือจำนวนไทล์ต่อ SC) มีขนาดใหญ่เกินไปสำหรับการรวบรวมตัวถูกดำเนินการชั่วคราวภายใน SPMEM ของไทล์ อาจเกิดข้อผิดพลาด เช่น "Gather operand too large..."
    • การลดผลกระทบ: ลดขนาดกลุ่มหรือเพิ่มจำนวนชิปที่ใช้ในการประมวลผล
  • สแต็ก HBM ล้น (รันไทม์หรือการคอมไพล์):
    • ปัญหา: หากการรวมกันของ feature_width, max_unique_nz_per_row และ logical_replica_count ทำให้ข้อกำหนดด้านหน่วยความจำของสแต็ก HBM เกิน HBM ที่พร้อมใช้งาน อาจทำให้เกิดข้อผิดพลาดหน่วยความจำไม่พอ (OOM) ไม่ว่าจะในขณะรันไทม์หรือระหว่างการคอมไพล์
    • การลดผลกระทบ: ปรับแต่งฟีเจอร์xla_sc_num_serialized_tables_to_optimize_hbmเพื่อลดการใช้สแต็ก HBM โดยการประมวลผลตารางแบบอนุกรม (โดยปกติแล้วจะมีผลต่อประสิทธิภาพ)
  • การใช้ฮีป HBM จนหมด:
    • ปัญหา: สาเหตุหลักเกิดจากน้ำหนักของเลเยอร์แบบหนาที่มีขนาดใหญ่มาก ค่าคงที่จำนวนมากที่จัดเก็บไว้ในหน่วยความจำ หรือการดึงข้อมูลอินพุตล่วงหน้าแบบรุกมากเกินไป (maximum_parallel_iterations สูง)
    • การลดผลกระทบ: ตรวจสอบการใช้งานฮีปโดยใช้เครื่องมือต่างๆ เช่น XProf Memory Viewer
  • ค่าใช้จ่ายในการเพิ่มพื้นที่
    • ปัญหา: ระบบจะเพิ่มช่องว่างในตารางการฝังเพื่อให้สอดคล้องกับ 32B (เทียบเท่ากับ 8 โฟลต) ในมิติข้อมูลฟีเจอร์ ด้วยเหตุนี้ ความกว้างของฟีเจอร์ขนาดเล็ก (เช่น 1 โฟลต) จึงทำให้เกิดค่าใช้จ่ายในการเพิ่มพื้นที่ว่างจำนวนมาก (เช่น 7/8 ของพื้นที่บัฟเฟอร์ที่จัดสรรคือการเพิ่มพื้นที่ว่าง) ซึ่งส่งผลให้ HBM เสียเปล่า นอกจากนี้ มิติข้อมูลคำศัพท์ของตารางยังได้รับการเพิ่มขนาดให้เป็นทวีคูณของจำนวน SparseCore ในระบบด้วย แต่โดยปกติแล้ว ผลกระทบนี้จะไม่มีนัยสำคัญสำหรับตารางที่มีขนาดคำศัพท์สูงเพียงพอ

ปัจจัยทั่วไปที่มีผลต่อประสิทธิภาพและหน่วยความจำ

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

11. การวิเคราะห์โปรไฟล์ SparseCore

การวิเคราะห์โปรไฟล์ประสิทธิภาพเป็นขั้นตอนสำคัญในการระบุจุดคอขวดและค้นหาโอกาสในการเพิ่มประสิทธิภาพภายในภาระงาน SparseCore

  1. รับการติดตาม
    • ใช้เครื่องมือสร้างโปรไฟล์ เช่น XProf เพื่อบันทึกการติดตามการดำเนินการโดยละเอียดขณะที่โมเดลกำลังฝึกหรือเรียกใช้การอนุมาน การติดตามนี้จะแสดงไทม์ไลน์ของการดำเนินการที่เกิดขึ้นในโฮสต์, TensorCore และ SparseCore
  2. ตรวจสอบ Trace Viewer (เช่น ใน XProf หรือ TensorBoard)
    • กิจกรรมของโฮสต์: ตรวจสอบกิจกรรมของโฮสต์ กิจกรรม TPU มีช่องว่างที่สำคัญไหม ช่องว่างดังกล่าวอาจบ่งชี้ว่าโฮสต์เป็นคอขวด ซึ่งป้อนข้อมูลได้ไม่เร็วพอ วิเคราะห์ประสิทธิภาพของไปป์ไลน์อินพุต
    • กิจกรรม TensorCore (TC) และ SparseCore (SC)
      • ดูไทม์ไลน์การดำเนินการของทั้ง TC และ SC ว่าทำงานควบคู่กันหรือไม่ ซึ่งบ่งบอกถึงการส่งต่อที่มีประสิทธิภาพ หรือมีช่วงเวลานานๆ ที่หน่วยหนึ่งไม่ได้ใช้งานและรออีกหน่วยหนึ่งไหม
      • ระบุการดำเนินการที่ใช้เวลานานที่สุด (การดำเนินการที่ใช้เวลานานที่สุด) ทั้งใน SC และ TC
      • เอาต์พุตการติดตามด้วยภาพ (มักจะแสดงบล็อกสีที่แสดงการดำเนินการต่างๆ เมื่อเวลาผ่านไป เช่น TPU:0 SparseCore 1 (pid 1005)) มีประโยชน์อย่างมากในการระบุการดำเนินการที่โดดเด่นและช่วงที่ไม่มีการใช้งานด้วยภาพ
    • การวิเคราะห์เวลาของขั้นตอน: สังเกตเวลาของขั้นตอนโดยรวม และทําความเข้าใจว่ามีการกระจายหรือแบ่งย่อยระหว่างการประมวลผลของโฮสต์ การคํานวณ SC และการคํานวณ TC อย่างไร
  3. การวิเคราะห์หน่วยความจำ (XProf Memory Viewer):
    • การใช้งานฮีป: ใช้เครื่องมือต่างๆ เช่น แท็บ "Memory Viewer" ของ XProf เพื่อตรวจสอบการใช้งานฮีป HBM ซึ่งจะช่วยพิจารณาได้ว่าน้ำหนักของโมเดลขนาดใหญ่ ค่าคงที่ หรือการดึงข้อมูลอินพุตล่วงหน้าแบบก้าวร้าวเกินไปใช้ HBM มากเกินไปหรือไม่ การเปิดใช้ฟีเจอร์อย่าง --vmodule=best_fit_allocator=1 อาจให้บันทึกการใช้งานฮีปสูงสุด
    • การใช้งานสแต็ก (โดยอ้อม): แม้ว่าการสร้างโปรไฟล์สแต็ก HBM โดยตรงอาจซับซ้อน แต่หากคุณพบข้อผิดพลาดหน่วยความจำไม่เพียงพอและดูเหมือนว่าการใช้งานฮีปจะสมเหตุสมผล การหมดสแต็ก HBM (มักเกิดจากขีดจำกัดหรือความกว้างของฟีเจอร์ที่มากเกินไป) ก็เป็นสาเหตุที่น่าสงสัย สูตรที่ระบุไว้สำหรับการใช้งานสแต็ก HBM จะช่วยในการประมาณค่านี้ได้
  4. มองหารูปแบบที่เฉพาะเจาะจง
    • การประมวลผลแบบมินิแบตช์: หากมีการเกินขีดจำกัดบ่อยครั้ง คุณอาจเห็นหลักฐานของการประมวลผลแบบมินิแบตช์ใน Trace (เช่น การดำเนินการ SC ขนาดเล็กจำนวนมากขึ้นกว่าที่คาดไว้สำหรับขนาดแบตช์ส่วนกลาง) ซึ่งมักจะอนุมานได้จากบันทึกหรือโดยการสังเกตจำนวนการเรียกใช้ของการดำเนินการบางอย่าง
    • การทิ้งรหัส: หากเปิดใช้การทิ้งรหัสและเกิดขึ้น บันทึกของระบบอาจระบุถึงเรื่องนี้ นอกจากนี้ยังเป็นสัญญาณที่ชัดเจนว่าขีดจำกัดที่กำหนดค่าไว้มีข้อจำกัดมากเกินไปสำหรับข้อมูลนำเข้า
    • เวลาในการคอมไพล์: เวลาในการคอมไพล์ที่นานขึ้น โดยเฉพาะอย่างยิ่งหากเปิดใช้การเพิ่มประสิทธิภาพที่อิงตามความคิดเห็น (FDO) และมีการปรับขีดจำกัดบ่อยครั้ง อาจเพิ่มค่าใช้จ่ายที่สำคัญให้กับเวลาในการฝึกโดยรวม
  5. เชื่อมโยงกับฟีเจอร์และการกำหนดค่า
    • เชื่อมโยงลักษณะการทำงานที่สังเกตได้ในโปรไฟล์กลับไปที่การกำหนดค่า SparseCore (การตั้งค่าในไฟล์ขีดจำกัด แฟล็ก XLA) เช่น หากตั้งค่า xla_sc_num_serialized_tables_to_optimize_hbm เป็นค่าสูง คุณอาจคาดหวังว่าประสิทธิภาพของ SC จะช้าลง แต่การใช้สแต็ก HBM จะต่ำลง
  6. กระบวนการแบบวนซ้ำ
    • การสร้างโปรไฟล์มักเป็นกระบวนการปรับแต่งแบบวนซ้ำ ทำการเปลี่ยนแปลงที่เฉพาะเจาะจง (ปรับขีดจํากัด เปิดหรือปิดใช้ฟีเจอร์) บันทึกโปรไฟล์ใหม่ แล้วเปรียบเทียบกับโปรไฟล์ก่อนหน้าเพื่อดูผลกระทบของการแก้ไข

12. Flag การแก้ไขข้อบกพร่องทั่วไป

คุณเปิดใช้ฟีเจอร์หลายอย่างเพื่อช่วยในการแก้ไขข้อบกพร่องที่เกี่ยวข้องกับการดำเนินการ SparseCore ได้ โปรดทราบว่าการเปิดใช้การตรวจสอบเหล่านี้มักจะทำให้ประสิทธิภาพลดลง ดังนั้นโดยปกติแล้วจึงควรปิดใช้สำหรับการเรียกใช้เวอร์ชันที่ใช้งานจริง

  • การตรวจสอบรหัส (อยู่นอกช่วง)
    • ธง: xla_sparse_core_enable_id_bound_check = true
    • วัตถุประสงค์: เปิดใช้การตรวจสอบในระบบโฮสต์เพื่อตรวจหาว่ามีรหัสการฝังในข้อมูลอินพุตที่อยู่นอกช่วงคำศัพท์ที่ถูกต้องซึ่งกำหนดไว้สำหรับตารางการฝังที่ระบุหรือไม่ ซึ่งจะช่วยตรวจหาปัญหาที่เกี่ยวข้องกับข้อมูลอินพุตที่ไม่ถูกต้องหรือเสียหาย
  • ตัวตรวจสอบ NaN:
    • ธง: xla_sc_detect_nan = true
    • วัตถุประสงค์: ช่วยให้ตรวจหาค่า NaN (ไม่ใช่ตัวเลข) ภายในข้อมูลจุดลอยตัวที่ประมวลผลใน SparseCore ได้ หากตรวจพบ NaN ในอินพุตหรือเอาต์พุตของการส่งผ่านคอมไพเลอร์ต่างๆ Flag นี้จะทำให้เกิดข้อผิดพลาด โดยปกติแล้ว ข้อผิดพลาดดังกล่าวจะให้ข้อมูลเกี่ยวกับตำแหน่งที่พบ NaN
  • เครื่องมือตรวจสอบขอบเขต (การเข้าถึงหน่วยความจำ):
    • ธง: xla_sc_assert_level=bounds
    • วัตถุประสงค์: แฟล็กนี้เปิดใช้เครื่องมือสไตล์ ASAN (AddressSanitizer) ที่เขียนคำสั่งการเข้าถึงหน่วยความจำใหม่ (เช่น การโหลด/จัดเก็บ VMEM และการดำเนินการ DMA) เพื่อรวมการตรวจสอบแบบไดนามิก การตรวจสอบเหล่านี้จะยืนยันว่าการเข้าถึงหน่วยความจำอยู่ภายในขอบเขตที่จัดสรรของรีเจียนหน่วยความจำเป้าหมายหรือไม่
    • ลักษณะการทำงาน: หากตรวจพบการเข้าถึงหน่วยความจำที่อยู่นอกขอบเขต การดำเนินการจะล้มเหลว
    • ข้อควรระวัง: เครื่องมือตรวจสอบนี้อาจให้ผลลบลวงได้ เช่น เนื่องจากรูปแบบการเข้าถึงแบบสไตรด์ที่ซับซ้อนซึ่งเครื่องมือตรวจสอบไม่เข้าใจอย่างถ่องแท้ การเปลี่ยนรูปแบบนี้จะมีผลในขั้นตอนท้ายๆ ของกระบวนการคอมไพล์แบ็กเอนด์
  • เครื่องมือตรวจสอบบัฟเฟอร์ (หน่วยความจำเสียหาย):
    • ธง
      • xla_tpu_buffer_contents_sanitizer_config='cores_to_sanitize: [TC, SC_SCS, SC_TILE], sanitizer_mode: LOCAL_ONLY'
      • xla_tpu_verify_launch_id_across_cores=true
    • วัตถุประสงค์: แฟล็กเหล่านี้ช่วยให้มั่นใจได้ว่าบัฟเฟอร์หน่วยความจำจะไม่เสียหายโดยไม่ตั้งใจหรือถูกเขียนทับโดยการดำเนินการที่ไม่เกี่ยวข้อง Buffer Sanitizer จะตรวจสอบเนื้อหาของบัฟเฟอร์เพื่อให้แน่ใจว่าไม่มีการเปลี่ยนแปลงโดยไม่คาดคิด

13. การรองรับการหาปริมาณ

SparseDenseMatmulOp ของ SparseCore ออกแบบมาเพื่อรองรับการดำเนินการในตารางการฝังโดยใช้ทั้งประเภทข้อมูลทศนิยม 32 บิต (FP32) และจำนวนเต็ม แม้ว่าโดยปกติแล้วการฝึกโมเดลจะดำเนินการโดยใช้ความแม่นยำ FP32 สำหรับตารางการฝัง แต่ก็สามารถใช้การวัดปริมาณหลังการฝึก (PTQ) ได้ PTQ อนุญาตให้ใช้ประเภทข้อมูลที่มีความแม่นยำต่ำกว่า (เช่น จำนวนเต็ม 8 บิต) สำหรับการอนุมาน ซึ่งอาจส่งผลให้ประสิทธิภาพดีขึ้นและลดการใช้หน่วยความจำ

การหาปริมาณจำลอง:

SparseDenseMatmulOp สามารถกำหนดค่าให้ดำเนินการ "การหาปริมาณจำลอง" ได้ ในโหมดการทำงานนี้ ระบบจะควอนไทซ์เวกเตอร์การฝังเป็นความแม่นยำที่ต่ำกว่าก่อน จากนั้นจึงจะยกเลิกการควอนไทซ์กลับเป็นความแม่นยำที่สูงกว่า (เช่น FP32) ก่อนที่จะนำไปใช้ในการคำนวณในภายหลัง เทคนิคนี้ช่วยให้ฝึกโมเดลได้ในขณะที่คำนึงถึงผลกระทบของสัญญาณรบกวนจากการหาปริมาณ การฝึกด้วยการจำลองการหาปริมาณจะช่วยปรับปรุงความแม่นยำของโมเดลสุดท้ายได้เมื่อมีการหาปริมาณอย่างเต็มรูปแบบสำหรับการอนุมาน

แอตทริบิวต์การกำหนดค่าสำหรับ SparseDenseMatmulOp (สำหรับการหาปริมาณ)

  • quantization_config_num_buckets = 256
    • แอตทริบิวต์นี้ระบุจำนวนกลุ่มหรือระดับที่ไม่ต่อเนื่องซึ่งจะมีการหาปริมาณตัวเลขทศนิยมแบบ 32 บิต ตัวอย่างเช่น เมื่อทำการควอนไทซ์เป็นจำนวนเต็ม 8 บิต โดยทั่วไปจะระบุ 2^8 =256 บัคเก็ต
  • quantization_config_low = -X.X
    • แอตทริบิวต์นี้กำหนดค่าทศนิยมขั้นต่ำในขอบเขตการหาปริมาณ ค่าอินพุตที่ต่ำกว่าค่าต่ำสุดที่ระบุนี้จะถูกตัดให้เป็นค่าต่ำสุดนี้ในระหว่างการหาปริมาณ
  • quantization_config_high = Y.Y
    • แอตทริบิวต์นี้กำหนดค่าทศนิยมแบบลอยตัวสูงสุดในช่วงการหาปริมาณ ค่าอินพุตที่สูงกว่าค่าสูงสุดที่ระบุนี้จะถูกตัดให้เป็นค่าสูงสุดนี้ในระหว่างการหาปริมาณ

การโต้ตอบกับตัวเลขและการส่งผ่านข้อมูล:

ลักษณะการทำงานเชิงตัวเลขของโมเดลอาจเปลี่ยนแปลงไปโดยขึ้นอยู่กับการเปิดใช้การส่งผ่านข้อมูลแบบไปป์ไลน์ระหว่าง TensorCore กับ SparseCore หากไปป์ไลน์ทำงานอยู่ การไล่ระดับสีที่ประมวลผลโดย SparseCore อาจ "ล้าสมัย" (จากการทำซ้ำครั้งก่อน) ซึ่งอาจโต้ตอบกับกระบวนการควอนไทเซชัน และอาจส่งผลต่อไดนามิกการฝึกโมเดลหรือความแม่นยำสุดท้าย

14. ฟีเจอร์ที่กำลังจะเปิดตัวและการปรับปรุงล่าสุด

ระบบนิเวศ SparseCore อยู่ภายใต้การพัฒนาและการปรับปรุงอย่างต่อเนื่อง

แผนกลยุทธ์:

  • การจัดกลุ่มมินิแบทช์ตามมิติข้อมูลตัวอย่าง
    • เราวางแผนที่จะให้ฟีเจอร์นี้เป็นฟีเจอร์เสริมความสามารถในการจัดกลุ่มมินิแบตช์ตามมิติคำศัพท์ที่มีอยู่
    • ซึ่งจะช่วยให้แบ่งพาร์ติชันอินพุตการฝังตามมิติข้อมูลตัวอย่างได้เพิ่มเติม โดยจะทำได้ด้วยการเปิดตัวลูปในอุปกรณ์ที่สามารถกรองและประมวลผลการค้นหาจากชุดตัวอย่างย่อยได้ทีละรายการ ฟีเจอร์ดังกล่าวอาจมีประโยชน์ในการจัดการจำนวนรหัสต่อตัวอย่างที่มาก หรือในการปรับปรุงการจัดสรรภาระงานระหว่างหน่วยประมวลผล
  • การรองรับการฝังที่ดียิ่งขึ้นโดยมีจำนวนเต็มต่อแถวน้อยกว่า 8 รายการ (ความกว้างของฟีเจอร์ขนาดเล็ก)
    • การออกแบบปัจจุบันมักใช้การเพิ่มพื้นที่ว่างจำนวนมากสำหรับความกว้างของฟีเจอร์การฝังที่น้อยกว่า 8 โฟลต (ซึ่งสอดคล้องกับ 32 ไบต์) การเพิ่มพื้นที่นี้อาจทำให้ HBM เสียเปล่าและอาจทำให้ทรัพยากรการประมวลผลถูกใช้งานน้อยเกินไป การปรับปรุงในอนาคตมีเป้าหมายเพื่อลดประสิทธิภาพที่ไม่ดีนี้สำหรับตารางที่มีมิติข้อมูลฟีเจอร์ขนาดเล็ก

การปรับปรุงล่าสุด

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

การปรับปรุงเหล่านี้มุ่งเน้นที่การปรับปรุงประสิทธิภาพของ SparseCore, ประสิทธิภาพของหน่วยความจำ และความยืดหยุ่นในการดำเนินการสำหรับภาระงานแบบกระจัดกระจายที่หลากหลายยิ่งขึ้น