نصائح حول الأداء

يقدم هذا المستند تلميحات أداء خاصة بمجموعات بيانات TensorFlow (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 للحصول على سلوك خلط جيد لمجموعات البيانات الأكبر التي يتم تجزئتها في ملفات متعددة. بخلاف ذلك ، ستقرأ العصور الأجزاء بالترتيب نفسه ، وبالتالي لن تكون البيانات عشوائية حقًا.

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)

هذا مكمل لواجهة برمجة التطبيقات الفرعية. أولاً ، يتم تطبيق subplit API: يتم تحويل train[:50%] إلى قائمة ملفات للقراءة. ثم يتم تطبيق ds.shard() op على تلك الملفات. على سبيل المثال ، عند استخدام train[:50%] مع num_input_pipelines=2 ، سيقرأ كل من العاملين 2 1/4 من البيانات.

عندما يكون shuffle_files=True ، يتم خلط الملفات داخل عامل واحد ، ولكن ليس بين العاملين. سيقرأ كل عامل نفس المجموعة الفرعية من الملفات بين العصور.

تقاسم بياناتك تلقائيًا عبر العاملين (جاكس)

باستخدام 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 يدويًا:

رمز كلا المثالين متاح في دليل فك التشفير.

تخطي الميزات غير المستخدمة

إذا كنت تستخدم مجموعة فرعية فقط من الميزات ، فمن الممكن تخطي بعض الميزات تمامًا. إذا كانت مجموعة البيانات الخاصة بك تحتوي على العديد من الميزات غير المستخدمة ، فإن عدم فك تشفيرها يمكن أن يؤدي إلى تحسين الأداء بشكل كبير. راجع https://www.tensorflow.org/datasets/decode#only_decode_a_sub-set_of_the_features