TensorFlow प्रोफाइलर के साथ TensorFlow GPU प्रदर्शन को अनुकूलित करें

सिंहावलोकन

यह मार्गदर्शिका आपको दिखाएगी कि अपने GPU के बारे में जानकारी प्राप्त करने और उससे अधिकतम प्रदर्शन प्राप्त करने के लिए TensorBoard के साथ TensorFlow प्रोफाइलर का उपयोग कैसे करें, और जब आपके एक या अधिक GPU का उपयोग कम हो जाए तो डीबग कैसे करें।

यदि आप प्रोफाइलर में नए हैं:

ध्यान रखें कि जीपीयू पर गणनाओं को ऑफलोड करना हमेशा फायदेमंद नहीं हो सकता है, खासकर छोटे मॉडलों के लिए। इसके कारण ओवरहेड हो सकता है:

  • होस्ट (सीपीयू) और डिवाइस (जीपीयू) के बीच डेटा ट्रांसफर; और
  • जब होस्ट जीपीयू कर्नेल लॉन्च करता है तो इसमें शामिल विलंबता के कारण।

प्रदर्शन अनुकूलन वर्कफ़्लो

यह मार्गदर्शिका बताती है कि एकल जीपीयू से शुरू करके, फिर एकाधिक जीपीयू वाले एकल होस्ट पर जाकर प्रदर्शन समस्याओं को कैसे डीबग किया जाए।

निम्नलिखित क्रम में प्रदर्शन समस्याओं को डीबग करने की अनुशंसा की जाती है:

  1. एक GPU पर प्रदर्शन को अनुकूलित और डीबग करें:
    1. जांचें कि क्या इनपुट पाइपलाइन एक अड़चन है।
    2. एक जीपीयू के प्रदर्शन को डीबग करें।
    3. मिश्रित परिशुद्धता सक्षम करें ( fp16 (फ्लोट16) के साथ) और वैकल्पिक रूप से XLA सक्षम करें।
  2. मल्टी-जीपीयू सिंगल होस्ट पर प्रदर्शन को अनुकूलित और डीबग करें।

उदाहरण के लिए, यदि आप एकाधिक जीपीयू के साथ एक ही होस्ट पर एक मॉडल को प्रशिक्षित करने के लिए टेन्सरफ्लो वितरण रणनीति का उपयोग कर रहे हैं और उप-इष्टतम जीपीयू उपयोग को नोटिस करते हैं, तो आपको मल्टी-जीपीयू सिस्टम को डीबग करने से पहले एक जीपीयू के लिए प्रदर्शन को अनुकूलित और डीबग करना चाहिए।

जीपीयू पर परफ़ॉर्मेंट कोड प्राप्त करने के लिए आधार रेखा के रूप में, यह मार्गदर्शिका मानती है कि आप पहले से ही tf.function उपयोग कर रहे हैं। केरस Model.compile और Model.fit एपीआई हुड के तहत स्वचालित रूप से tf.function उपयोग करेंगे। tf.GradientTape के साथ एक कस्टम प्रशिक्षण लूप लिखते समय, tf.function s को सक्षम करने के तरीके के बारे में tf.function के साथ बेहतर प्रदर्शन देखें।

अगले अनुभाग प्रदर्शन बाधाओं को पहचानने और ठीक करने में सहायता के लिए उपरोक्त प्रत्येक परिदृश्य के लिए सुझाए गए दृष्टिकोणों पर चर्चा करते हैं।

1. एक जीपीयू पर प्रदर्शन को अनुकूलित करें

आदर्श स्थिति में, आपके प्रोग्राम में उच्च GPU उपयोग, न्यूनतम CPU (होस्ट) से GPU (डिवाइस) संचार होना चाहिए, और इनपुट पाइपलाइन से कोई ओवरहेड नहीं होना चाहिए।

प्रदर्शन का विश्लेषण करने में पहला कदम एक जीपीयू के साथ चलने वाले मॉडल के लिए एक प्रोफ़ाइल प्राप्त करना है।

TensorBoard का प्रोफाइलर अवलोकन पृष्ठ - जो प्रोफ़ाइल रन के दौरान आपके मॉडल ने कैसा प्रदर्शन किया है, इसका एक शीर्ष स्तरीय दृश्य दिखाता है - यह अंदाजा दे सकता है कि आपका प्रोग्राम आदर्श परिदृश्य से कितना दूर है।

TensorFlow Profiler Overview Page

अवलोकन पृष्ठ पर ध्यान देने योग्य प्रमुख संख्याएँ हैं:

  1. वास्तविक डिवाइस निष्पादन से चरण का कितना समय है
  2. डिवाइस बनाम होस्ट पर रखे गए ऑप्स का प्रतिशत
  3. कितने कर्नेल fp16 उपयोग करते हैं

