इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

TF प्रोफाइलर के साथ tf.data प्रदर्शन का विश्लेषण करें

अवलोकन

यह गाइड TensorFlow Profiler और tf.data साथ परिचित है। इसका उद्देश्य उपयोगकर्ताओं को निदान और इनपुट पाइपलाइन प्रदर्शन समस्याओं को ठीक करने में मदद करने के लिए उदाहरणों के साथ कदम से कदम निर्देश प्रदान करना है।

शुरू करने के लिए, अपने TensorFlow जॉब की एक प्रोफ़ाइल एकत्र करें। ऐसा करने के निर्देश सीपीयू / जीपीयू और क्लाउड टीपीयू के लिए उपलब्ध हैं।

TensorFlow Trace Viewer

नीचे दिए गए विश्लेषण वर्कफ़्लो प्रोफाइलर टूल में प्रोफाइलर टूल पर केंद्रित है। यह उपकरण एक समयरेखा प्रदर्शित करता है जो आपके TensorFlow कार्यक्रम द्वारा निष्पादित ऑप्स की अवधि को दर्शाता है और आपको यह पहचानने की अनुमति देता है कि कौन सा ऑप्स निष्पादित करने में सबसे लंबा समय लेता है। ट्रेस दर्शक पर अधिक जानकारी के लिए, TF Profiler गाइड के इस भाग को देखें। सामान्य तौर पर, tf.data ईवेंट होस्ट CPU टाइमलाइन पर दिखाई देगा।

विश्लेषण वर्कफ़्लो

कृपया नीचे दिए गए वर्कफ़्लो का पालन करें। यदि आपके पास इसे बेहतर बनाने में हमारी सहायता करने के लिए फीडबैक है, तो कृपया "कॉम्प: डेटा" लेबल के साथ जीथब्यू इश्यू बनाएं

1. क्या आपका tf.data पाइपलाइन काफी तेजी से डेटा का उत्पादन कर रहा है?

यह पता लगाने से शुरू करें कि क्या इनपुट पाइपलाइन आपके TensorFlow प्रोग्राम के लिए अड़चन है।

ऐसा करने के लिए, ट्रेस दर्शक में IteratorGetNext::DoCompute ops देखें। सामान्य तौर पर, आप चरण की शुरुआत में इन्हें देखने की उम्मीद करते हैं। ये स्लाइस आपके इनपुट पाइप लाइन के तत्वों के एक बैच के उत्पादन में लगने वाले समय का प्रतिनिधित्व करते हैं जब यह अनुरोध किया जाता है। आप keras का उपयोग कर या एक में अपने डाटासेट से अधिक पुनरावृत्ति कर रहे हैं tf.function , इन में पाया जाना चाहिए tf_data_iterator_get_next धागे।

ध्यान दें कि यदि आप वितरण रणनीति का उपयोग कर रहे हैं, तो आप IteratorGetNextAsOptional::DoCompute देख सकते हैं: IteratorGetNextAsOptional::DoCompute बजाय IteratorGetNextAsOptional::DoCompute इवेंट IteratorGetNext::DoCompute (TF 2.3 के रूप में)।

image

यदि कॉल जल्दी लौटते हैं (<= 50 us), इसका मतलब है कि आपका डेटा उपलब्ध होने पर अनुरोध किया जाता है। इनपुट पाइपलाइन आपकी अड़चन नहीं है; अधिक सामान्य प्रदर्शन विश्लेषण सुझावों के लिए प्रोफाइलर गाइड देखें।

image

यदि कॉल धीरे-धीरे वापस tf.data है , तो tf.data उपभोक्ता के अनुरोधों को पूरा करने में असमर्थ है। अगले भाग पर जारी रखें।

2. क्या आप डेटा प्रीफ़ेट कर रहे हैं?

इनपुट पाइपलाइन प्रदर्शन के लिए सबसे अच्छा अभ्यास अपने tf.data पाइपलाइन के अंत में एक tf.data.Dataset.prefetch परिवर्तन सम्मिलित करना है। यह परिवर्तन मॉडल कम्प्यूटेशन के अगले चरण के साथ इनपुट पाइपलाइन की प्रीप्रोसेसिंग गणना को ओवरलैप करता है और आपके मॉडल को प्रशिक्षित करते समय इष्टतम इनपुट पाइपलाइन प्रदर्शन के लिए आवश्यक है। यदि आप डेटा IteratorGetNext::DoCompute कर रहे हैं, तो आपको Iterator::Prefetch देखना चाहिए Iterator::Prefetch IteratorGetNext::DoCompute op के समान धागे पर IteratorGetNext::DoCompute

