सिंहावलोकन
यह मार्गदर्शिका TensorFlow प्रोफाइलर और tf.data
से परिचित होने का अनुमान लगाती है। इसका उद्देश्य उपयोगकर्ताओं को इनपुट पाइपलाइन प्रदर्शन समस्याओं का निदान करने और उन्हें ठीक करने में मदद करने के लिए उदाहरणों के साथ चरण-दर-चरण निर्देश प्रदान करना है।
आरंभ करने के लिए, अपने TensorFlow कार्य का एक प्रोफ़ाइल एकत्र करें। ऐसा करने के निर्देश सीपीयू/जीपीयू और क्लाउड टीपीयू के लिए उपलब्ध हैं।
नीचे विस्तृत विश्लेषण वर्कफ़्लो प्रोफाइलर में ट्रेस व्यूअर टूल पर केंद्रित है। यह टूल एक टाइमलाइन प्रदर्शित करता है जो आपके TensorFlow प्रोग्राम द्वारा निष्पादित ऑप्स की अवधि दिखाता है और आपको यह पहचानने की अनुमति देता है कि कौन से ऑप्स को निष्पादित होने में सबसे अधिक समय लगता है। ट्रेस व्यूअर के बारे में अधिक जानकारी के लिए, टीएफ प्रोफाइलर गाइड का यह अनुभाग देखें। सामान्य तौर पर, tf.data
इवेंट होस्ट CPU टाइमलाइन पर दिखाई देंगे।
विश्लेषण वर्कफ़्लो
कृपया नीचे दिए गए वर्कफ़्लो का पालन करें. यदि आपके पास इसे बेहतर बनाने में हमारी मदद करने के लिए फीडबैक है, तो कृपया "comp:data" लेबल के साथ एक जीथब मुद्दा बनाएं ।
1. क्या आपकी tf.data
पाइपलाइन काफी तेजी से डेटा का उत्पादन कर रही है?
यह पता लगाने से शुरुआत करें कि क्या इनपुट पाइपलाइन आपके TensorFlow प्रोग्राम के लिए बाधा है।
ऐसा करने के लिए, ट्रेस व्यूअर में IteratorGetNext::DoCompute
ops देखें। सामान्य तौर पर, आप इन्हें एक चरण की शुरुआत में देखने की उम्मीद करते हैं। ये स्लाइस आपके इनपुट पाइपलाइन द्वारा अनुरोध किए जाने पर तत्वों का एक बैच प्राप्त करने में लगने वाले समय का प्रतिनिधित्व करते हैं। यदि आप केरस का उपयोग कर रहे हैं या tf.function
में अपने डेटासेट पर पुनरावृत्ति कर रहे हैं, तो इन्हें tf_data_iterator_get_next
थ्रेड्स में पाया जाना चाहिए।
ध्यान दें कि यदि आप वितरण रणनीति का उपयोग कर रहे हैं, तो आप IteratorGetNextAsOptional::DoCompute
IteratorGetNext::DoCompute
DoCompute ईवेंट देख सकते हैं।
यदि कॉल जल्दी वापस आती है (<= 50 हमें), तो इसका मतलब है कि आपका डेटा अनुरोध किए जाने पर उपलब्ध है। इनपुट पाइपलाइन आपकी बाधा नहीं है; अधिक सामान्य प्रदर्शन विश्लेषण युक्तियों के लिए प्रोफाइलर गाइड देखें।
यदि कॉल धीरे-धीरे वापस आती है, तो tf.data
उपभोक्ता के अनुरोधों को पूरा करने में असमर्थ है। अगले भाग पर जारी रखें.
2. क्या आप डेटा प्रीफ़ेच कर रहे हैं?
इनपुट पाइपलाइन प्रदर्शन के लिए सबसे अच्छा अभ्यास अपनी tf.data
पाइपलाइन के अंत में tf.data.Dataset.prefetch
परिवर्तन सम्मिलित करना है। यह परिवर्तन मॉडल गणना के अगले चरण के साथ इनपुट पाइपलाइन की प्रीप्रोसेसिंग गणना को ओवरलैप करता है और आपके मॉडल को प्रशिक्षित करते समय इष्टतम इनपुट पाइपलाइन प्रदर्शन के लिए आवश्यक है। यदि आप डेटा प्रीफ़ेच कर रहे हैं, तो आपको IteratorGetNext::DoCompute
op के समान थ्रेड पर Iterator::Prefetch
स्लाइस देखना चाहिए।
यदि आपकी पाइपलाइन के अंत में prefetch
नहीं है , तो आपको एक जोड़ना चाहिए। tf.data
प्रदर्शन अनुशंसाओं के बारे में अधिक जानकारी के लिए, tf.data प्रदर्शन मार्गदर्शिका देखें।
यदि आप पहले से ही डेटा प्रीफ़ेच कर रहे हैं , और इनपुट पाइपलाइन अभी भी आपकी बाधा है, तो प्रदर्शन का और विश्लेषण करने के लिए अगले अनुभाग पर जारी रखें।
3. क्या आप उच्च CPU उपयोग तक पहुँच रहे हैं?
tf.data
उपलब्ध संसाधनों का सर्वोत्तम संभव उपयोग करने का प्रयास करके उच्च थ्रूपुट प्राप्त करता है। सामान्य तौर पर, अपने मॉडल को जीपीयू या टीपीयू जैसे एक्सेलेरेटर पर चलाने पर भी, tf.data
पाइपलाइन सीपीयू पर चलती हैं। यदि आप GCP पर चल रहे हैं तो आप sar और htop जैसे टूल या क्लाउड मॉनिटरिंग कंसोल में अपने उपयोग की जांच कर सकते हैं।
यदि आपका उपयोग कम है, तो इसका मतलब है कि आपकी इनपुट पाइपलाइन होस्ट सीपीयू का पूरा लाभ नहीं ले रही है। आपको सर्वोत्तम प्रथाओं के लिए 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
ईवेंट को कैसे पढ़ा जाए ताकि यह समझा जा सके कि बाधा कहां है और संभावित शमन रणनीतियों को कैसे समझा जाए।
प्रोफाइलर में tf.data
इवेंट को समझना
प्रोफाइलर में प्रत्येक 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
से शुरू करेंगे, फिर BatchV2
, FiniteRepeat
, Map
और अंत में Range
तक ऊपर की ओर चलेंगे।
सामान्य तौर पर, धीमा परिवर्तन उस व्यक्ति से मेल खाता है जिसकी घटनाएँ लंबी हैं, लेकिन जिनकी इनपुट घटनाएँ छोटी हैं। कुछ उदाहरण नीचे दिए गए हैं।
ध्यान दें कि अधिकांश होस्ट इनपुट पाइपलाइनों में अंतिम (सबसे बाहरी) परिवर्तन Iterator::Model
इवेंट है। मॉडल परिवर्तन स्वचालित रूप से tf.data
रनटाइम द्वारा पेश किया जाता है और इसका उपयोग इनपुट पाइपलाइन प्रदर्शन को इंस्ट्रूमेंट करने और ऑटोट्यूनिंग के लिए किया जाता है।
यदि आपका काम वितरण रणनीति का उपयोग कर रहा है, तो ट्रेस व्यूअर में अतिरिक्त ईवेंट शामिल होंगे जो डिवाइस इनपुट पाइपलाइन के अनुरूप होंगे। डिवाइस पाइपलाइन का सबसे बाहरी परिवर्तन ( IteratorGetNextOp::DoCompute
या IteratorGetNextAsOptionalOp::DoCompute
अंतर्गत नेस्टेड) एक अपस्ट्रीम 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()
यह उदाहरण उपरोक्त के समान है, लेकिन मानचित्र के बजाय ParallelMap का उपयोग करता है। हम यहां देखते हैं कि (1) Iterator::ParallelMap
इवेंट लंबे हैं, लेकिन (2) इसके इनपुट इवेंट Iterator::FlatMap
(जो एक अलग थ्रेड पर हैं, क्योंकि ParallelMap एसिंक्रोनस है) छोटे हैं। इससे पता चलता है कि पैरेललमैप परिवर्तन बाधा है।
अड़चन को संबोधित करना
स्रोत डेटासेट
यदि आपने किसी डेटासेट स्रोत को बाधा के रूप में पहचाना है, जैसे कि TFRecord फ़ाइलों से पढ़ना, तो आप डेटा निष्कर्षण को समानांतर करके प्रदर्शन में सुधार कर सकते हैं। ऐसा करने के लिए, सुनिश्चित करें कि आपका डेटा कई फ़ाइलों में विभाजित है और tf.data.Dataset.interleave
का उपयोग num_parallel_calls
पैरामीटर के साथ tf.data.AUTOTUNE
पर सेट करें। यदि नियतिवाद आपके कार्यक्रम के लिए महत्वपूर्ण नहीं है, तो आप टीएफ 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
परिवर्तन को बाधा के रूप में पहचाना है, तो यदि आपका डेटा मेमोरी में फिट बैठता है और यह उपयुक्त है, तो आप परिवर्तन को समानांतर करके या गणना को कैशिंग करके इसे संबोधित कर सकते हैं। 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
सर्वोत्तम अभ्यास - प्रोफाइलर गाइड
- कोलाब के साथ प्रोफाइलर ट्यूटोरियल