अवलोकन
यह मार्गदर्शिका TensorFlow Profiler और tf.data
से परिचित होने का अनुमान लगाती है। इसका उद्देश्य उपयोगकर्ताओं को इनपुट पाइपलाइन प्रदर्शन समस्याओं का निदान करने और उन्हें ठीक करने में मदद करने के लिए उदाहरण के साथ चरण-दर-चरण निर्देश प्रदान करना है।
आरंभ करने के लिए, अपने TensorFlow जॉब की एक प्रोफ़ाइल एकत्र करें। ऐसा करने के निर्देश सीपीयू/जीपीयू और क्लाउड टीपीयू के लिए उपलब्ध हैं।
नीचे विस्तृत विश्लेषण कार्यप्रवाह प्रोफाइलर में ट्रेस व्यूअर टूल पर केंद्रित है। यह टूल एक टाइमलाइन प्रदर्शित करता है जो आपके 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 के अनुसार) के बजाय देख सकते हैं।
अगर कॉल जल्दी वापस आती हैं (<= 50 हमें), तो इसका मतलब है कि अनुरोध किए जाने पर आपका डेटा उपलब्ध है। इनपुट पाइपलाइन आपकी अड़चन नहीं है; अधिक सामान्य प्रदर्शन विश्लेषण युक्तियों के लिए प्रोफाइलर गाइड देखें।
यदि कॉल धीरे-धीरे वापस आती हैं, tf.data
उपभोक्ता के अनुरोधों को पूरा करने में असमर्थ होता है। अगले भाग पर जारी रखें।
2. क्या आप डेटा प्रीफ़ेच कर रहे हैं?
इनपुट पाइपलाइन प्रदर्शन के लिए सबसे अच्छा तरीका है कि आप अपनी tf.data
पाइपलाइन के अंत में एक tf.data.Dataset.prefetch
रूपांतरण डालें। यह परिवर्तन इनपुट पाइपलाइन की प्रीप्रोसेसिंग संगणना को मॉडल संगणना के अगले चरण के साथ ओवरलैप करता है और आपके मॉडल को प्रशिक्षित करते समय इष्टतम इनपुट पाइपलाइन प्रदर्शन के लिए आवश्यक है। यदि आप डेटा को प्रीफ़ेच कर रहे हैं, तो आपको IteratorGetNext::DoCompute
ऑप के समान थ्रेड पर एक Iterator::Prefetch
स्लाइस दिखाई देनी चाहिए।
यदि आपकी पाइपलाइन के अंत में कोई 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>
से मेल खाता है, और लंबे नाम में अन्य डेटासेट डाउनस्ट्रीम परिवर्तनों का प्रतिनिधित्व करते हैं।
उदाहरण के लिए, उपरोक्त स्क्रीनशॉट निम्न कोड से उत्पन्न किया गया था:
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
) अपस्ट्रीम ट्रांसफ़ॉर्मेशन की घटनाएँ एक अलग थ्रेड पर होंगी। ऐसे मामलों में, "लंबा नाम" आपको यह पहचानने में मदद कर सकता है कि पाइपलाइन में कौन सा परिवर्तन एक घटना से मेल खाता है।
उदाहरण के लिए, उपरोक्त स्क्रीनशॉट निम्न कोड से उत्पन्न किया गया था:
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
उपरोक्त स्क्रीनशॉट निम्न इनपुट पाइपलाइन से उत्पन्न होता है:
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
उपरोक्त स्क्रीनशॉट निम्न इनपुट पाइपलाइन से उत्पन्न होता है:
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)
अतिरिक्त संसाधन
- प्रदर्शन
tf.data
इनपुट पाइपलाइन कैसे लिखें, इस पर tf.data प्रदर्शन मार्गदर्शिका - TensorFlow वीडियो के अंदर:
tf.data
सर्वोत्तम अभ्यास - प्रोफाइलर गाइड
- कोलाब के साथ प्रोफाइलर ट्यूटोरियल