Dostosowywanie dekodowania funkcji

Interfejs API tfds.decode umożliwia zastąpienie domyślnego dekodowania funkcji. Głównym przypadkiem użycia jest pominięcie dekodowania obrazu w celu uzyskania lepszej wydajności.

Przykłady użycia

Pomijanie dekodowania obrazu

Aby zachować pełną kontrolę nad potokiem dekodowania lub zastosować filtr przed dekodowaniem obrazów (w celu uzyskania lepszej wydajności), możesz całkowicie pominąć dekodowanie obrazu. Działa to zarówno z tfds.features.Image jak i tfds.features.Video .

ds = tfds.load('imagenet2012', split='train', decoders={
    'image': tfds.decode.SkipDecoding(),
})

for example in ds.take(1):
  assert example['image'].dtype == tf.string  # Images are not decoded

Filtruj/tasuj zbiór danych, zanim obrazy zostaną zdekodowane

Podobnie jak w poprzednim przykładzie, możesz użyć tfds.decode.SkipDecoding() w celu wstawienia dodatkowego dostosowania potoku tf.data przed zdekodowaniem obrazu. W ten sposób przefiltrowane obrazy nie zostaną zdekodowane i będzie można użyć większego bufora losowego.

# Load the base dataset without decoding
ds, ds_info = tfds.load(
    'imagenet2012',
    split='train',
    decoders={
        'image': tfds.decode.SkipDecoding(),  # Image won't be decoded here
    },
    as_supervised=True,
    with_info=True,
)
# Apply filter and shuffle
ds = ds.filter(lambda image, label: label != 10)
ds = ds.shuffle(10000)
# Then decode with ds_info.features['image']
ds = ds.map(
    lambda image, label: ds_info.features['image'].decode_example(image), label)

Przycinanie i dekodowanie w tym samym czasie

Aby zastąpić domyślną operację tf.io.decode_image , możesz utworzyć nowy obiekt tfds.decode.Decoder za pomocą dekoratora tfds.decode.make_decoder() .

@tfds.decode.make_decoder()
def decode_example(serialized_image, feature):
  crop_y, crop_x, crop_height, crop_width = 10, 10, 64, 64
  return tf.image.decode_and_crop_jpeg(
      serialized_image,
      [crop_y, crop_x, crop_height, crop_width],
      channels=feature.feature.shape[-1],
  )

ds = tfds.load('imagenet2012', split='train', decoders={
    # With video, decoders are applied to individual frames
    'image': decode_example(),
})

Co jest równoważne:

def decode_example(serialized_image, feature):
  crop_y, crop_x, crop_height, crop_width = 10, 10, 64, 64
  return tf.image.decode_and_crop_jpeg(
      serialized_image,
      [crop_y, crop_x, crop_height, crop_width],
      channels=feature.shape[-1],
  )

ds, ds_info = tfds.load(
    'imagenet2012',
    split='train',
    with_info=True,
    decoders={
        'image': tfds.decode.SkipDecoding(),  # Skip frame decoding
    },
)
ds = ds.map(functools.partial(decode_example, feature=ds_info.features['image']))

Dostosowywanie dekodowania wideo

Wideo to Sequence(Image()) . W przypadku stosowania niestandardowych dekoderów zostaną one zastosowane do poszczególnych klatek. Oznacza to, że dekodery obrazów są automatycznie kompatybilne z wideo.

@tfds.decode.make_decoder()
def decode_example(serialized_image, feature):
  crop_y, crop_x, crop_height, crop_width = 10, 10, 64, 64
  return tf.image.decode_and_crop_jpeg(
      serialized_image,
      [crop_y, crop_x, crop_height, crop_width],
      channels=feature.feature.shape[-1],
  )

ds = tfds.load('ucf101', split='train', decoders={
    # With video, decoders are applied to individual frames
    'video': decode_example(),
})

Co jest równoważne:

def decode_frame(serialized_image):
  """Decodes a single frame."""
  crop_y, crop_x, crop_height, crop_width = 10, 10, 64, 64
  return tf.image.decode_and_crop_jpeg(
      serialized_image,
      [crop_y, crop_x, crop_height, crop_width],
      channels=ds_info.features['video'].shape[-1],
  )


def decode_video(example):
  """Decodes all individual frames of the video."""
  video = example['video']
  video = tf.map_fn(
      decode_frame,
      video,
      dtype=ds_info.features['video'].dtype,
      parallel_iterations=10,
  )
  example['video'] = video
  return example


ds, ds_info = tfds.load('ucf101', split='train', with_info=True, decoders={
    'video': tfds.decode.SkipDecoding(),  # Skip frame decoding
})
ds = ds.map(decode_video)  # Decode the video

Dekoduj tylko podzbiór cech.

Można także całkowicie pominąć niektóre funkcje, określając tylko te, których potrzebujesz. Wszystkie inne funkcje zostaną zignorowane/pominięte.

builder = tfds.builder('my_dataset')
builder.as_dataset(split='train', decoders=tfds.decode.PartialDecoding({
    'image': True,
    'metadata': {'num_objects', 'scene_name'},
    'objects': {'label'},
})

TFDS wybierze podzbiór builder.info.features pasujący do podanej struktury tfds.decode.PartialDecoding .

W powyższym kodzie wyróżnione elementy są domyślnie wyodrębniane w celu dopasowania do builder.info.features . Możliwe jest także wyraźne zdefiniowanie cech. Powyższy kod jest równoważny:

builder = tfds.builder('my_dataset')
builder.as_dataset(split='train', decoders=tfds.decode.PartialDecoding({
    'image': tfds.features.Image(),
    'metadata': {
        'num_objects': tf.int64,
        'scene_name': tfds.features.Text(),
    },
    'objects': tfds.features.Sequence({
        'label': tfds.features.ClassLabel(names=[]),
    }),
})

Oryginalne metadane (nazwy etykiet, kształt obrazu itp.) są automatycznie ponownie wykorzystywane, więc ich podawanie nie jest wymagane.

tfds.decode.SkipDecoding można przekazać do tfds.decode.PartialDecoding za pomocą kwargs PartialDecoding(..., decoders={}) .