این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

عملکرد tf.data را با TF Profiler تجزیه و تحلیل کنید

بررسی اجمالی

این راهنما با tf.data Profiler و tf.data آشنایی را فرض می کند. این هدف برای ارائه راهنمای گام به گام با مثال هایی برای کمک به کاربران در تشخیص و رفع مشکلات عملکرد خط لوله ورودی است.

برای شروع ، نمایه ای از کار TensorFlow خود را جمع آوری کنید. دستورالعمل نحوه انجام این کار برای CPU / GPU و TPU های Cloud در دسترس است.

TensorFlow Trace Viewer

گردش کار تجزیه و تحلیل که به شرح زیر است ، روی ابزار مشاهده ردیاب در Profiler متمرکز است. این ابزار یک جدول زمانی را نشان می دهد که مدت زمان انجام گزینه های اجرا شده توسط برنامه TensorFlow شما را نشان می دهد و به شما اجازه می دهد تا مشخص کنید که کدام گزینه ها بیشترین اجرای را دارند. برای کسب اطلاعات بیشتر در مورد ردیاب ردیاب ، این بخش از راهنمای TF Profiler را بررسی کنید. به طور کلی ، رویدادهای tf.data در جدول زمانی CPU میزبان ظاهر می شوند.

گردش کار تجزیه و تحلیل

لطفاً روند کار را در زیر دنبال کنید. اگر بازخوردی برای کمک به ما در بهبود آن دارید ، لطفاً یک شماره github با برچسب "comp: data" ایجاد کنید.

1- آیا خط لوله tf.data شما داده کافی را تولید می کند؟

با بررسی این نکته که آیا خط لوله ورودی تنگنای برنامه TensorFlow شما است ، شروع کنید.

برای این کار ، به دنبال گزینه IteratorGetNext::DoCompute در نمایشگر IteratorGetNext::DoCompute . به طور کلی ، انتظار دارید که در شروع یک مرحله این موارد را ببینید. این برش ها مدت زمان لازم را برای انجام خط لوله ورودی شما برای نمایش دسته ای از عناصر در هنگام درخواست نشان می دهد. اگر از عملکردهای keras استفاده می کنید یا در یک tf.function از مجموعه داده های خود در حال tf.function ، این موارد باید در موضوعات tf_data_iterator_get_next یافت شود.

توجه داشته باشید که اگر از یک استراتژی توزیع استفاده می کنید ، می توانید به جای IteratorGetNext::DoCompute (به ترتیب از TF 2.3) رویدادهای IteratorGetNextAsOptional::DoCompute رویدادهای IteratorGetNextAsOptional::DoCompute ببینید.

image

اگر تماسها به سرعت بازگردند (<= 50 ما) ، این بدان معنی است که وقتی درخواست می شود داده های شما در دسترس هستند. خط لوله ورودی تنگنا نیست برای راهنمایی بیشتر درباره تحلیل عملکرد عملکرد ، به راهنمای Profiler مراجعه کنید.

image

اگر تماسها به آهستگی برگردد ، tf.data قادر به پیگیری درخواست های مصرف کننده نیست. به بخش بعدی ادامه دهید.

2. آیا داده ها را از پیش تنظیم می کنید؟

بهترین روش برای عملکرد خط لوله ورودی درج یک تحول tf.data.Dataset.prefetch در انتهای خط لوله tf.data . این تحول محاسبات پیش پردازش خط لوله ورودی را با مرحله بعدی محاسبه مدل همپوشانی می کند و برای عملکرد بهینه خط لوله ورودی هنگام آموزش مدل شما مورد نیاز است. اگر در حال پیش تنظیم کردن داده ها هستید ، باید یک برش Iterator::Prefetch prefetch را در همان نخ IteratorGetNext::DoCompute op ببینید.

image

اگر شما یک ندارد prefetch در پایان خط لوله خود را، شما باید یک اضافه کنید. برای اطلاعات بیشتر در مورد توصیه های عملکرد tf.data ، به راهنمای عملکرد tf.data مراجعه کنید.

اگر داده ها را از پیش تنظیم کرده اید ، و خط لوله ورودی هنوز تنگنای شما است ، برای تجزیه و تحلیل بیشتر عملکرد به بخش بعدی بروید.

