ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

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

ภาพรวม

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

อ่าน Profiler กวดวิชา ที่จะเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการเริ่มต้นกับการใช้ Profiler นอกจากนี้อ่าน คู่มือ Profiler เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับเครื่องมือโปรไฟล์ต่างๆที่มีอยู่และวิธีการต่างๆที่มีต่อประสิทธิภาพการทำงาน TensorFlow เพิ่มประสิทธิภาพบนโฮสต์ (CPU)

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

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

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

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

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

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

เพิ่มประสิทธิภาพบน 1 GPU

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

หน้าภาพรวม ของ TensorFlow Profiler ให้ความคิดของวิธีห่างไกลโปรแกรมของคุณจากสถานการณ์ที่เหมาะ

TensorFlow Profiler Overview Page

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

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

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

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

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

image

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

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

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

image

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

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

ยังเห็นคำแนะนำ ที่นี่

ดีบักประสิทธิภาพของ 1 GPU

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

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

การสังเกตทั่วไปเมื่อโปรแกรมของคุณไม่ทำงานอย่างเหมาะสมคือช่องว่างระหว่างขั้นตอนการฝึก ในภาพด้านล่าง มีช่องว่างขนาดใหญ่ระหว่างขั้นตอนที่ 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

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

GPU Kernels ขนาดเล็กและโฮสต์ Kernel Launch Delays

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

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

image

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

image

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

image

หากโปรแกรมดูการติดตามของคุณแสดงช่องว่างเล็กๆ จำนวนมากระหว่าง ops บน GPU เช่นเดียวกับรูปภาพด้านบน คุณสามารถ:

  • เชื่อมต่อเมตริกซ์ขนาดเล็กและใช้ ops แบบเวกเตอร์หรือใช้ขนาดแบทช์ที่ใหญ่ขึ้นเพื่อให้เคอร์เนลที่เปิดใช้งานแต่ละตัวทำงานมากขึ้น ซึ่งจะทำให้ GPU ยุ่งนานขึ้น
  • ให้แน่ใจว่าคุณกำลังใช้ tf.function ในการสร้างกราฟ TF และไม่ได้ใช้ปฏิบัติการในโหมดความกระตือรือร้นที่บริสุทธิ์ ใช้ tf.keras.Model.compile โดยอัตโนมัติไม่นี้
  • ฟิวส์เมล็ดโดยใช้ XLA สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ ส่วน ด้านล่างเกี่ยวกับวิธีการเปิดใช้ XLA เพื่อให้ได้ประสิทธิภาพที่สูงขึ้น นี่เป็นคุณลักษณะทดลอง แต่นำไปสู่การใช้อุปกรณ์สูง
Tensorflow Op Placement Op

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

image

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

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

image

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

เคอร์เนลที่มีประสิทธิภาพมากขึ้นบน GPU

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

ใช้แกนเทนเซอร์

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

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

ฟิวส์ ops

ใช้ tf.xla.experimental_compile ที่จะหลอมรวมปฏิบัติการขนาดเล็กในรูปแบบเมล็ดขนาดใหญ่นำไปสู่การเพิ่มประสิทธิภาพการทำงานอย่างมีนัยสำคัญ

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

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

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

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

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

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

ใช้เคอร์เนล fp16 ที่เหมาะสมที่สุด

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

image

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

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

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

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

เปิดใช้งาน XLA

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

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

เพิ่มประสิทธิภาพบน Multi-GPU Single Host

tf.distribute.MirroredStrategy API สามารถใช้ในการฝึกอบรมแบบจำลองขนาดตั้งแต่ 1 GPU เพื่อ GPUs หลายคนบนโฮสต์เดียว ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการดำเนินการฝึกอบรมกระจายกับ Tensorflow โปรดดูที่ การฝึกอบรมกระจายกับ 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) ถูกจองเกินเพราะโฮสต์ผิดพลาดทำให้ต้องทำงานหนักขึ้น
  6. สุดท้าย ตรวจสอบขั้นตอนการฝึกอบรมสำหรับ GPU ทั้งหมดในมุมมองการติดตามของคุณสำหรับการดำเนินการใดๆ ที่ดำเนินการตามลำดับ ซึ่งมักจะเกิดขึ้นเมื่อโปรแกรมของคุณมีการควบคุมการขึ้นต่อกันจาก GPU หนึ่งไปยังอีกตัวหนึ่ง ประสิทธิภาพการดีบักในสถานการณ์นี้ได้รับการแก้ไขเป็นกรณี ๆ ไปในอดีต ถ้าคุณสังเกตพฤติกรรมนี้ในโปรแกรมของคุณ ยื่นปัญหา Github กับภาพในมุมมองของการติดตามของคุณ

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

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

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

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

โปรดทราบว่าพารามิเตอร์แต่ละรุ่นมีขนาด 4 ไบต์ เนื่องจาก Tensorflow ใช้ fp32 เพื่อสื่อสารการไล่ระดับสี แม้ว่าคุณจะเปิดใช้งาน fp16 แล้ว NCCL AllReduce ยังใช้พารามิเตอร์ fp32 ในอนาคต Tensorflow จะสนับสนุนการดำเนินการ AllReduce โดยใช้ fp16 รวมถึงการไพพ์ไลน์การไล่ระดับสี AllReduce เพื่อให้ซ้อนทับกับการคำนวณการไล่ระดับสี

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

ความขัดแย้งของเธรดโฮสต์ 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 ไปยังหมายเลขที่ต้องการของหัวข้อ