
Форма данных: вещание, индексация и кодирование с рваными тенорами
29 июля 2025 г.Обзор контента
- Индексация
- Примеры индексации: 2 -й рваный тензор
- Примеры индексации: 3D рванный тензор
- Преобразование типа тензора
- Оценка рваных тензоров
- Рваные формы
- Статическая форма
- Динамическая форма
- Вещание
- Raggedtensor Кодирование
- Многочисленные рваные размеры
- Рваные звания и плоские значения
- Единообразные внутренние размеры
- Равномерные неинтересные измерения
Индексация
Руггенные тензоры поддерживают индексацию в стиле Python, включая многомерную индексацию и нарезку. Следующие примеры демонстрируют индексацию рваного тензора с 2D и 3D -рваным тензором.
Примеры индексации: 2 -й рваный тензор
queries = tf.ragged.constant(
[['Who', 'is', 'George', 'Washington'],
['What', 'is', 'the', 'weather', 'tomorrow'],
['Goodnight']])
print(queries[1]) # A single query
tf.Tensor([b'What' b'is' b'the' b'weather' b'tomorrow'], shape=(5,), dtype=string)
print(queries[1, 2]) # A single word
tf.Tensor(b'the', shape=(), dtype=string)
print(queries[1:]) # Everything but the first row
<tf.RaggedTensor [[b'What', b'is', b'the', b'weather', b'tomorrow'], [b'Goodnight']]><tf.RaggedTensor [[b'What', b'is', b'the', b'weather', b'tomorrow'], [b'Goodnight']]>
print(queries[:, :3]) # The first 3 words of each query
<tf.RaggedTensor [[b'Who', b'is', b'George'], [b'What', b'is', b'the'], [b'Goodnight']]>
print(queries[:, -2:]) # The last 2 words of each query
<tf.RaggedTensor [[b'George', b'Washington'], [b'weather', b'tomorrow'], [b'Goodnight']]>
Примеры индексации: 3D рванный тензор
rt = tf.ragged.constant([[[1, 2, 3], [4]],
[[5], [], [6]],
[[7]],
[[8, 9], [10]]])
print(rt[1]) # Second row (2D RaggedTensor)
<tf.RaggedTensor [[5], [], [6]]>
print(rt[3, 0]) # First element of fourth row (1D Tensor)
tf.Tensor([8 9], shape=(2,), dtype=int32)
print(rt[:, 1:3]) # Items 1-3 of each row (3D RaggedTensor)
<tf.RaggedTensor [[[4]], [[], [6]], [], [[10]]]>
print(rt[:, -1:]) # Last item of each row (3D RaggedTensor)
<tf.RaggedTensor [[[4]],
[[6]],
[[7]],
[[10]]]>
RaggedTensor
S поддерживает многомерную индексацию и нарезку с одним ограничением: индексация в рваное измерение не допускается. Этот случай проблематичен, поскольку указанное значение может существовать в некоторых рядах, но не в других. В таких случаях не очевидно, следует ли вам (1) поднятьIndexError
; (2) использовать значение по умолчанию; или (3) пропустите это значение и верните тензор с меньшим количеством рядов, чем вы начали. Послеруководящие принципы питона(«Перед лицом двусмысленности отказ от искушения угадать»), эта операция в настоящее время запрещена.
Преобразование типа тензора
АRaggedTensor
Класс определяет методы, которые можно использовать для преобразования междуRaggedTensor
песокtf.Tensor
s илиtf.SparseTensors
:
ragged_sentences = tf.ragged.constant([
['Hi'], ['Welcome', 'to', 'the', 'fair'], ['Have', 'fun']])
# RaggedTensor -> Tensor
print(ragged_sentences.to_tensor(default_value='', shape=[None, 10]))
tf.Tensor(
[[b'Hi' b'' b'' b'' b'' b'' b'' b'' b'' b'']
[b'Welcome' b'to' b'the' b'fair' b'' b'' b'' b'' b'' b'']
[b'Have' b'fun' b'' b'' b'' b'' b'' b'' b'' b'']], shape=(3, 10), dtype=string)
# Tensor -> RaggedTensor
x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]
print(tf.RaggedTensor.from_tensor(x, padding=-1))
<tf.RaggedTensor [[1, 3], [2], [4, 5, 8, 9]]>
#RaggedTensor -> SparseTensor
print(ragged_sentences.to_sparse())
SparseTensor(indices=tf.Tensor(
[[0 0]
[1 0]
[1 1]
[1 2]
[1 3]
[2 0]
[2 1]], shape=(7, 2), dtype=int64), values=tf.Tensor([b'Hi' b'Welcome' b'to' b'the' b'fair' b'Have' b'fun'], shape=(7,), dtype=string), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))
# SparseTensor -> RaggedTensor
st = tf.SparseTensor(indices=[[0, 0], [2, 0], [2, 1]],
values=['a', 'b', 'c'],
dense_shape=[3, 3])
print(tf.RaggedTensor.from_sparse(st))
<tf.RaggedTensor [[b'a'], [], [b'b', b'c']]>
Оценка рваных тензоров
Чтобы получить доступ к значениям в рваном тензоре, вы можете:
- Использовать
tf.RaggedTensor.to_list
Чтобы преобразовать рваный тензор в вложенный список Python. - Использовать
tf.RaggedTensor.numpy
Преобразовать рваный тензор в массив Numpy, ценности которых являются вложенными массивами Numpy. - Разложить рваный тензор в свои компоненты, используя
tf.RaggedTensor.values
иtf.RaggedTensor.row_splits
свойства или методы участия в строке, такие какtf.RaggedTensor.row_lengths
иtf.RaggedTensor.value_rowids
Полем - Используйте индексацию Python, чтобы выбрать значения из рваного тензора.
rt = tf.ragged.constant([[1, 2], [3, 4, 5], [6], [], [7]])
print("Python list:", rt.to_list())
print("NumPy array:", rt.numpy())
print("Values:", rt.values.numpy())
print("Splits:", rt.row_splits.numpy())
print("Indexed value:", rt[1].numpy())
Python list: [[1, 2], [3, 4, 5], [6], [], [7]]
NumPy array: [array([1, 2], dtype=int32) array([3, 4, 5], dtype=int32)
array([6], dtype=int32) array([], dtype=int32) array([7], dtype=int32)]
Values: [1 2 3 4 5 6 7]
Splits: [0 2 5 6 6 7]
Indexed value: [3 4 5]
Рваные формы
Форма тензора указывает размер каждой оси. Например, форма[[1, 2], [3, 4], [5, 6]]
является[3, 2]
, поскольку есть 3 ряда и 2 столбца. Tensorflow имеет два отдельных, но связанных способа для описания форм:
- статическая форма: Информация о размерах оси, которая известна статически (например, при отслеживании
tf.function
) Может быть частично указан. - динамическая форма: Информация о времени выполнения о размерах оси.
Статическая форма
Статическая форма тензора содержит информацию о размерах оси, которая известна во время строительства графа. Для обоихtf.Tensor
иtf.RaggedTensor
, он доступен с помощью.shape
свойство и кодируется с помощьюtf.TensorShape
:
x = tf.constant([[1, 2], [3, 4], [5, 6]])
x.shape # shape of a tf.tensor
TensorShape([3, 2])
rt = tf.ragged.constant([[1], [2, 3], [], [4]])
rt.shape # shape of a tf.RaggedTensor
TensorShape([4, None])
Статическая форма рваного измерения всегдаNone
(т.е. не указано). Однако обратное неправда - еслиTensorShape
измерение естьNone
, тогда это может указывать на то, что измерение оборван,илиЭто может указывать на то, что измерение равномерно, но его размер не известен.
Динамическая форма
Динамическая форма тензора содержит информацию о размерах оси, которая известна при запуске графика. Он построен с использованиемtf.shape
операция Дляtf.Tensor
Вtf.shape
Возвращает форму как 1D Целое числоTensor
, гдеtf.shape(x)[i]
размер осиi
Полем
x = tf.constant([['a', 'b'], ['c', 'd'], ['e', 'f']])
tf.shape(x)
<tf.Tensor: shape=(2,), dtype=int32, numpy=array([3, 2], dtype=int32)>
Однако 1dTensor
недостаточно выразительна, чтобы описать формуtf.RaggedTensor
Полем Вместо этого динамическая форма для рваных тензоров кодируется с использованием выделенного типа,tf.experimental.DynamicRaggedShape
Полем В следующем примереDynamicRaggedShape
вернулсяtf.shape(rt)
Указывает, что рваный тензор имеет 4 ряда, с длиной 1, 3, 0 и 2:
rt = tf.ragged.constant([[1], [2, 3, 4], [], [5, 6]])
rt_shape = tf.shape(rt)
print(rt_shape)
<DynamicRaggedShape lengths=[4, (1, 3, 0, 2)] num_row_partitions=1>
Динамическая форма: операции
DynamicRaggedShape
S может использоваться с большинством Tensorflow Ops, которые ожидают формы, включаяtf.reshape
Вtf.zeros
Вtf.ones
Полемtf.fill
Вtf.broadcast_dynamic_shape
, иtf.broadcast_to
Полем
print(f"tf.reshape(x, rt_shape) = {tf.reshape(x, rt_shape)}")
print(f"tf.zeros(rt_shape) = {tf.zeros(rt_shape)}")
print(f"tf.ones(rt_shape) = {tf.ones(rt_shape)}")
print(f"tf.fill(rt_shape, 9) = {tf.fill(rt_shape, 'x')}")
tf.reshape(x, rt_shape) = <tf.RaggedTensor [[b'a'], [b'b', b'c', b'd'], [], [b'e', b'f']]>
tf.zeros(rt_shape) = <tf.RaggedTensor [[0.0], [0.0, 0.0, 0.0], [], [0.0, 0.0]]>
tf.ones(rt_shape) = <tf.RaggedTensor [[1.0], [1.0, 1.0, 1.0], [], [1.0, 1.0]]>
tf.fill(rt_shape, 9) = <tf.RaggedTensor [[b'x'], [b'x', b'x', b'x'], [], [b'x', b'x']]>
Динамическая форма: индексация и нарезка
DynamicRaggedShape
Можно также быть проиндексирован, чтобы получить размеры равномерных размеров. Например, мы можем найти количество рядов в рваном Тенсоре, используяtf.shape(rt)[0]
(Как и для нерагированного тензора):
rt_shape[0]
<tf.Tensor: shape=(), dtype=int32, numpy=4>
Тем не менее, это ошибка использования индексации, чтобы попытаться получить размер рваного измерения, поскольку у нее нет одного размера. (СRaggedTensor
отслеживает, какие оси уморожены, эта ошибка бросается только во время энергичного выполнения или при отслеживанииtf.function
; Он никогда не будет брошен при выполнении конкретной функции.)
try:
rt_shape[1]
except ValueError as e:
print("Got expected ValueError:", e)
Got expected ValueError: Index 1 is not uniform
DynamicRaggedShape
S также может быть нарезан, пока срез либо начинается с оси0
, или содержит только плотные размеры.
rt_shape[:1]
<DynamicRaggedShape lengths=[4] num_row_partitions=0>
Динамическая форма: кодирование
DynamicRaggedShape
кодируется с использованием двух полей:
inner_shape
: Целочисленный вектор, дающий форму плотногоtf.Tensor
Полемrow_partitions
: Списокtf.experimental.RowPartition
Объекты, описывающие, как наиболее внешнее измерение этой внутренней формы должно быть разделено, чтобы добавить рваные оси.
Для получения дополнительной информации о разделах строк см. В разделе «Raggedtensor Coding» ниже, а также документы API дляtf.experimental.RowPartition
Полем
Динамическая форма: конструкция
DynamicRaggedShape
чаще всего строится путем примененияtf.shape
вRaggedTensor
, но это также может быть построено напрямую:
tf.experimental.DynamicRaggedShape(
row_partitions=[tf.experimental.RowPartition.from_row_lengths([5, 3, 2])],
inner_shape=[10, 8])
<DynamicRaggedShape lengths=[3, (5, 3, 2), 8] num_row_partitions=1>
Если длина всех рядов известна статически,DynamicRaggedShape.from_lengths
Также можно использовать для построения динамической рваной формы. (Это в основном полезно для тестирования и демонстрационного кода, так как редко можно известно длина рваных измерений статически).
tf.experimental.DynamicRaggedShape.from_lengths([4, (2, 1, 0, 8), 12])
<DynamicRaggedShape lengths=[4, (2, 1, 0, 8), 12] num_row_partitions=1>
Вещание
Вещание - это процесс создания тензоров с различными формами, которые имеют совместимые формы для ElementWise Operations. Для получения дополнительной информации о вещании см.
- Numpy: вещание
tf.broadcast_dynamic_shape
tf.broadcast_to
Основные шаги для трансляции двух входовx
иy
иметь совместимые формы:
- Если
x
иy
Не иметь одинакового количества размеров, затем добавьте внешние размеры (с размером 1), пока они не сделают. - Для каждого измерения, где
x
иy
иметь разные размеры:
- Если
x
илиy
иметь размер1
в измеренииd
, затем повторите его значения по всему измерениюd
Чтобы соответствовать размеру другого ввода. - В противном случае поднимите исключение (
x
иy
не совместимы).
Где размер тензора в равномерном измерении представляет собой одно число (размер ломтиков по этому измерению); И размер тензора в рваном измерении представляет собой список длины среза (для всех срезов по всему измерению).
Примеры вещания
# x (2D ragged): 2 x (num_rows)
# y (scalar)
# result (2D ragged): 2 x (num_rows)
x = tf.ragged.constant([[1, 2], [3]])
y = 3
print(x + y)
<tf.RaggedTensor [[4, 5], [6]]>
# x (2d ragged): 3 x (num_rows)
# y (2d tensor): 3 x 1
# Result (2d ragged): 3 x (num_rows)
x = tf.ragged.constant(
[[10, 87, 12],
[19, 53],
[12, 32]])
y = [[1000], [2000], [3000]]
print(x + y)
<tf.RaggedTensor [[1010, 1087, 1012], [2019, 2053], [3012, 3032]]>
# x (3d ragged): 2 x (r1) x 2
# y (2d ragged): 1 x 1
# Result (3d ragged): 2 x (r1) x 2
x = tf.ragged.constant(
[[[1, 2], [3, 4], [5, 6]],
[[7, 8]]],
ragged_rank=1)
y = tf.constant([[10]])
print(x + y)
<tf.RaggedTensor [[[11, 12],
[13, 14],
[15, 16]], [[17, 18]]]>
# x (3d ragged): 2 x (r1) x (r2) x 1
# y (1d tensor): 3
# Result (3d ragged): 2 x (r1) x (r2) x 3
x = tf.ragged.constant(
[
[
[[1], [2]],
[],
[[3]],
[[4]],
],
[
[[5], [6]],
[[7]]
]
],
ragged_rank=2)
y = tf.constant([10, 20, 30])
print(x + y)
<tf.RaggedTensor [[[[11, 21, 31],
[12, 22, 32]], [], [[13, 23, 33]], [[14, 24, 34]]],
[[[15, 25, 35],
[16, 26, 36]], [[17, 27, 37]]]]>
Вот несколько примеров форм, которые не транслируются:
# x (2d ragged): 3 x (r1)
# y (2d tensor): 3 x 4 # trailing dimensions do not match
x = tf.ragged.constant([[1, 2], [3, 4, 5, 6], [7]])
y = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
try:
x + y
except tf.errors.InvalidArgumentError as exception:
print(exception)
Condition x == y did not hold.
Indices of first 3 different values:
[[1]
[2]
[3]]
Corresponding x values:
[ 4 8 12]
Corresponding y values:
[2 6 7]
First 3 elements of x:
[0 4 8]
First 3 elements of y:
[0 2 6]
# x (2d ragged): 3 x (r1)
# y (2d ragged): 3 x (r2) # ragged dimensions do not match.
x = tf.ragged.constant([[1, 2, 3], [4], [5, 6]])
y = tf.ragged.constant([[10, 20], [30, 40], [50]])
try:
x + y
except tf.errors.InvalidArgumentError as exception:
print(exception)
Condition x == y did not hold.
Indices of first 2 different values:
[[1]
[3]]
Corresponding x values:
[3 6]
Corresponding y values:
[2 5]
First 3 elements of x:
[0 3 4]
First 3 elements of y:
[0 2 4]
# x (3d ragged): 3 x (r1) x 2
# y (3d ragged): 3 x (r1) x 3 # trailing dimensions do not match
x = tf.ragged.constant([[[1, 2], [3, 4], [5, 6]],
[[7, 8], [9, 10]]])
y = tf.ragged.constant([[[1, 2, 0], [3, 4, 0], [5, 6, 0]],
[[7, 8, 0], [9, 10, 0]]])
try:
x + y
except tf.errors.InvalidArgumentError as exception:
print(exception)
Condition x == y did not hold.
Indices of first 3 different values:
[[1]
[2]
[3]]
Corresponding x values:
[2 4 6]
Corresponding y values:
[3 6 9]
First 3 elements of x:
[0 2 4]
First 3 elements of y:
[0 3 6]
Raggedtensor Кодирование
Рваные тензоры кодируются с использованиемRaggedTensor
сорт. Внутренне каждыйRaggedTensor
состоит из:
- А
values
Тенсор, который объединяет ряды с переменной длиной в сплющенном списке. - А
row_partition
, что указывает на то, как эти сплющенные значения делятся на ряды.
Аrow_partition
можно хранить с помощью четырех разных кодировки:
row_splits
является целочисленным вектором, указывающим точки разделения между рядами.value_rowids
это целочисленный вектор, указывающий индекс строки для каждого значения.row_lengths
это целочисленный вектор, указывающий длину каждой строки.uniform_row_length
это целочисленный скаляр, указывающий одну длину для всех рядов.
Целочисленный скалярnrows
также может быть включен вrow_partition
кодирование для учета пустых строк с запеканием сvalue_rowids
или пустые ряды сuniform_row_length
Полем
rt = tf.RaggedTensor.from_row_splits(
values=[3, 1, 4, 1, 5, 9, 2],
row_splits=[0, 4, 4, 6, 7])
print(rt)
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>
Выбор того, какой кодирование для использования для разделов строк управляется внутренне рваными тензорами для повышения эффективности в некоторых контекстах. В частности, некоторые из преимуществ и недостатков различных схем, связанных с участием строк:
- Эффективная индексация:
row_splits
Кодирование позволяет индексировать постоянное время и нарезать на рваные тензоры. - Эффективная конкатенация:
row_lengths
Кодирование более эффективно при сознании рваных тензоров, поскольку длина строк не меняется, когда два тензора объединяются вместе. - Маленький размер кодирования:
value_rowids
Кодирование более эффективно при хранении рваных тензоров, которые имеют большое количество пустых рядов, поскольку размер тензора зависит только от общего количества значений. С другой стороны,row_splits
иrow_lengths
Кодирования более эффективны при хранении рваных тензоров с более длинными рядами, поскольку им требуется только одно скалярное значение для каждой строки. - Совместимость:
value_rowids
Схема соответствуетсегментацияформат, используемый операциями, напримерtf.segment_sum
Полем Аrow_limits
схема соответствует формату, используемому OP, такими какtf.sequence_mask
Полем - Равномерные размеры: Как обсуждалось ниже,
uniform_row_length
Кодирование используется для кодирования рваных тензоров с однородными размерами.
Многочисленные рваные размеры
Рваный тензор с несколькими рваными размерами кодируется с использованием вложенногоRaggedTensor
дляvalues
тензор. Каждый вложенRaggedTensor
Добавляет одно рваное измерение.
rt = tf.RaggedTensor.from_row_splits(
values=tf.RaggedTensor.from_row_splits(
values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
row_splits=[0, 3, 3, 5, 9, 10]),
row_splits=[0, 1, 1, 5])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>
Shape: (3, None, None)
Number of partitioned dimensions: 2
Функциональная функцияtf.RaggedTensor.from_nested_row_splits
может быть использован для построения рваного денсора с несколькими рваными размерами непосредственно путем предоставления спискаrow_splits
Тенсоры:
rt = tf.RaggedTensor.from_nested_row_splits(
flat_values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
nested_row_splits=([0, 1, 1, 5], [0, 3, 3, 5, 9, 10]))
print(rt)
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>
Рваные звания и плоские значения
Рваный тензоррваное званиеэто количество раз, что базовыйvalues
тензор был разделен (то есть глубина гнездованияRaggedTensor
объекты). Внутреннийvalues
тензор известен как егоflat_valuesПолем В следующем примере,conversations
имеет Ragged_rank = 3, и егоflat_values
1dTensor
с 24 струнами:
# shape = [batch, (paragraph), (sentence), (word)]
conversations = tf.ragged.constant(
[[[["I", "like", "ragged", "tensors."]],
[["Oh", "yeah?"], ["What", "can", "you", "use", "them", "for?"]],
[["Processing", "variable", "length", "data!"]]],
[[["I", "like", "cheese."], ["Do", "you?"]],
[["Yes."], ["I", "do."]]]])
conversations.shape
TensorShape([2, None, None, None])
assert conversations.ragged_rank == len(conversations.nested_row_splits)
conversations.ragged_rank # Number of partitioned dimensions.
3
conversations.flat_values.numpy()
array([b'I', b'like', b'ragged', b'tensors.', b'Oh', b'yeah?', b'What',
b'can', b'you', b'use', b'them', b'for?', b'Processing',
b'variable', b'length', b'data!', b'I', b'like', b'cheese.', b'Do',
b'you?', b'Yes.', b'I', b'do.'], dtype=object)
Единообразные внутренние размеры
Рваные тензоры с равномерными внутренними размерами кодируются с использованием многомерногоtf.Tensor
для flat_values (т.е.values
)
rt = tf.RaggedTensor.from_row_splits(
values=[[1, 3], [0, 0], [1, 3], [5, 3], [3, 3], [1, 2]],
row_splits=[0, 3, 4, 6])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
print("Flat values shape: {}".format(rt.flat_values.shape))
print("Flat values:\n{}".format(rt.flat_values))
<tf.RaggedTensor [[[1, 3],
[0, 0],
[1, 3]], [[5, 3]], [[3, 3],
[1, 2]]]>
Shape: (3, None, 2)
Number of partitioned dimensions: 1
Flat values shape: (6, 2)
Flat values:
[[1 3]
[0 0]
[1 3]
[5 3]
[3 3]
[1 2]]
Равномерные неинтересные измерения
Рваные тензоры с равномерными неинтересными измерениями кодируются распределительными рядами сuniform_row_length
Полем
rt = tf.RaggedTensor.from_uniform_row_length(
values=tf.RaggedTensor.from_row_splits(
values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
row_splits=[0, 3, 5, 9, 10]),
uniform_row_length=2)
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
<tf.RaggedTensor [[[10, 11, 12], [13, 14]],
[[15, 16, 17, 18], [19]]]>
Shape: (2, 2, None)
Number of partitioned dimensions: 2
Первоначально опубликовано на
Оригинал