Форма данных: вещание, индексация и кодирование с рваными тенорами

Форма данных: вещание, индексация и кодирование с рваными тенорами

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

RaggedTensorS поддерживает многомерную индексацию и нарезку с одним ограничением: индексация в рваное измерение не допускается. Этот случай проблематичен, поскольку указанное значение может существовать в некоторых рядах, но не в других. В таких случаях не очевидно, следует ли вам (1) поднятьIndexError; (2) использовать значение по умолчанию; или (3) пропустите это значение и верните тензор с меньшим количеством рядов, чем вы начали. Послеруководящие принципы питона(«Перед лицом двусмысленности отказ от искушения угадать»), эта операция в настоящее время запрещена.

Преобразование типа тензора

АRaggedTensorКласс определяет методы, которые можно использовать для преобразования междуRaggedTensorпесокtf.Tensors или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']]>

Оценка рваных тензоров

Чтобы получить доступ к значениям в рваном тензоре, вы можете:

  1. Использоватьtf.RaggedTensor.to_listЧтобы преобразовать рваный тензор в вложенный список Python.
  2. Использоватьtf.RaggedTensor.numpyПреобразовать рваный тензор в массив Numpy, ценности которых являются вложенными массивами Numpy.
  3. Разложить рваный тензор в свои компоненты, используяtf.RaggedTensor.valuesиtf.RaggedTensor.row_splitsсвойства или методы участия в строке, такие какtf.RaggedTensor.row_lengthsиtf.RaggedTensor.value_rowidsПолем
  4. Используйте индексацию 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>

Динамическая форма: операции

DynamicRaggedShapeS может использоваться с большинством 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

DynamicRaggedShapeS также может быть нарезан, пока срез либо начинается с оси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иметь совместимые формы:

  1. ЕслиxиyНе иметь одинакового количества размеров, затем добавьте внешние размеры (с размером 1), пока они не сделают.
  2. Для каждого измерения, где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_values1dTensorс 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

Первоначально опубликовано наTensorflowВеб -сайт, эта статья появляется здесь под новым заголовком и имеет лицензию в CC на 4.0. Образцы кода, разделенные по лицензии Apache 2.0.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE