0

我正在尝试构建一个以稀疏张量列表作为输入的模型。(列表长度等于批量大小)

我使用稀疏张量的原因是我必须将邻接矩阵传递给我的 GNN 模型,而且它非常稀疏。(~99%)

我熟悉使用 pytorch,将稀疏张量输入网络非常容易。

但是我发现我必须使用 tf.data.Dataset 或 keras.utils.Sequence 在 tensorflow 中制作数据集。

但是当我使用稀疏张量列表作为输入时,这些方法会向我抛出错误。

例如,下面的代码使 TypeError

import tensorflow as tf
tf.data.Dataset.from_tensor_slices(sparse_lists)
TypeError: Neither a SparseTensor nor SparseTensorValue: 
[<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2e25b5c0>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c22ada0>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c22a400>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed240>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed390>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed470>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed5c0>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed710>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed828>, 
<tensorflow.python.framework.sparse_tensor.SparseTensor object at 0x7fbf2c1ed940>].

我知道如果我将列表中的所有稀疏张量连接为一个巨大的张量,它将起作用。但是,这不是我的选择,因为我以后必须对稀疏张量使用索引。(如果我将 2D 稀疏张量连接成 3D 稀疏张量,我不能使用如下索引)

Some3DSparseTensor[:10]

此外,这将花费更多时间,因为我必须对 3D 张量进行切片,以便与其他密集网络进行矩阵乘法。

此外,我知道如果我通过索引创建稀疏张量,每批的值会很好,但是每批会花费太多时间。

因此,由于索引、时间问题,我想让 tf.data.Dataset 能够从稀疏张量列表中生成批处理。

有谁能够帮我?:)


长话短说,

我所拥有的:稀疏张量列表(例如 1000000 长度列表)

我需要做的:稀疏张量的批处理列表(例如 1024 长度列表,而不是稀疏连接)

4

2 回答 2

0

另一种解决方案使用from_tensor_slices每个稀疏张量(在添加虚拟批次维度之后)来创建具有单个元素的多个数据集,这些元素可以连接到单个数据集中。

dataset = None
for sparse_tensor in sparse_list:
    batched_sparse_tensor = tf.sparse.expand_dims(sparse_tensor, axis=0)
    element_dataset = tf.data.Dataset.from_tensor_slices(batched_sparse_tensor)
    if dataset is None:
        dataset = element_dataset
    else:
        dataset = dataset.concatenate(element_dataset)

请注意,使用此解决方案,稀疏张量可以有不同dense_shape的 s。

于 2021-07-09T11:20:19.247 回答
0

如果 SparseTensor 具有相同的dense_shape内容,您可以创建一个唯一的 SparseTensor 而不是列表并将其传递给from_tensor_slices.

例如,下面的代码从一个大的 SparseTensor 产生单独的 SparseTensor,s将它们沿第一维拆分

s = tf.sparse.SparseTensor(
    indices=tf.constant([[0, 0, 0], [1, 0, 0], [1, 0, 1], [2, 1, 1]], dtype=tf.int64), 
    values=tf.range(4, dtype=tf.float32), 
    dense_shape=(3, 2, 2))
d = tf.data.Dataset.from_tensor_slices(s)
for t in d:
    print(t)
>>> SparseTensor(indices=tf.Tensor([[0 0]], shape=(1, 2), dtype=int64), values=tf.Tensor([0.], shape=(1,), dtype=float32), dense_shape=tf.Tensor([2 2], shape=(2,), dtype=int64))
SparseTensor(indices=tf.Tensor(
[[0 0]
 [0 1]], shape=(2, 2), dtype=int64), values=tf.Tensor([1. 2.], shape=(2,), dtype=float32), dense_shape=tf.Tensor([2 2], shape=(2,), dtype=int64))
SparseTensor(indices=tf.Tensor([[1 1]], shape=(1, 2), dtype=int64), values=tf.Tensor([3.], shape=(1,), dtype=float32), dense_shape=tf.Tensor([2 2], shape=(2,), dtype=int64))

from_tensor_slices以这种方式使用,您需要一个函数将列表转换sparse_lists为大型 SparseTensor s(如下所述)。

回顾一下,你可以做

import tensorflow as tf

def sparse_list_to_sparse_tensor(sparse_lists):
    n = len(sparse_lists)
    shape = sparse_lists[0].dense_shape
    out_shape = (n, *shape)
    out_values = tf.concat([s.values for s in sparse_lists], axis=0)
    out_indices = []
    for i, s in enumerate(sparse_lists):
        element_idx = tf.cast(tf.fill((s.indices.shape[0], 1), i), dtype=tf.int64)
        out_indices.append(tf.concat([element_idx, s.indices], axis=1))
    out_indices = tf.concat(out_indices, axis=0)
    return tf.sparse.SparseTensor(out_indices, out_values, out_shape)


tf.data.Dataset.from_tensor_slices(sparse_list_to_sparse_tensor(sparse_lists))
于 2021-07-08T10:35:56.867 回答