
Tensorflow Sparse Tensors объяснены с примерами
19 июля 2025 г.Обзор контента
- Sparse Tensors в Tensorflow
- Создание tf.sparse.sparsetensor
- Манипулируя редкими тензорами
- Использование tf.sparse.sparsetensor с другими API -интерфейсом tensorflow
- tf.keras
- tf.data
- tf.train.example
- tf.function
- Дальнейшее чтение и ресурсы
Работая с тензорами, которые содержат много нулевых значений, важно хранить их в пространстве и временем. Разреженные тензоры обеспечивают эффективное хранение и обработку тензоров, которые содержат много нулевых значений. Sparsy Tensors широко используются в схемах кодирования, какTF-IDFВ рамках предварительной обработки данных в приложениях NLP и для предварительной обработки изображений с большим количеством темных пикселей в приложениях компьютерного зрения.
Sparse Tensors в Tensorflow
TensorFlow представляет редкие тензоры черезtf.sparse.SparseTensor
объект. В настоящее время разреженные тензоры в Tensorflow кодируются с использованием формата списка координат (COO). Этот формат кодирования оптимизирован для матриц гипер-склада, таких как встраивание.
Кодирование COO для разреженных тензоров состоит из:
values
: 1D тензор с формой[N]
содержащий все ненулевые значения.indices
: 2D тензор с формой[N, rank]
, содержащий индексы ненулевых значений.dense_shape
: 1D тензор с формой[rank]
, указав форму тензора.
Аненулевойценность в контекстеtf.sparse.SparseTensor
это значение, которое явно не закодировано. Можно явно включить нулевые значения вvalues
из редкой матрицы COO, но эти «явные нули», как правило, не включены при ссылке на ненулевые значения в скудном тензоре.
Примечание:tf.sparse.SparseTensor
не требует, чтобы индексы/значения были в каком-либо конкретном порядке, но несколько операций предполагают, что они находятся в порядке строя. Использоватьtf.sparse.reorder
Чтобы создать копию разреженного тензора, которая отсортирована в каноническом порядке строк.
Создание аtf.sparse.SparseTensor
Построить разреженные тензоры, непосредственно указав ихvalues
Вindices
, иdense_shape
Полем
import tensorflow as tf
2024-10-25 01:24:09.202320: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
E0000 00:00:1729819449.223893 16549 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
E0000 00:00:1729819449.230517 16549 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
st1 = tf.sparse.SparseTensor(indices=[[0, 3], [2, 4]],
values=[10, 20],
dense_shape=[3, 10])
W0000 00:00:1729819451.911465 16549 gpu_device.cc:2344] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.
Skipping registering GPU devices...
Когда вы используетеprint()
Функция для печати скудного тензора, он показывает содержимое трех компонентных тензоров:
print(st1)
SparseTensor(indices=tf.Tensor(
[[0 3]
[2 4]], shape=(2, 2), dtype=int64), values=tf.Tensor([10 20], shape=(2,), dtype=int32), dense_shape=tf.Tensor([ 3 10], shape=(2,), dtype=int64))
Легче понять содержимое разреженного тензора, если ненулевойvalues
соответствуют их соответствующимindices
Полем Определите вспомогательную функцию для довольно печатных тонких тензоров, так что каждое ненулевое значение показано на его собственной линии.
def pprint_sparse_tensor(st):
s = "<SparseTensor shape=%s \n values={" % (st.dense_shape.numpy().tolist(),)
for (index, value) in zip(st.indices, st.values):
s += f"\n %s: %s" % (index.numpy().tolist(), value.numpy().tolist())
return s + "}>"
print(pprint_sparse_tensor(st1))
<SparseTensor shape=[3, 10]
values={
[0, 3]: 10
[2, 4]: 20}>
Вы также можете построить разреженные тензоры из плотных тензоров, используяtf.sparse.from_dense
и преобразовать их обратно в плотные тензоры, используяtf.sparse.to_dense
Полем
st2 = tf.sparse.from_dense([[1, 0, 0, 8], [0, 0, 0, 0], [0, 0, 3, 0]])
print(pprint_sparse_tensor(st2))
<SparseTensor shape=[3, 4]
values={
[0, 0]: 1
[0, 3]: 8
[2, 2]: 3}>
st3 = tf.sparse.to_dense(st2)
print(st3)
tf.Tensor(
[[1 0 0 8]
[0 0 0 0]
[0 0 3 0]], shape=(3, 4), dtype=int32)
Манипулируя редкими тензорами
Используйте утилиты вtf.sparse
Пакет для манипулирования редкими тензорами. ОПС какtf.math.add
То, что вы можете использовать для арифметических манипуляций с плотными тензорами, не работает с редкими тензорами.
Добавить разреженные тензоры той же формы, используяtf.sparse.add
Полем
st_a = tf.sparse.SparseTensor(indices=[[0, 2], [3, 4]],
values=[31, 2],
dense_shape=[4, 10])
st_b = tf.sparse.SparseTensor(indices=[[0, 2], [3, 0]],
values=[56, 38],
dense_shape=[4, 10])
st_sum = tf.sparse.add(st_a, st_b)
print(pprint_sparse_tensor(st_sum))
<SparseTensor shape=[4, 10]
values={
[0, 2]: 87
[3, 0]: 38
[3, 4]: 2}>
Использоватьtf.sparse.sparse_dense_matmul
умножить скудные тензоры с плотными матрицами.
st_c = tf.sparse.SparseTensor(indices=([0, 1], [1, 0], [1, 1]),
values=[13, 15, 17],
dense_shape=(2,2))
mb = tf.constant([[4], [6]])
product = tf.sparse.sparse_dense_matmul(st_c, mb)
print(product)
tf.Tensor(
[[ 78]
[162]], shape=(2, 1), dtype=int32)
Собрать разреженные тензоры, используяtf.sparse.concat
и разбери их, используяtf.sparse.slice
Полем
sparse_pattern_A = tf.sparse.SparseTensor(indices = [[2,4], [3,3], [3,4], [4,3], [4,4], [5,4]],
values = [1,1,1,1,1,1],
dense_shape = [8,5])
sparse_pattern_B = tf.sparse.SparseTensor(indices = [[0,2], [1,1], [1,3], [2,0], [2,4], [2,5], [3,5],
[4,5], [5,0], [5,4], [5,5], [6,1], [6,3], [7,2]],
values = [1,1,1,1,1,1,1,1,1,1,1,1,1,1],
dense_shape = [8,6])
sparse_pattern_C = tf.sparse.SparseTensor(indices = [[3,0], [4,0]],
values = [1,1],
dense_shape = [8,6])
sparse_patterns_list = [sparse_pattern_A, sparse_pattern_B, sparse_pattern_C]
sparse_pattern = tf.sparse.concat(axis=1, sp_inputs=sparse_patterns_list)
print(tf.sparse.to_dense(sparse_pattern))
tf.Tensor(
[[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]
[0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0]
[0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0]
[0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0]
[0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0]
[0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]], shape=(8, 17), dtype=int32)
sparse_slice_A = tf.sparse.slice(sparse_pattern_A, start = [0,0], size = [8,5])
sparse_slice_B = tf.sparse.slice(sparse_pattern_B, start = [0,5], size = [8,6])
sparse_slice_C = tf.sparse.slice(sparse_pattern_C, start = [0,10], size = [8,6])
print(tf.sparse.to_dense(sparse_slice_A))
print(tf.sparse.to_dense(sparse_slice_B))
print(tf.sparse.to_dense(sparse_slice_C))
tf.Tensor(
[[0 0 0 0 0]
[0 0 0 0 0]
[0 0 0 0 1]
[0 0 0 1 1]
[0 0 0 1 1]
[0 0 0 0 1]
[0 0 0 0 0]
[0 0 0 0 0]], shape=(8, 5), dtype=int32)
tf.Tensor(
[[0]
[0]
[1]
[1]
[1]
[1]
[0]
[0]], shape=(8, 1), dtype=int32)
tf.Tensor([], shape=(8, 0), dtype=int32)
Если вы используете TensorFlow 2.4 или выше, используйтеtf.sparse.map_values
Для элементных операций на ненулевых значениях в разреженных тензорах.
st2_plus_5 = tf.sparse.map_values(tf.add, st2, 5)
print(tf.sparse.to_dense(st2_plus_5))
tf.Tensor(
[[ 6 0 0 13]
[ 0 0 0 0]
[ 0 0 8 0]], shape=(3, 4), dtype=int32)
Обратите внимание, что только ненулевые значения были изменены - нулевые значения остаются нулевыми.
Эквивалентно, вы можете следовать шаблону дизайна ниже для более ранних версий Tensorflow:
st2_plus_5 = tf.sparse.SparseTensor(
st2.indices,
st2.values + 5,
st2.dense_shape)
print(tf.sparse.to_dense(st2_plus_5))
tf.Tensor(
[[ 6 0 0 13]
[ 0 0 0 0]
[ 0 0 8 0]], shape=(3, 4), dtype=int32)
С использованиемtf.sparse.SparseTensor
с другими APIS TensorFlow
Sparsy Tensors работают прозрачно с этими API -интерфейсом Tensorflow:
tf.keras
tf.data
tf.Train.Example
Протобуфtf.function
tf.while_loop
tf.cond
tf.identity
tf.cast
tf.print
tf.saved_model
tf.io.serialize_sparse
tf.io.serialize_many_sparse
tf.io.deserialize_many_sparse
tf.math.abs
tf.math.negative
tf.math.sign
tf.math.square
tf.math.sqrt
tf.math.erf
tf.math.tanh
tf.math.bessel_i0e
tf.math.bessel_i1e
Примеры показаны ниже для нескольких из вышеперечисленных API.
tf.keras
Подмножествоtf.keras
API поддерживает разреженные тензоры без дорогого кастинга или конверсии. API Keras позволяет вам передавать разреженные тензоры в качестве входных данных в модель Keras. Наборsparse=True
При звонкеtf.keras.Input
илиtf.keras.layers.InputLayer
Полем Вы можете пройти скудные тензоры между слоями кераса, а также модели Keras возвращают их в качестве выходов. Если вы используете разреженные тензоры вtf.keras.layers.Dense
Слои В вашей модели они выводят плотные тензоры.
В приведенном ниже примере показано, как пропустить разреженный тензор в качестве ввода в модель кераса, если вы используете только слои, которые поддерживают разреженные входы.
x = tf.keras.Input(shape=(4,), sparse=True)
y = tf.keras.layers.Dense(4)(x)
model = tf.keras.Model(x, y)
sparse_data = tf.sparse.SparseTensor(
indices = [(0,0),(0,1),(0,2),
(4,3),(5,0),(5,1)],
values = [1,1,1,1,1,1],
dense_shape = (6,4)
)
model(sparse_data)
model.predict(sparse_data)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 87ms/step
array([[ 1.8707037e-02, 7.7025330e-01, 2.2425324e-01, -1.9139588e+00],
[ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00],
[ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00],
[ 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00],
[-6.2435389e-02, -4.5783034e-01, 1.2970567e-03, -1.8046319e-01],
[-8.0019468e-01, 9.0452707e-01, 2.1884918e-02, -1.3622781e+00]],
dtype=float32)
tf.data
Аtf.data
API позволяет создавать сложные входные трубопроводы из простых, многоразовых кусочков. Его основная структура данныхtf.data.Dataset
, который представляет последовательность элементов, в которых каждый элемент состоит из одного или нескольких компонентов.
Создание наборов данных с редкими тензорами
Создайте наборы данных от Sparsy Tensors, используя те же методы, которые используются для их создания изtf.Tensor
s или numpy массивы, такие какtf.data.Dataset.from_tensor_slices
Полем Этот OP сохраняет разреженную (или редкую природу) данных.
dataset = tf.data.Dataset.from_tensor_slices(sparse_data)
for element in dataset:
print(pprint_sparse_tensor(element))
<SparseTensor shape=[4]
values={
[0]: 1
[1]: 1
[2]: 1}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={
[3]: 1}>
<SparseTensor shape=[4]
values={
[0]: 1
[1]: 1}>
Пакетные и непредвзятые наборы данных с редкими тензорами
Вы можете привести к сочетанию (объединить элементы подряд в один элемент) и разоблачить наборы данных с редкими тензорами, используяDataset.batch
иDataset.unbatch
Методы соответственно.
batched_dataset = dataset.batch(2)
for element in batched_dataset:
print (pprint_sparse_tensor(element))
<SparseTensor shape=[2, 4]
values={
[0, 0]: 1
[0, 1]: 1
[0, 2]: 1}>
<SparseTensor shape=[2, 4]
values={}>
<SparseTensor shape=[2, 4]
values={
[0, 3]: 1
[1, 0]: 1
[1, 1]: 1}>
unbatched_dataset = batched_dataset.unbatch()
for element in unbatched_dataset:
print (pprint_sparse_tensor(element))
<SparseTensor shape=[4]
values={
[0]: 1
[1]: 1
[2]: 1}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={
[3]: 1}>
<SparseTensor shape=[4]
values={
[0]: 1
[1]: 1}>
Вы также можете использоватьtf.data.experimental.dense_to_sparse_batch
для составления элементов наборов данных различных форм в разреженные тензоры.
Преобразование наборов данных с редкими тензорами
Преобразовать и создавать разреженные тензоры в наборах данных, используяDataset.map
Полем
transform_dataset = dataset.map(lambda x: x*2)
for i in transform_dataset:
print(pprint_sparse_tensor(i))
<SparseTensor shape=[4]
values={
[0]: 2
[1]: 2
[2]: 2}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={}>
<SparseTensor shape=[4]
values={
[3]: 2}>
<SparseTensor shape=[4]
values={
[0]: 2
[1]: 2}>
tf.train.example
tf.train.Example
является стандартным кодированием Protobuf для данных TensorFlow. При использовании разреженных тензоров сtf.train.Example
, ты можешь:
- Прочитать данные с переменной длиной в
tf.sparse.SparseTensor
с использованиемtf.io.VarLenFeature
Полем Тем не менее, вам следует рассмотреть возможность использованияtf.io.RaggedFeature
вместо. - Прочитать произвольные разреженные данные в
tf.sparse.SparseTensor
с использованиемtf.io.SparseFeature
, который использует три отдельных ключа функций для храненияindices
Вvalues
, иdense_shape
Полем
tf.function
Аtf.function
Декоратор предварительно считывает графики тензора для функций Python, что может существенно улучшить производительность вашего кода TensorFlow. Sparsy Tensors работают прозрачно с обоимиtf.function
иконкретные функцииПолем
@tf.function
def f(x,y):
return tf.sparse.sparse_dense_matmul(x,y)
a = tf.sparse.SparseTensor(indices=[[0, 3], [2, 4]],
values=[15, 25],
dense_shape=[3, 10])
b = tf.sparse.to_dense(tf.sparse.transpose(a))
c = f(a,b)
print(c)
tf.Tensor(
[[225 0 0]
[ 0 0 0]
[ 0 0 625]], shape=(3, 3), dtype=int32)
Отличие пропущенных значений от нулевых значений
Большинство операцийtf.sparse.SparseTensor
S Обработка пропущенных значений и явных нулевых значений одинаково. Это по дизайну -tf.sparse.SparseTensor
Предполагается действовать как плотный тензор.
Тем не менее, есть несколько случаев, когда может быть полезно отличать нулевые значения от пропущенных значений. В частности, это позволяет одному способу кодировать отсутствующие/неизвестные данные в ваших учебных данных. Например, рассмотрим вариант использования, когда у вас есть тензор баллов (который может иметь какое -либо значение плавающей запятой от -inf до +inf), с некоторыми отсутствующими оценками. Вы можете кодировать этот тензор, используя разреженный тензор, где явные нули известны нулевые оценки, но неявные нулевые значения фактически представляют недостающие данные, а не ноль.
Примечание:Как правило, это не предполагаемое использованиеtf.sparse.SparseTensor
S; И вы можете также рассмотреть другие методы кодирования этого, например, с использованием отдельного тензора маски, который идентифицирует местоположения известных/неизвестных значений. Тем не менее, проявляйте осторожность при использовании этого подхода, поскольку большинство разреженных операций будут одинаково рассматривать явные и неявные нулевые значения.
Обратите внимание, что некоторые операции любятtf.sparse.reduce_max
Не обращайтесь с недостающими значениями, как если бы они были нулю. Например, когда вы запускаете блок кода ниже, ожидаемый вывод0
Полем Однако из -за этого исключения вывод-3
Полем
print(tf.sparse.reduce_max(tf.sparse.from_dense([-5, 0, -3])))
tf.Tensor(-3, shape=(), dtype=int32)
Напротив, когда вы применяетеtf.math.reduce_max
К плотному тензору выходной выход равен 0, как и ожидалось.
print(tf.math.reduce_max([-5, 0, -3]))
tf.Tensor(0, shape=(), dtype=int32)
Дальнейшее чтение и ресурсы
- СмТенсорский гидЧтобы узнать о тензорах.
- ЧитатьРуководство с рваным тензоромЧтобы узнать, как работать с рваными тензорами, типом тензора, который позволяет вам работать с неравномерными данными.
- Проверьте эту модель обнаружения объекта вTensorflow Model Gardenкоторый использует разреженные тензоры в
tf.Example
Декодер данных.
Первоначально опубликовано на
Оригинал