Personnalisation du décodage des fonctionnalités

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

L' tfds.decode API vous permet de passer outre le décodage de fonction par défaut. Le cas d'utilisation principal est de sauter le décodage de l'image pour de meilleures performances.

Exemples d'utilisation

Sauter le décodage de l'image

Pour garder un contrôle total sur le pipeline de décodage, ou pour appliquer un filtre avant que les images ne soient décodées (pour de meilleures performances), vous pouvez ignorer complètement le décodage de l'image. Cela fonctionne aussi bien avec tfds.features.Image et 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

Filtrer / mélanger l'ensemble de données avant que les images ne soient décodées

De même à l'exemple précédent, vous pouvez utiliser tfds.decode.SkipDecoding() pour insérer plus tf.data personnalisation du pipeline avant le décodage de l'image. De cette façon, les images filtrées ne seront pas décodées et vous pourrez utiliser un plus grand tampon de lecture aléatoire.

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

Recadrage et décodage en même temps

Pour remplacer la valeur par défaut tf.io.decode_image opération, vous pouvez créer un nouveau tfds.decode.Decoder objet en utilisant l' tfds.decode.make_decoder() décorateur.

@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(),
})

Ce qui équivaut à :

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']))

Personnalisation du décodage vidéo

Vidéo sont Sequence(Image()) . Lors de l'application de décodeurs personnalisés, ils seront appliqués à des images individuelles. Cela signifie que les décodeurs d'images sont automatiquement compatibles avec la vidéo.

@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(),
})

Ce qui équivaut à :

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

Décoder uniquement un sous-ensemble des fonctionnalités.

Il est également possible d'ignorer entièrement certaines fonctionnalités en spécifiant uniquement les fonctionnalités dont vous avez besoin. Toutes les autres fonctionnalités seront ignorées/sautées.

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

TFDS sélectionne le sous - ensemble de builder.info.features qui correspond à la donnée tfds.decode.PartialDecoding structure.

Dans le code ci - dessus, la vedette sont extraits implicitement correspondre builder.info.features . Il est également possible de définir explicitement les fonctionnalités. Le code ci-dessus équivaut à :

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=[]),
    }),
})

Les métadonnées d'origine (noms des étiquettes, forme de l'image,...) sont automatiquement réutilisées, il n'est donc pas nécessaire de les fournir.

tfds.decode.SkipDecoding peut être passé à tfds.decode.PartialDecoding , par la PartialDecoding(..., decoders={}) kwargs.