Gracias por sintonizar Google I/O. Ver todas las sesiones bajo demanda Ver bajo demanda

Personalización de la decodificación de funciones

El tfds.decode API le permite anular la decodificación función predeterminada. El caso de uso principal es omitir la decodificación de imágenes para un mejor rendimiento.

Ejemplos de uso

Omitir la decodificación de imágenes

Para mantener el control total sobre la canalización de decodificación, o para aplicar un filtro antes de que se decodifiquen las imágenes (para un mejor rendimiento), puede omitir la decodificación de la imagen por completo. Esto funciona tanto con tfds.features.Image y 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

Filtrar / mezclar el conjunto de datos antes de decodificar las imágenes

Al igual que en el ejemplo anterior, puede utilizar tfds.decode.SkipDecoding() para insertar adicional tf.data personalización de tuberías antes de decodificar la imagen. De esa forma, las imágenes filtradas no se decodificarán y podrá utilizar un búfer de reproducción aleatoria más grande.

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

Recortar y decodificar al mismo tiempo

Para reemplazar el valor predeterminado tf.io.decode_image operación, puede crear un nuevo tfds.decode.Decoder objeto mediante el tfds.decode.make_decoder() decorador.

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

Que es equivalente a:

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

Personalización de la decodificación de video

De vídeo son Sequence(Image()) . Al aplicar decodificadores personalizados, se aplicarán a fotogramas individuales. Esto significa que los decodificadores de imágenes son automáticamente compatibles con el video.

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

Que es equivalente a:

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

Solo decodifica un subconjunto de funciones.

También es posible omitir por completo algunas funciones especificando solo las funciones que necesita. Todas las demás funciones se ignorarán / omitirán.

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

TFDS seleccionará el subconjunto de builder.info.features que cumplan el criterio dado tfds.decode.PartialDecoding estructura.

En el código anterior, la destacada se extraen de forma implícita para que coincida con builder.info.features . También es posible definir explícitamente las características. El código anterior es equivalente a:

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

Los metadatos originales (nombres de etiquetas, forma de la imagen, ...) se reutilizan automáticamente, por lo que no es necesario proporcionarlos.

tfds.decode.SkipDecoding se puede pasar a tfds.decode.PartialDecoding , a través de la PartialDecoding(..., decoders={}) kwargs.