หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

เพิ่มประสิทธิภาพ TensorFlow GPU ด้วย TensorFlow Profiler

ภาพรวม

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

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

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

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

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

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

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

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

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

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

TensorFlow Profiler Overview Page

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

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

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

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

image

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

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

ขั้นตอนแรกในการดีบักประสิทธิภาพของ GPU คือการตรวจสอบว่าโปรแกรมของคุณเชื่อมต่อกับอินพุตหรือไม่ วิธีที่ง่ายที่สุดในการหาข้อมูลนี้คือการใช้ Input-Pipeline Analyzer ของ 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 work

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

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

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

เคอร์เนล GPU ขนาดเล็กและโฮสต์เคอร์เนลล่าช้าในการเปิดตัว

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

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

image

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

image

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

image

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

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

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

image

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

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

image

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

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

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

การใช้ Tensor Cores

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

สำหรับคำแนะนำโดยละเอียดอื่น ๆ เกี่ยวกับวิธีทำให้เมล็ดมีประสิทธิภาพสำหรับ GPU โปรดดูคู่มือ NVIDIA Deep Learning Performance ซึ่งครอบคลุมเทคนิคต่างๆที่คุณสามารถทดลองได้เช่นการใช้รูปแบบ NCHW เทียบกับ NHWC เพื่อแสดงอินพุตหรือการกำหนดขนาดอินพุตให้เป็น ผลคูณของ 8

Fusing Ops

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

เปิดใช้งาน fp16 และ XLA

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

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

คู่มือ TensorFlow Mixed Precision แสดงวิธีเปิดใช้งานความแม่นยำ fp16 บน GPU เมื่อคำนึงถึงประโยชน์ด้านประสิทธิภาพของ fp16 มีคำแนะนำบางประการที่ควรทราบ

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

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

image

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

Dynamic vs Static Loss Scaling

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

กำลังเปิดใช้งาน XLA

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

เพิ่มประสิทธิภาพให้กับ Multi-GPU Single Host

tf.distribute.MirroredStrategy API สามารถใช้เพื่อปรับขนาดการฝึกโมเดลจาก 1 GPU ไปยัง GPU หลายตัวในโฮสต์เดียว หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการฝึกอบรมแบบกระจายกับ Tensorflow โปรดดูคู่มือ การฝึกอบรมแบบกระจายกับ Keras แม้ว่าการเปลี่ยนจาก GPU หนึ่งไปเป็น GPU หลายตัวควรปรับขนาดได้ทันที แต่บางครั้งคุณอาจพบปัญหาด้านประสิทธิภาพ

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

image

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

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

เพิ่มประสิทธิภาพ Gradient AllReduce

เมื่อฝึกด้วยกลยุทธ์ซิงโครนัสอุปกรณ์แต่ละชิ้นจะได้รับข้อมูลอินพุตบางส่วน หลังจากคำนวณไปข้างหน้าและข้างหลังผ่านโมเดลแล้วการไล่ระดับสีที่คำนวณในแต่ละอุปกรณ์จะต้องมีการรวมและลดลง AllReduce การไล่ระดับสีนี้เกิดขึ้นหลังจากการคำนวณการไล่ระดับสีบนอุปกรณ์แต่ละเครื่องและก่อนที่เครื่องมือเพิ่มประสิทธิภาพจะอัปเดตน้ำหนักของโมเดล GPU แต่ละตัวจะเชื่อมต่อการไล่ระดับสีข้ามเลเยอร์โมเดลก่อนโดยสื่อสารผ่าน GPU โดยใช้ 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 หนึ่งตัวซีพียูสามารถตัดสินใจที่จะใช้เธรดโฮสต์จำนวนมากเพื่อให้ GPU หนึ่งตัวไม่ว่างจากนั้นจึงเปิดเคอร์เนลบน GPU อื่นตามลำดับที่ไม่ได้กำหนด . ซึ่งอาจทำให้การปรับเอียงหรือลบซึ่งอาจส่งผลเสียต่อประสิทธิภาพการทำงาน

โปรแกรมดูการติดตามด้านล่างแสดงค่าใช้จ่ายเมื่อ CPU ส่ายเคอร์เนล GPU ทำงานอย่างไม่มีประสิทธิภาพเนื่องจาก GPU1 ไม่ได้ใช้งานจากนั้นจึงเริ่มรัน ops หลังจากที่ GPU2 เริ่มทำงาน

image

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

image

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

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