image

यदि आपके पास अपनी पाइपलाइन के अंत में prefetch नहीं है , तो आपको एक जोड़ना चाहिए। tf.data प्रदर्शन अनुशंसाओं के बारे में अधिक जानकारी के लिए, tf.data प्रदर्शन मार्गदर्शिका देखें

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

3. क्या आप उच्च CPU उपयोग तक पहुँच रहे हैं?

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

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

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

tf.data में अनावश्यक गणना से बचकर आप अपने इनपुट पाइपलाइन की दक्षता में सुधार कर सकते हैं। ऐसा करने का एक तरीका यह है कि कम्प्यूट-इंटेंसिव कार्य के बाद tf.data.Dataset.cache परिवर्तन सम्मिलित किया tf.data.Dataset.cache यदि आपका डेटा मेमोरी में फिट बैठता है; यह स्मृति के उपयोग में वृद्धि की गणना को कम करता है। इसके अतिरिक्त, tf.data में इंट्रा-ओप समानता की tf.data में दक्षता में 10% की वृद्धि करने की क्षमता है, और आपके इनपुट पाइपलाइन पर निम्न विकल्प सेट करके किया जा सकता है:

 dataset = ...
options = tf.data.Options()
options.experimental_threading.max_intra_op_parallelism = 1
dataset = dataset.with_options(options)
 

4. टोंटी विश्लेषण

निम्न अनुभाग ट्रेस में कैसे tf.data ईवेंट्स पढ़ने के लिए चलता है, ट्रेस व्यूअर में यह समझने के लिए कि अड़चन कहां है और संभव शमन रणनीतियों।

Profiler में tf.data घटनाओं को समझना

Profiler में प्रत्येक tf.data ईवेंट का नाम Iterator::<Dataset> , जहां <Dataset> डेटासेट स्रोत या परिवर्तन का नाम है। प्रत्येक ईवेंट में लंबा नाम Iterator::<Dataset_1>::...::<Dataset_n> , जिसे आप tf.data इवेंट पर क्लिक करके देख सकते हैं। लंबे नाम में, <Dataset_n> <Dataset> ( <Dataset> ) नाम से (लघु) नाम से मेल खाता है, और लंबे नाम में अन्य डेटासेट डाउनस्ट्रीम परिवर्तनों का प्रतिनिधित्व करते हैं।

image

उदाहरण के लिए, उपरोक्त स्क्रीनशॉट निम्न कोड से उत्पन्न किया गया था:

 dataset = tf.data.Dataset.range(10)
dataset = dataset.map(lambda x: x)
dataset = dataset.repeat(2)
dataset = dataset.batch(5)
 

यहाँ, Iterator::Map इवेंट का लंबा नाम Iterator::BatchV2::FiniteRepeat::Map । ध्यान दें कि डेटासेट का नाम अजगर एपीआई से थोड़ा भिन्न हो सकता है (उदाहरण के लिए, दोहराने के बजाय फिनाइटिपेट), लेकिन पार्स करने के लिए पर्याप्त सहज होना चाहिए।

तुल्यकालिक और अतुल्यकालिक परिवर्तन

सिंक्रोनस tf.data ट्रांसफ़ॉर्मेशन (जैसे Batch और Map ) के लिए, आप एक ही थ्रेड पर अपस्ट्रीम ट्रांसफ़ॉर्मेशन से इवेंट देखेंगे। उपरोक्त उदाहरण में, चूंकि उपयोग किए जाने वाले सभी रूपांतरण समकालिक हैं, सभी घटनाएं एक ही धागे पर दिखाई देती हैं।

(जैसे अतुल्यकालिक परिवर्तनों के लिए Prefetch , ParallelMap , ParallelInterleave और MapAndBatch ) नदी के ऊपर परिवर्तनों से घटनाओं एक अलग धागे पर किया जाएगा। ऐसे मामलों में, "लंबा नाम" आपको यह पहचानने में मदद कर सकता है कि किसी घटना में पाइपलाइन में किस परिवर्तन से मेल खाती है।

