ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

เคล็ดลับประสิทธิภาพ

เอกสารนี้แสดงเคล็ดลับประสิทธิภาพเฉพาะชุดข้อมูล TensorFlow (TFDS) โปรดทราบว่า TFDS ให้ชุดข้อมูลเป็น tf.data.Dataset วัตถุเพื่อให้คำแนะนำจากที่ tf.data คู่มือ ยังคงใช้

ชุดข้อมูลเกณฑ์มาตรฐาน

ใช้ tfds.benchmark(ds) มาตรฐานใด ๆ tf.data.Dataset วัตถุ

ตรวจสอบให้แน่ใจเพื่อระบุ batch_size= ปกติผล (เช่นเราเตอร์ 100 / วินาที -> 3200 อดีต / วินาที) งานนี้กับ iterable ใด ๆ (เช่น 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 ตัวเดียว

หากชุดข้อมูลของคุณพอดีกับหน่วยความจำ คุณยังสามารถโหลดชุดข้อมูลทั้งหมดเป็นอาร์เรย์ 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 จะได้รับพฤติกรรมสับดีสำหรับชุดข้อมูลขนาดใหญ่ที่มีการ sharded เป็นหลายไฟล์ มิฉะนั้น ยุคจะอ่านชาร์ดในลำดับเดียวกัน ดังนั้นข้อมูลจะไม่ถูกสุ่มอย่างแท้จริง

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

นอกจากนี้เมื่อ shuffle_files=True , TFDS ปิดการใช้งาน options.experimental_deterministic ซึ่งอาจให้เพิ่มประสิทธิภาพการทำงานเล็กน้อย ที่จะได้รับการสับกำหนดขึ้นก็เป็นไปได้ที่จะเลือกจากคุณสมบัตินี้กับ tfds.ReadConfig : ทั้งโดยการตั้งค่า read_config.shuffle_seed หรือเขียนทับ read_config.options.experimental_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.even_splits API เพื่อเผยแพร่ข้อมูลของคุณในแรงงาน ดู คู่มือ API แยก

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

ถอดรหัสภาพได้เร็วขึ้น

ตามค่าเริ่มต้น TFDS จะถอดรหัสภาพโดยอัตโนมัติ แต่มีกรณีที่จะสามารถเป็น performant มากขึ้นที่จะข้ามภาพถอดรหัสกับ 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