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
:
- Khi lọc các ví dụ (với
tf.data.Dataset.filter
), để giải mã hình ảnh sau khi các ví dụ đã được lọc. - Khi cắt ảnh, để sử dụng op
tf.image.decode_and_crop_jpeg
được hợp nhất.
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