3. آیا به کارآیی پردازنده بالایی رسیده اید؟

tf.data با تلاش برای استفاده tf.data از منابع موجود ، به توان بالایی دست می یابد. به طور کلی ، حتی هنگام اجرای مدل خود بر روی یک شتاب دهنده مانند GPU یا TPU ، خطوط لوله tf.data روی CPU اجرا می شوند. اگر در GCP کار می کنید می توانید میزان استفاده خود را با ابزارهایی مانند sar و htop یا در کنسول مانیتور ابری بررسی کنید.

اگر میزان استفاده شما کم باشد ، این نشان می دهد که خط لوله ورودی شما ممکن است از CPU میزبان نهایت استفاده را نکند. برای بهترین کارها باید با راهنمای عملکرد tf.data مشورت کنید. اگر بهترین شیوه ها را به کار برده اید و میزان بهره وری و توان آن پایین است ، به تجزیه و تحلیل بوتلنک در زیر ادامه دهید.

اگر میزان استفاده شما به محدوده منابع نزدیک شده است ، برای بهبود عملکرد بیشتر ، باید بازده خط لوله ورودی خود را (مثلاً اجتناب از محاسبه غیر ضروری) یا محاسبه offload را بهبود بخشید.

با اجتناب از محاسبه غیر ضروری در tf.data می توانید بازده خط لوله ورودی خود را بهبود بخشید. اگر داده های شما در حافظه متناسب باشد ، یکی از راه های انجام این کار درج یک تحول 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 در tf.data ردیابی tf.data می شود تا بفهمیم تنگنا در کجاست و استراتژی های کاهش احتمالی.

درک وقایع tf.data در tf.data

هر رویداد tf.data در Profiler دارای نام 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 . توجه داشته باشید که ممکن است نام مجموعه داده ها با API پایتون کمی متفاوت باشد (برای مثال ، به جای تکرار FiniteRepeat) ، اما برای تجزیه باید به اندازه کافی شهودی باشد

تحولات همزمان و ناهمزمان

برای تبدیل های همزمان 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 موضوعات tf_data_iterator_get_next . از آنجا که Prefetch ناهمزمان است ، وقایع ورودی آن ( BatchV2 ) در نخ متفاوتی خواهد بود و با جستجو برای نام طولانی Iterator::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 ) خواهد بود 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 وقایع 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 به جای Map استفاده می کند. در اینجا متوجه می شویم که (1) Iterator::ParallelMap رویدادهای طولانی است ، اما (2) رویدادهای ورودی آن Iterator::FlatMap (که روی یک موضوع دیگر قرار دارند ، زیرا ParallelMap ناهمزمان است) کوتاه هستند. این نشان می دهد که تحول ParallelMap تنگنا است.

پرداختن به تنگنا

منبع داده

اگر یک منبع داده را بعنوان تنگناها شناسایی کرده اید ، مانند خواندن پرونده های TFRecord ، می توانید با موازی کردن استخراج داده ها ، عملکرد را بهبود بخشید. برای انجام این کار ، اطمینان حاصل کنید که داده های شما در چندین فایل tf.data.Dataset.interleave شده است و از tf.data.Dataset.interleave با پارامتر num_parallel_calls تنظیم شده روی tf.data.experimental.AUTOTUNE . اگر جبرگرایی برای برنامه شما مهم نیست ، می توانید با قرار دادن پرچم deterministic=False در tf.data.Dataset.interleave از TF 2.2 عملکرد را بهبود بخشید. به عنوان مثال ، اگر از TFRecords می خوانید ، می توانید موارد زیر را انجام دهید:

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

توجه داشته باشید که پرونده های sharded باید بطور منطقی بزرگ باشند تا بتوانند سربار باز کردن پرونده را از بین ببرند. برای اطلاعات بیشتر در مورد استخراج موازی داده ها ، به این بخش از راهنمای عملکرد tf.data .

مجموعه داده های تحول

اگر یک تغییر واسطه متوسط 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.experimental.AUTOTUNE)
dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)
 

منابع اضافی