API tfds.decode
позволяет переопределить декодирование функций по умолчанию. Основной вариант использования — пропустить декодирование изображения для повышения производительности.
Примеры использования
Пропуск декодирования изображения
Чтобы сохранить полный контроль над конвейером декодирования или применить фильтр перед декодированием изображений (для повышения производительности), вы можете полностью пропустить декодирование изображения. Это работает как с tfds.features.Image
, так и 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
Фильтровать/перетасовать набор данных перед декодированием изображений
Как и в предыдущем примере, вы можете использовать tfds.decode.SkipDecoding()
чтобы вставить дополнительные настройки конвейера tf.data
перед декодированием изображения. Таким образом, отфильтрованные изображения не будут декодированы, и вы сможете использовать буфер перемешивания большего размера.
# 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)
Обрезка и декодирование одновременно
Чтобы переопределить операцию tf.io.decode_image
по умолчанию, вы можете создать новый объект tfds.decode.Decoder
, используя декоратор 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(),
})
Что эквивалентно:
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']))
Настройка декодирования видео
Видео — это Sequence(Image())
. При применении пользовательских декодеров они будут применяться к отдельным кадрам. Это означает, что декодеры изображений автоматически совместимы с видео.
@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(),
})
Что эквивалентно:
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
Декодируйте только подмножество функций.
Также можно полностью пропустить некоторые функции, указав только те функции, которые вам нужны. Все остальные функции будут игнорироваться/пропускаться.
builder = tfds.builder('my_dataset')
builder.as_dataset(split='train', decoders=tfds.decode.PartialDecoding({
'image': True,
'metadata': {'num_objects', 'scene_name'},
'objects': {'label'},
})
TFDS выберет подмножество builder.info.features
соответствующее заданной структуре tfds.decode.PartialDecoding
.
В приведенном выше коде функции неявно извлекаются в соответствии с builder.info.features
. Также возможно явно определить признаки. Приведенный выше код эквивалентен:
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=[]),
}),
})
Исходные метаданные (названия меток, форма изображения и т. д.) автоматически используются повторно, поэтому их не требуется предоставлять.
tfds.decode.SkipDecoding
можно передать в tfds.decode.PartialDecoding
через kwargs PartialDecoding(..., decoders={})
.