Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Wskazówki dotyczące wydajności

Ten dokument zawiera wskazówki dotyczące wydajności specyficzne dla TFDS. Należy pamiętać, że TFDS udostępnia zestawy danych jako tf.data.Dataset s, więc porady z przewodnika tf.data nadal mają zastosowanie.

Zestawy danych porównawczych

Użyj tfds.core.benchmark(ds) aby wykonać test porównawczy dowolnego obiektu tf.data.Dataset .

Upewnij się, że wskazałeś batch_size= aby znormalizować wyniki (np. 100 iter / sec -> 3200 ex / sec).

ds = tfds.load('mnist', split='train').batch(32).prefetch()
# Display some benchmark statistics
tfds.core.benchmark(ds, batch_size=32)
# Second iteration is much faster, due to auto-caching
tfds.core.benchmark(ds, batch_size=32)

Małe zbiory danych (<GB)

Wszystkie zestawy danych TFDS przechowują dane na dysku w formacie TFRecord . W przypadku małych zbiorów danych (np. Mnist, Cifar, ...), czytanie z .tfrecord może .tfrecord znaczne obciążenie.

Ponieważ te zestawy danych mieszczą się w pamięci, można znacznie poprawić wydajność poprzez buforowanie lub wstępne ładowanie zestawu danych. Należy zauważyć, że TFDS automatycznie buforuje małe zestawy danych (szczegółowe informacje znajdują się w następnej sekcji).

Buforowanie zbioru danych

Oto przykład potoku danych, który jawnie buforuje zestaw danych po normalizacji obrazów.

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.experimental.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)

Podczas iteracji po tym zestawie danych druga iteracja będzie znacznie szybsza niż pierwsza dzięki buforowaniu.

Automatyczne buforowanie

Domyślnie TFDS automatycznie buforuje zestawy danych, które spełniają następujące ograniczenia:

  • Całkowity rozmiar zbioru danych (wszystkie podziały) jest zdefiniowany i wynosi <250 MB
  • shuffle_files jest wyłączone lub shuffle_files jest tylko jeden fragment

Można zrezygnować z automatycznego buforowania, przekazując try_autocaching=False do tfds.ReadConfig w tfds.load . Zapoznaj się z dokumentacją katalogu zestawów danych, aby sprawdzić, czy określony zestaw danych będzie korzystał z automatycznego buforowania.

Ładowanie pełnych danych jako pojedynczego Tensora

Jeśli Twój zestaw danych mieści się w pamięci, możesz również załadować pełny zestaw danych jako pojedynczą tablicę Tensor lub NumPy. Można to zrobić, ustawiając batch_size=-1 aby batch_size=-1 wszystkie przykłady w jednym tf.Tensor . Następnie użyj tfds.as_numpy do konwersji z tf.Tensor na 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,
))

Duże zbiory danych

Duże zestawy danych są podzielone na fragmenty (podzielone na wiele plików) i zwykle nie mieszczą się w pamięci, więc nie powinny być buforowane.

Shuffle i trening

Podczas treningu ważne jest, aby dobrze przetasować dane; źle przetasowane dane mogą spowodować niższą dokładność treningu.

Oprócz używania ds.shuffle do tasowania rekordów, powinieneś także ustawić shuffle_files=True aby uzyskać dobre zachowanie podczas tasowania dla większych zestawów danych, które są podzielone na fragmenty w wielu plikach. W przeciwnym razie epoki będą odczytywać fragmenty w tej samej kolejności, więc dane nie będą w pełni losowe.

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

Dodatkowo, gdy shuffle_files=True , TFDS wyłącza options.experimental_deterministic , co może nieznacznie zwiększyć wydajność. Aby uzyskać losowanie deterministyczne, można zrezygnować z tej funkcji za pomocą tfds.ReadConfig : albo ustawiając read_config.shuffle_seed albo nadpisując read_config.options.experimental_deterministic .

Automatycznie dziel dane między pracownikami

Podczas szkolenia na wielu pracowników, można użyć input_context argument tfds.ReadConfig , więc każdy pracownik będzie czytać podzbiór danych.

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)

Jest to uzupełnienie interfejsu API subplit. Najpierw stosowane jest subplit API ( train[:50%] jest konwertowane na listę plików do odczytania), a następnie do tych plików stosowana jest ds.shard() . Przykład: używając train[:50%] z num_input_pipelines=2 , każdy z 2 pracowników odczyta 1/4 danych.

Gdy shuffle_files=True , pliki są tasowane w ramach jednego pracownika, ale nie między pracownikami. Każdy pracownik będzie czytać ten sam podzbiór plików między epokami.

Szybsze dekodowanie obrazu

Domyślnie TFDS automatycznie dekoduje obrazy. Istnieją jednak przypadki, w których skuteczniejsze może być pominięcie dekodowania obrazu za pomocą tfds.decode.SkipDecoding i ręczne zastosowanie opcji tf.io.decode_image :

  • Podczas filtrowania przykładów (za pomocą ds.filter ), aby zdekodować obrazy po przefiltrowaniu przykładów.
  • Podczas kadrowania zdjęć, użyj fused tf.image.decode_and_crop_jpeg op.

Kod obu przykładów jest dostępny w przewodniku po dekodowaniu .