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

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.

अवलोकन

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

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

TensorFlow Trace Viewer

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

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

कृपया नीचे दिए गए कार्यप्रवाह का पालन करें। यदि आपके पास इसे बेहतर बनाने में हमारी मदद करने के लिए प्रतिक्रिया है, तो कृपया "comp:data" लेबल के साथ एक github समस्या बनाएं

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

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

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

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

image

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

image

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

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

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

image

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

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

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

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

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

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

आप tf.data में अनावश्यक संगणना से बचकर अपनी इनपुट पाइपलाइन की दक्षता में सुधार कर सकते हैं। ऐसा करने का एक तरीका यह है कि यदि आपका डेटा मेमोरी में फ़िट हो जाता है तो संगणना-गहन कार्य के बाद एक tf.data.Dataset.cache रूपांतरण सम्मिलित करना; यह बढ़ी हुई मेमोरी उपयोग की कीमत पर संगणना को कम करता है। इसके अतिरिक्त, 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> से मेल खाता है, और लंबे नाम में अन्य डेटासेट डाउनस्ट्रीम परिवर्तनों का प्रतिनिधित्व करते हैं।

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 अपस्ट्रीम है। इसके अलावा, BatchV2 इवेंट का parent_id Prefetch इवेंट की आईडी से मेल खाएगा।

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

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

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

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

यदि आपका काम वितरण रणनीति का उपयोग कर रहा है, तो ट्रेस व्यूअर में अतिरिक्त ईवेंट होंगे जो डिवाइस इनपुट पाइपलाइन से संबंधित होंगे। डिवाइस पाइपलाइन का सबसे बाहरी परिवर्तन ( IteratorGetNextOp::DoCompute या IteratorGetNextAsOptionalOp::DoCompute DoCompute के अंतर्गत नेस्टेड) ​​एक Upstream Iterator::Generator ईवेंट के साथ एक Iterator::Prefetch ईवेंट होगा। आप Iterator::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()

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

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

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

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

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

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

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

यदि आपने एक मध्यवर्ती tf.data परिवर्तन को बाधा के रूप में पहचाना है, तो यदि आपका डेटा स्मृति में फिट बैठता है और यह उचित है तो आप परिवर्तन को समानांतर करके या गणना को कैशिंग करके इसे संबोधित कर सकते हैं। कुछ परिवर्तन जैसे Map में समानांतर प्रतिरूप होते हैं; 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.AUTOTUNE)
dataset = dataset.prefetch(tf.data.AUTOTUNE)

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