ปรับแต่งประสิทธิภาพของ TensorFlow GPU ด้วย TensorFlow Profiler

ภาพรวม

คู่มือนี้จะแสดงให้คุณเห็นถึงวิธีใช้ TensorFlow Profiler กับ TensorBoard เพื่อรับข้อมูลเชิงลึกและรับประสิทธิภาพสูงสุดจาก GPU ของคุณ และดีบักเมื่อ GPU ของคุณอย่างน้อยหนึ่งตัวใช้งานน้อยเกินไป

หากคุณยังใหม่ต่อ Profiler:

พึงระลึกไว้เสมอว่าการนำการคำนวณออกไปยัง GPU อาจไม่เป็นประโยชน์เสมอไป โดยเฉพาะอย่างยิ่งสำหรับรุ่นขนาดเล็ก อาจมีค่าใช้จ่ายเนื่องจาก:

  • การถ่ายโอนข้อมูลระหว่างโฮสต์ (CPU) และอุปกรณ์ (GPU) และ
  • เนื่องจากเวลาแฝงที่เกี่ยวข้องเมื่อโฮสต์เปิดตัวเคอร์เนล GPU

เวิร์กโฟลว์การเพิ่มประสิทธิภาพประสิทธิภาพ

คู่มือนี้สรุปวิธีการดีบักปัญหาด้านประสิทธิภาพโดยเริ่มจาก GPU ตัวเดียว จากนั้นจึงย้ายไปยังโฮสต์เดียวที่มี GPU หลายตัว

ขอแนะนำให้ดีบักปัญหาประสิทธิภาพการทำงานตามลำดับต่อไปนี้:

  1. เพิ่มประสิทธิภาพและดีบักประสิทธิภาพใน GPU เดียว:
    1. ตรวจสอบว่าไปป์ไลน์อินพุตเป็นคอขวดหรือไม่
    2. ดีบักประสิทธิภาพของ GPU ตัวเดียว
    3. เปิดใช้งานความแม่นยำผสม (กับ fp16 (float16)) และเลือกที่จะเปิดใช้งาน XLA
  2. เพิ่มประสิทธิภาพและดีบักประสิทธิภาพการทำงานบนโฮสต์เดียวที่มี GPU หลายตัว

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

ในฐานะที่เป็นพื้นฐานสำหรับการรับรหัส performant บน GPUs คู่มือนี้จะถือว่าคุณกำลังใช้ tf.function Keras Model.compile และ Model.fit API ที่จะใช้ tf.function โดยอัตโนมัติภายใต้ประทุน เมื่อเขียนห่วงการฝึกอบรมที่กำหนดเองกับ tf.GradientTape ให้ดูที่ ผลการดำเนินงานที่ดีขึ้นด้วย tf.function เกี่ยวกับวิธีการเปิดใช้งาน tf.function s

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

1. เพิ่มประสิทธิภาพบน GPU ตัวเดียว

ในกรณีที่เหมาะสม โปรแกรมของคุณควรมีการใช้ GPU สูง การสื่อสาร CPU (โฮสต์) กับ GPU (อุปกรณ์) น้อยที่สุด และไม่มีโอเวอร์เฮดจากไปป์ไลน์อินพุต

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

TensorBoard ของ Profiler ภาพรวมหน้า -which แสดงมุมมองระดับบนสุดของวิธีการรูปแบบของคุณดำเนินการในช่วงโปรไฟล์วิ่งสามารถให้ความคิดของวิธีห่างไกลโปรแกรมของคุณจากสถานการณ์ที่เหมาะ ๆ

TensorFlow Profiler Overview Page

ตัวเลขสำคัญที่ต้องให้ความสนใจในหน้าภาพรวมคือ:

  1. ระยะเวลาของขั้นตอนมาจากการทำงานของอุปกรณ์จริง
  2. เปอร์เซ็นต์ของการดำเนินการบนอุปกรณ์เทียบกับโฮสต์
  3. วิธีการหลายเมล็ดใช้ fp16

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