इष्टतम प्रदर्शन प्राप्त करने का अर्थ है तीनों मामलों में इन संख्याओं को अधिकतम करना। अपने प्रोग्राम की गहराई से समझ पाने के लिए, आपको TensorBoard के प्रोफाइलर ट्रेस व्यूअर से परिचित होना होगा। नीचे दिए गए अनुभाग कुछ सामान्य ट्रेस व्यूअर पैटर्न दिखाते हैं जिन्हें आपको प्रदर्शन बाधाओं का निदान करते समय देखना चाहिए।

नीचे एक जीपीयू पर चल रहे मॉडल ट्रेस व्यू की एक छवि है। TensorFlow नाम स्कोप और TensorFlow Ops अनुभागों से, आप मॉडल के विभिन्न भागों की पहचान कर सकते हैं, जैसे फॉरवर्ड पास, लॉस फ़ंक्शन, बैकवर्ड पास/ग्रेडिएंट गणना और ऑप्टिमाइज़र वेट अपडेट। आप प्रत्येक स्ट्रीम के बगल में GPU पर ऑप्स भी चला सकते हैं, जो CUDA स्ट्रीम को संदर्भित करता है। प्रत्येक स्ट्रीम का उपयोग विशिष्ट कार्यों के लिए किया जाता है। इस ट्रेस में, स्ट्रीम#118 का उपयोग कंप्यूट कर्नेल और डिवाइस-टू-डिवाइस प्रतियां लॉन्च करने के लिए किया जाता है। स्ट्रीम#119 का उपयोग होस्ट-टू-डिवाइस कॉपी के लिए और स्ट्रीम#120 का उपयोग डिवाइस से होस्ट कॉपी के लिए किया जाता है।

नीचे दिया गया ट्रेस एक निष्पादक मॉडल की सामान्य विशेषताओं को दर्शाता है।

image

