tf.data.experimental.SqlDataset
Dataset, состоящий из результатов SQL-запроса.
Наследует: Dataset
tf.data.experimental.SqlDataset(
driver_name, data_source_name, query, output_types
)
SqlDataset позволяет пользователю считывать данные из результирующего набора SQL-запроса. Например:
dataset = tf.data.experimental.SqlDataset("sqlite", "/foo/bar.sqlite3",
"SELECT name, age FROM people",
(tf.string, tf.int32))
# Prints the rows of the result set of the above query.
for element in dataset:
print(element)
| Аргументы | |
|---|---|
driver_name | Тензор tf.string ранга 0, содержащий тип базы данных. В настоящее время поддерживается только значение 'sqlite'. |
data_source_name | Тензор tf.string ранга 0, содержащий строку подключения к базе данных. |
query | Тензор tf.string ранга 0, содержащий SQL-запрос для выполнения. |
output_types | Кортеж объектов tf.DType, представляющих типы столбцов, возвращаемых query. |
| Атрибуты | |
|---|---|
element_spec | Спецификация типов элемента этого набора данных.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset.element_spec TensorSpec(shape=(), dtype=tf.int32, name=None) Подробнее см. в этом руководстве. |
Методы
apply
apply(
transformation_func
) -> 'DatasetV2'
Применяет функцию преобразования к этому набору данных.
apply позволяет объединять в цепочку пользовательские преобразования Dataset, представленные функциями, которые принимают один аргумент Dataset и возвращают преобразованный Dataset.
dataset = tf.data.Dataset.range(100) def dataset_fn(ds): return ds.filter(lambda x: x < 5) dataset = dataset.apply(dataset_fn) list(dataset.as_numpy_iterator()) [0, 1, 2, 3, 4]
| Аргументы | |
|---|---|
transformation_func | Функция, принимающая один аргумент Dataset и возвращающая Dataset. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
as_numpy_iterator
as_numpy_iterator()
Возвращает итератор, преобразующий все элементы набора данных в массивы NumPy.
Используйте as_numpy_iterator для просмотра содержимого набора данных. Чтобы увидеть формы и типы элементов, выводите элементы набора данных напрямую, а не используйте as_numpy_iterator.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) for element in dataset: print(element) tf.Tensor(1, shape=(), dtype=int32) tf.Tensor(2, shape=(), dtype=int32) tf.Tensor(3, shape=(), dtype=int32)
Для этого метода требуется, чтобы выполнение происходило в энергичном режиме, а element_spec набора данных содержал только компоненты TensorSpec.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) for element in dataset.as_numpy_iterator(): print(element) 1 2 3
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) print(list(dataset.as_numpy_iterator())) [1, 2, 3]
as_numpy_iterator() сохраняет вложенную структуру элементов набора данных.
dataset = tf.data.Dataset.from_tensor_slices({'a': ([1, 2], [3, 4]),
'b': [5, 6]})
list(dataset.as_numpy_iterator()) == [{'a': (1, 3), 'b': 5},
{'a': (2, 4), 'b': 6}]
True| Возвращает | |
|---|---|
| Итерируемый объект, содержащий элементы набора данных, тензоры которых преобразованы в массивы NumPy. |
| Вызывает исключения | |
|---|---|
TypeError | если элемент содержит значение, не относящееся к Tensor. |
RuntimeError | если энергичное выполнение не включено. |
batch
batch(
batch_size,
drop_remainder=False,
num_parallel_calls=None,
deterministic=None,
name=None
) -> 'DatasetV2'
Объединяет последовательные элементы этого набора данных в пакеты.
dataset = tf.data.Dataset.range(8) dataset = dataset.batch(3) list(dataset.as_numpy_iterator()) [array([0, 1, 2]), array([3, 4, 5]), array([6, 7])]
dataset = tf.data.Dataset.range(8) dataset = dataset.batch(3, drop_remainder=True) list(dataset.as_numpy_iterator()) [array([0, 1, 2]), array([3, 4, 5])]
Компоненты результирующего элемента получат дополнительное внешнее измерение, равное batch_size (или N % batch_size для последнего элемента, если batch_size не делит число входных элементов N нацело и drop_remainder имеет значение False). Если программа предполагает, что внешнее измерение пакетов одинаково, задайте аргумент drop_remainder равным True, чтобы не создавать пакет меньшего размера.
Примечание: Если программе требуются данные со статически известной формой (например, при использовании XLA), следует использоватьdrop_remainder=True. Безdrop_remainder=Trueформа выходного набора данных будет иметь неизвестное начальное измерение из-за возможности создания последнего пакета меньшего размера.
| Аргументы | |
|---|---|
batch_size | Скалярный тензор tf.int64 tf.Tensor, задающий число последовательных элементов этого набора данных, объединяемых в один пакет. |
drop_remainder | (Необязательно.) Скалярный тензор tf.bool tf.Tensor, указывающий, следует ли отбрасывать последний пакет, если в нем меньше batch_size элементов; по умолчанию пакет меньшего размера не отбрасывается. |
num_parallel_calls | (Необязательно.) Скалярный тензор tf.int64 tf.Tensor, задающий число пакетов, которые следует вычислять асинхронно параллельно. Если параметр не указан, пакеты вычисляются последовательно. Если используется значение tf.data.AUTOTUNE, число параллельных вызовов задается динамически с учетом доступных ресурсов. |
deterministic | (Необязательно.) Если задан параметр num_parallel_calls и указано это логическое значение (True или False), оно определяет порядок выдачи элементов преобразованием. Если задано значение False, преобразование может выдавать элементы не по порядку, обменивая детерминированность на производительность. Если параметр не указан, поведение определяется параметром tf.data.Options.deterministic (по умолчанию — True). |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
bucket_by_sequence_length
bucket_by_sequence_length(
element_length_func,
bucket_boundaries,
bucket_batch_sizes,
padded_shapes=None,
padding_values=None,
pad_to_bucket_boundary=False,
no_padding=False,
drop_remainder=False,
name=None
) -> 'DatasetV2'
Преобразование, распределяющее элементы Dataset по корзинам в зависимости от длины.
Элементы Dataset группируются по длине, после чего выполняются дополнение и пакетирование.
Это полезно для задач обработки последовательностей, в которых элементы имеют переменную длину. Группировка элементов близкой длины уменьшает долю дополнения в пакете, повышая эффективность шага обучения.
Ниже приведен пример распределения входных данных по 3 корзинам "[0, 3), [3, 5), [5, inf)" в зависимости от длины последовательности, с размером пакета 2.
elements = [
[0], [1, 2, 3, 4], [5, 6, 7],
[7, 8, 9, 10, 11], [13, 14, 15, 16, 19, 20], [21, 22]]
dataset = tf.data.Dataset.from_generator(
lambda: elements, tf.int64, output_shapes=[None])
dataset = dataset.bucket_by_sequence_length(
element_length_func=lambda elem: tf.shape(elem)[0],
bucket_boundaries=[3, 5],
bucket_batch_sizes=[2, 2, 2])
for elem in dataset.as_numpy_iterator():
print(elem)
[[1 2 3 4]
[5 6 7 0]]
[[ 7 8 9 10 11 0]
[13 14 15 16 19 20]]
[[ 0 0]
[21 22]]| Аргументы | |
|---|---|
element_length_func | Функция, преобразующая элемент Dataset в tf.int32; определяет длину элемента, которая задает корзину для него. |
bucket_boundaries | list<int>, верхние границы длины корзин. |
bucket_batch_sizes | list<int>, размер пакета для каждой корзины. Длина должна быть len(bucket_boundaries) + 1. |
padded_shapes | Вложенная структура объектов tf.TensorShape, передаваемая в tf.data.Dataset.padded_batch. Если не указана, используется dataset.output_shapes; в результате измерения переменной длины дополняются до максимальной длины в каждом пакете. |
padding_values | Значения для дополнения, передаваемые в tf.data.Dataset.padded_batch. По умолчанию используется дополнение нулями. |
pad_to_bucket_boundary | Логическое значение: если False, измерения неизвестного размера дополняются до максимальной длины в пакете. Если True, измерения неизвестного размера дополняются до границы корзины минус 1 (то есть до максимальной длины в каждой корзине), и вызывающий код должен гарантировать, что исходный Dataset не содержит элементов длиной больше max(bucket_boundaries). |
no_padding | bool, указывает, следует ли дополнять признаки пакета (признаки должны иметь тип tf.sparse.SparseTensor либо одинаковую форму). |
drop_remainder | (Необязательно.) Скалярный тензор tf.bool tf.Tensor, указывающий, следует ли отбрасывать последний пакет, если в нем меньше batch_size элементов; по умолчанию пакет меньшего размера не отбрасывается. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
| Вызывает исключения | |
|---|---|
ValueError | если len(bucket_batch_sizes) != len(bucket_boundaries) + 1. |
cache
cache(
filename='', name=None
) -> 'DatasetV2'
Кэширует элементы этого набора данных.
При первом обходе набора данных его элементы кэшируются в указанном файле или в памяти. При последующих обходах используются кэшированные данные.
Примечание: Чтобы гарантировать завершение создания кэша, входной набор данных необходимо обойти полностью, до вызова StopIteration. В противном случае при последующих обходах кэшированные данные могут не использоваться.
dataset = tf.data.Dataset.range(5) dataset = dataset.map(lambda x: x**2) dataset = dataset.cache() # The first time reading through the data will generate the data using # `range` and `map`. list(dataset.as_numpy_iterator()) [0, 1, 4, 9, 16] # Subsequent iterations read from the cache. list(dataset.as_numpy_iterator()) [0, 1, 4, 9, 16]
При кэшировании в файл данные сохраняются между запусками. Даже при первом обходе данные считываются из файла кэша. Изменение входного конвейера перед вызовом .cache() не даст результата, пока файл кэша не будет удален или имя файла не будет изменено.
dataset = tf.data.Dataset.range(5)
dataset = dataset.cache("/path/to/file")
list(dataset.as_numpy_iterator())
# [0, 1, 2, 3, 4]
dataset = tf.data.Dataset.range(10)
dataset = dataset.cache("/path/to/file") # Same file!
list(dataset.as_numpy_iterator())
# [0, 1, 2, 3, 4]
Примечание:cacheбудет выдавать одни и те же элементы при каждом обходе набора данных. Если требуется рандомизировать порядок обхода, обязательно вызовитеshuffleпосле вызоваcache.
| Аргументы | |
|---|---|
filename | Скалярный тензор tf.string tf.Tensor, задающий имя каталога файловой системы для кэширования элементов этого набора данных. Если имя файла не указано, набор данных кэшируется в памяти. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
cardinality
cardinality()
Возвращает мощность набора данных, если она известна.
cardinality может возвращать tf.data.INFINITE_CARDINALITY, если набор данных содержит бесконечное число элементов, или tf.data.UNKNOWN_CARDINALITY, если анализу не удалось определить число элементов набора данных (например, когда источником набора данных является файл).
dataset = tf.data.Dataset.range(42) print(dataset.cardinality().numpy()) 42 dataset = dataset.repeat() cardinality = dataset.cardinality() print((cardinality == tf.data.INFINITE_CARDINALITY).numpy()) True dataset = dataset.filter(lambda x: True) cardinality = dataset.cardinality() print((cardinality == tf.data.UNKNOWN_CARDINALITY).numpy()) True
| Возвращает | |
|---|---|
Скалярный Tensor типа tf.int64, представляющий мощность набора данных. Если мощность бесконечна или неизвестна, cardinality возвращает именованные константы tf.data.INFINITE_CARDINALITY и tf.data.UNKNOWN_CARDINALITY соответственно. |
choose_from_datasets
@staticmethod
choose_from_datasets(
datasets, choice_dataset, stop_on_empty_dataset=True
) -> 'DatasetV2'
Создает набор данных, детерминированно выбирающий элементы из datasets.
Например, для следующих наборов данных:
datasets = [tf.data.Dataset.from_tensors("foo").repeat(),
tf.data.Dataset.from_tensors("bar").repeat(),
tf.data.Dataset.from_tensors("baz").repeat()]
# Define a dataset containing `[0, 1, 2, 0, 1, 2, 0, 1, 2]`.
choice_dataset = tf.data.Dataset.range(3).repeat(3)
result = tf.data.Dataset.choose_from_datasets(datasets, choice_dataset)
Элементами result будут:
"foo", "bar", "baz", "foo", "bar", "baz", "foo", "bar", "baz"
| Аргументы | |
|---|---|
datasets | Непустой список объектов tf.data.Dataset с совместимой структурой. |
choice_dataset | tf.data.Dataset типа tf.int64, состоящий из скалярных тензоров между 0 и len(datasets) - 1. |
stop_on_empty_dataset | Если True, выбор прекращается при обнаружении пустого набора данных. Если False, пустые наборы данных пропускаются. Рекомендуется задать значение True. Иначе выбранные элементы сначала будут соответствовать намерениям пользователя, но могут измениться, когда входные наборы данных опустеют. Это может быть трудно заметить, поскольку изначально набор данных выглядит корректно. По умолчанию — True. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
| Вызывает исключения | |
|---|---|
TypeError | Если datasets или choice_dataset имеет неверный тип. |
ValueError | Если datasets пуст. |
concatenate
concatenate(
dataset, name=None
) -> 'DatasetV2'
Создает Dataset, объединяя указанный набор данных с этим набором данных.
a = tf.data.Dataset.range(1, 4) # ==> [ 1, 2, 3 ] b = tf.data.Dataset.range(4, 8) # ==> [ 4, 5, 6, 7 ] ds = a.concatenate(b) list(ds.as_numpy_iterator()) [1, 2, 3, 4, 5, 6, 7] # The input dataset and dataset to be concatenated should have # compatible element specs. c = tf.data.Dataset.zip((a, b)) a.concatenate(c) Traceback (most recent call last): TypeError: Two datasets to concatenate have different types <dtype: 'int64'> and (tf.int64, tf.int64) d = tf.data.Dataset.from_tensor_slices(["a", "b", "c"]) a.concatenate(d) Traceback (most recent call last): TypeError: Two datasets to concatenate have different types <dtype: 'int64'> and <dtype: 'string'>
| Аргументы | |
|---|---|
dataset | Dataset для объединения. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
counter
@staticmethod
counter(
start=0,
step=1,
dtype=tf.dtypes.int64,
name=None
) -> 'DatasetV2'
Создает Dataset, которое ведет отсчет от start с шагом step.
В отличие от tf.data.Dataset.range, которое останавливается на заданном конечном числе, tf.data.Dataset.counter бесконечно выдает элементы.
dataset = tf.data.experimental.Counter().take(5) list(dataset.as_numpy_iterator()) [0, 1, 2, 3, 4] dataset.element_spec TensorSpec(shape=(), dtype=tf.int64, name=None) dataset = tf.data.experimental.Counter(dtype=tf.int32) dataset.element_spec TensorSpec(shape=(), dtype=tf.int32, name=None) dataset = tf.data.experimental.Counter(start=2).take(5) list(dataset.as_numpy_iterator()) [2, 3, 4, 5, 6] dataset = tf.data.experimental.Counter(start=2, step=5).take(5) list(dataset.as_numpy_iterator()) [2, 7, 12, 17, 22] dataset = tf.data.experimental.Counter(start=10, step=-1).take(5) list(dataset.as_numpy_iterator()) [10, 9, 8, 7, 6]
| Аргументы | |
|---|---|
start | (Необязательно.) Начальное значение счетчика. По умолчанию — 0. |
step | (Необязательно.) Шаг счетчика. По умолчанию — 1. |
dtype | (Необязательно.) Тип данных элементов счетчика. По умолчанию — tf.int64. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Dataset скалярных элементов dtype. |
enumerate
enumerate(
start=0, name=None
) -> 'DatasetV2'
Нумерует элементы этого набора данных.
Этот метод аналогичен enumerate в Python.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.enumerate(start=5) for element in dataset.as_numpy_iterator(): print(element) (5, 1) (6, 2) (7, 3)
# The (nested) structure of the input dataset determines the # structure of elements in the resulting dataset. dataset = tf.data.Dataset.from_tensor_slices([(7, 8), (9, 10)]) dataset = dataset.enumerate() for element in dataset.as_numpy_iterator(): print(element) (0, array([7, 8], dtype=int32)) (1, array([ 9, 10], dtype=int32))
| Аргументы | |
|---|---|
start | Скалярный тензор tf.int64 tf.Tensor, задающий начальное значение для нумерации. |
name | Необязательно. Имя операций tf.data, используемых enumerate. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
filter
filter(
predicate, name=None
) -> 'DatasetV2'
Фильтрует этот набор данных в соответствии с predicate.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.filter(lambda x: x < 3) list(dataset.as_numpy_iterator()) [1, 2] # `tf.math.equal(x, y)` is required for equality comparison def filter_fn(x): return tf.math.equal(x, 1) dataset = dataset.filter(filter_fn) list(dataset.as_numpy_iterator()) [1]
| Аргументы | |
|---|---|
predicate | Функция, преобразующая элемент набора данных в логическое значение. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
fingerprint
fingerprint()
Вычисляет отпечаток этого Dataset.
Если у двух наборов данных одинаковый отпечаток, гарантируется, что они будут выдавать идентичные элементы, если содержимое исходных входных файлов не меняется и данные выдаются детерминированно.
Однако одинаковые значения, выдаваемые двумя наборами данных, не всегда означают, что у них будет одинаковый отпечаток, поскольку графы могут быть построены по-разному.
Иными словами, даже если отпечатки двух наборов данных различаются, они все еще могут выдавать одинаковые значения.
| Возвращает | |
|---|---|
Скалярный тензор tf.Tensor типа tf.uint64. |
flat_map
flat_map(
map_func, name=None
) -> 'DatasetV2'
Применяет map_func к этому набору данных и объединяет результат в плоскую последовательность.
Сигнатура типа:
def flat_map( self: Dataset[T], map_func: Callable[[T], Dataset[S]] ) -> Dataset[S]
Используйте flat_map, если необходимо сохранить исходный порядок элементов набора данных. Например, чтобы преобразовать набор данных из пакетов в набор данных, состоящий из их элементов:
dataset = tf.data.Dataset.from_tensor_slices(
[[1, 2, 3], [4, 5, 6], [7, 8, 9]])
dataset = dataset.flat_map(tf.data.Dataset.from_tensor_slices)
list(dataset.as_numpy_iterator())
[1, 2, 3, 4, 5, 6, 7, 8, 9]tf.data.Dataset.interleave() является обобщением flat_map, поскольку flat_map дает тот же результат, что и tf.data.Dataset.interleave(cycle_length=1)
| Аргументы | |
|---|---|
map_func | Функция, преобразующая элемент набора данных в набор данных. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
from_generator
@staticmethod
from_generator(
generator,
output_types=None,
output_shapes=None,
args=None,
output_signature=None,
name=None
) -> 'DatasetV2'
Создает Dataset, элементы которого генерируются с помощью generator. (Устаревшие аргументы)
Примечание: В текущей реализацииDataset.from_generator()используетсяtf.numpy_function, поэтому на нее распространяются те же ограничения. В частности, операции, связанные с набором данных и итератором, должны выполняться на устройстве в том же процессе, что и программа Python, вызвавшаяDataset.from_generator(). В частности, использованиеfrom_generatorне позволит использовать службу tf.data для масштабирования обработки наборов данных. Телоgeneratorне будет сериализовано вGraphDef, поэтому этот метод не следует использовать, если необходимо сериализовать модель и восстановить ее в другой среде.
Аргумент generator должен быть вызываемым объектом, возвращающим объект, который поддерживает протокол iter() (например, функцию-генератор).
Элементы, генерируемые generator, должны быть совместимы либо с указанным аргументом output_signature, либо с указанными аргументами output_types и (необязательно) output_shapes.
Рекомендуется вызывать from_generator с помощью аргумента output_signature. В этом случае предполагается, что результат состоит из объектов с классами, формами и типами, заданными объектами tf.TypeSpec из аргумента output_signature:
def gen():
ragged_tensor = tf.ragged.constant([[1, 2], [3]])
yield 42, ragged_tensor
dataset = tf.data.Dataset.from_generator(
gen,
output_signature=(
tf.TensorSpec(shape=(), dtype=tf.int32),
tf.RaggedTensorSpec(shape=(2, None), dtype=tf.int32)))
list(dataset.take(1))
[(<tf.Tensor: shape=(), dtype=int32, numpy=42>,
<tf.RaggedTensor [[1, 2], [3]]>)]Также существует устаревший способ вызова from_generator: с одним аргументом output_types или вместе с аргументом output_shapes. В этом случае предполагается, что функция возвращает объекты tf.Tensor с типами, определёнными в output_types, и формами, которые либо неизвестны, либо определены в output_shapes.
Примечание: Еслиgeneratorзависит от изменяемых глобальных переменных или другого внешнего состояния, имейте в виду, что среда выполнения может вызыватьgeneratorнесколько раз (для поддержки повторного выполненияDataset) и в любой момент между вызовомDataset.from_generator()и созданием первого элемента генератором. Изменение глобальных переменных или внешнего состояния может привести к неопределённому поведению. Рекомендуем явно кэшировать любое внешнее состояние вgeneratorперед вызовомDataset.from_generator().
Примечание: Хотя параметрoutput_signatureпозволяет создавать элементыDataset, применениеDataset.from_generator()следует ограничить логикой, которую нельзя выразить с помощью операций tf.data. Использование операций tf.data внутри функции-генератора считается антипаттерном и может привести к постепенному росту объёма используемой памяти.
| Аргументы | |
|---|---|
generator | Вызываемый объект, возвращающий объект, поддерживающий протокол iter(). Если args не указан, функция generator не должна принимать аргументов; в противном случае она должна принимать столько аргументов, сколько значений содержится в args. |
output_types | (Необязательно.) Вложенная структура объектов tf.DType, соответствующих каждому компоненту элемента, созданного функцией generator. |
output_shapes | (Необязательно.) Вложенная структура объектов tf.TensorShape, соответствующих каждому компоненту элемента, созданного функцией generator. |
args | (Необязательно.) Кортеж объектов tf.Tensor, которые будут вычислены и переданы функции generator в качестве аргументов-массивов NumPy. |
output_signature | (Необязательно.) Вложенная структура объектов tf.TypeSpec, соответствующих каждому компоненту элемента, созданного функцией generator. |
name | (Необязательно.) Имя для операций tf.data, используемых функцией from_generator. |
| Возвращает | |
|---|---|
Dataset | Объект Dataset. |
from_tensor_slices
@staticmethod
from_tensor_slices(
tensors, name=None
) -> 'DatasetV2'
Создаёт Dataset, элементами которого являются срезы заданных тензоров.
Заданные тензоры разбиваются на срезы вдоль первого измерения. Эта операция сохраняет структуру входных тензоров, удаляя первое измерение каждого тензора и используя его в качестве измерения набора данных. Размеры первого измерения всех входных тензоров должны совпадать.
# Slicing a 1D tensor produces scalar tensor elements. dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) list(dataset.as_numpy_iterator()) [1, 2, 3]
# Slicing a 2D tensor produces 1D tensor elements. dataset = tf.data.Dataset.from_tensor_slices([[1, 2], [3, 4]]) list(dataset.as_numpy_iterator()) [array([1, 2], dtype=int32), array([3, 4], dtype=int32)]
# Slicing a tuple of 1D tensors produces tuple elements containing # scalar tensors. dataset = tf.data.Dataset.from_tensor_slices(([1, 2], [3, 4], [5, 6])) list(dataset.as_numpy_iterator()) [(1, 3, 5), (2, 4, 6)]
# Dictionary structure is also preserved.
dataset = tf.data.Dataset.from_tensor_slices({"a": [1, 2], "b": [3, 4]})
list(dataset.as_numpy_iterator()) == [{'a': 1, 'b': 3},
{'a': 2, 'b': 4}]
True# Two tensors can be combined into one Dataset object.
features = tf.constant([[1, 3], [2, 1], [3, 3]]) # ==> 3x2 tensor
labels = tf.constant(['A', 'B', 'A']) # ==> 3x1 tensor
dataset = Dataset.from_tensor_slices((features, labels))
# Both the features and the labels tensors can be converted
# to a Dataset object separately and combined after.
features_dataset = Dataset.from_tensor_slices(features)
labels_dataset = Dataset.from_tensor_slices(labels)
dataset = Dataset.zip((features_dataset, labels_dataset))
# A batched feature and label set can be converted to a Dataset
# in similar fashion.
batched_features = tf.constant([[[1, 3], [2, 3]],
[[2, 1], [1, 2]],
[[3, 3], [3, 2]]], shape=(3, 2, 2))
batched_labels = tf.constant([['A', 'A'],
['B', 'B'],
['A', 'B']], shape=(3, 2, 1))
dataset = Dataset.from_tensor_slices((batched_features, batched_labels))
for element in dataset.as_numpy_iterator():
print(element)
(array([[1, 3],
[2, 3]], dtype=int32), array([[b'A'],
[b'A']], dtype=object))
(array([[2, 1],
[1, 2]], dtype=int32), array([[b'B'],
[b'B']], dtype=object))
(array([[3, 3],
[3, 2]], dtype=int32), array([[b'A'],
[b'B']], dtype=object))Обратите внимание: если tensors содержит массив NumPy, а немедленное выполнение отключено, значения будут встроены в граф в виде одной или нескольких операций tf.constant. Для больших наборов данных (> 1 GB) это может привести к излишнему расходу памяти и превышению ограничений на размер сериализуемого графа. Если tensors содержит один или несколько больших массивов NumPy, рассмотрите альтернативный подход, описанный в этом руководстве.
| Аргументы | |
|---|---|
tensors | Элемент набора данных, компоненты которого имеют одинаковое первое измерение. Поддерживаемые значения описаны здесь. |
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Dataset | Объект Dataset. |
from_tensors
@staticmethod
from_tensors(
tensors, name=None
) -> 'DatasetV2'
Создаёт Dataset с одним элементом, состоящим из заданных тензоров.
from_tensors создаёт набор данных, содержащий только один элемент. Чтобы разбить входной тензор на несколько элементов, используйте from_tensor_slices.
dataset = tf.data.Dataset.from_tensors([1, 2, 3]) list(dataset.as_numpy_iterator()) [array([1, 2, 3], dtype=int32)] dataset = tf.data.Dataset.from_tensors(([1, 2, 3], 'A')) list(dataset.as_numpy_iterator()) [(array([1, 2, 3], dtype=int32), b'A')]
# You can use `from_tensors` to produce a dataset which repeats # the same example many times. example = tf.constant([1,2,3]) dataset = tf.data.Dataset.from_tensors(example).repeat(2) list(dataset.as_numpy_iterator()) [array([1, 2, 3], dtype=int32), array([1, 2, 3], dtype=int32)]
Обратите внимание: если tensors содержит массив NumPy, а немедленное выполнение отключено, значения будут встроены в граф в виде одной или нескольких операций tf.constant. Для больших наборов данных (> 1 GB) это может привести к излишнему расходу памяти и превышению ограничений на размер сериализуемого графа. Если tensors содержит один или несколько больших массивов NumPy, рассмотрите альтернативный подход, описанный в этом руководстве.
| Аргументы | |
|---|---|
tensors | «Элемент» набора данных. Поддерживаемые значения описаны здесь. |
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Dataset | Объект Dataset. |
get_single_element
get_single_element(
name=None
)
Возвращает единственный элемент dataset.
Функция позволяет использовать tf.data.Dataset в безсостояниевом выражении «тензор на входе — тензор на выходе», не создавая итератор. Это упрощает преобразование данных в тензорах с помощью оптимизированной абстракции tf.data.Dataset, построенной на их основе.
Например, рассмотрим preprocessing_fn, которая принимает на вход необработанные признаки и возвращает обработанный признак вместе с его меткой.
def preprocessing_fn(raw_feature):
# ... the raw_feature is preprocessed as per the use-case
return feature
raw_features = ... # input batch of BATCH_SIZE elements.
dataset = (tf.data.Dataset.from_tensor_slices(raw_features)
.map(preprocessing_fn, num_parallel_calls=BATCH_SIZE)
.batch(BATCH_SIZE))
processed_features = dataset.get_single_element()
В приведённом выше примере тензор raw_features длины BATCH_SIZE был преобразован в tf.data.Dataset. Затем каждый raw_feature был обработан с помощью preprocessing_fn, а обработанные признаки были объединены в один пакет. Итоговый dataset содержит только один элемент — пакет со всеми обработанными признаками.
Примечание: dataset должен содержать только один элемент.
Теперь вместо создания итератора для dataset и получения пакета признаков используется функция tf.data.get_single_element(), которая позволяет пропустить создание итератора и напрямую получить пакет признаков.
Это особенно полезно, если преобразования тензоров представлены в виде операций tf.data.Dataset и вы хотите использовать их при обслуживании модели.
Keras
model = ... # A pre-built or custom model
class PreprocessingModel(tf.keras.Model):
def __init__(self, model):
super().__init__(self)
self.model = model
@tf.function(input_signature=[...])
def serving_fn(self, data):
ds = tf.data.Dataset.from_tensor_slices(data)
ds = ds.map(preprocessing_fn, num_parallel_calls=BATCH_SIZE)
ds = ds.batch(batch_size=BATCH_SIZE)
return tf.argmax(self.model(ds.get_single_element()), axis=-1)
preprocessing_model = PreprocessingModel(model)
your_exported_model_dir = ... # save the model to this path.
tf.saved_model.save(preprocessing_model, your_exported_model_dir,
signatures={'serving_default': preprocessing_model.serving_fn}
)
| Аргументы | |
|---|---|
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Вложенная структура объектов tf.Tensor, соответствующая единственному элементу dataset. |
| Вызывает исключение | |
|---|---|
InvalidArgumentError | (во время выполнения), если dataset содержит не ровно один элемент. |
group_by_window
group_by_window(
key_func, reduce_func, window_size=None, window_size_func=None, name=None
) -> 'DatasetV2'
Группирует окна элементов по ключу и сокращает их.
Это преобразование сопоставляет каждому следующему элементу набора данных ключ с помощью key_func и группирует элементы по ключам. Затем оно применяет reduce_func не более чем к window_size_func(key) элементам с одинаковым ключом. Все окна, кроме последнего для каждого ключа, содержат window_size_func(key) элементов; последнее окно может быть меньше.
Можно задать постоянное значение window_size или размер окна, определяемый ключом с помощью window_size_func.
dataset = tf.data.Dataset.range(10)
window_size = 5
key_func = lambda x: x%2
reduce_func = lambda key, dataset: dataset.batch(window_size)
dataset = dataset.group_by_window(
key_func=key_func,
reduce_func=reduce_func,
window_size=window_size)
for elem in dataset.as_numpy_iterator():
print(elem)
[0 2 4 6 8]
[1 3 5 7 9]| Аргументы | |
|---|---|
key_func | Функция, сопоставляющая вложенную структуру тензоров (с формами и типами, заданными в self.output_shapes и self.output_types) скалярному тензору tf.int64. |
reduce_func | Функция, сопоставляющая ключу и набору данных, содержащему до window_size последовательных элементов с этим ключом, другой набор данных. |
window_size | Скалярный тензор tf.Tensor типа tf.int64, задающий число последовательных элементов с одинаковым ключом, объединяемых в один пакет, который будет передан в reduce_func. Не может использоваться одновременно с window_size_func. |
window_size_func | Функция, сопоставляющая ключ скалярному тензору tf.Tensor типа tf.int64, задающему число последовательных элементов с одинаковым ключом, объединяемых в один пакет, который будет передан в reduce_func. Не может использоваться одновременно с window_size. |
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, применённым, как описано выше. |
| Вызывает исключение | |
|---|---|
ValueError | если не передан ни один аргумент из {window_size, window_size_func} или переданы оба. |
ignore_errors
ignore_errors(
log_warning=False, name=None
) -> 'DatasetV2'
Удаляет элементы, вызывающие ошибки.
dataset = tf.data.Dataset.from_tensor_slices([1., 2., 0., 4.]) dataset = dataset.map(lambda x: tf.debugging.check_numerics(1. / x, "")) list(dataset.as_numpy_iterator()) Traceback (most recent call last): InvalidArgumentError: ... Tensor had Inf values dataset = dataset.ignore_errors() list(dataset.as_numpy_iterator()) [1.0, 0.5, 0.25]
| Аргументы | |
|---|---|
log_warning | (Необязательно.) Логическое значение, указывающее, нужно ли записывать игнорируемые ошибки в stderr. По умолчанию — False. |
name | (Необязательно.) Строка с именем операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, применённым, как описано выше. |
interleave
interleave(
map_func,
cycle_length=None,
block_length=None,
num_parallel_calls=None,
deterministic=None,
name=None
) -> 'DatasetV2'
Применяет map_func к этому набору данных и чередует полученные результаты.
Сигнатура типа:
def interleave( self: Dataset[T], map_func: Callable[[T], Dataset[S]] ) -> Dataset[S]
Например, можно использовать Dataset.interleave() для параллельной обработки множества входных файлов:
# Preprocess 4 files concurrently, and interleave blocks of 16 records
# from each file.
filenames = ["/var/data/file1.txt", "/var/data/file2.txt",
"/var/data/file3.txt", "/var/data/file4.txt"]
dataset = tf.data.Dataset.from_tensor_slices(filenames)
def parse_fn(filename):
return tf.data.Dataset.range(10)
dataset = dataset.interleave(lambda x:
tf.data.TextLineDataset(x).map(parse_fn, num_parallel_calls=1),
cycle_length=4, block_length=16)Аргументы cycle_length и block_length определяют порядок создания элементов. cycle_length задаёт число входных элементов, обрабатываемых одновременно. Если установить cycle_length равным 1, это преобразование будет обрабатывать по одному входному элементу за раз и выдаст те же результаты, что и tf.data.Dataset.flat_map. В общем случае это преобразование применит map_func к cycle_length входным элементам, откроет итераторы для возвращённых объектов Dataset и будет циклически обходить их, создавая block_length последовательных элементов из каждого итератора и потребляя следующий входной элемент при достижении конца итератора.
Например:
dataset = Dataset.range(1, 6) # ==> [ 1, 2, 3, 4, 5 ]
# NOTE: New lines indicate "block" boundaries.
dataset = dataset.interleave(
lambda x: Dataset.from_tensors(x).repeat(6),
cycle_length=2, block_length=4)
list(dataset.as_numpy_iterator())
[1, 1, 1, 1,
2, 2, 2, 2,
1, 1,
2, 2,
3, 3, 3, 3,
4, 4, 4, 4,
3, 3,
4, 4,
5, 5, 5, 5,
5, 5]Примечание: Порядок элементов, создаваемых этим преобразованием, детерминирован, еслиmap_funcявляется чистой функцией иdeterministic=True. Еслиmap_funcсодержит операции с состоянием, порядок доступа к этому состоянию не определён.
Часто производительность можно повысить, задав num_parallel_calls, чтобы interleave использовал несколько потоков для получения элементов. Если детерминированность не требуется, производительность также можно повысить, задав deterministic=False.
filenames = ["/var/data/file1.txt", "/var/data/file2.txt",
"/var/data/file3.txt", "/var/data/file4.txt"]
dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.interleave(lambda x: tf.data.TFRecordDataset(x),
cycle_length=4, num_parallel_calls=tf.data.AUTOTUNE,
deterministic=False)| Аргументы | |
|---|---|
map_func | Функция, принимающая элемент набора данных и возвращающая tf.data.Dataset. |
cycle_length | (Необязательно.) Число входных элементов, обрабатываемых одновременно. Если значение не задано, среда выполнения tf.data определяет его на основе доступных ресурсов ЦП. Если для num_parallel_calls задано значение tf.data.AUTOTUNE, аргумент cycle_length задаёт максимальную степень параллелизма. |
block_length | (Необязательно.) Число последовательных элементов, создаваемых из каждого входного элемента перед переключением на другой входной элемент. По умолчанию — 1. |
num_parallel_calls | (Необязательно.) Если задано, реализация создаёт пул потоков, который используется для асинхронного и параллельного получения входных данных из элементов цикла. По умолчанию входные данные из элементов цикла извлекаются синхронно, без параллелизма. Если используется значение tf.data.AUTOTUNE, число параллельных вызовов динамически определяется на основе доступных ресурсов ЦП. |
deterministic | (Необязательно.) Если задан num_parallel_calls, это логическое значение (True или False) управляет порядком создания элементов преобразованием. Если задано значение False, преобразованию разрешено выдавать элементы не по порядку, обменивая детерминированность на производительность. Если значение не задано, поведение определяется параметром tf.data.Options.deterministic (по умолчанию — True). |
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, применённым, как описано выше. |
list_files
@staticmethod
list_files(
file_pattern, shuffle=None, seed=None, name=None
) -> 'DatasetV2'
Набор данных, содержащий все файлы, соответствующие одному или нескольким шаблонам glob.
Аргумент file_pattern должен содержать небольшое число шаблонов glob. Если имена файлов уже получены с помощью glob, используйте вместо этого Dataset.from_tensor_slices(filenames), поскольку повторное применение glob к каждому имени файла с помощью list_files может снизить производительность при работе с удалёнными системами хранения.
Примечание: По умолчанию этот метод возвращает имена файлов в случайном, недетерминированном порядке. Чтобы получить результаты в детерминированном порядке, передайтеseedилиshuffle=False.
| Пример | |
|---|---|
Предположим, что в нашей файловой системе имеются следующие файлы:
Если передать "/path/to/dir/*.py" в качестве каталога, набор данных будет содержать:
|
| Аргументы | |
|---|---|
file_pattern | Строка, список строк или tf.Tensor строкового типа (скаляр или вектор), задающие шаблон(ы) glob для имён файлов (то есть шаблон(ы) с подстановочными знаками оболочки), которым должны соответствовать имена файлов. |
shuffle | (Необязательно.) Если задано True, имена файлов будут перемешаны в случайном порядке. По умолчанию — True. |
seed | (Необязательно.) Скалярный тензор tf.Tensor типа tf.int64, задающий начальное значение для генерации случайных чисел. Описание поведения см. в разделе tf.random.set_seed. |
name | Необязательно. Имя для операций tf.data, используемых функцией list_files. |
| Возвращает | |
|---|---|
Dataset | Объект Dataset со строками, соответствующими именам файлов. |
load
@staticmethod
load(
path, element_spec=None, compression=None, reader_func=None
) -> 'DatasetV2'
Загружает ранее сохранённый набор данных.
Пример использования:
import tempfile path = os.path.join(tempfile.gettempdir(), "saved_data") # Save a dataset dataset = tf.data.Dataset.range(2) tf.data.Dataset.save(dataset, path) new_dataset = tf.data.Dataset.load(path) for elem in new_dataset: print(elem) tf.Tensor(0, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
Если при сохранении набора данных использовалось разбиение на части по умолчанию, при загрузке порядок элементов сохранённого набора данных будет сохранён.
Аргумент reader_func можно использовать, чтобы задать порядок загрузки элементов из отдельных частей. Ожидается, что reader_func принимает один аргумент — набор данных, состоящий из наборов данных, каждый из которых содержит элементы одной из частей, — и возвращает набор данных из элементов. Например, при загрузке порядок частей можно перемешать следующим образом:
def custom_reader_func(datasets):
datasets = datasets.shuffle(NUM_SHARDS)
return datasets.interleave(lambda x: x, num_parallel_calls=AUTOTUNE)
dataset = tf.data.Dataset.load(
path="/path/to/data", ..., reader_func=custom_reader_func)
| Аргументы | |
|---|---|
path | Обязательный аргумент. Путь к ранее сохранённому набору данных. |
element_spec | Необязательный аргумент. Вложенная структура объектов tf.TypeSpec, соответствующая структуре элемента сохранённого набора данных и задающая тип отдельных компонентов элемента. Если аргумент не указан, используется вложенная структура tf.TypeSpec, сохранённая вместе с набором данных. Обратите внимание: этот аргумент обязателен в режиме графа. |
compression | Необязательный аргумент. Алгоритм распаковки данных при чтении. Поддерживаются значения GZIP и NONE. По умолчанию — NONE. |
reader_func | Необязательный аргумент. Функция, управляющая чтением данных из частей. Если она задана, функция будет трассирована и выполнена как вычисление графа. |
| Возвращает | |
|---|---|
Экземпляр tf.data.Dataset. |
| Вызывает исключение | |
|---|---|
FileNotFoundError | Если element_spec не задан, а сохранённую вместе с набором данных вложенную структуру tf.TypeSpec не удаётся найти. |
ValueError | Если element_spec не задан, а метод выполняется в режиме графа. |
map
map(
map_func, num_parallel_calls=None, deterministic=None, name=None
)
Применяет map_func к элементам этого набора данных.
Это преобразование применяет map_func к каждому элементу набора данных и возвращает новый набор данных, содержащий преобразованные элементы в том же порядке, что и во входных данных. map_func можно использовать для изменения значений и структуры элементов набора данных. Поддерживаемые типы структур описаны здесь.
Например, map можно использовать, чтобы прибавить 1 к каждому элементу или выбрать подмножество компонентов элементов.
dataset = Dataset.range(1, 6) # ==> [ 1, 2, 3, 4, 5 ] dataset = dataset.map(lambda x: x + 1) list(dataset.as_numpy_iterator()) [2, 3, 4, 5, 6]
Сигнатура входных данных map_func определяется структурой каждого элемента этого набора данных.
dataset = Dataset.range(5) # `map_func` takes a single argument of type `tf.Tensor` with the same # shape and dtype. result = dataset.map(lambda x: x + 1)
# Each element is a tuple containing two `tf.Tensor` objects.
elements = [(1, "foo"), (2, "bar"), (3, "baz")]
dataset = tf.data.Dataset.from_generator(
lambda: elements, (tf.int32, tf.string))
# `map_func` takes two arguments of type `tf.Tensor`. This function
# projects out just the first component.
result = dataset.map(lambda x_int, y_str: x_int)
list(result.as_numpy_iterator())
[1, 2, 3]# Each element is a dictionary mapping strings to `tf.Tensor` objects.
elements = ([{"a": 1, "b": "foo"},
{"a": 2, "b": "bar"},
{"a": 3, "b": "baz"}])
dataset = tf.data.Dataset.from_generator(
lambda: elements, {"a": tf.int32, "b": tf.string})
# `map_func` takes a single argument of type `dict` with the same keys
# as the elements.
result = dataset.map(lambda d: str(d["a"]) + d["b"])Структура каждого элемента возвращаемого набора данных определяется значением или значениями, возвращаемыми функцией map_func.
dataset = tf.data.Dataset.range(3) # `map_func` returns two `tf.Tensor` objects. def g(x): return tf.constant(37.0), tf.constant(["Foo", "Bar", "Baz"]) result = dataset.map(g) result.element_spec (TensorSpec(shape=(), dtype=tf.float32, name=None), TensorSpec(shape=(3,), dtype=tf.string, name=None)) # Python primitives, lists, and NumPy arrays are implicitly converted to # `tf.Tensor`. def h(x): return 37.0, ["Foo", "Bar"], np.array([1.0, 2.0], dtype=np.float64) result = dataset.map(h) result.element_spec (TensorSpec(shape=(), dtype=tf.float32, name=None), TensorSpec(shape=(2,), dtype=tf.string, name=None), TensorSpec(shape=(2,), dtype=tf.float64, name=None)) # `map_func` can return nested structures. def i(x): return (37.0, [42, 16]), "foo" result = dataset.map(i) result.element_spec ((TensorSpec(shape=(), dtype=tf.float32, name=None), TensorSpec(shape=(2,), dtype=tf.int32, name=None)), TensorSpec(shape=(), dtype=tf.string, name=None))
Функция map_func может принимать аргументы и возвращать значения любого типа, допустимого для элементов набора данных.
Обратите внимание: независимо от контекста, в котором определена функция map_func (немедленное выполнение или граф), tf.data трассирует функцию и выполняет её как граф. Для использования кода Python внутри функции есть несколько способов:
1) Использовать AutoGraph для преобразования кода Python в эквивалентное вычисление графа. Недостаток этого подхода в том, что AutoGraph может преобразовать не весь код Python.
2) Использовать tf.py_function, позволяющую писать произвольный код Python, но обычно работающую медленнее, чем подход 1). Например:
d = tf.data.Dataset.from_tensor_slices(['hello', 'world'])
# transform a string tensor to upper case string using a Python function
def upper_case_fn(t: tf.Tensor):
return t.numpy().decode('utf-8').upper()
d = d.map(lambda x: tf.py_function(func=upper_case_fn,
inp=[x], Tout=tf.string))
list(d.as_numpy_iterator())
[b'HELLO', b'WORLD']3) Использовать tf.numpy_function, которая также позволяет писать произвольный код Python. Обратите внимание: tf.py_function принимает объекты tf.Tensor, тогда как tf.numpy_function принимает массивы NumPy и возвращает только массивы NumPy. Например:
d = tf.data.Dataset.from_tensor_slices(['hello', 'world'])
def upper_case_fn(t: np.ndarray):
return t.decode('utf-8').upper()
d = d.map(lambda x: tf.numpy_function(func=upper_case_fn,
inp=[x], Tout=tf.string))
list(d.as_numpy_iterator())
[b'HELLO', b'WORLD']Обратите внимание: использование tf.numpy_function и tf.py_function обычно исключает возможность параллельного выполнения пользовательских преобразований (из-за GIL Python).
Часто производительность можно повысить, задав num_parallel_calls, чтобы map использовал несколько потоков для обработки элементов. Если порядок выполнения не должен быть детерминированным, производительность также можно повысить, задав deterministic=False.
dataset = Dataset.range(1, 6) # ==> [ 1, 2, 3, 4, 5 ]
dataset = dataset.map(lambda x: x + 1,
num_parallel_calls=tf.data.AUTOTUNE,
deterministic=False)Порядок элементов, создаваемых этим преобразованием, детерминирован, если deterministic=True. Если map_func содержит операции с состоянием и num_parallel_calls > 1, порядок доступа к этому состоянию не определён, поэтому значения выходных элементов могут быть недетерминированными независимо от значения флага deterministic.
| Аргументы | |
|---|---|
map_func | Функция, преобразующая элемент набора данных в другой элемент набора данных. |
num_parallel_calls | (Необязательно.) Скалярный тензор tf.Tensor типа tf.int64, задающий число элементов, обрабатываемых асинхронно и параллельно. Если значение не задано, элементы обрабатываются последовательно. Если используется значение tf.data.AUTOTUNE, число параллельных вызовов динамически определяется на основе доступных ресурсов ЦП. |
deterministic | (Необязательно.) Если задан num_parallel_calls, это логическое значение (True или False) управляет порядком создания элементов преобразованием. Если задано значение False, преобразованию разрешено выдавать элементы не по порядку, обменивая детерминированность на производительность. Если значение не задано, поведение определяется параметром tf.data.Options.deterministic (по умолчанию — True). |
name | (Необязательно.) Имя для операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, применённым, как описано выше. |
options
options()
Возвращает параметры этого набора данных и его входных данных.
| Возвращает | |
|---|---|
Объект tf.data.Options, представляющий параметры набора данных. |
padded_batch
padded_batch(
batch_size,
padded_shapes=None,
padding_values=None,
drop_remainder=False,
name=None
) -> 'DatasetV2'
Объединяет последовательные элементы этого набора данных в пакеты с дополнением.
Это преобразование объединяет несколько последовательных элементов входного набора данных в один элемент.
Как и в tf.data.Dataset.batch, компоненты результирующего элемента будут иметь дополнительное внешнее измерение, которое будет batch_size (или N % batch_size для последнего элемента, если batch_size не делит количество входных элементов N нацело и drop_remainder равен False). Если ваша программа зависит от того, что внешнее измерение пакетов одинаково, установите аргумент drop_remainder в значение True, чтобы не создавать пакет меньшего размера.
В отличие от tf.data.Dataset.batch, входные элементы для объединения в пакеты могут иметь разные формы, и это преобразование дополнит каждый компонент до соответствующей формы в padded_shapes. Аргумент padded_shapes определяет результирующую форму для каждого измерения каждого компонента в выходном элементе:
- Если размерность задана константой, компонент будет дополнен до указанной длины в этой размерности.
- Если размерность неизвестна, компонент будет дополнен до максимальной длины всех элементов в этой размерности.
A = (tf.data.Dataset
.range(1, 5, output_type=tf.int32)
.map(lambda x: tf.fill([x], x)))
# Pad to the smallest per-batch size that fits all elements.
B = A.padded_batch(2)
for element in B.as_numpy_iterator():
print(element)
[[1 0]
[2 2]]
[[3 3 3 0]
[4 4 4 4]]
# Pad to a fixed size.
C = A.padded_batch(2, padded_shapes=5)
for element in C.as_numpy_iterator():
print(element)
[[1 0 0 0 0]
[2 2 0 0 0]]
[[3 3 3 0 0]
[4 4 4 4 0]]
# Pad with a custom value.
D = A.padded_batch(2, padded_shapes=5, padding_values=-1)
for element in D.as_numpy_iterator():
print(element)
[[ 1 -1 -1 -1 -1]
[ 2 2 -1 -1 -1]]
[[ 3 3 3 -1 -1]
[ 4 4 4 4 -1]]
# Components of nested elements can be padded independently.
elements = [([1, 2, 3], [10]),
([4, 5], [11, 12])]
dataset = tf.data.Dataset.from_generator(
lambda: iter(elements), (tf.int32, tf.int32))
# Pad the first component of the tuple to length 4, and the second
# component to the smallest size that fits.
dataset = dataset.padded_batch(2,
padded_shapes=([4], [None]),
padding_values=(-1, 100))
list(dataset.as_numpy_iterator())
[(array([[ 1, 2, 3, -1], [ 4, 5, -1, -1]], dtype=int32),
array([[ 10, 100], [ 11, 12]], dtype=int32))]
# Pad with a single value and multiple components.
E = tf.data.Dataset.zip((A, A)).padded_batch(2, padding_values=-1)
for element in E.as_numpy_iterator():
print(element)
(array([[ 1, -1],
[ 2, 2]], dtype=int32), array([[ 1, -1],
[ 2, 2]], dtype=int32))
(array([[ 3, 3, 3, -1],
[ 4, 4, 4, 4]], dtype=int32), array([[ 3, 3, 3, -1],
[ 4, 4, 4, 4]], dtype=int32))См. также tf.data.experimental.dense_to_sparse_batch, которое объединяет элементы с разными формами в tf.sparse.SparseTensor.
| Аргументы | |
|---|---|
batch_size | Скалярный tf.int64 tf.Tensor, представляющий количество последовательных элементов этого набора данных, объединяемых в один пакет. |
padded_shapes | (Необязательно.) (Вложенная) структура объектов типа tf.TensorShape или векторных тензоров, подобных tf.int64, задающая форму, до которой соответствующий компонент каждого входного элемента должен быть дополнен перед объединением в пакет. Все неизвестные размерности будут дополнены до максимального размера этой размерности в каждом пакете. Если параметр не задан, все размерности всех компонентов дополняются до максимального размера в пакете. Параметр padded_shapes необходимо задать, если у какого-либо компонента неизвестен ранг. |
padding_values | (Необязательно.) (Вложенная) структура скалярных tf.Tensor, задающая значения заполнения для соответствующих компонентов. Значение None означает, что (вложенная) структура должна заполняться значениями по умолчанию. Для числовых типов значением по умолчанию является 0, а для строковых типов — пустая строка. Параметр padding_values должен иметь ту же (вложенную) структуру, что и входной набор данных. Если padding_values состоит из одного элемента, а входной набор данных содержит несколько компонентов, для заполнения каждого компонента набора данных будет использоваться один и тот же padding_values. Если padding_values является скаляром, его значение будет транслировано до формы каждого компонента. |
drop_remainder | (Необязательно.) Скалярный tf.bool tf.Tensor, указывающий, следует ли отбрасывать последний пакет, если в нем меньше batch_size элементов; по умолчанию пакет меньшего размера не отбрасывается. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
| Вызывает исключения | |
|---|---|
ValueError | Если у компонента неизвестен ранг и аргумент padded_shapes не задан. |
TypeError | Если компонент имеет неподдерживаемый тип. Список поддерживаемых типов приведен в документации: https://www.tensorflow.org/guide/data#dataset_structure |
prefetch
prefetch(
buffer_size, name=None
) -> 'DatasetV2'
Создает Dataset, предварительно загружающий элементы из этого набора данных.
Большинство конвейеров ввода данных должны завершаться вызовом prefetch. Это позволяет подготавливать последующие элементы, пока обрабатывается текущий элемент. Часто это повышает скорость отклика и пропускную способность, но требует дополнительной памяти для хранения предварительно загруженных элементов.
Примечание: Как и другие методыDataset, prefetch работает с элементами входного набора данных. Метод не различает примеры и пакеты.examples.prefetch(2)предварительно загрузит два элемента (2 примера), аexamples.batch(20).prefetch(2)— 2 элемента (2 пакета по 20 примеров в каждом).
dataset = tf.data.Dataset.range(3) dataset = dataset.prefetch(2) list(dataset.as_numpy_iterator()) [0, 1, 2]
| Аргументы | |
|---|---|
buffer_size | Скалярный tf.int64 tf.Tensor, задающий максимальное количество элементов, которые будут буферизованы при предварительной загрузке. Если указано значение tf.data.AUTOTUNE, размер буфера настраивается динамически. |
name | Необязательно. Имя преобразования tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
ragged_batch
ragged_batch(
batch_size,
drop_remainder=False,
row_splits_dtype=tf.dtypes.int64,
name=None
) -> 'DatasetV2'
Объединяет последовательные элементы этого набора данных в объекты tf.RaggedTensor.
Как и в tf.data.Dataset.batch, компоненты результирующего элемента будут иметь дополнительное внешнее измерение, которое будет batch_size (или N % batch_size для последнего элемента, если batch_size не делит количество входных элементов N нацело и drop_remainder равен False). Если ваша программа зависит от того, что внешнее измерение пакетов одинаково, установите аргумент drop_remainder в значение True, чтобы не создавать пакет меньшего размера.
В отличие от tf.data.Dataset.batch, входные элементы для объединения в пакеты могут иметь разные формы:
- Если входной элемент — это
tf.Tensorс полностью определенной статическойtf.TensorShape, он объединяется в пакет обычным образом. - Если входной элемент — это
tf.Tensor, статическаяtf.TensorShapeкоторого содержит одну или несколько осей с неизвестным размером (то естьshape[i]=None), выходные данные будут содержатьtf.RaggedTensor, разреженный по всем таким измерениям. - Если входной элемент — это
tf.RaggedTensorили объект любого другого типа, он объединяется в пакет обычным образом.
Пример:
dataset = tf.data.Dataset.range(6) dataset = dataset.map(lambda x: tf.range(x)) dataset.element_spec.shape TensorShape([None]) dataset = dataset.ragged_batch(2) for batch in dataset: print(batch) <tf.RaggedTensor [[], [0]]> <tf.RaggedTensor [[0, 1], [0, 1, 2]]> <tf.RaggedTensor [[0, 1, 2, 3], [0, 1, 2, 3, 4]]>
| Аргументы | |
|---|---|
batch_size | Скалярный tf.int64 tf.Tensor, представляющий количество последовательных элементов этого набора данных, объединяемых в один пакет. |
drop_remainder | (Необязательно.) Скалярный tf.bool tf.Tensor, указывающий, следует ли отбрасывать последний пакет, если в нем меньше batch_size элементов; по умолчанию пакет меньшего размера не отбрасывается. |
row_splits_dtype | Тип данных, который следует использовать для row_splits любых новых разреженных тензоров. Тип row_splits существующих элементов tf.RaggedTensor не изменяется. |
name | (Необязательно.) Строка, задающая имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
random
@staticmethod
random(
seed=None, rerandomize_each_iteration=None, name=None
) -> 'DatasetV2'
Создает Dataset псевдослучайных значений.
Набор данных генерирует последовательность равномерно распределенных целочисленных значений.
Параметр rerandomize_each_iteration определяет, следует ли заново рандомизировать последовательность генерируемых случайных чисел для каждой эпохи. Значение по умолчанию — False: в этом случае набор данных генерирует одну и ту же последовательность случайных чисел для каждой эпохи.
ds1 = tf.data.Dataset.random(seed=4).take(10) ds2 = tf.data.Dataset.random(seed=4).take(10) print(list(ds1.as_numpy_iterator())==list(ds2.as_numpy_iterator())) True
ds3 = tf.data.Dataset.random(seed=4).take(10) ds3_first_epoch = list(ds3.as_numpy_iterator()) ds3_second_epoch = list(ds3.as_numpy_iterator()) print(ds3_first_epoch == ds3_second_epoch) True
ds4 = tf.data.Dataset.random(
seed=4, rerandomize_each_iteration=True).take(10)
ds4_first_epoch = list(ds4.as_numpy_iterator())
ds4_second_epoch = list(ds4.as_numpy_iterator())
print(ds4_first_epoch == ds4_second_epoch)
False| Аргументы | |
|---|---|
seed | (Необязательно.) Если задано, набор данных создает детерминированную последовательность значений. |
rerandomize_each_iteration | (Необязательно.) Если задано значение False, набор данных генерирует одну и ту же последовательность случайных чисел для каждой эпохи. Если задано значение True, для каждой эпохи генерируется своя детерминированная последовательность случайных чисел. Если параметр не задан, по умолчанию используется False. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Dataset | Dataset. |
range
@staticmethod
range(
*args, **kwargs
) -> 'DatasetV2'
Создает Dataset значений диапазона с заданным шагом.
list(Dataset.range(5).as_numpy_iterator()) [0, 1, 2, 3, 4] list(Dataset.range(2, 5).as_numpy_iterator()) [2, 3, 4] list(Dataset.range(1, 5, 2).as_numpy_iterator()) [1, 3] list(Dataset.range(1, 5, -2).as_numpy_iterator()) [] list(Dataset.range(5, 1).as_numpy_iterator()) [] list(Dataset.range(5, 1, -2).as_numpy_iterator()) [5, 3] list(Dataset.range(2, 5, output_type=tf.int32).as_numpy_iterator()) [2, 3, 4] list(Dataset.range(1, 5, 2, output_type=tf.float32).as_numpy_iterator()) [1.0, 3.0]
| Аргументы | |
|---|---|
*args | Семантика соответствует функции range в Python. len(args) == 1 -> start = 0, stop = args[0], step = 1. len(args) == 2 -> start = args[0], stop = args[1], step = 1. len(args) == 3 -> start = args[0], stop = args[1], step = args[2]. |
**kwargs |
|
| Возвращает | |
|---|---|
Dataset | RangeDataset. |
| Вызывает исключения | |
|---|---|
ValueError | если len(args) == 0. |
rebatch
rebatch(
batch_size, drop_remainder=False, name=None
) -> 'DatasetV2'
Создает Dataset, изменяющий разбиение элементов этого набора данных на пакеты.
Функционально rebatch(N) эквивалентен unbatch().batch(N), но работает эффективнее, выполняя одно копирование вместо двух.
ds = tf.data.Dataset.range(6) ds = ds.batch(2) ds = ds.rebatch(3) list(ds.as_numpy_iterator()) [array([0, 1, 2]), array([3, 4, 5])]
ds = tf.data.Dataset.range(7) ds = ds.batch(4) ds = ds.rebatch(3) list(ds.as_numpy_iterator()) [array([0, 1, 2]), array([3, 4, 5]), array([6])]
ds = tf.data.Dataset.range(7) ds = ds.batch(2) ds = ds.rebatch(3, drop_remainder=True) list(ds.as_numpy_iterator()) [array([0, 1, 2]), array([3, 4, 5])]
Если аргумент batch_size является списком, rebatch циклически перебирает список, чтобы определить размер каждого пакета.
ds = tf.data.Dataset.range(8) ds = ds.batch(4) ds = ds.rebatch([2, 1, 1]) list(ds.as_numpy_iterator()) [array([0, 1]), array([2]), array([3]), array([4, 5]), array([6]), array([7])]
| Аргументы | |
|---|---|
batch_size | Скаляр или вектор tf.int64, задающий размер создаваемых пакетов. Если этот аргумент является вектором, значения перебираются по кругу. |
drop_remainder | (Необязательно.) Скалярный tf.bool tf.Tensor, указывающий, следует ли отбрасывать последний пакет, если в нем меньше batch_size[cycle_index] элементов; по умолчанию пакет меньшего размера не отбрасывается. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Dataset из скалярных элементов dtype. |
reduce
reduce(
initial_state, reduce_func, name=None
)
Сводит входной набор данных к одному элементу.
Преобразование последовательно вызывает reduce_func для каждого элемента входного набора данных, пока набор данных не будет исчерпан, накапливая информацию во внутреннем состоянии. Аргумент initial_state используется как начальное состояние, а итоговое состояние возвращается в качестве результата.
tf.data.Dataset.range(5).reduce(np.int64(0), lambda x, _: x + 1).numpy() 5 tf.data.Dataset.range(5).reduce(np.int64(0), lambda x, y: x + y).numpy() 10
| Аргументы | |
|---|---|
initial_state | Элемент, представляющий начальное состояние преобразования. |
reduce_func | Функция, преобразующая (old_state, input_element) в new_state. Она должна принимать два аргумента и возвращать новый элемент. Структура new_state должна соответствовать структуре initial_state. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
| Элемент набора данных, соответствующий итоговому состоянию преобразования. |
rejection_resample
rejection_resample(
class_func, target_dist, initial_dist=None, seed=None, name=None
) -> 'DatasetV2'
Повторно выбирает элементы, чтобы достичь целевого распределения.
Примечание: Эта реализация может отбрасывать или повторять элементы, чтобы достичьtarget_dist. Поэтому в некоторых случаях выходнойDatasetможет быть больше входногоDataset.
initial_dist = [0.6, 0.4] n = 1000 elems = np.random.choice(len(initial_dist), size=n, p=initial_dist) dataset = tf.data.Dataset.from_tensor_slices(elems) zero, one = np.bincount(list(dataset.as_numpy_iterator())) / n
На основании initial_dist, zero составляет ~0.6, а one — ~0.4.
target_dist = [0.5, 0.5] dataset = dataset.rejection_resample( class_func=lambda x: x, target_dist=target_dist, initial_dist=initial_dist) dataset = dataset.map(lambda class_func_result, data: data) zero, one = np.bincount(list(dataset.as_numpy_iterator())) / n
На основании target_dist, zero составляет ~0.5, а one — ~0.5.
| Аргументы | |
|---|---|
class_func | Функция, преобразующая элемент входного набора данных в скалярный тензор tf.int32. Значения должны находиться в [0, num_classes). |
target_dist | Тензор с типом данных с плавающей запятой и формой [num_classes]. |
initial_dist | (Необязательно.) Тензор с типом данных с плавающей запятой и формой [num_classes]. Если параметр не задан, истинное распределение классов оценивается в реальном времени в потоковом режиме. |
seed | (Необязательно.) Целочисленное значение seed Python для повторной выборки. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
repeat
repeat(
count=None, name=None
) -> 'DatasetV2'
Повторяет этот набор данных, чтобы каждое исходное значение встречалось count раз.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.repeat(3) list(dataset.as_numpy_iterator()) [1, 2, 3, 1, 2, 3, 1, 2, 3]
Примечание: Если входной набор данных зависит от глобального состояния (например, от генератора случайных чисел) или его выходные данные недетерминированы (например, из-за вышестоящего shuffle), при разных повторах могут создаваться разные элементы.
| Аргументы | |
|---|---|
count | (Необязательно.) Скалярный tf.int64 tf.Tensor, задающий количество повторений набора данных. По умолчанию (если count равно None или -1) набор данных повторяется бесконечно. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
sample_from_datasets
@staticmethod
sample_from_datasets(
datasets,
weights=None,
seed=None,
stop_on_empty_dataset=False,
rerandomize_each_iteration=None
) -> 'DatasetV2'
Случайным образом выбирает элементы из наборов данных в datasets.
Создает набор данных, перемежая элементы из datasets; вероятность выбора элемента из набора данных i задается в weight[i]. Выборка выполняется без возвращения. Например, предположим, что у нас есть два набора данных:
dataset1 = tf.data.Dataset.range(0, 3) dataset2 = tf.data.Dataset.range(100, 103)
Предположим, что мы выбираем элементы из этих двух наборов данных с такими весами:
sample_dataset = tf.data.Dataset.sample_from_datasets(
[dataset1, dataset2], weights=[0.5, 0.5])
Одним из возможных результатов для элементов в sample_dataset будет:
print(list(sample_dataset.as_numpy_iterator())) # [100, 0, 1, 101, 2, 102]
| Аргументы | |
|---|---|
datasets | Непустой список объектов tf.data.Dataset с совместимой структурой. |
weights | (Необязательно.) Список или тензор из len(datasets) значений с плавающей запятой, где weights[i] задает вероятность выбора элемента из datasets[i], либо объект tf.data.Dataset, каждый элемент которого представляет собой такой список. По умолчанию используется равномерное распределение по datasets. |
seed | (Необязательно.) Скалярный tf.int64 tf.Tensor, задающий случайное начальное значение, которое будет использоваться для создания распределения. См. описание поведения в разделе tf.random.set_seed. |
stop_on_empty_dataset | Если значение равно True, выборка прекращается при обнаружении пустого набора данных. Если значение равно False, выборка продолжается, а пустые наборы данных пропускаются. Рекомендуется установить значение True. В противном случае распределение выборки сначала будет соответствовать заданному пользователем, но может измениться, когда входные наборы данных опустеют. Это может быть трудно заметить, поскольку изначально набор данных выглядит корректно. Для обратной совместимости по умолчанию используется False. |
rerandomize_each_iteration | Необязательный bool. Булев аргумент определяет, будет ли последовательность случайных чисел, используемая для выбора набора данных, повторно рандомизироваться в каждой эпохе. То есть он определяет, будут ли наборы данных выбираться в одинаковом порядке в разных эпохах (поведение по умолчанию). |
| Возвращает | |
|---|---|
Набор данных, случайным образом перемежающий элементы из datasets согласно weights, если оно задано, или с равномерной вероятностью в противном случае. |
| Вызывает исключения | |
|---|---|
TypeError | Если аргументы datasets или weights имеют неверный тип. |
ValueError |
|
save
save(
path, compression=None, shard_func=None, checkpoint_args=None
)
Сохраняет содержимое заданного набора данных.
Пример использования:
import tempfile path = os.path.join(tempfile.gettempdir(), "saved_data") # Save a dataset dataset = tf.data.Dataset.range(2) dataset.save(path) new_dataset = tf.data.Dataset.load(path) for elem in new_dataset: print(elem) tf.Tensor(0, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
Сохраненный набор данных записывается в несколько файловых «частей». По умолчанию выходные данные набора распределяются по частям по очереди, но пользовательское разбиение можно задать с помощью функции shard_func. Например, набор данных можно сохранить в одной части следующим образом:
dataset = make_dataset()
def custom_shard_func(element):
return np.int64(0)
dataset.save(
path="/path/to/data", ..., shard_func=custom_shard_func)
Чтобы включить создание контрольных точек, передайте checkpoint_args методу save следующим образом:
dataset = tf.data.Dataset.range(100)
save_dir = "..."
checkpoint_prefix = "..."
step_counter = tf.Variable(0, trainable=False)
checkpoint_args = {
"checkpoint_interval": 50,
"step_counter": step_counter,
"directory": checkpoint_prefix,
"max_to_keep": 20,
}
dataset.save(dataset, save_dir, checkpoint_args=checkpoint_args)
Примечание: Структура каталогов и формат файлов, используемые для сохранения набора данных, считаются деталями реализации и могут измениться. Поэтому наборы данных, сохраненные с помощьюtf.data.Dataset.save, следует использовать только черезtf.data.Dataset.load, для которого гарантирована обратная совместимость.
| Аргументы | |
|---|---|
path | Обязательный аргумент. Каталог для сохранения набора данных. |
compression | Необязательный аргумент. Алгоритм сжатия данных при записи. Поддерживаются варианты GZIP и NONE. По умолчанию используется NONE. |
shard_func | Необязательный аргумент. Функция для управления распределением элементов набора данных по файловым частям. Ожидается, что функция будет сопоставлять элементам входного набора данных целочисленные идентификаторы частей типа int64. Если функция задана, она будет трассирована и выполнена как вычисление графа. |
checkpoint_args | Необязательные аргументы для создания контрольных точек, которые будут переданы в tf.train.CheckpointManager. Если аргументы checkpoint_args не заданы, контрольные точки создаваться не будут. Реализация save() внутренне создает объект tf.train.Checkpoint, поэтому пользователям не следует задавать аргумент checkpoint в checkpoint_args. |
| Возвращает | |
|---|---|
| Операцию, выполнение которой сохраняет набор данных. При записи контрольных точек возвращает None. Возвращаемое значение удобно использовать в модульных тестах. |
| Вызывает исключения | |
|---|---|
ValueError, если checkpoint передан в checkpoint_args. |
scan
scan(
initial_state, scan_func, name=None
) -> 'DatasetV2'
Преобразование, применяющее функцию scan к входному набору данных.
Это преобразование является версией tf.data.Dataset.map с состоянием. Помимо применения scan_func к элементам входного набора данных, scan() накапливает один или несколько тензоров состояния, начальные значения которых равны initial_state.
dataset = tf.data.Dataset.range(10) initial_state = tf.constant(0, dtype=tf.int64) scan_func = lambda state, i: (state + i, state + i) dataset = dataset.scan(initial_state=initial_state, scan_func=scan_func) list(dataset.as_numpy_iterator()) [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
| Аргументы | |
|---|---|
initial_state | Вложенная структура тензоров, представляющая начальное состояние аккумулятора. |
scan_func | Функция, преобразующая (old_state, input_element) в (new_state, output_element). Она должна принимать два аргумента и возвращать пару вложенных структур тензоров. Структура new_state должна соответствовать структуре initial_state. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с примененным описанным выше преобразованием. |
shard
shard(
num_shards, index, name=None
) -> 'DatasetV2'
Создает Dataset, содержащий только 1/num_shards этого набора данных.
shard детерминирован. Набор данных, созданный с помощью A.shard(n, i), будет содержать все элементы A, для которых индекс mod n = i.
A = tf.data.Dataset.range(10) B = A.shard(num_shards=3, index=0) list(B.as_numpy_iterator()) [0, 3, 6, 9] C = A.shard(num_shards=3, index=1) list(C.as_numpy_iterator()) [1, 4, 7] D = A.shard(num_shards=3, index=2) list(D.as_numpy_iterator()) [2, 5, 8]
Этот оператор набора данных очень полезен при распределенном обучении: он позволяет каждой рабочей машине читать уникальное подмножество данных.
При чтении одного входного файла элементы можно разделить на части следующим образом:
d = tf.data.TFRecordDataset(input_file) d = d.shard(num_workers, worker_index) d = d.repeat(num_epochs) d = d.shuffle(shuffle_buffer_size) d = d.map(parser_fn, num_parallel_calls=num_map_threads)
Важные замечания:
- Обязательно разделяйте данные на части до применения любого оператора рандомизации (например, shuffle).
- Обычно оператор shard лучше применять в начале конвейера обработки набора данных. Например, при чтении набора файлов TFRecord разделяйте данные на части до преобразования набора данных во входные образцы. Это позволяет избежать чтения каждого файла на каждой рабочей машине. Ниже приведен пример эффективной стратегии разделения данных на части в полном конвейере:
d = Dataset.list_files(pattern, shuffle=False)
d = d.shard(num_workers, worker_index)
d = d.repeat(num_epochs)
d = d.shuffle(shuffle_buffer_size)
d = d.interleave(tf.data.TFRecordDataset,
cycle_length=num_readers, block_length=1)
d = d.map(parser_fn, num_parallel_calls=num_map_threads)
| Аргументы | |
|---|---|
num_shards | Скаляpный tf.int64 tf.Tensor, представляющий количество сегментов, работающих параллельно. |
index | Скаляpный tf.int64 tf.Tensor, представляющий индекс рабочего процесса. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
| Вызывает исключение | |
|---|---|
InvalidArgumentError | если num_shards или index имеют недопустимые значения. Примечание: проверка ошибок выполняется по возможности, и нет гарантии, что ошибки будут обнаружены при создании набора данных. (Например, передача тензора-заполнителя обходит предварительную проверку и вместо этого приводит к ошибке во время вызова session.run.) |
shuffle
shuffle(
buffer_size, seed=None, reshuffle_each_iteration=None, name=None
) -> 'DatasetV2'
Случайным образом перемешивает элементы этого набора данных.
Этот набор данных заполняет буфер элементами buffer_size, а затем случайным образом выбирает элементы из буфера, заменяя выбранные элементы новыми. Для идеального перемешивания размер буфера должен быть не меньше полного размера набора данных.
Например, если набор данных содержит 10 000 элементов, но для buffer_size задано значение 1 000, то shuffle сначала выберет случайный элемент только из первых 1 000 элементов в буфере. После выбора элемента его место в буфере займет следующий элемент (то есть элемент 1 001), поддерживая размер буфера в 1 000 элементов.
Параметр reshuffle_each_iteration определяет, должен ли порядок перемешивания меняться для каждой эпохи. В TF 1.X идиоматичный способ создания эпох заключался в использовании преобразования repeat:
dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=True) dataset = dataset.repeat(2) # [1, 0, 2, 1, 2, 0] dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=False) dataset = dataset.repeat(2) # [1, 0, 2, 1, 0, 2]
В TF 2.0 объекты tf.data.Dataset являются итерируемыми объектами Python, что позволяет создавать эпохи также с помощью итерации Python:
dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=True) list(dataset.as_numpy_iterator()) # [1, 0, 2] list(dataset.as_numpy_iterator()) # [1, 2, 0]
dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=False) list(dataset.as_numpy_iterator()) # [1, 0, 2] list(dataset.as_numpy_iterator()) # [1, 0, 2]
Полное перемешивание всех данных
Чтобы перемешать весь набор данных, задайте buffer_size=dataset.cardinality(). Это эквивалентно заданию buffer_size, равного количеству элементов в наборе данных, что обеспечивает равномерное перемешивание.
Примечание: shuffle(dataset.cardinality()) загружает весь набор данных в память, чтобы его можно было перемешать. Если набор данных слишком велик, это приведет к ошибке переполнения памяти (OOM), поэтому полное перемешивание следует использовать только для наборов данных, которые заведомо помещаются в память, например наборов имен файлов или других небольших наборов данных.
dataset = tf.data.Dataset.range(20) dataset = dataset.shuffle(dataset.cardinality()) # [18, 4, 9, 2, 17, 8, 5, 10, 0, 6, 16, 3, 19, 7, 14, 11, 15, 13, 12, 1]
| Аргументы | |
|---|---|
buffer_size | Скаляpный tf.int64 tf.Tensor, представляющий количество элементов этого набора данных, из которых будут выбираться элементы нового набора данных. Чтобы равномерно перемешать весь набор данных, используйте buffer_size=dataset.cardinality(). |
seed | (Необязательно.) Скаляpный tf.int64 tf.Tensor, представляющий случайное начальное значение, которое будет использоваться для создания распределения. Описание поведения см. в разделе tf.random.set_seed. |
reshuffle_each_iteration | (Необязательно.) Логическое значение, указывающее, следует ли псевдослучайно перемешивать набор данных при каждой итерации по нему. (По умолчанию — True.) |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
skip
skip(
count, name=None
) -> 'DatasetV2'
Создает Dataset, пропускающий count элементов этого набора данных.
dataset = tf.data.Dataset.range(10) dataset = dataset.skip(7) list(dataset.as_numpy_iterator()) [7, 8, 9]
| Аргументы | |
|---|---|
count | Скаляpный tf.int64 tf.Tensor, представляющий количество элементов этого набора данных, которые следует пропустить при формировании нового набора данных. Если count больше размера этого набора данных, новый набор данных не будет содержать элементов. Если count равно -1, пропускается весь набор данных. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
snapshot
snapshot(
path,
compression='AUTO',
reader_func=None,
shard_func=None,
name=None
) -> 'DatasetV2'
API для сохранения выходных данных входного набора данных.
API snapshot позволяет прозрачно сохранять на диск выходные данные конвейера предварительной обработки, а также материализовать предварительно обработанные данные при другом запуске обучения.
Этот API позволяет объединять повторяющиеся этапы предварительной обработки и повторно использовать уже обработанные данные, обменивая дисковое пространство и пропускную способность сети на высвобождение более ценных ресурсов ЦП и времени вычислений на ускорителях.
https://github.com/tensorflow/community/blob/master/rfcs/20200107-tf-data-snapshot.md содержит подробную документацию по проектированию этой функции.
Пользователи могут задавать различные параметры для управления поведением snapshot, в том числе способом чтения и записи снимков, передавая пользовательские функции в параметры reader_func и shard_func.
shard_func — это заданная пользователем функция, сопоставляющая входные элементы сегментам снимка.
Пользователи могут задать эту функцию, чтобы управлять записью файлов снимка на диск. Ниже приведен пример возможной реализации shard_func.
dataset = ...
dataset = dataset.enumerate()
dataset = dataset.snapshot("/path/to/snapshot/dir",
shard_func=lambda x, y: x % NUM_SHARDS, ...)
dataset = dataset.map(lambda x, y: y)
reader_func — это заданная пользователем функция, принимающая один аргумент: (1) Dataset, состоящий из Dataset, каждый из которых представляет собой «часть» элементов исходного набора данных. Кардинальность входного набора данных совпадает с количеством сегментов, указанным в shard_func (см. выше). Функция должна возвращать Dataset с элементами исходного набора данных.
Пользователи могут задать эту функцию, чтобы управлять чтением файлов снимка с диска, в том числе объемом перемешивания и параллелизмом.
Ниже приведен пример стандартной функции чтения, которую может определить пользователь. Эта функция обеспечивает перемешивание набора данных и параллельное чтение наборов данных:
def user_reader_func(datasets):
# shuffle the datasets splits
datasets = datasets.shuffle(NUM_CORES)
# read datasets in parallel and interleave their elements
return datasets.interleave(lambda x: x, num_parallel_calls=AUTOTUNE)
dataset = dataset.snapshot("/path/to/snapshot/dir",
reader_func=user_reader_func)
По умолчанию snapshot выполняет чтение параллельно, используя количество ядер, доступных в системе, но не пытается перемешивать данные.
| Аргументы | |
|---|---|
path | Обязательный параметр. Каталог для сохранения и загрузки снимка. |
compression | Необязательный параметр. Тип сжатия для снимка, записываемого на диск. Поддерживаются варианты GZIP, SNAPPY, AUTO или None. По умолчанию используется AUTO, которое пытается выбрать подходящий алгоритм сжатия для набора данных. |
reader_func | Необязательный параметр. Функция для управления чтением данных из сегментов снимка. |
shard_func | Необязательный параметр. Функция для управления разбиением данных на сегменты при записи снимка. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
sparse_batch
sparse_batch(
batch_size, row_shape, name=None
) -> 'DatasetV2'
Объединяет последовательные элементы в tf.sparse.SparseTensor.
Как и Dataset.padded_batch(), это преобразование объединяет несколько последовательных элементов набора данных, которые могут иметь разные формы, в один элемент. Полученный элемент имеет три компонента (indices, values и dense_shape), образующие tf.sparse.SparseTensor, представляющий те же данные. row_shape представляет плотную форму каждой строки в результирующем tf.sparse.SparseTensor, к которой добавляется эффективный размер пакета. Например:
# NOTE: The following examples use `{ ... }` to represent the
# contents of a dataset.
a = { ['a', 'b', 'c'], ['a', 'b'], ['a', 'b', 'c', 'd'] }
a.apply(tf.data.experimental.dense_to_sparse_batch(
batch_size=2, row_shape=[6])) ==
{
([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1]], # indices
['a', 'b', 'c', 'a', 'b'], # values
[2, 6]), # dense_shape
([[0, 0], [0, 1], [0, 2], [0, 3]],
['a', 'b', 'c', 'd'],
[1, 6])
}
| Аргументы | |
|---|---|
batch_size | Скаляpный tf.int64 tf.Tensor, представляющий количество последовательных элементов этого набора данных, объединяемых в один пакет. |
row_shape | Объект типа tf.TensorShape или векторный объект, подобный тензору tf.int64, представляющий эквивалентную плотную форму строки в результирующем tf.sparse.SparseTensor. Каждый элемент этого набора данных должен иметь тот же ранг, что и row_shape, а его размер в каждом измерении не должен превышать row_shape. |
name | (Необязательно.) Строка, задающая имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
take
take(
count, name=None
) -> 'DatasetV2'
Создает Dataset, содержащий не более count элементов этого набора данных.
dataset = tf.data.Dataset.range(10) dataset = dataset.take(3) list(dataset.as_numpy_iterator()) [0, 1, 2]
| Аргументы | |
|---|---|
count | Скаляpный tf.int64 tf.Tensor, представляющий количество элементов этого набора данных, которые следует взять для формирования нового набора данных. Если count равно -1 или count больше размера этого набора данных, новый набор данных будет содержать все его элементы. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
take_while
take_while(
predicate, name=None
) -> 'DatasetV2'
Преобразование, останавливающее итерацию по набору данных на основе predicate.
dataset = tf.data.Dataset.range(10) dataset = dataset.take_while(lambda x: x < 5) list(dataset.as_numpy_iterator()) [0, 1, 2, 3, 4]
| Аргументы | |
|---|---|
predicate | Функция, преобразующая вложенную структуру тензоров (формы и типы которых определяются параметрами self.output_shapes и self.output_types) в скалярный тензор tf.bool. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
unbatch
unbatch(
name=None
) -> 'DatasetV2'
Разбивает элементы набора данных на несколько элементов.
Например, если элементы набора данных имеют форму [B, a0, a1, ...], где B может различаться для каждого входного элемента, то для каждого элемента набора данных набор данных после разбиения пакетов будет содержать B последовательных элементов формы [a0, a1, ...].
elements = [ [1, 2, 3], [1, 2], [1, 2, 3, 4] ] dataset = tf.data.Dataset.from_generator(lambda: elements, tf.int64) dataset = dataset.unbatch() list(dataset.as_numpy_iterator()) [1, 2, 3, 1, 2, 1, 2, 3, 4]
Примечание: Для выполненияunbatchтребуется копирование данных, чтобы разделить пакетный тензор на более мелкие тензоры без пакетирования. При оптимизации производительности старайтесь избегать ненужного использованияunbatch.
| Аргументы | |
|---|---|
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
unique
unique(
name=None
) -> 'DatasetV2'
Преобразование, удаляющее повторяющиеся элементы из Dataset.
Используйте это преобразование, чтобы создать набор данных, содержащий по одному экземпляру каждого уникального элемента входных данных. Например:
dataset = tf.data.Dataset.from_tensor_slices([1, 37, 2, 37, 2, 1]) dataset = dataset.unique() sorted(list(dataset.as_numpy_iterator())) [1, 2, 37]
Примечание: Это преобразование поддерживает только наборы данных, помещающиеся в память и содержащие элементы типаtf.int32,tf.int64илиtf.string.
| Аргументы | |
|---|---|
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
window
window(
size, shift=None, stride=1, drop_remainder=False, name=None
) -> 'DatasetV2'
Возвращает набор данных из «окон».
Каждое «окно» — это набор данных, содержащий подмножество элементов входного набора данных. Эти наборы данных конечны и имеют размер size (или могут быть меньше, если входных элементов недостаточно для заполнения окна и drop_remainder принимает значение False).
Например:
dataset = tf.data.Dataset.range(7).window(3) for window in dataset: print(window) <...Dataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)> <...Dataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)> <...Dataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)>
Поскольку окна являются наборами данных, по ним можно выполнять итерацию:
for window in dataset: print(list(window.as_numpy_iterator())) [0, 1, 2] [3, 4, 5] [6]
Сдвиг
Аргумент shift определяет количество входных элементов, на которое сдвигается начало каждого окна. Если нумерация окон и элементов начинается с 0, первым элементом окна k будет элемент k * shift входного набора данных. В частности, первым элементом первого окна всегда будет первый элемент входного набора данных.
dataset = tf.data.Dataset.range(7).window(3, shift=1,
drop_remainder=True)
for window in dataset:
print(list(window.as_numpy_iterator()))
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]Шаг
Аргумент stride определяет шаг между входными элементами внутри окна.
dataset = tf.data.Dataset.range(7).window(3, shift=1, stride=2,
drop_remainder=True)
for window in dataset:
print(list(window.as_numpy_iterator()))
[0, 2, 4]
[1, 3, 5]
[2, 4, 6]Вложенные элементы
Если преобразование window применяется к набору данных, элементы которого представляют собой вложенные структуры, оно создает набор данных с такой же вложенной структурой, но каждый лист заменяется окном. Иными словами, вложенность применяется снаружи окон, а не внутри них.
Сигнатура типа:
def window(
self: Dataset[Nest[T]], ...
) -> Dataset[Nest[Dataset[T]]]
Применение window к Dataset кортежей дает кортеж окон:
dataset = tf.data.Dataset.from_tensor_slices(([1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]))
dataset = dataset.window(2)
windows = next(iter(dataset))
windows
(<...Dataset element_spec=TensorSpec(shape=(), dtype=tf.int32, name=None)>,
<...Dataset element_spec=TensorSpec(shape=(), dtype=tf.int32, name=None)>)def to_numpy(ds): return list(ds.as_numpy_iterator()) for windows in dataset: print(to_numpy(windows[0]), to_numpy(windows[1])) [1, 2] [6, 7] [3, 4] [8, 9] [5] [10]
Применение window к Dataset словарей дает словарь Datasets:
dataset = tf.data.Dataset.from_tensor_slices({'a': [1, 2, 3],
'b': [4, 5, 6],
'c': [7, 8, 9]})
dataset = dataset.window(2)
def to_numpy(ds):
return list(ds.as_numpy_iterator())
for windows in dataset:
print(tf.nest.map_structure(to_numpy, windows))
{'a': [1, 2], 'b': [4, 5], 'c': [7, 8]}
{'a': [3], 'b': [6], 'c': [9]}Преобразование набора данных окон в плоскую структуру
Методы Dataset.flat_map и Dataset.interleave можно использовать для преобразования набора данных окон в единый набор данных.
Аргумент flat_map — это функция, которая принимает элемент набора данных и возвращает Dataset. flat_map последовательно объединяет полученные наборы данных.
Например, чтобы преобразовать каждое окно в плотный тензор:
dataset = tf.data.Dataset.range(7).window(3, shift=1,
drop_remainder=True)
batched = dataset.flat_map(lambda x:x.batch(3))
for batch in batched:
print(batch.numpy())
[0 1 2]
[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]| Аргументы | |
|---|---|
size | Скаляpный tf.int64 tf.Tensor, представляющий количество элементов входного набора данных, объединяемых в окно. Должен быть положительным. |
shift | (Необязательно.) Скаляpный tf.int64 tf.Tensor, представляющий количество входных элементов, на которое окно сдвигается при каждой итерации. По умолчанию — size. Должен быть положительным. |
stride | (Необязательно.) Скаляpный tf.int64 tf.Tensor, представляющий шаг входных элементов в скользящем окне. Должен быть положительным. Значение по умолчанию 1 означает «сохранять каждый входной элемент». |
drop_remainder | (Необязательно.) Скаляpный tf.bool tf.Tensor, указывающий, следует ли отбрасывать последние окна, если их размер меньше size. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
with_options
with_options(
options, name=None
) -> 'DatasetV2'
Возвращает новый tf.data.Dataset с заданными параметрами.
Параметры являются «глобальными» в том смысле, что применяются ко всему набору данных. Если параметры задаются несколько раз, они объединяются, если для разных параметров не указаны различные значения, отличные от значений по умолчанию.
ds = tf.data.Dataset.range(5)
ds = ds.interleave(lambda x: tf.data.Dataset.range(5),
cycle_length=3,
num_parallel_calls=3)
options = tf.data.Options()
# This will make the interleave order non-deterministic.
options.deterministic = False
ds = ds.with_options(options)| Аргументы | |
|---|---|
options | tf.data.Options, задающий используемые параметры. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
| Вызывает исключение | |
|---|---|
ValueError | если для параметра несколько раз задано значение, отличное от значения по умолчанию |
zip
@staticmethod
zip(
*args, datasets=None, name=None
) -> 'DatasetV2'
Создает Dataset, объединяя в пары указанные наборы данных.
Семантика этого метода похожа на семантику встроенной функции Python zip(); главное отличие состоит в том, что аргумент datasets может быть (вложенной) структурой объектов Dataset. Поддерживаемые механизмы вложения описаны здесь.
# The datasets or nested structure of datasets `*args` argument
# determines the structure of elements in the resulting dataset.
a = tf.data.Dataset.range(1, 4) # ==> [ 1, 2, 3 ]
b = tf.data.Dataset.range(4, 7) # ==> [ 4, 5, 6 ]
ds = tf.data.Dataset.zip(a, b)
list(ds.as_numpy_iterator())
[(1, 4), (2, 5), (3, 6)]
ds = tf.data.Dataset.zip(b, a)
list(ds.as_numpy_iterator())
[(4, 1), (5, 2), (6, 3)]
# The `datasets` argument may contain an arbitrary number of datasets.
c = tf.data.Dataset.range(7, 13).batch(2) # ==> [ [7, 8],
# [9, 10],
# [11, 12] ]
ds = tf.data.Dataset.zip(a, b, c)
for element in ds.as_numpy_iterator():
print(element)
(1, 4, array([7, 8]))
(2, 5, array([ 9, 10]))
(3, 6, array([11, 12]))
# The number of elements in the resulting dataset is the same as
# the size of the smallest dataset in `datasets`.
d = tf.data.Dataset.range(13, 15) # ==> [ 13, 14 ]
ds = tf.data.Dataset.zip(a, d)
list(ds.as_numpy_iterator())
[(1, 13), (2, 14)]| Аргументы | |
|---|---|
*args | Наборы данных или вложенные структуры наборов данных для объединения в пары. Этот параметр нельзя задавать, если задан datasets. |
datasets | (Вложенная) структура наборов данных. Этот параметр нельзя задавать, если задан *args. Обратите внимание: он существует только для обратной совместимости; предпочтительно использовать *args. |
name | (Необязательно.) Имя операции tf.data. |
| Возвращает | |
|---|---|
Новый Dataset с преобразованием, примененным, как описано выше. |
__bool__
__bool__()
__iter__
__iter__() -> iterator_ops.OwnedIterator
Создает итератор для элементов этого набора данных.
Возвращаемый итератор реализует протокол итератора Python.
| Возвращает | |
|---|---|
tf.data.Iterator для элементов этого набора данных. |
| Вызывает исключение | |
|---|---|
RuntimeError | Если выполнение происходит вне tf.function и не в eager-режиме. |
__len__
__len__()
Возвращает длину набора данных, если она известна и конечна.
Для использования этого метода необходимо выполнять код в eager-режиме, а длина набора данных должна быть известна и конечна. Если длина может быть неизвестной или бесконечной либо используется режим графов, вместо этого воспользуйтесь tf.data.Dataset.cardinality.
| Возвращает | |
|---|---|
| Целое число, представляющее длину набора данных. |
| Вызывает исключение | |
|---|---|
RuntimeError | Если длина набора данных неизвестна или бесконечна либо не включено eager-выполнение. |
__nonzero__
__nonzero__()
© 2022 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 4.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/api_docs/python/tf/data/experimental/SqlDataset