نکات عملکردی

این سند نکات عملکردی خاص TensorFlow Datasets (TFDS) را ارائه می دهد. توجه داشته باشید که TFDS مجموعه های داده را به عنوان اشیاء tf.data.Dataset ارائه می دهد، بنابراین توصیه های راهنمای tf.data همچنان اعمال می شود.

مجموعه داده های معیار

از tfds.benchmark(ds) برای محک زدن هر شی tf.data.Dataset استفاده کنید.

مطمئن شوید که برای عادی سازی نتایج batch_size= را نشان داده اید (مثلاً 100 iter/sec -> 3200 ex/sec). این با هر تکراری کار می کند (مثلا tfds.benchmark(tfds.as_numpy(ds)) ).

ds = tfds.load('mnist', split='train').batch(32).prefetch()
# Display some benchmark statistics
tfds.benchmark(ds, batch_size=32)
# Second iteration is much faster, due to auto-caching
tfds.benchmark(ds, batch_size=32)

مجموعه داده های کوچک (کمتر از 1 گیگابایت)

همه مجموعه داده های TFDS داده ها را در قالب TFRecord روی دیسک ذخیره می کنند. برای مجموعه داده‌های کوچک (مانند MNIST، CIFAR-10/-100)، خواندن از .tfrecord می‌تواند سربار قابل توجهی را اضافه کند.

از آنجایی که مجموعه داده‌ها در حافظه جا می‌شوند، می‌توان با ذخیره کردن یا بارگذاری پیش‌بار مجموعه داده، عملکرد را به میزان قابل توجهی بهبود بخشید. توجه داشته باشید که TFDS به طور خودکار مجموعه داده های کوچک را ذخیره می کند (در بخش زیر جزئیات وجود دارد).

ذخیره مجموعه داده

در اینجا نمونه‌ای از خط لوله داده است که به صراحت مجموعه داده‌ها را پس از عادی‌سازی تصاویر ذخیره می‌کند.

def normalize_img(image, label):
  """Normalizes images: `uint8` -> `float32`."""
  return tf.cast(image, tf.float32) / 255., label


ds, ds_info = tfds.load(
    'mnist',
    split='train',
    as_supervised=True,  # returns `(img, label)` instead of dict(image=, ...)
    with_info=True,
)
# Applying normalization before `ds.cache()` to re-use it.
# Note: Random transformations (e.g. images augmentations) should be applied
# after both `ds.cache()` (to avoid caching randomness) and `ds.batch()` (for
# vectorization [1]).
ds = ds.map(normalize_img, num_parallel_calls=tf.data.AUTOTUNE)
ds = ds.cache()
# For true randomness, we set the shuffle buffer to the full dataset size.
ds = ds.shuffle(ds_info.splits['train'].num_examples)
# Batch after shuffling to get unique batches at each epoch.
ds = ds.batch(128)
ds = ds.prefetch(tf.data.experimental.AUTOTUNE)

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

ذخیره خودکار

به‌طور پیش‌فرض، TFDS مجموعه‌داده‌هایی را به صورت خودکار ذخیره می‌کند (با ds.cache() ) که محدودیت‌های زیر را برآورده می‌کند:

  • اندازه کل مجموعه داده (همه تقسیمات) تعریف شده است و کمتر از 250 مگابایت است
  • shuffle_files غیرفعال است یا فقط یک قطعه خوانده می شود

امکان انصراف از ذخیره خودکار با عبور دادن try_autocaching=False به tfds.ReadConfig در tfds.load وجود دارد. به مستندات کاتالوگ مجموعه داده نگاهی بیندازید تا ببینید آیا یک مجموعه داده خاص از کش خودکار استفاده می کند یا خیر.

بارگیری داده های کامل به عنوان یک تانسور

اگر مجموعه داده شما در حافظه جا می شود، می توانید مجموعه داده کامل را به صورت یک آرایه Tensor یا NumPy نیز بارگیری کنید. انجام این کار با تنظیم batch_size=-1 برای دسته‌بندی همه نمونه‌ها در یک tf.Tensor امکان پذیر است. سپس از tfds.as_numpy برای تبدیل از tf.Tensor به np.array استفاده کنید.

(img_train, label_train), (img_test, label_test) = tfds.as_numpy(tfds.load(
    'mnist',
    split=['train', 'test'],
    batch_size=-1,
    as_supervised=True,
))

مجموعه داده های بزرگ

مجموعه داده‌های بزرگ به صورت خرد شده (در چندین فایل تقسیم می‌شوند) و معمولاً در حافظه جا نمی‌شوند، بنابراین نباید در حافظه پنهان ذخیره شوند.

مخلوط کردن و آموزش

در حین آموزش، مهم است که داده ها را به خوبی در هم آمیخته کنید - داده های به هم ریخته ضعیف می تواند باعث کاهش دقت آموزش شود.