image

उदाहरण के लिए, उपरोक्त स्क्रीनशॉट निम्न कोड से उत्पन्न किया गया था:

 dataset = tf.data.Dataset.range(10)
dataset = dataset.map(lambda x: x)
dataset = dataset.repeat(2)
dataset = dataset.batch(5)
dataset = dataset.prefetch(1)
 

यहाँ, Iterator::Prefetch tf_data_iterator_get_next थ्रेड पर हैं। चूंकि Prefetch अतुल्यकालिक है, इसके इनपुट ईवेंट ( BatchV2 ) एक अलग धागे पर हो जाएगा, और लंबे समय तक नाम की खोज करके स्थित हो सकता है Iterator::Prefetch::BatchV2 । इस मामले में, वे tf_data_iterator_resource धागा पर हैं। अपने लंबे नाम से, आप मान सकते हैं कि BatchV2 की नदी के ऊपर है Prefetch । इसके अलावा, parent_id की BatchV2 घटना की आईडी से मेल खाएगी Prefetch घटना।

अड़चन की पहचान करना

सामान्य तौर पर, अपने इनपुट पाइपलाइन में अड़चन की पहचान करने के लिए, सभी तरह से बाहरी परिवर्तन से इनपुट पाइप लाइन को चलें। अपनी पाइपलाइन में अंतिम परिवर्तन से शुरू होकर, अपस्ट्रीम परिवर्तनों में TFRecord जब तक कि आप एक धीमी गति से परिवर्तन नहीं पाते हैं या एक स्रोत डेटासेट तक नहीं पहुंचते हैं, जैसे कि TFRecord । ऊपर के उदाहरण में, आप Prefetch से शुरू करेंगे, फिर BatchV2 , FiniteRepeat , Map , और अंत में Range ऊपर की ओर चलें।

सामान्य तौर पर, एक धीमी गति से परिवर्तन उसी से मेल खाती है जिसकी घटनाएं लंबी होती हैं, लेकिन जिनके इनपुट की घटनाएं कम होती हैं। कुछ उदाहरण नीचे दिए गए हैं।

ध्यान दें कि अधिकांश होस्ट इनपुट पाइपलाइनों में अंतिम (सबसे बाहरी) परिवर्तन Iterator::Model ईवेंट है। मॉडल परिवर्तन स्वचालित रूप से tf.data रनटाइम द्वारा पेश किया जाता है और इसका उपयोग इनपुट पाइपलाइन के प्रदर्शन को स्वचालित और स्वचालित करने के लिए किया जाता है।

यदि आपकी नौकरी वितरण रणनीति का उपयोग कर रही है, तो ट्रेस दर्शक में अतिरिक्त इवेंट होंगे जो डिवाइस इनपुट पाइपलाइन के अनुरूप हैं। डिवाइस पाइपलाइन का सबसे बाहरी परिवर्तन ( IteratorGetNextOp::DoCompute या IteratorGetNextAsOptionalOp::DoCompute तहत IteratorGetNextAsOptionalOp::DoCompute ) एक Iterator::Prefetch अपस्ट्रीम Iterator::Generator ईवेंट के साथ Iterator::PrefetchIterator::Model ईवेंट की खोज करके आप संबंधित होस्ट पाइपलाइन पा सकते हैं।

उदाहरण 1

image

उपरोक्त स्क्रीनशॉट निम्नलिखित इनपुट पाइपलाइन से उत्पन्न होता है:

 dataset = tf.data.TFRecordDataset(filename)
dataset = dataset.map(parse_record)
dataset = dataset.batch(32)
dataset = dataset.repeat()
 

स्क्रीनशॉट में, यह देखें कि (1) Iterator::Map ईवेंट लंबे हैं, लेकिन (2) इसके इनपुट ईवेंट ( Iterator::FlatMap ) जल्दी लौटते हैं। यह बताता है कि अनुक्रमिक मानचित्र परिवर्तन अड़चन है।

ध्यान दें कि स्क्रीनशॉट में, InstantiatedCapturedFunction::Run फ़ंक्शन उस समय से मेल खाता है जो मानचित्र फ़ंक्शन को निष्पादित करने में समय लेता है।

उदाहरण 2

image