उदाहरण के लिए, GPU कंप्यूट टाइमलाइन ( स्ट्रीम#118 ) बहुत कम अंतराल के साथ "व्यस्त" दिखती है। होस्ट से डिवाइस ( स्ट्रीम #119 ) और डिवाइस से होस्ट ( स्ट्रीम #120 ) पर न्यूनतम प्रतियां हैं, साथ ही चरणों के बीच न्यूनतम अंतराल भी हैं। जब आप अपने प्रोग्राम के लिए प्रोफाइलर चलाते हैं, तो आप अपने ट्रेस व्यू में इन आदर्श विशेषताओं की पहचान करने में सक्षम नहीं हो सकते हैं। इस मार्गदर्शिका के शेष भाग में सामान्य परिदृश्य और उन्हें ठीक करने के तरीके शामिल हैं।

1. इनपुट पाइपलाइन को डीबग करें

GPU प्रदर्शन डिबगिंग में पहला चरण यह निर्धारित करना है कि आपका प्रोग्राम इनपुट-बाउंड है या नहीं। इसका पता लगाने का सबसे आसान तरीका टेन्सरबोर्ड पर प्रोफाइलर के इनपुट-पाइपलाइन विश्लेषक का उपयोग करना है, जो इनपुट पाइपलाइन में बिताए गए समय का अवलोकन प्रदान करता है।

image

यदि आपकी इनपुट-पाइपलाइन कदम समय में महत्वपूर्ण योगदान देती है तो आप निम्नलिखित संभावित कार्रवाई कर सकते हैं:

  • आप अपनी इनपुट पाइपलाइन को डीबग करने का तरीका जानने के लिए tf.data -विशिष्ट मार्गदर्शिका का उपयोग कर सकते हैं।
  • यह जांचने का एक और त्वरित तरीका है कि इनपुट पाइपलाइन बाधा है या नहीं, यादृच्छिक रूप से उत्पन्न इनपुट डेटा का उपयोग करना है जिसे किसी पूर्व-प्रसंस्करण की आवश्यकता नहीं है। ResNet मॉडल के लिए इस तकनीक का उपयोग करने का एक उदाहरण यहां दिया गया है । यदि इनपुट पाइपलाइन इष्टतम है, तो आपको वास्तविक डेटा और उत्पन्न यादृच्छिक/सिंथेटिक डेटा के साथ समान प्रदर्शन का अनुभव करना चाहिए। सिंथेटिक डेटा मामले में एकमात्र ओवरहेड इनपुट डेटा कॉपी के कारण होगा जिसे फिर से प्रीफ़ेच और अनुकूलित किया जा सकता है।

इसके अलावा, इनपुट डेटा पाइपलाइन को अनुकूलित करने के लिए सर्वोत्तम प्रथाओं का संदर्भ लें।

2. एक जीपीयू के प्रदर्शन को डीबग करें

ऐसे कई कारक हैं जो कम GPU उपयोग में योगदान कर सकते हैं। नीचे कुछ परिदृश्य दिए गए हैं जो आमतौर पर ट्रेस व्यूअर और संभावित समाधानों को देखते समय देखे जाते हैं।

1. चरणों के बीच अंतराल का विश्लेषण करें

जब आपका प्रोग्राम इष्टतम रूप से नहीं चल रहा हो तो एक सामान्य अवलोकन प्रशिक्षण चरणों के बीच अंतराल है। नीचे दिए गए ट्रेस दृश्य की छवि में, चरण 8 और 9 के बीच एक बड़ा अंतर है, जिसका अर्थ है कि उस दौरान GPU निष्क्रिय है।

image

यदि आपका ट्रेस व्यूअर चरणों के बीच बड़े अंतराल दिखाता है, तो यह एक संकेत हो सकता है कि आपका प्रोग्राम इनपुट बाउंड है। उस स्थिति में आपको अपनी इनपुट पाइपलाइन को डीबग करने पर पिछले अनुभाग का संदर्भ लेना चाहिए यदि आपने पहले से ऐसा नहीं किया है।

हालाँकि, एक अनुकूलित इनपुट पाइपलाइन के साथ भी, सीपीयू थ्रेड विवाद के कारण आपके पास अभी भी एक चरण के अंत और दूसरे की शुरुआत के बीच अंतराल हो सकता है। tf.data पाइपलाइन प्रोसेसिंग को समानांतर करने के लिए बैकग्राउंड थ्रेड्स का उपयोग करता है। ये थ्रेड प्रत्येक चरण की शुरुआत में होने वाली GPU होस्ट-साइड गतिविधि में हस्तक्षेप कर सकते हैं, जैसे डेटा की प्रतिलिपि बनाना या GPU संचालन शेड्यूल करना।

यदि आप होस्ट साइड पर बड़े अंतराल देखते हैं, जो GPU पर इन ऑप्स को शेड्यूल करता है, तो आप पर्यावरण चर TF_GPU_THREAD_MODE=gpu_private सेट कर सकते हैं। यह सुनिश्चित करता है कि GPU कर्नेल अपने स्वयं के समर्पित थ्रेड्स से लॉन्च किए गए हैं, और tf.data कार्य के पीछे कतारबद्ध नहीं हैं।

चरणों के बीच अंतराल मीट्रिक गणना, केरस कॉलबैक या होस्ट पर चलने वाले tf.function के बाहर के ऑप्स के कारण भी हो सकता है। इन ऑप्स का प्रदर्शन TensorFlow ग्राफ़ के अंदर के ऑप्स जितना अच्छा नहीं है। इसके अतिरिक्त, इनमें से कुछ ऑप्स सीपीयू पर चलते हैं और जीपीयू से टेंसर को आगे और पीछे कॉपी करते हैं।

यदि अपनी इनपुट पाइपलाइन को अनुकूलित करने के बाद भी आपको ट्रेस व्यूअर में चरणों के बीच अंतराल दिखाई देता है, तो आपको चरणों के बीच मॉडल कोड को देखना चाहिए और जांचना चाहिए कि कॉलबैक/मेट्रिक्स को अक्षम करने से प्रदर्शन में सुधार होता है या नहीं। इन ऑप्स के कुछ विवरण ट्रेस व्यूअर (डिवाइस और होस्ट दोनों तरफ) पर भी हैं। इस परिदृश्य में अनुशंसा प्रत्येक चरण के बजाय चरणों की एक निश्चित संख्या के बाद निष्पादित करके इन ऑप्स के ओवरहेड को परिशोधित करने की है। tf.keras API में Model.compile विधि का उपयोग करते समय, steps_per_execution फ़्लैग सेट करने से यह स्वचालित रूप से होता है। कस्टम प्रशिक्षण लूप के लिए, tf.while_loop उपयोग करें।

2. उच्च उपकरण उपयोग प्राप्त करें

1. छोटे जीपीयू कर्नेल और होस्ट कर्नेल लॉन्च में देरी

होस्ट कर्नेल को GPU पर चलाने के लिए कतारबद्ध करता है, लेकिन कर्नेल को वास्तव में GPU पर निष्पादित करने से पहले एक विलंबता (लगभग 20-40 μs) शामिल होती है। एक आदर्श स्थिति में, होस्ट जीपीयू पर पर्याप्त कर्नेल को एनक्यू करता है जैसे कि जीपीयू अधिक कर्नेल को एनक्यू करने के लिए होस्ट की प्रतीक्षा करने के बजाय अपना अधिकांश समय निष्पादित करने में व्यतीत करता है।

TensorBoard पर प्रोफाइलर का अवलोकन पृष्ठ दिखाता है कि कर्नेल लॉन्च करने के लिए होस्ट की प्रतीक्षा के कारण GPU कितने समय तक निष्क्रिय रहा। नीचे दी गई छवि में, कर्नेल के लॉन्च होने की प्रतीक्षा में लगभग 10% चरण समय के लिए GPU निष्क्रिय है।

image

इसी प्रोग्राम के लिए ट्रेस व्यूअर कर्नेल के बीच छोटे अंतराल दिखाता है जहां होस्ट जीपीयू पर कर्नेल लॉन्च करने में व्यस्त है।

image

GPU पर बहुत सारे छोटे ऑप्स लॉन्च करके (उदाहरण के लिए स्केलर ऐड की तरह), होस्ट GPU के साथ तालमेल नहीं रख सकता है। उसी प्रोफ़ाइल के लिए TensorBoard में TensorFlow आँकड़े उपकरण 2.77 सेकंड लेते हुए 126,224 मूल ऑपरेशन दिखाता है। इस प्रकार, प्रत्येक कर्नेल लगभग 21.9 μs है, जो बहुत छोटा है (लगभग लॉन्च विलंबता के समान समय) और संभावित रूप से होस्ट कर्नेल लॉन्च में देरी हो सकती है।

image

यदि आपका ट्रेस व्यूअर उपरोक्त छवि की तरह GPU पर ऑप्स के बीच कई छोटे अंतराल दिखाता है, तो आप यह कर सकते हैं:

  • छोटे टेंसरों को संयोजित करें और वेक्टरकृत ऑप्स का उपयोग करें या प्रत्येक लॉन्च किए गए कर्नेल को अधिक काम करने के लिए बड़े बैच आकार का उपयोग करें, जो GPU को अधिक समय तक व्यस्त रखेगा।
  • सुनिश्चित करें कि आप TensorFlow ग्राफ़ बनाने के लिए tf.function उपयोग कर रहे हैं, ताकि आप ऑप्स को शुद्ध उत्सुक मोड में न चला रहे हों। यदि आप Model.fit उपयोग कर रहे हैं ( tf.GradientTape के साथ कस्टम प्रशिक्षण लूप के विपरीत), तो tf.keras.Model.compile स्वचालित रूप से आपके लिए यह करेगा।
  • tf.function(jit_compile=True) या ऑटो-क्लस्टरिंग के साथ XLA का उपयोग करके फ्यूज कर्नेल। अधिक जानकारी के लिए, उच्च प्रदर्शन प्राप्त करने के लिए XLA को सक्षम करने का तरीका जानने के लिए नीचे मिश्रित परिशुद्धता और XLA सक्षम करें अनुभाग पर जाएँ। यह सुविधा उच्च डिवाइस उपयोग को जन्म दे सकती है।
2. टेंसरफ्लो ऑप प्लेसमेंट

प्रोफाइलर अवलोकन पृष्ठ आपको होस्ट बनाम डिवाइस पर रखे गए ऑप्स का प्रतिशत दिखाता है (आप ट्रेस व्यूअर को देखकर विशिष्ट ऑप्स के प्लेसमेंट को भी सत्यापित कर सकते हैं। नीचे दी गई छवि की तरह, आप होस्ट पर ऑप्स का प्रतिशत चाहते हैं डिवाइस की तुलना में बहुत छोटा होना।

image

आदर्श रूप से, अधिकांश गणना गहन ऑप्स को GPU पर रखा जाना चाहिए।

यह पता लगाने के लिए कि आपके मॉडल में संचालन और टेंसर किन उपकरणों को सौंपे गए हैं, tf.debugging.set_log_device_placement(True) अपने प्रोग्राम के पहले स्टेटमेंट के रूप में सेट करें।

ध्यान दें कि कुछ मामलों में, भले ही आप किसी विशेष डिवाइस पर रखे जाने वाले ऑप को निर्दिष्ट करते हैं, इसका कार्यान्वयन इस स्थिति को ओवरराइड कर सकता है (उदाहरण: tf.unique )। यहां तक ​​कि एकल जीपीयू प्रशिक्षण के लिए, वितरण रणनीति निर्दिष्ट करने से, जैसे कि tf.distribute.OneDeviceStrategy , आपके डिवाइस पर ऑप्स की अधिक नियतात्मक नियुक्ति हो सकती है।

अधिकांश ऑप्स को GPU पर रखने का एक कारण होस्ट और डिवाइस के बीच अत्यधिक मेमोरी कॉपी को रोकना है (होस्ट और डिवाइस के बीच मॉडल इनपुट/आउटपुट डेटा के लिए मेमोरी कॉपी अपेक्षित है)। अत्यधिक नकल का एक उदाहरण नीचे दिए गए ट्रेस दृश्य में GPU स्ट्रीम #167 , #168 , और #169 पर प्रदर्शित किया गया है।

image

यदि ये प्रतिलिपियाँ GPU कर्नेल को निष्पादित होने से रोकती हैं तो कभी-कभी प्रदर्शन को नुकसान पहुँच सकता है। ट्रेस व्यूअर में मेमोरी कॉपी ऑपरेशंस में उन ऑप्स के बारे में अधिक जानकारी होती है जो इन कॉपी किए गए टेंसरों का स्रोत हैं, लेकिन एक मेमकॉपी को एक ऑप के साथ जोड़ना हमेशा आसान नहीं हो सकता है। इन मामलों में, यह जांचने के लिए आस-पास के ऑप्स को देखना सहायक होता है कि क्या मेमोरी कॉपी हर चरण में एक ही स्थान पर होती है।

3. GPU पर अधिक कुशल कर्नेल

एक बार जब आपके प्रोग्राम का GPU उपयोग स्वीकार्य हो जाता है, तो अगला कदम Tensor Cores या फ़्यूज़िंग ऑप्स का उपयोग करके GPU कर्नेल की दक्षता बढ़ाने पर विचार करना है।

1. टेंसर कोर का उपयोग करें

आधुनिक NVIDIA® GPU में विशेष Tensor Cores हैं जो योग्य कर्नेल के प्रदर्शन में उल्लेखनीय सुधार कर सकते हैं।

आप यह देखने के लिए TensorBoard के GPU कर्नेल आँकड़ों का उपयोग कर सकते हैं कि कौन से GPU कर्नेल Tensor Core-योग्य हैं, और कौन से कर्नेल Tensor Cores का उपयोग कर रहे हैं। fp16 सक्षम करना (नीचे मिश्रित परिशुद्धता अनुभाग को सक्षम करना देखें) आपके प्रोग्राम के जनरल मैट्रिक्स मल्टीप्ली (GEMM) कर्नेल (मैटमुल ऑप्स) को टेन्सर कोर का उपयोग करने का एक तरीका है। जब परिशुद्धता fp16 होती है और इनपुट/आउटपुट टेंसर आयाम 8 या 16 ( int8 के लिए) से विभाज्य होते हैं, तो GPU कर्नेल टेन्सर कोर का कुशलतापूर्वक उपयोग करते हैं।

जीपीयू के लिए कर्नेल को कुशल कैसे बनाया जाए, इस पर अन्य विस्तृत अनुशंसाओं के लिए, NVIDIA® गहन शिक्षण प्रदर्शन मार्गदर्शिका देखें।

2. फ़्यूज़ ऑप्स

बड़े कर्नेल बनाने के लिए छोटे ऑप्स को फ़्यूज़ करने के लिए tf.function(jit_compile=True) उपयोग करें जिससे महत्वपूर्ण प्रदर्शन लाभ प्राप्त होता है। अधिक जानने के लिए, XLA गाइड देखें।

3. मिश्रित परिशुद्धता और XLA सक्षम करें

उपरोक्त चरणों का पालन करने के बाद, मिश्रित परिशुद्धता और XLA को सक्षम करना दो वैकल्पिक कदम हैं जिन्हें आप प्रदर्शन को और बेहतर बनाने के लिए उठा सकते हैं। सुझाया गया दृष्टिकोण उन्हें एक-एक करके सक्षम करना और यह सत्यापित करना है कि प्रदर्शन लाभ अपेक्षा के अनुरूप हैं।

1. मिश्रित परिशुद्धता सक्षम करें

TensorFlow मिश्रित परिशुद्धता गाइड दिखाता है कि GPU पर fp16 परिशुद्धता कैसे सक्षम करें। टेन्सर कोर का उपयोग करने के लिए NVIDIA® GPU पर AMP सक्षम करें और वोल्टा और नए GPU आर्किटेक्चर पर केवल fp32 (फ्लोट32) परिशुद्धता का उपयोग करने की तुलना में 3x समग्र स्पीडअप का एहसास करें।

सुनिश्चित करें कि मैट्रिक्स/टेंसर आयाम टेन्सर कोर का उपयोग करने वाले कर्नेल को कॉल करने के लिए आवश्यकताओं को पूरा करते हैं। जब परिशुद्धता fp16 होती है और इनपुट/आउटपुट आयाम 8 या 16 (int8 के लिए) से विभाज्य होते हैं, तो GPU कर्नेल टेन्सर कोर का कुशलतापूर्वक उपयोग करते हैं।

ध्यान दें कि cuDNN v7.6.3 और बाद के संस्करण के साथ, टेन्सर कोर का लाभ उठाने के लिए जहां आवश्यक हो वहां कनवल्शन आयाम स्वचालित रूप से पैड किए जाएंगे।

fp16 परिशुद्धता के प्रदर्शन लाभों को अधिकतम करने के लिए नीचे दी गई सर्वोत्तम प्रथाओं का पालन करें।

1. इष्टतम fp16 कर्नेल का उपयोग करें

fp16 सक्षम होने पर, आपके प्रोग्राम के मैट्रिक्स गुणन (जीईएमएम) कर्नेल को संबंधित fp16 संस्करण का उपयोग करना चाहिए जो टेन्सर कोर का उपयोग करता है। हालाँकि, कुछ मामलों में, ऐसा नहीं होता है और आपको fp16 सक्षम करने से अपेक्षित गति का अनुभव नहीं होता है, क्योंकि आपका प्रोग्राम इसके बजाय अकुशल कार्यान्वयन पर वापस आ जाता है।

image

GPU कर्नेल आँकड़े पृष्ठ दिखाता है कि कौन से ऑप्स Tensor Core योग्य हैं और कौन से कर्नेल वास्तव में कुशल Tensor Core का उपयोग कर रहे हैं। गहन शिक्षण प्रदर्शन पर NVIDIA® गाइड में टेन्सर कोर का लाभ उठाने के बारे में अतिरिक्त सुझाव शामिल हैं। इसके अतिरिक्त, fp16 का उपयोग करने के लाभ उन कर्नेल में भी दिखाई देंगे जो पहले मेमोरी बाउंड थे, क्योंकि अब ऑप्स में आधा समय लगेगा।

2. गतिशील बनाम स्थैतिक हानि स्केलिंग

कम परिशुद्धता के कारण अंडरफ़्लो को रोकने के लिए fp16 उपयोग करते समय हानि स्केलिंग आवश्यक है। हानि स्केलिंग दो प्रकार की होती है, गतिशील और स्थिर, दोनों को मिश्रित परिशुद्धता मार्गदर्शिका में अधिक विस्तार से समझाया गया है। आप केरस ऑप्टिमाइज़र के भीतर हानि स्केलिंग को स्वचालित रूप से सक्षम करने के लिए mixed_float16 नीति का उपयोग कर सकते हैं।

प्रदर्शन को अनुकूलित करने का प्रयास करते समय, यह याद रखना महत्वपूर्ण है कि गतिशील हानि स्केलिंग होस्ट पर चलने वाले अतिरिक्त सशर्त ऑप्स को पेश कर सकती है, और अंतराल पैदा कर सकती है जो ट्रेस व्यूअर में चरणों के बीच दिखाई देगी। दूसरी ओर, स्थैतिक हानि स्केलिंग में ऐसे ओवरहेड्स नहीं होते हैं और प्रदर्शन के मामले में यह एक बेहतर विकल्प हो सकता है, जिसमें आपको सही स्थैतिक-हानि स्केल मान निर्दिष्ट करने की आवश्यकता होती है।

2. XLA को tf.function(git_compile=True) या ऑटो-क्लस्टरिंग के साथ सक्षम करें

एकल जीपीयू के साथ सर्वोत्तम प्रदर्शन प्राप्त करने के अंतिम चरण के रूप में, आप XLA को सक्षम करने के साथ प्रयोग कर सकते हैं, जो ऑप्स को फ्यूज करेगा और बेहतर डिवाइस उपयोग और कम मेमोरी फ़ुटप्रिंट को जन्म देगा। tf.function(jit_compile=True) या ऑटो-क्लस्टरिंग के साथ अपने प्रोग्राम में XLA को सक्षम करने के तरीके के विवरण के लिए, XLA गाइड देखें।

आप वैश्विक JIT स्तर को -1 (बंद), 1 , या 2 पर सेट कर सकते हैं। उच्च स्तर अधिक आक्रामक होता है और समानता को कम कर सकता है और अधिक मेमोरी का उपयोग कर सकता है। यदि आपके पास स्मृति प्रतिबंध हैं तो मान को 1 पर सेट करें। ध्यान दें कि XLA वैरिएबल इनपुट टेंसर आकृतियों वाले मॉडलों के लिए अच्छा प्रदर्शन नहीं करता है क्योंकि XLA कंपाइलर को जब भी नई आकृतियाँ मिलती हैं तो उसे कर्नेल संकलित करना पड़ता है।

2. मल्टी-जीपीयू सिंगल होस्ट पर प्रदर्शन को अनुकूलित करें

tf.distribute.MirroredStrategy API का उपयोग एक ही होस्ट पर एक GPU से एकाधिक GPU तक मॉडल प्रशिक्षण को स्केल करने के लिए किया जा सकता है। (TensorFlow के साथ वितरित प्रशिक्षण कैसे करें, इसके बारे में अधिक जानने के लिए, TensorFlow के साथ वितरित प्रशिक्षण , GPU का उपयोग करें , और TPU गाइड का उपयोग करें और Keras ट्यूटोरियल के साथ वितरित प्रशिक्षण देखें ।)

यद्यपि एक जीपीयू से एकाधिक जीपीयू में संक्रमण आदर्श रूप से बॉक्स से बाहर स्केलेबल होना चाहिए, आप कभी-कभी प्रदर्शन समस्याओं का सामना कर सकते हैं।

एक ही होस्ट पर एक ही जीपीयू से कई जीपीयू के साथ प्रशिक्षण पर जाते समय, आदर्श रूप से आपको केवल ग्रेडिएंट संचार के अतिरिक्त ओवरहेड और बढ़े हुए होस्ट थ्रेड उपयोग के साथ प्रदर्शन स्केलिंग का अनुभव करना चाहिए। इस ओवरहेड के कारण, उदाहरण के लिए, यदि आप 1 से 2 जीपीयू पर जाते हैं तो आपके पास सटीक 2x स्पीडअप नहीं होगा।

नीचे दिया गया ट्रेस दृश्य एकाधिक जीपीयू पर प्रशिक्षण के दौरान अतिरिक्त संचार ओवरहेड का एक उदाहरण दिखाता है। ग्रेडिएंट्स को संयोजित करने, उन्हें प्रतिकृतियों में संप्रेषित करने और वजन अद्यतन करने से पहले उन्हें विभाजित करने के लिए कुछ ओवरहेड है।

image

मल्टी-जीपीयू परिदृश्य में प्रदर्शन को अनुकूलित करते समय निम्नलिखित चेकलिस्ट आपको बेहतर प्रदर्शन प्राप्त करने में मदद करेगी:

  1. बैच आकार को अधिकतम करने का प्रयास करें, जिससे डिवाइस का उपयोग अधिक होगा और कई जीपीयू में संचार की लागत में कमी आएगी। मेमोरी प्रोफाइलर का उपयोग करने से यह समझने में मदद मिलती है कि आपका प्रोग्राम चरम मेमोरी उपयोग के कितना करीब है। ध्यान दें कि जबकि उच्च बैच आकार अभिसरण को प्रभावित कर सकता है, यह आमतौर पर प्रदर्शन लाभों से अधिक होता है।
  2. एक जीपीयू से एकाधिक जीपीयू में जाने पर, एक ही होस्ट को अब बहुत अधिक इनपुट डेटा प्रोसेस करना पड़ता है। इसलिए, (1) के बाद, इनपुट पाइपलाइन के प्रदर्शन की दोबारा जांच करने और यह सुनिश्चित करने की सिफारिश की जाती है कि यह कोई बाधा नहीं है।
  3. किसी भी अनावश्यक AllReduce कॉल के लिए अपने प्रोग्राम के ट्रेस व्यू में GPU टाइमलाइन की जाँच करें, क्योंकि इसके परिणामस्वरूप सभी डिवाइसों में एक सिंक्रनाइज़ेशन होता है। ऊपर दिखाए गए ट्रेस दृश्य में, AllReduce NCCL कर्नेल के माध्यम से किया जाता है, और प्रत्येक चरण पर ग्रेडिएंट के लिए प्रत्येक GPU पर केवल एक NCCL कॉल होती है।
  4. अनावश्यक D2H, H2D और D2D प्रतिलिपि संचालन की जाँच करें जिन्हें कम किया जा सकता है।
  5. यह सुनिश्चित करने के लिए चरण समय की जाँच करें कि प्रत्येक प्रतिकृति समान कार्य कर रही है। उदाहरण के लिए, ऐसा हो सकता है कि एक GPU (आमतौर पर, GPU0 ) ओवरसब्सक्राइब हो जाता है क्योंकि होस्ट गलती से उस पर अधिक काम कर देता है।
  6. अंत में, क्रमिक रूप से निष्पादित होने वाले किसी भी ऑप्स के लिए अपने ट्रेस व्यू में सभी जीपीयू में प्रशिक्षण चरण की जांच करें। यह आमतौर पर तब होता है जब आपके प्रोग्राम में एक जीपीयू से दूसरे जीपीयू पर नियंत्रण निर्भरता शामिल होती है। अतीत में, इस स्थिति में प्रदर्शन की डिबगिंग को मामला-दर-मामला आधार पर हल किया गया है। यदि आप अपने प्रोग्राम में इस व्यवहार को देखते हैं, तो अपने ट्रेस व्यू की छवियों के साथ GitHub समस्या दर्ज करें

1. ग्रेडिएंट AllReduce को अनुकूलित करें

एक तुल्यकालिक रणनीति के साथ प्रशिक्षण करते समय, प्रत्येक डिवाइस को इनपुट डेटा का एक हिस्सा प्राप्त होता है।

मॉडल के माध्यम से आगे और पीछे की गणना करने के बाद, प्रत्येक डिवाइस पर गणना किए गए ग्रेडिएंट को एकत्रित और कम करने की आवश्यकता होती है। यह ग्रेडिएंट AllReduce प्रत्येक डिवाइस पर ग्रेडिएंट गणना के बाद और ऑप्टिमाइज़र द्वारा मॉडल वेट अपडेट करने से पहले होता है।

प्रत्येक GPU पहले मॉडल परतों में ग्रेडिएंट्स को जोड़ता है, उन्हें tf.distribute.CrossDeviceOps ( tf.distribute.NcclAllReduce डिफ़ॉल्ट है) का उपयोग करके GPU में संचारित करता है, और फिर प्रति परत कमी के बाद ग्रेडिएंट्स लौटाता है।

ऑप्टिमाइज़र आपके मॉडल के वज़न को अपडेट करने के लिए इन कम ग्रेडिएंट्स का उपयोग करेगा। आदर्श रूप से, किसी भी ओवरहेड्स को रोकने के लिए यह प्रक्रिया सभी जीपीयू पर एक ही समय में होनी चाहिए।

AllReduce का समय लगभग समान होना चाहिए:

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

यह गणना यह समझने के लिए एक त्वरित जांच के रूप में उपयोगी है कि वितरित प्रशिक्षण कार्य चलाने के दौरान आपका प्रदर्शन अपेक्षित है या नहीं, या क्या आपको आगे प्रदर्शन डीबगिंग करने की आवश्यकता है। आप अपने मॉडल में पैरामीटर्स की संख्या Model.summary से प्राप्त कर सकते हैं।

ध्यान दें कि प्रत्येक मॉडल पैरामीटर का आकार 4 बाइट्स है क्योंकि TensorFlow ग्रेडिएंट्स को संचारित करने के लिए fp32 (फ्लोट32) का उपयोग करता है। यहां तक ​​कि जब आपने fp16 सक्षम किया हुआ है, तब भी NCCL AllReduce fp32 पैरामीटर का उपयोग करता है।

स्केलिंग का लाभ प्राप्त करने के लिए, इन ओवरहेड्स की तुलना में चरण-समय बहुत अधिक होना चाहिए। इसे प्राप्त करने का एक तरीका उच्च बैच आकार का उपयोग करना है क्योंकि बैच आकार चरण समय को प्रभावित करता है, लेकिन संचार ओवरहेड को प्रभावित नहीं करता है।

2. GPU होस्ट थ्रेड विवाद

एकाधिक जीपीयू चलाते समय, सीपीयू का काम सभी डिवाइसों में जीपीयू कर्नेल को कुशलतापूर्वक लॉन्च करके सभी डिवाइसों को व्यस्त रखना है।

हालाँकि, जब बहुत सारे स्वतंत्र ऑपरेशन होते हैं जिन्हें सीपीयू एक जीपीयू पर शेड्यूल कर सकता है, तो सीपीयू एक जीपीयू को व्यस्त रखने के लिए अपने कई होस्ट थ्रेड्स का उपयोग करने का निर्णय ले सकता है, और फिर गैर-नियतात्मक क्रम में दूसरे जीपीयू पर कर्नेल लॉन्च कर सकता है। . इससे विषमता या नकारात्मक स्केलिंग हो सकती है, जो प्रदर्शन को नकारात्मक रूप से प्रभावित कर सकती है।

नीचे दिया गया ट्रेस व्यूअर ओवरहेड दिखाता है जब सीपीयू जीपीयू कर्नेल को अक्षम रूप से लॉन्च करता है, क्योंकि GPU1 निष्क्रिय है और फिर GPU2 शुरू होने के बाद ऑप्स चलाना शुरू कर देता है।

image

होस्ट के लिए ट्रेस दृश्य से पता चलता है कि होस्ट GPU1 पर लॉन्च करने से पहले GPU2 पर कर्नेल लॉन्च कर रहा है (ध्यान दें कि नीचे दिए गए tf_Compute* ऑप्स CPU थ्रेड्स के संकेतक नहीं हैं)।

image

यदि आप अपने प्रोग्राम के ट्रेस व्यू में GPU कर्नेल की इस प्रकार की चौंका देने वाली स्थिति का अनुभव करते हैं, तो अनुशंसित कार्रवाई यह है:

  • TensorFlow पर्यावरण चर TF_GPU_THREAD_MODE gpu_private पर सेट करें। यह पर्यावरण चर होस्ट को GPU के लिए थ्रेड्स को निजी रखने के लिए कहेगा।
  • डिफ़ॉल्ट रूप से, TF_GPU_THREAD_MODE=gpu_private थ्रेड्स की संख्या 2 पर सेट करता है, जो अधिकांश मामलों में पर्याप्त है। हालाँकि, उस संख्या को TensorFlow पर्यावरण चर TF_GPU_THREAD_COUNT थ्रेड की वांछित संख्या पर सेट करके बदला जा सकता है।