علاوه بر استفاده از ds.shuffle برای به هم زدن رکوردها، باید shuffle_files=True نیز تنظیم کنید تا برای مجموعه داده های بزرگتر که در چندین فایل به اشتراک گذاشته شده اند، رفتار ترکیبی خوبی داشته باشید. در غیر این صورت، epoch ها خرده ها را به همان ترتیب می خوانند و بنابراین داده ها واقعاً تصادفی نمی شوند.

ds = tfds.load('imagenet2012', split='train', shuffle_files=True)

علاوه بر این، وقتی shuffle_files=True ، TFDS options.deterministic غیرفعال می کند، که ممکن است کمی عملکرد را افزایش دهد. برای دستیابی به ترکیب قطعی، می توان با tfds.ReadConfig از این ویژگی انصراف داد: یا با تنظیم read_config.shuffle_seed یا بازنویسی read_config.options.deterministic .

اشتراک‌گذاری خودکار داده‌های خود در بین کارگران (TF)

هنگام آموزش روی چندین کارگر، می‌توانید از آرگومان input_context tfds.ReadConfig استفاده کنید، بنابراین هر کارگر زیرمجموعه‌ای از داده‌ها را می‌خواند.

input_context = tf.distribute.InputContext(
    input_pipeline_id=1,  # Worker id
    num_input_pipelines=4,  # Total number of workers
)
read_config = tfds.ReadConfig(
    input_context=input_context,
)
ds = tfds.load('dataset', split='train', read_config=read_config)

این مکمل برای subsplit API است. ابتدا، subplit API اعمال می‌شود: train[:50%] به فهرستی از فایل‌ها برای خواندن تبدیل می‌شود. سپس، ds.shard() op روی آن فایل ها اعمال می شود. به عنوان مثال، هنگام استفاده از train[:50%] با num_input_pipelines=2 ، هر یک از 2 کارگر 1/4 از داده ها را خواهند خواند.

وقتی shuffle_files=True ، فایل‌ها در یک کارگر به هم ریخته می‌شوند، اما نه در بین کارگران. هر کارگر همان زیرمجموعه فایل‌ها را بین دوره‌ها می‌خواند.

به طور خودکار داده های خود را در بین کارگران تقسیم کنید (Jax)

با Jax، می توانید از tfds.split_for_jax_process یا tfds.even_splits API برای توزیع داده های خود در بین کارگران استفاده کنید. راهنمای تقسیم API را ببینید.

split = tfds.split_for_jax_process('train', drop_remainder=True)
ds = tfds.load('my_dataset', split=split)

tfds.split_for_jax_process یک نام مستعار ساده برای:

# The current `process_index` loads only `1 / process_count` of the data.
splits = tfds.even_splits('train', n=jax.process_count(), drop_remainder=True)
split = splits[jax.process_index()]

رمزگشایی سریعتر تصویر

به طور پیش فرض، TFDS به طور خودکار تصاویر را رمزگشایی می کند. با این حال، مواردی وجود دارد که می‌توان از رمزگشایی تصویر با tfds.decode.SkipDecoding صرفنظر کرد و tf.io.decode_image op را به صورت دستی اعمال کرد:

  • هنگام فیلتر کردن نمونه ها (با tf.data.Dataset.filter )، برای رمزگشایی تصاویر پس از فیلتر شدن نمونه ها.
  • هنگام برش تصاویر، برای استفاده از ترکیب tf.image.decode_and_crop_jpeg op.

کد هر دو نمونه در راهنمای رمزگشایی موجود است.

از ویژگی های استفاده نشده صرف نظر کنید

اگر فقط از زیرمجموعه‌ای از ویژگی‌ها استفاده می‌کنید، می‌توانید به طور کامل از برخی ویژگی‌ها صرفنظر کنید. اگر مجموعه داده شما دارای بسیاری از ویژگی های استفاده نشده باشد، رمزگشایی نکردن آنها می تواند به طور قابل توجهی عملکرد را بهبود بخشد. به https://www.tensorflow.org/datasets/decode#only_decode_a_sub-set_of_the_features مراجعه کنید

tf.data از تمام رم من استفاده می کند!

اگر در حافظه RAM محدود هستید، یا اگر هنگام استفاده از tf.data مجموعه های داده زیادی را به صورت موازی بارگیری می کنید، در اینجا چند گزینه وجود دارد که می تواند کمک کند:

نادیده گرفتن اندازه بافر

builder.as_dataset(
  read_config=tfds.ReadConfig(
    ...
    override_buffer_size=1024,  # Save quite a bit of RAM.
  ),
  ...
)

این buffer_size ارسال شده به TFRecordDataset (یا معادل آن) را لغو می کند: https://www.tensorflow.org/api_docs/python/tf/data/TFRecordDataset#args

برای متوقف کردن رفتارهای جادویی از tf.data.Dataset.with_options استفاده کنید

https://www.tensorflow.org/api_docs/python/tf/data/Dataset#with_options

options = tf.data.Options()

# Stop magic stuff that eats up RAM:
options.autotune.enabled = False
options.experimental_distribute.auto_shard_policy = (
  tf.data.experimental.AutoShardPolicy.OFF)
options.experimental_optimization.inject_prefetch = False

data = data.with_options(options)