این سند نکات عملکردی خاص 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)