सहायता Kaggle पर TensorFlow साथ ग्रेट बैरियर रीफ की रक्षा चैलेंज में शामिल हों

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

अवलोकन

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

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

TensorFlow Trace Viewer

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

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

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

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 slice को एक ही थ्रेड पर IteratorGetNext::DoCompute op के रूप में देखना चाहिए।

image

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

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

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

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

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

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

tf.data में अनावश्यक गणना से बचकर आप अपने इनपुट पाइपलाइन की दक्षता में सुधार कर सकते हैं। ऐसा करने का एक तरीका यह है कि कम्प्यूट-इंटेंसिव कार्य के बाद tf.data.Dataset.cache परिवर्तन 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> ( <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 अंतर्गत IteratorGetNextOp::DoCompute या IteratorGetNextAsOptionalOp::DoCompute ) एक Iterator::Prefetch एक अपस्ट्रीम Iterator::Generator साथ Iterator::Prefetch Iterator::Generator इवेंट। 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()

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

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

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

यदि आपने एक डेटा स्रोत को टोंटी के रूप में पहचाना है, जैसे कि TFRecord फ़ाइलों से पढ़ना, तो आप डेटा निष्कर्षण को समानांतर करके प्रदर्शन में सुधार कर सकते हैं। ऐसा करने के लिए, सुनिश्चित करें कि आपका डेटा कई फ़ाइलों में tf.data.Dataset.interleave किया गया है और num_parallel_calls को tf.data.AUTOTUNE सेट num_parallel_calls पैरामीटर के साथ उपयोग करें। यदि नियतांक आपके कार्यक्रम के लिए महत्वपूर्ण नहीं है, तो आप 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.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.AUTOTUNE)
dataset = dataset.prefetch(tf.data.AUTOTUNE)

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