Mẹo về hiệu suất

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Tài liệu này cung cấp các mẹo hiệu suất cụ thể của Bộ dữ liệu TensorFlow (TFDS). Lưu ý rằng TFDS cung cấp tập dữ liệu dưới dạng đối tượng tf.data.Dataset , vì vậy lời khuyên từ hướng dẫn tf.data vẫn được áp dụng.

Bộ dữ liệu điểm chuẩn

Sử dụng tfds.benchmark(ds) để chuẩn bất kỳ đối tượng tf.data.Dataset nào.

Đảm bảo chỉ ra batch_size= để chuẩn hóa kết quả (ví dụ: 100 iter / sec -> 3200 ex / sec). Điều này hoạt động với bất kỳ tệp nào có thể lặp lại (ví dụ: 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)

Bộ dữ liệu nhỏ (dưới 1 GB)

Tất cả các tập dữ liệu TFDS lưu trữ dữ liệu trên đĩa ở định dạng TFRecord . Đối với các tập dữ liệu nhỏ (ví dụ: MNIST, CIFAR-10 / -100), việc đọc từ .tfrecord có thể thêm chi phí đáng kể.

Khi các tập dữ liệu đó vừa với bộ nhớ, có thể cải thiện đáng kể hiệu suất bằng cách lưu vào bộ nhớ đệm hoặc tải trước tập dữ liệu. Lưu ý rằng TFDS tự động lưu vào bộ nhớ cache các tập dữ liệu nhỏ (phần sau có chi tiết).

Lưu vào bộ nhớ đệm tập dữ liệu

Đây là một ví dụ về đường ống dữ liệu lưu trữ rõ ràng tập dữ liệu sau khi chuẩn hóa hình ảnh.

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)

Khi lặp qua tập dữ liệu này, lần lặp thứ hai sẽ nhanh hơn nhiều so với lần đầu tiên nhờ vào bộ nhớ đệm.

Tự động lưu vào bộ nhớ đệm

Theo mặc định, tập dữ liệu tự động lưu vào bộ nhớ đệm TFDS (với ds.cache() ) đáp ứng các ràng buộc sau:

  • Tổng kích thước tập dữ liệu (tất cả các phần tách) được xác định và <250 MiB
  • shuffle_files bị tắt hoặc chỉ đọc một phân đoạn duy nhất

Có thể bỏ chọn tính năng tự động lưu vào bộ nhớ đệm bằng cách chuyển try_autocaching=False đến tfds.ReadConfig trong tfds.load . Hãy xem tài liệu danh mục tập dữ liệu để xem liệu một tập dữ liệu cụ thể có sử dụng bộ đệm tự động hay không.

Tải toàn bộ dữ liệu dưới dạng một Tensor duy nhất

Nếu tập dữ liệu của bạn vừa với bộ nhớ, bạn cũng có thể tải tập dữ liệu đầy đủ dưới dạng một mảng Tensor hoặc NumPy. Có thể làm như vậy bằng cách đặt batch_size=-1 để gộp tất cả các ví dụ trong một tf.Tensor duy nhất. Sau đó, sử dụng tfds.as_numpy để chuyển đổi từ tf.Tensor sang 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,
))

Bộ dữ liệu lớn

Các tập dữ liệu lớn được chia nhỏ (chia thành nhiều tệp) và thường không vừa với bộ nhớ, vì vậy chúng không nên được lưu vào bộ nhớ đệm.

Xáo trộn và đào tạo

Trong quá trình đào tạo, điều quan trọng là phải xáo trộn dữ liệu tốt - dữ liệu xáo trộn kém có thể dẫn đến độ chính xác đào tạo thấp hơn.

Ngoài việc sử dụng ds.shuffle để xáo trộn các bản ghi, bạn cũng nên đặt shuffle_files=True để có được hành vi xáo trộn tốt cho các tập dữ liệu lớn hơn được chia nhỏ thành nhiều tệp. Nếu không, các kỷ nguyên sẽ đọc các phân đoạn theo cùng một thứ tự và vì vậy dữ liệu sẽ không thực sự ngẫu nhiên.

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

Ngoài ra, khi shuffle_files=True , TFDS vô hiệu hóa các options.deterministic . Xác định, điều này có thể làm tăng hiệu suất một chút. Để xáo trộn xác định, có thể chọn không sử dụng tính năng này với tfds.ReadConfig : bằng cách đặt read_config.shuffle_seed hoặc ghi đè read_config.options.deterministic .

Tự động phân chia dữ liệu của bạn trên các công nhân (TF)

Khi đào tạo trên nhiều công nhân, bạn có thể sử dụng đối số input_context của tfds.ReadConfig , vì vậy mỗi công nhân sẽ đọc một tập con dữ liệu.

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)

Điều này bổ sung cho API subsplit. Đầu tiên, API subplit được áp dụng: train[:50%] được chuyển đổi thành danh sách các tệp để đọc. Sau đó, một ds.shard() được áp dụng trên các tệp đó. Ví dụ: khi sử dụng train[:50%] với num_input_pipelines=2 , mỗi người trong số 2 công nhân sẽ đọc 1/4 dữ liệu.

Khi shuffle_files=True , các tệp được xáo trộn trong một worker, nhưng không phải giữa các worker. Mỗi worker sẽ đọc cùng một tập hợp con của các tệp giữa các kỷ nguyên.

Tự động phân chia dữ liệu của bạn trên các công nhân (Jax)

Với Jax, bạn có thể sử dụng API tfds.split_for_jax_process hoặc tfds.even_splits để phân phối dữ liệu của bạn trên các công nhân. Xem hướng dẫn API phân tách .

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

tfds.split_for_jax_process là một bí danh đơn giản cho:

# 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()]

Giải mã hình ảnh nhanh hơn

Theo mặc định, TFDS tự động giải mã hình ảnh. Tuy nhiên, có những trường hợp có thể hiệu quả hơn nếu bỏ qua giải mã hình ảnh bằng tfds.decode.SkipDecoding và áp dụng thủ công op tf.io.decode_image :

Mã cho cả hai ví dụ có sẵn trong hướng dẫn giải mã .

Bỏ qua các tính năng không sử dụng

Nếu bạn chỉ sử dụng một tập hợp con của các tính năng, bạn có thể bỏ qua hoàn toàn một số tính năng. Nếu tập dữ liệu của bạn có nhiều tính năng không được sử dụng, việc không giải mã chúng có thể cải thiện đáng kể hiệu suất. Xem https://www.tensorflow.org/datasets/decode#only_decode_a_sub-set_of_the_features