Dostosowywanie dekodowania funkcji

tfds.decode API pozwala zastąpić domyślny funkcji dekodowania. 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 (dla lepszej wydajności), można całkowicie pominąć dekodowanie obrazu. Działa to zarówno tfds.features.Image 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/mieszaj zbiór danych przed dekodowaniem obrazów

Podobnie jak w poprzednim przykładzie, można użyć tfds.decode.SkipDecoding() , aby wstawić dodatkowe tf.data dostosowywania rurociągu przed dekodowania obrazu. W ten sposób przefiltrowane obrazy nie zostaną zdekodowane i możesz 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)

Kadrowanie i dekodowanie w tym samym czasie

Aby zastąpić domyślny tf.io.decode_image operację, można utworzyć nowy tfds.decode.Decoder obiekt używając tfds.decode.make_decoder() dekoratora.

@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ównoznaczne z:

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 są Sequence(Image()) . Przy stosowaniu niestandardowych dekoderów zostaną one zastosowane do poszczególnych ramek. 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ównoznaczne z:

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 funkcji.

Możliwe jest również całkowite pominięcie niektórych funkcji, 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 będzie wybrać podzbiór builder.info.features zgodne z podaną tfds.decode.PartialDecoding strukturę.

W powyższym kodzie, funkcjonalnym są niejawnie ekstrakcji dopasować builder.info.features . Możliwe jest również jednoznaczne zdefiniowanie cech. Powyższy kod jest odpowiednikiem:

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 mogą być przekazywane do tfds.decode.PartialDecoding poprzez PartialDecoding(..., decoders={}) kwargs.