ค่อนข้างตรงไปตรงมาในการอธิบายการคำนวณ Tensor
แต่เมื่อใดและอย่างไรการคำนวณนั้นจะขึ้นอยู่กับว่าแบ็กเอนด์ใดที่ใช้สำหรับ Tensor
และเมื่อใดที่ต้องการผลลัพธ์บน CPU โฮสต์
เบื้องหลัง การดำเนินการบน Tensor
จะถูกส่งไปยังตัวเร่งความเร็ว เช่น GPU หรือ TPU หรือทำงานบน CPU เมื่อไม่มีตัวเร่งความเร็ว สิ่งนี้จะเกิดขึ้นโดยอัตโนมัติสำหรับคุณ และทำให้ง่ายต่อการคำนวณแบบขนานที่ซับซ้อนโดยใช้อินเทอร์เฟซระดับสูง อย่างไรก็ตาม การทำความเข้าใจว่าการจัดส่งนี้เกิดขึ้นได้อย่างไร และสามารถปรับแต่งเพื่อประสิทธิภาพสูงสุดได้อาจเป็นประโยชน์
Swift สำหรับ TensorFlow มีแบ็กเอนด์สองรายการสำหรับดำเนินการคำนวณแบบเร่งความเร็ว: โหมดกระตือรือร้น TensorFlow และ X10 แบ็กเอนด์เริ่มต้นคือโหมดกระตือรือร้นของ TensorFlow แต่สามารถแทนที่ได้ มี บทช่วยสอนแบบโต้ตอบ ที่จะแนะนำคุณเกี่ยวกับการใช้แบ็กเอนด์ที่แตกต่างกันเหล่านี้
โหมดกระตือรือร้น TensorFlow
แบ็คเอนด์โหมดกระตือรือร้นของ TensorFlow ใช้ประโยชน์จาก TensorFlow C API เพื่อส่งการทำงาน Tensor
แต่ละรายการไปยัง GPU หรือ CPU ทันทีที่พบ ผลลัพธ์ของการดำเนินการนั้นจะถูกดึงข้อมูลและส่งต่อไปยังการดำเนินการถัดไป
การจัดส่งแบบดำเนินการทีละขั้นตอนนี้เข้าใจได้ง่ายและไม่ต้องมีการกำหนดค่าที่ชัดเจนภายในโค้ดของคุณ อย่างไรก็ตาม ในหลายกรณี ไม่ได้ส่งผลให้ได้ประสิทธิภาพที่ดีที่สุด เนื่องจากมีค่าใช้จ่ายจากการส่งการดำเนินการเล็กๆ จำนวนมากออกไป รวมกับการขาดการผสมผสานการดำเนินการและการเพิ่มประสิทธิภาพที่อาจเกิดขึ้นได้เมื่อมีกราฟของการดำเนินการอยู่ สุดท้ายนี้ โหมดกระตือรือร้นของ TensorFlow เข้ากันไม่ได้กับ TPU และใช้ได้กับ CPU และ GPU เท่านั้น
X10 (การติดตามแบบ XLA)
X10 เป็นชื่อของแบ็กเอนด์ Swift สำหรับ TensorFlow ที่ใช้การติดตามเทนเซอร์แบบขี้เกียจและ คอมไพเลอร์ที่ปรับให้เหมาะสม XLA ในหลาย ๆ กรณีปรับปรุงประสิทธิภาพที่เหนือกว่าการจัดส่งแบบปฏิบัติการต่อการปฏิบัติงานอย่างมีนัยสำคัญ นอกจากนี้ยังเพิ่มความเข้ากันได้สำหรับ TPU ซึ่งเป็นตัวเร่งความเร็วที่ได้รับการปรับให้เหมาะสมโดยเฉพาะสำหรับประเภทการคำนวณที่พบในโมเดลการเรียนรู้ของเครื่อง
การใช้ X10 สำหรับการคำนวณ Tensor
ไม่ใช่ค่าเริ่มต้น ดังนั้นคุณจึงต้องเลือกใช้แบ็กเอนด์นี้ ซึ่งทำได้โดยการระบุว่า Tensor
วางอยู่บนอุปกรณ์ XLA:
let tensor1 = Tensor<Float>([0.0, 1.0, 2.0], on: Device.defaultXLA)
let tensor2 = Tensor<Float>([1.5, 2.5, 3.5], on: Device.defaultXLA)
หลังจากนั้น การอธิบายการคำนวณจะเหมือนกับโหมดกระตือรือร้นของ TensorFlow ทุกประการ:
let tensor3 = tensor1 + tensor2
สามารถให้รายละเอียดเพิ่มเติมได้เมื่อสร้าง Tensor
เช่น ตัวเร่งความเร็วชนิดใดที่จะใช้ และแม้แต่ตัวเร่งความเร็วใด หากมีหลายตัว ตัวอย่างเช่น คุณสามารถสร้าง Tensor
บนอุปกรณ์ TPU ตัวที่สองได้ (สมมติว่าโฮสต์ที่โปรแกรมกำลังทำงานอยู่มองเห็นได้) โดยใช้สิ่งต่อไปนี้:
let tpuTensor = Tensor<Float>([0.0, 1.0, 2.0], on: Device(kind: .TPU, ordinal: 1, backend: .XLA))
ไม่มีการเคลื่อนไหวโดยปริยายของ Tensor
ระหว่างอุปกรณ์ ดังนั้นหากใช้ Tensor
สองตัวบนอุปกรณ์ที่แตกต่างกันในการดำเนินการร่วมกัน ข้อผิดพลาดรันไทม์จะเกิดขึ้น หากต้องการคัดลอกเนื้อหาของ Tensor
ไปยังอุปกรณ์ใหม่ด้วยตนเอง คุณสามารถใช้เครื่องมือเริ่มต้น Tensor(copying:to:)
ได้ โครงสร้างขนาดใหญ่บางแห่งที่มีเทน Tensor
อยู่ภายใน เช่น โมเดลและเครื่องมือเพิ่มประสิทธิภาพ มีฟังก์ชันตัวช่วยสำหรับการย้าย Tensor
ภายในทั้งหมดไปยังอุปกรณ์ใหม่ในขั้นตอนเดียว
ต่างจากโหมดกระตือรือร้นของ TensorFlow ตรงที่การดำเนินการที่ใช้แบ็กเอนด์ X10 จะไม่ถูกจัดส่งแยกกันเมื่อพบ แต่การสั่งงานไปยังเครื่องเร่งความเร็วจะถูกกระตุ้นโดยการอ่านค่าที่คำนวณกลับไปยังโฮสต์หรือโดยการวางสิ่งกีดขวางที่ชัดเจนเท่านั้น วิธีการทำงานคือรันไทม์เริ่มต้นจากค่าที่อ่านไปยังโฮสต์ (หรือการคำนวณครั้งสุดท้ายก่อนอุปสรรคแบบแมนนวล) และติดตามกราฟของการคำนวณที่ส่งผลให้เกิดค่านั้น
กราฟที่ติดตามนี้จะถูกแปลงเป็นตัวแทนระดับกลาง XLA HLO และส่งผ่านไปยังคอมไพลเลอร์ XLA เพื่อรับการปรับให้เหมาะสมและคอมไพล์สำหรับการดำเนินการบนตัวเร่งความเร็ว จากนั้นการคำนวณทั้งหมดจะถูกส่งไปยังคันเร่งและผลลัพธ์สุดท้ายจะได้รับ
การคำนวณเป็นกระบวนการที่ใช้เวลานาน ดังนั้นจึงเหมาะที่สุดที่จะใช้ X10 กับการคำนวณแบบขนานจำนวนมากซึ่งแสดงผ่านกราฟและดำเนินการหลายครั้ง มีการใช้ค่าแฮชและการแคชเพื่อให้กราฟที่เหมือนกันถูกคอมไพล์เพียงครั้งเดียวสำหรับการกำหนดค่าที่ไม่ซ้ำกันทุกครั้ง
สำหรับโมเดลการเรียนรู้ของเครื่อง กระบวนการฝึกมักจะเกี่ยวข้องกับการวนซ้ำซึ่งโมเดลจะต้องได้รับการคำนวณชุดเดียวกันซ้ำแล้วซ้ำเล่า คุณจะต้องให้แต่ละรอบเหล่านี้ถูกมองว่าเป็นการซ้ำของการติดตามเดียวกัน แทนที่จะเป็นกราฟยาวหนึ่งอันที่มีหน่วยซ้ำอยู่ข้างใน ซึ่งเปิดใช้งานได้โดยการแทรกการเรียกฟังก์ชัน LazyTensorBarrier()
ด้วยตนเองในตำแหน่งในโค้ดของคุณที่คุณต้องการให้การติดตามสิ้นสุด
การรองรับแบบผสมความแม่นยำใน X10
รองรับการฝึกอบรมที่มีความแม่นยำแบบผสมผ่าน X10 และมีทั้ง API ระดับต่ำและระดับสูงเพื่อควบคุม API ระดับต่ำ มีคุณสมบัติในการคำนวณสองประการ: toReducedPrecision
และ toFullPrecision
ซึ่งจะแปลงระหว่างความแม่นยำเต็มและความแม่นยำที่ลดลง พร้อมด้วย isReducedPrecision
เพื่อสืบค้นความแม่นยำ นอกจาก Tensor
แล้ว โมเดลและเครื่องมือเพิ่มประสิทธิภาพยังสามารถแปลงระหว่างความแม่นยำเต็มและความแม่นยำลดลงได้โดยใช้ API นี้
โปรดทราบว่าการแปลงเป็นความแม่นยำที่ลดลงจะไม่เปลี่ยนประเภทลอจิคัลของ Tensor
หาก t
เป็น Tensor<Float>
t.toReducedPrecision
ก็เป็น Tensor<Float>
ด้วยการนำเสนอพื้นฐานที่มีความแม่นยำลดลง
เช่นเดียวกับอุปกรณ์ต่างๆ ไม่อนุญาตให้ใช้งานระหว่างเทนเซอร์ที่มีความแม่นยำต่างกัน วิธีนี้จะหลีกเลี่ยงการเลื่อนระดับแบบเงียบๆ และไม่พึงประสงค์ไปเป็นโฟลต 32 บิต ซึ่งผู้ใช้ตรวจพบได้ยาก