ด้านล่างเป็นรูปภาพของมุมมองการติดตามแบบจำลองที่ทำงานบน GPU ตัวเดียว จาก TensorFlow ชื่อขอบเขตและ TensorFlow ส่วน Ops คุณสามารถระบุชิ้นส่วนที่แตกต่างกันของรูปแบบเช่นไปข้างหน้าผ่านฟังก์ชั่นการสูญเสียผ่านถอยหลัง / คำนวณลาดและปรับปรุงน้ำหนักเพิ่มประสิทธิภาพ นอกจากนี้คุณยังสามารถมีปฏิบัติการที่ทำงานบน GPU ถัดจากแต่ละสตรีมซึ่งหมายถึง CUDA ลำธาร แต่ละสตรีมจะใช้สำหรับงานเฉพาะ ในการติดตามนี้กระแส # 118 จะใช้ในการคำนวณเมล็ดเปิดตัวและสำเนาต่ออุปกรณ์เข้ากับอุปกรณ์ สตรีม # 119 ถูกนำมาใช้สำหรับการคัดลอกโฮสต์ต่ออุปกรณ์และสตรีม # 120 สำหรับอุปกรณ์เพื่อคัดลอกโฮสต์

การติดตามด้านล่างแสดงลักษณะทั่วไปของโมเดลนักแสดง

image