उपरोक्त स्क्रीनशॉट निम्नलिखित इनपुट पाइपलाइन से उत्पन्न होता है:

 dataset = tf.data.TFRecordDataset(filename)
dataset = dataset.map(parse_record, num_parallel_calls=2)
dataset = dataset.batch(32)
dataset = dataset.repeat()
 

यह उदाहरण उपरोक्त के समान है, लेकिन मैप के बजाय ParallelMap का उपयोग करता है। हम यहाँ ध्यान देते हैं कि (1) Iterator::ParallelMap ईवेंट लंबे होते हैं, लेकिन (2) इसके इनपुट इवेंट Iterator::FlatMap (जो एक अलग थ्रेड पर हैं, क्योंकि ParallelMap अतुल्यकालिक हैं) कम हैं। इससे पता चलता है कि ParallelMap परिवर्तन अड़चन है।

अड़चन को संबोधित करते हुए

स्रोत डेटासेट

यदि आपने किसी डेटा स्रोत को टोंटी के रूप में पहचाना है, जैसे कि TFRecord फ़ाइलों से पढ़ना, तो आप डेटा निष्कर्षण को समानांतर करके प्रदर्शन में सुधार कर सकते हैं। ऐसा करने के लिए, सुनिश्चित करें कि आपके डेटा एकाधिक फ़ाइलों को भर में sharded जाता है और का उपयोग tf.data.Dataset.interleave साथ num_parallel_calls को सेट पैरामीटर tf.data.experimental.AUTOTUNE । यदि नियतत्ववाद आपके कार्यक्रम के लिए महत्वपूर्ण नहीं है, तो आप TF 2.2 के रूप में tf.data.Dataset.interleave पर deterministic=False ध्वज सेट करके प्रदर्शन में सुधार कर सकते हैं। उदाहरण के लिए, यदि आप TFRecords से पढ़ रहे हैं, तो आप निम्न कार्य कर सकते हैं:

 dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.interleave(tf.data.TFRecordDataset,
  num_parallel_calls=tf.data.experimental.AUTOTUNE,
  deterministic=False)
 

ध्यान दें कि फ़ाइल को खोलने के ओवरहेड को परिमित करने के लिए शार्प की गई फाइलें यथोचित रूप से बड़ी होनी चाहिए। समानांतर डेटा निष्कर्षण पर अधिक जानकारी के लिए, tf.data प्रदर्शन मार्गदर्शिका का यह अनुभाग देखें।

परिवर्तन डेटासेट

यदि आपने एक मध्यवर्ती tf.data परिवर्तन को अड़चन के रूप में पहचाना है, तो आप इसे परिवर्तन को tf.data कर सकते हैं या गणना को कैशिंग कर सकते हैं यदि आपका डेटा मेमोरी में फिट बैठता है और यह उपयुक्त है। Map जैसे कुछ परिवर्तनों में समानांतर समकक्ष हैं; tf.data प्रदर्शन मार्गदर्शिका प्रदर्शित करती है कि tf.data कैसे समानांतर किया जाए। अन्य परिवर्तन, जैसे कि Filter , Unbatch और Batch स्वाभाविक रूप से अनुक्रमिक हैं; आप "बाहरी समानता" की शुरुआत करके उन्हें समानांतर कर सकते हैं। उदाहरण के लिए, शुरू में आपके इनपुट पाइप लाइन को दबाने से निम्न जैसा दिखता है, Batch साथ अड़चन के रूप में:

 filenames = tf.data.Dataset.list_files(file_path, shuffle=is_training)
dataset = filenames_to_dataset(filenames)
dataset = dataset.batch(batch_size)
 

आप शार्प किए गए इनपुट पर इनपुट पाइपलाइन की कई प्रतियाँ चलाकर और परिणामों के संयोजन से "बाहरी समानता" का परिचय कर सकते हैं:

 filenames = tf.data.Dataset.list_files(file_path, shuffle=is_training)

def make_dataset(shard_index):
  filenames = filenames.shard(NUM_SHARDS, shard_index)
  dataset = filenames_to_dataset(filenames)
  Return dataset.batch(batch_size)

indices = tf.data.Dataset.range(NUM_SHARDS)
dataset = indices.interleave(make_dataset,
                             num_parallel_calls=tf.data.experimental.AUTOTUNE)
dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)
 

अतिरिक्त संसाधन