เอกสารนี้ให้คำแนะนำด้านประสิทธิภาพเฉพาะสำหรับชุดข้อมูล TensorFlow (TFDS) โปรดทราบว่า TFDS จัดเตรียมชุดข้อมูลเป็นออบเจ็กต์ tf.data.Dataset
ดังนั้นคำแนะนำจาก คู่มือ tf.data
จึงยังคงมีผลบังคับใช้
ชุดข้อมูลเปรียบเทียบ
ใช้ tfds.benchmark(ds)
เพื่อเปรียบเทียบออบเจ็กต์ tf.data.Dataset
ใดๆ
ตรวจสอบให้แน่ใจว่าได้ระบุ batch_size=
เพื่อทำให้ผลลัพธ์เป็นมาตรฐาน (เช่น 100 iter/วินาที -> 3200 ex/วินาที) สิ่งนี้ใช้ได้กับการทำซ้ำได้ (เช่น 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 GB)
ชุดข้อมูล 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 MiB
-
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)
นี่เป็นส่วนเสริมของ 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
) เพื่อถอดรหัสรูปภาพหลังจากกรองตัวอย่างแล้ว - เมื่อทำการครอบตัดรูปภาพ ให้ใช้ fused
tf.image.decode_and_crop_jpeg
op
รหัสสำหรับทั้งสองตัวอย่างมีอยู่ใน คู่มือการถอดรหัส
ข้ามคุณสมบัติที่ไม่ได้ใช้
หากคุณใช้คุณสมบัติเพียงบางส่วนเท่านั้น คุณสามารถข้ามคุณสมบัติบางอย่างไปโดยสิ้นเชิงได้ หากชุดข้อมูลของคุณมีคุณสมบัติที่ไม่ได้ใช้มากมาย การไม่ถอดรหัสสามารถปรับปรุงประสิทธิภาพได้อย่างมาก ดู https://www.tensorflow.org/datasets/decode#only_decode_a_sub-set_of_the_features
tf.data ใช้ RAM ทั้งหมดของฉัน!
หากคุณมี 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)