ยกตัวอย่างเช่นระยะเวลาการประมวลผล GPU (สตรีม # 118) มีลักษณะ "ไม่ว่าง" มีไม่กี่ช่องว่างมาก มีสำเนาน้อยที่สุดจากโฮสต์อยู่กับอุปกรณ์ (สตรีม # 119) และจากอุปกรณ์ไปยังโฮสต์ (สตรีม # 120) เช่นเดียวกับช่องว่างน้อยที่สุดระหว่างขั้นตอน เมื่อคุณรัน Profiler สำหรับโปรแกรมของคุณ คุณอาจไม่สามารถระบุคุณลักษณะในอุดมคติเหล่านี้ในมุมมองการติดตามของคุณ ส่วนที่เหลือของคู่มือนี้ครอบคลุมสถานการณ์ทั่วไปและวิธีแก้ไข

1. ดีบักไปป์ไลน์อินพุต

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

image

คุณสามารถดำเนินการต่อไปนี้ได้หากไปป์ไลน์อินพุตของคุณมีส่วนอย่างมากต่อเวลาของขั้นตอน:

  • คุณสามารถใช้ tf.data -specific คู่มือ เพื่อเรียนรู้วิธีที่จะแก้ปัญหาท่อป้อนข้อมูลของคุณ
  • อีกวิธีที่รวดเร็วในการตรวจสอบว่าไพพ์ไลน์อินพุตเป็นคอขวดหรือไม่คือการใช้ข้อมูลอินพุตที่สร้างแบบสุ่มซึ่งไม่ต้องการการประมวลผลล่วงหน้าใดๆ นี่คือตัวอย่าง ของการใช้เทคนิคนี้สำหรับรูปแบบ RESNET หากไปป์ไลน์อินพุตเหมาะสมที่สุด คุณควรพบกับประสิทธิภาพที่คล้ายคลึงกันกับข้อมูลจริงและด้วยข้อมูลสุ่ม/สังเคราะห์ที่สร้างขึ้น ค่าใช้จ่ายเพียงอย่างเดียวในกรณีข้อมูลสังเคราะห์จะเกิดจากการคัดลอกข้อมูลอินพุตซึ่งสามารถดึงข้อมูลล่วงหน้าและปรับให้เหมาะสมได้อีกครั้ง

นอกจากนี้ยังหมายถึง การปฏิบัติที่ดีที่สุดสำหรับการเพิ่มประสิทธิภาพการป้อนข้อมูลท่อส่งข้อมูล

2. ดีบักประสิทธิภาพของหนึ่ง GPU

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

1. วิเคราะห์ช่องว่างระหว่างขั้นตอน

การสังเกตทั่วไปเมื่อโปรแกรมของคุณไม่ทำงานอย่างเหมาะสมคือช่องว่างระหว่างขั้นตอนการฝึก ในภาพมุมมองการติดตามด้านล่าง มีช่องว่างขนาดใหญ่ระหว่างขั้นตอนที่ 8 ถึง 9 ซึ่งหมายความว่า GPU ไม่ได้ใช้งานในช่วงเวลานั้น

image

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

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

ถ้าคุณสังเกตเห็นช่องว่างขนาดใหญ่ในด้านพื้นที่ซึ่งตารางการปฏิบัติการเหล่านี้บน GPU ที่คุณสามารถตั้งค่าตัวแปรสภาพแวดล้อม TF_GPU_THREAD_MODE=gpu_private เพื่อให้แน่ใจว่าเมล็ด GPU จะเปิดตัวจากหัวข้อเฉพาะของตัวเองและไม่ได้รับการจัดคิวอยู่เบื้องหลัง tf.data ทำงาน

ช่องว่างระหว่างขั้นตอนนอกจากนี้ยังสามารถเกิดจากการคำนวณตัวชี้วัดการเรียกกลับ Keras หรือปฏิบัติการนอก tf.function ที่ทำงานบนโฮสต์ ops เหล่านี้ไม่มีประสิทธิภาพที่ดีเท่ากับ ops ในกราฟ TensorFlow นอกจากนี้ ops เหล่านี้บางส่วนทำงานบน CPU และคัดลอกเทนเซอร์ไปมาจาก GPU

หากหลังจากเพิ่มประสิทธิภาพไพพ์ไลน์อินพุตของคุณแล้ว คุณยังคงสังเกตเห็นช่องว่างระหว่างขั้นตอนในโปรแกรมดูการติดตาม คุณควรดูโค้ดโมเดลระหว่างขั้นตอนต่างๆ และตรวจสอบว่าการปิดใช้งานการเรียกกลับ/เมตริกช่วยเพิ่มประสิทธิภาพหรือไม่ รายละเอียดบางอย่างของ ops เหล่านี้ยังอยู่ในโปรแกรมดูการติดตาม (ทั้งด้านอุปกรณ์และโฮสต์) คำแนะนำในสถานการณ์นี้คือการตัดจำหน่ายค่าใช้จ่ายของ ops เหล่านี้โดยดำเนินการตามจำนวนขั้นตอนคงที่แทนที่จะเป็นทุกขั้นตอน เมื่อใช้ compile วิธีการใน tf.keras API, การตั้งค่า experimental_steps_per_execution ธงไม่นี้โดยอัตโนมัติ สำหรับลูปที่กำหนดเองการฝึกอบรมการใช้ tf.while_loop

2. บรรลุการใช้งานอุปกรณ์ที่สูงขึ้น

1. เคอร์เนล GPU ขนาดเล็กและโฮสต์เคอร์เนลเริ่มต้นล่าช้า host

โฮสต์จัดคิวเมล็ดให้ทำงานบน GPU แต่มีเวลาแฝง (ประมาณ 20-40 μs) ที่เกี่ยวข้องก่อนที่เมล็ดจะถูกดำเนินการบน GPU ในกรณีที่เหมาะสม โฮสต์จะจัดคิวเคอร์เนลให้เพียงพอบน GPU เพื่อให้ GPU ใช้เวลาส่วนใหญ่ในการดำเนินการ แทนที่จะรอให้โฮสต์จัดคิวเมล็ดเพิ่ม

ของ Profiler หน้าภาพรวม เกี่ยวกับการแสดง TensorBoard เวลาเท่าไร GPU ก็ไม่ได้ใช้งานเนื่องจากรออยู่บนโฮสต์ที่จะเปิดตัวเมล็ด ในภาพด้านล่าง GPU ไม่ได้ใช้งานประมาณ 10% ของเวลาขั้นตอนที่รอการเปิดเมล็ด

image

ผู้ชมร่องรอย สำหรับเรื่องนี้แสดงให้เห็นว่าโปรแกรมเดียวกันช่องว่างเล็ก ๆ ระหว่างเมล็ดที่โฮสต์เมล็ดเปิดตัวยุ่งเกี่ยวกับของ GPU

image

โดยการเปิดใช้ตัวเลือกเล็กๆ จำนวนมากบน GPU (เช่น การเพิ่มสเกลาร์) โฮสต์อาจไม่สามารถตาม GPU ได้ TensorFlow สถิติ เครื่องมือใน TensorBoard สำหรับเดียวกันแสดงให้เห็นรายละเอียดการดำเนินงาน 126,224 Mul การ 2.77 วินาที ดังนั้น เคอร์เนลแต่ละตัวจะมีขนาดประมาณ 21.9 μs ซึ่งมีขนาดเล็กมาก (ในช่วงเวลาเดียวกับเวลาแฝงในการเรียกใช้) และอาจส่งผลให้เกิดความล่าช้าในการเรียกใช้เคอร์เนลของโฮสต์

image

หากคุณ ร่องรอยของผู้ชม ช่องว่างเล็ก ๆ หลายรายการระหว่างปฏิบัติการบน GPU เช่นในภาพด้านบนคุณสามารถ:

  • เชื่อมต่อเมตริกซ์ขนาดเล็กและใช้ ops แบบเวกเตอร์หรือใช้ขนาดแบทช์ที่ใหญ่ขึ้นเพื่อให้เคอร์เนลที่เปิดใช้งานแต่ละตัวทำงานมากขึ้น ซึ่งจะทำให้ GPU ยุ่งนานขึ้น
  • ให้แน่ใจว่าคุณกำลังใช้ tf.function ในการสร้างกราฟ TensorFlow เพื่อให้คุณไม่ได้ใช้ปฏิบัติการในโหมดความกระตือรือร้นที่บริสุทธิ์ หากคุณกำลังใช้ Model.fit (เป็นคัดค้านไปยังห่วงการฝึกอบรมที่กำหนดเองกับ tf.GradientTape ) แล้ว tf.keras.Model.compile จะทำโดยอัตโนมัตินี้สำหรับคุณ
  • ฟิวส์เมล็ดใช้ XLA กับ tf.function(jit_compile=True) หรือการจัดกลุ่มโดยอัตโนมัติ สำหรับรายละเอียดเพิ่มเติมไปที่ แม่นยำเปิดใช้งานผสมและ XLA ส่วนด้านล่างเพื่อเรียนรู้วิธีการเปิดใช้งาน XLA เพื่อให้ได้ประสิทธิภาพที่สูงขึ้น คุณลักษณะนี้สามารถนำไปสู่การใช้อุปกรณ์สูง
2. TensorFlow op ตำแหน่ง

ตัวรวมข้อมูล ภาพรวมของหน้า แสดงเปอร์เซ็นต์ของปฏิบัติการที่วางอยู่บนโฮสต์กับอุปกรณ์ (คุณยังสามารถตรวจสอบตำแหน่งของปฏิบัติการโดยเฉพาะการมองหาที่ ผู้ชมร่องรอย . เช่นเดียวกับในภาพด้านล่างที่คุณต้องการร้อยละของการปฏิบัติการในพื้นที่ที่ จะเล็กมากเมื่อเทียบกับตัวเครื่อง

image

ตามหลักการแล้ว ops ที่เน้นการประมวลผลส่วนใหญ่ควรวางบน GPU

เพื่อหาที่อุปกรณ์การดำเนินงานและเทนเซอร์ในรูปแบบของคุณได้รับมอบหมายให้ชุด tf.debugging.set_log_device_placement(True) เป็นคำสั่งแรกของโปรแกรมของคุณ

โปรดทราบว่าในบางกรณีแม้ว่าคุณระบุสหกรณ์ที่จะถูกวางไว้บนอุปกรณ์เฉพาะการดำเนินงานที่อาจแทนที่สภาพนี้ (ตัวอย่าง: tf.unique ) แม้สำหรับการฝึกอบรม GPU เดียวระบุกลยุทธ์การกระจายเช่น tf.distribute.OneDeviceStrategy สามารถส่งผลในตำแหน่งที่กำหนดมากขึ้นของการปฏิบัติการบนอุปกรณ์ของคุณ

เหตุผลหนึ่งที่ทำให้ ops ส่วนใหญ่วางบน GPU คือการป้องกันไม่ให้มีการคัดลอกหน่วยความจำมากเกินไประหว่างโฮสต์และอุปกรณ์ (คาดว่าจะมีการคัดลอกหน่วยความจำสำหรับข้อมูลอินพุต/เอาต์พุตรุ่นระหว่างโฮสต์และอุปกรณ์) ตัวอย่างของการคัดลอกมากเกินไปจะแสดงให้เห็นในมุมมองการติดตามด้านล่างเกี่ยวกับ GPU ลำธาร # 167, # 168 และ # 169

image

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

3. เมล็ดที่มีประสิทธิภาพมากขึ้นบน GPUs

เมื่อยอมรับการใช้งาน GPU ของโปรแกรมแล้ว ขั้นตอนต่อไปคือพิจารณาการเพิ่มประสิทธิภาพของเคอร์เนล GPU โดยใช้ Tensor Cores หรือการรวม ops

1. ใช้เทนเซอร์คอร์

โมเดิร์นNVIDIA® GPU ที่มีความเชี่ยวชาญ Tensor Cores ที่มีนัยสำคัญสามารถปรับปรุงประสิทธิภาพของเมล็ดที่มีสิทธิ์

คุณสามารถใช้ TensorBoard ของ สถิติ GPU เคอร์เนล ที่จะเห็นภาพที่เมล็ด GPU เป็น Tensor หลักที่มีสิทธิ์และที่กำลังใช้เมล็ด Tensor Cores การเปิดใช้งาน fp16 (ดูการเปิดใช้งานส่วนแม่นยำผสมด้านล่าง) เป็นวิธีหนึ่งที่จะทำให้โปรแกรมของคุณทั่วไปเมทริกซ์คูณ (Ops matmul) (GEMM) เมล็ดใช้เทนเซอร์หลัก เมล็ด GPU ใช้เมตริกซ์คอร์ได้อย่างมีประสิทธิภาพเมื่อแม่นยำเป็น fp16 และขนาดเมตริกซ์อินพุต / เอาต์พุตเป็นหารด้วย 8 หรือ 16 ( int8 )

สำหรับคำแนะนำรายละเอียดอื่น ๆ เกี่ยวกับวิธีที่จะทำให้เมล็ดมีประสิทธิภาพสำหรับ GPUs โปรดดูที่ NVIDIA®ลึกการเรียนรู้การปฏิบัติงาน คู่มือ

2. ฟิวส์ ops

ใช้ tf.function(jit_compile=True) ที่จะหลอมรวมปฏิบัติการขนาดเล็กในรูปแบบเมล็ดขนาดใหญ่นำไปสู่การเพิ่มประสิทธิภาพการทำงานอย่างมีนัยสำคัญ ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ XLA คู่มือ

3. เปิดใช้งานความแม่นยำแบบผสมและ XLA

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

1. เปิดใช้งานความแม่นยำแบบผสม

TensorFlow แม่นยำผสม คู่มือแสดงวิธีการเปิดใช้ fp16 ความแม่นยำใน GPUs เปิดใช้งาน แอมป์ ในNVIDIA® GPU ที่ใช้ Tensor Cores และตระหนักถึง 3x speedups รวมเมื่อเทียบกับการใช้เพียง fp32 (float32) ความแม่นยำใน Volta และใหม่กว่าสถาปัตยกรรม GPU

ตรวจสอบให้แน่ใจว่ามิติเมทริกซ์/เทนเซอร์ตรงตามข้อกำหนดสำหรับการเรียกเคอร์เนลที่ใช้เทนเซอร์คอร์ เคอร์เนล GPU ใช้ Tensor Cores อย่างมีประสิทธิภาพเมื่อความแม่นยำเป็น fp16 และขนาดอินพุต/เอาต์พุตหารด้วย 8 หรือ 16 ลงตัว (สำหรับ int8)

โปรดทราบว่าด้วย cuDNN v7.6.3 และใหม่กว่า มิติของการบิดจะถูกเสริมโดยอัตโนมัติเมื่อจำเป็นเพื่อใช้ประโยชน์จาก Tensor Cores

ตามวิธีปฏิบัติที่ดีที่สุดต่อไปนี้เพื่อให้เกิดประโยชน์สูงสุดประสิทธิภาพการทำงานของ fp16 แม่นยำ

1. ใช้เมล็ด fp16 ที่เหมาะสมที่สุด

ด้วย fp16 เปิดใช้งานโปรแกรมของคุณคูณเมทริกซ์ (GEMM) เมล็ดควรใช้ที่สอดคล้อง fp16 รุ่นที่ใช้ Tensor Cores อย่างไรก็ตามในบางกรณีนี้ไม่ได้เกิดขึ้นและคุณไม่พบ speedup คาดว่าจากการเปิดใช้งาน fp16 เป็นโปรแกรมของคุณอยู่กลับไปยังการดำเนินงานไม่มีประสิทธิภาพแทน

image

GPU เคอร์เนล สถิติแสดงให้เห็นหน้าซึ่ง Ops เป็น Tensor หลักซึ่งมีสิทธิ์และเมล็ดเป็นจริงโดยใช้มีประสิทธิภาพเทนเซอร์หลัก คู่มือNVIDIA®เกี่ยวกับประสิทธิภาพการเรียนรู้ลึก มีคำแนะนำเพิ่มเติมเกี่ยวกับวิธีการใช้ประโยชน์จาก Tensor Cores นอกจากนี้ประโยชน์ของการใช้ fp16 ยังจะแสดงในเมล็ดที่มีหน่วยความจำที่ถูกผูกไว้ก่อนหน้านี้เป็นตอนนี้ Ops จะใช้เวลาครึ่งเวลา

2. การปรับขนาดการสูญเสียแบบไดนามิกเทียบกับแบบคงที่

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

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

2. เปิดใช้งาน XLA ด้วย tf.function(jit_compile=True) หรือ auto-clustering

เป็นขั้นตอนสุดท้ายในการรับประสิทธิภาพที่ดีที่สุดด้วย GPU ตัวเดียว คุณสามารถทดลองเปิดใช้งาน XLA ซึ่งจะหลอมรวม ops และนำไปสู่การใช้อุปกรณ์ที่ดีขึ้นและลดพื้นที่หน่วยความจำ สำหรับรายละเอียดเกี่ยวกับวิธีการเปิดใช้งาน XLA ในโปรแกรมของคุณกับ tf.function(jit_compile=True) หรืออัตโนมัติจัดกลุ่มอ้างถึง XLA คู่มือ

คุณสามารถตั้งค่าระดับ JIT ทั่วโลกเพื่อ -1 (off), 1 หรือ 2 ระดับที่สูงขึ้นจะก้าวร้าวมากขึ้นและอาจลดความขนานและใช้หน่วยความจำมากขึ้น ตั้งค่าเป็น 1 ถ้าคุณมีข้อ จำกัด ของหน่วยความจำ โปรดทราบว่า XLA ทำงานได้ไม่ดีสำหรับรุ่นที่มีรูปร่างเทนเซอร์อินพุตแบบแปรผัน เนื่องจากคอมไพเลอร์ XLA จะต้องคอยรวบรวมเมล็ดทุกครั้งที่พบรูปร่างใหม่

2. เพิ่มประสิทธิภาพการทำงานบนโฮสต์เดียวที่มี GPU หลายตัว

tf.distribute.MirroredStrategy API สามารถใช้ในการฝึกอบรมแบบจำลองขนาดจากที่หนึ่งไปยัง GPU GPUs หลายคนบนโฮสต์เดียว (หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการดำเนินการฝึกอบรมกระจายกับ TensorFlow โปรดดูที่ การฝึกอบรมกระจายกับ TensorFlow , ใช้ GPU และ ใช้ TPUs คำแนะนำและ การฝึกอบรมที่มีการแจกจ่าย Keras กวดวิชา.)

แม้ว่าการเปลี่ยนจาก GPU ตัวหนึ่งไปเป็น GPU หลายตัวควรจะสามารถปรับขนาดได้ตั้งแต่แกะกล่อง แต่บางครั้งคุณอาจประสบปัญหาด้านประสิทธิภาพ

เมื่อเปลี่ยนจากการฝึกด้วย GPU ตัวเดียวไปเป็น GPU หลายตัวบนโฮสต์เดียวกัน คุณควรสัมผัสประสบการณ์การปรับขนาดประสิทธิภาพโดยมีค่าใช้จ่ายเพิ่มเติมในการสื่อสารแบบเกรเดียนต์และการใช้เธรดของโฮสต์ที่เพิ่มขึ้น ด้วยเหตุนี้ คุณจะไม่มีการเพิ่มความเร็ว 2x ที่แน่นอนหากคุณย้ายจาก 1 เป็น 2 GPU เป็นต้น

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

image

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

  1. พยายามเพิ่มขนาดแบตช์ให้สูงสุด ซึ่งจะนำไปสู่การใช้อุปกรณ์ที่สูงขึ้นและลดต้นทุนการสื่อสารระหว่าง GPU หลายตัว ใช้ Profiler หน่วยความจำ จะช่วยให้ได้รับความรู้สึกของวิธีการปิดโปรแกรมของคุณคือการใช้หน่วยความจำสูงสุด โปรดทราบว่าแม้ว่าขนาดแบทช์ที่สูงขึ้นอาจส่งผลต่อการบรรจบกัน แต่มักจะถูกมองข้ามโดยข้อดีด้านประสิทธิภาพ
  2. เมื่อย้ายจาก GPU ตัวเดียวไปเป็น GPU หลายตัว โฮสต์เดียวกันจะต้องประมวลผลข้อมูลที่ป้อนมากขึ้น ดังนั้น หลังจาก (1) ขอแนะนำให้ตรวจสอบประสิทธิภาพของไปป์ไลน์อินพุตอีกครั้ง และตรวจสอบให้แน่ใจว่าไม่ใช่คอขวด
  3. ตรวจสอบไทม์ไลน์ของ GPU ในมุมมองการติดตามของโปรแกรมของคุณสำหรับการโทร AllReduce ที่ไม่จำเป็น ซึ่งจะทำให้เกิดการซิงโครไนซ์กับอุปกรณ์ทั้งหมด ในมุมมองร่องรอยที่ปรากฏข้างต้น AllReduce จะทำผ่านทาง NCCL เคอร์เนลและมีเพียงหนึ่งโทร NCCL ในแต่ละ GPU สำหรับการไล่ระดับสีในแต่ละขั้นตอน
  4. ตรวจสอบการทำสำเนา D2H, H2D และ D2D ที่ไม่จำเป็นซึ่งสามารถย่อให้เล็กสุดได้
  5. ตรวจสอบเวลาของขั้นตอนเพื่อให้แน่ใจว่าแบบจำลองแต่ละตัวทำงานเหมือนกัน ยกตัวอย่างเช่นมันสามารถเกิดขึ้นได้ที่หนึ่ง GPU (โดยทั่วไป GPU0 ) จะ oversubscribed เนื่องจากโฮสต์ผิดพลาดจบลงด้วยการวางงานเพิ่มเติมเกี่ยวกับมัน
  6. สุดท้าย ตรวจสอบขั้นตอนการฝึกอบรมสำหรับ GPU ทั้งหมดในมุมมองการติดตามของคุณสำหรับการดำเนินการใดๆ ที่ดำเนินการตามลำดับ ซึ่งมักจะเกิดขึ้นเมื่อโปรแกรมของคุณมีการควบคุมการขึ้นต่อกันจาก GPU หนึ่งไปยังอีกตัวหนึ่ง ในอดีต การดีบักประสิทธิภาพในสถานการณ์นี้ได้รับการแก้ไขเป็นกรณีไป ถ้าคุณสังเกตพฤติกรรมนี้ในโปรแกรมของคุณ ยื่นปัญหา GitHub กับภาพในมุมมองของการติดตามของคุณ

1. ปรับการไล่ระดับสีให้เหมาะสม AllReduce

เมื่อฝึกด้วยกลยุทธ์แบบซิงโครนัส อุปกรณ์แต่ละเครื่องจะได้รับส่วนหนึ่งของข้อมูลที่ป้อนเข้า

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

แต่ละ GPU แรกที่เชื่อมการไล่ระดับสีข้ามชั้นรูปแบบการติดต่อสื่อสารข้าม GPUs ใช้ tf.distribute.CrossDeviceOps ( tf.distribute.NcclAllReduce เป็นค่าเริ่มต้น) และจากนั้นส่งกลับไล่ระดับสีได้หลังจากที่ลดลงต่อชั้น

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

เวลาในการ AllReduce ควรใกล้เคียงกับ:

(number of parameters * 4bytes)/ (communication bandwidth)

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

โปรดทราบว่าแต่ละพารามิเตอร์รุ่น 4 ไบต์ในขนาดตั้งแต่ TensorFlow ใช้ fp32 (float32) ในการสื่อสารการไล่ระดับสี แม้เมื่อคุณได้ fp16 เปิดใช้งาน NCCL AllReduce ใช้ fp32 พารามิเตอร์

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

2. ความขัดแย้งเธรดโฮสต์ GPU GPU

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

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

ร่องรอยของผู้ชม ด้านล่างแสดงค่าใช้จ่ายเมื่อ CPU โรคสมองเปิดตัว GPU เคอร์เนลได้ผลเป็น GPU1 ไม่ได้ใช้งานแล้วเริ่มทำงาน Ops หลังจาก GPU2 ได้เริ่มต้น

image

มุมมองร่องรอยแสดงให้เห็นว่าพื้นที่ที่โฮสต์เปิดตัวในเมล็ด GPU2 ก่อนที่จะเปิดตัวพวกเขาใน GPU1 (หมายเหตุที่ด้านล่าง tf_Compute* Ops ไม่ได้บ่งบอกถึงหัวข้อ CPU)

image

หากคุณประสบปัญหาการส่ายของเคอร์เนล GPU ในมุมมองการติดตามของโปรแกรม การดำเนินการที่แนะนำคือ:

  • ตั้งค่าตัวแปรสภาพแวดล้อม TensorFlow TF_GPU_THREAD_MODE เพื่อ gpu_private ตัวแปรสภาพแวดล้อมนี้จะบอกโฮสต์ให้เก็บเธรดสำหรับ GPU ส่วนตัว
  • โดยค่าเริ่มต้น TF_GPU_THREAD_MODE=gpu_private ชุดจำนวนกระทู้ 2 ซึ่งเพียงพอในกรณีส่วนใหญ่ อย่างไรก็ตามจำนวนที่สามารถเปลี่ยนแปลงได้โดยการตั้งค่าตัวแปรสภาพแวดล้อม TensorFlow TF_GPU_THREAD_COUNT ไปยังหมายเลขที่ต้องการของหัวข้อ