TensorFlow 中是否实现了稀疏张量乘法?

Is sparse tensor multiplication implemented in TensorFlow?

稀疏张量与自身或密集张量的乘法在 TensorFlow 中似乎不起作用。下面的例子

from __future__ import print_function
import tensorflow as tf

x = tf.constant([[1.0,2.0],
                 [3.0,4.0]])
y = tf.SparseTensor(indices=[[0,0],[1,1]], values=[1.0,1.0], shape=[2,2])
z = tf.matmul(x,y)

sess = tf.Session()
sess.run(tf.initialize_all_variables())
print(sess.run([x, y, z]))

失败并显示错误消息

TypeError: Input 'b' of 'MatMul' Op has type string that does not match type 
float32 of argument 'a'

两个张量都具有 float32 类型的值,通过在没有乘法运算的情况下对其进行评估可以看出。 y 与自身相乘 returns 类似的错误信息。 x 与自身的乘法运算正常。

tf.SparseTensor 的通用乘法当前未在 TensorFlow 中实现。但是,一共有三个部分解决方案,选择合适的解决方案将取决于您的数据特征:

  • 如果你有一个tf.SparseTensor和一个tf.Tensor,你可以用tf.sparse_tensor_dense_matmul()将它们相乘。如果其中一个张量在密集化时太大而无法放入内存,这比下一种方法更有效:文档有更多关于如何在这两种方法之间做出决定的指导。请注意,它接受 tf.SparseTensor 作为 first 参数,因此要解决您的确切问题,您需要使用 adjoint_aadjoint_b 参数,并转置结果。

  • 如果您有两个稀疏张量并需要将它们相乘,最简单(如果不是最高效)的方法是将它们转换为密集张量并使用 tf.matmul:

    a = tf.SparseTensor(...)
    b = tf.SparseTensor(...)
    
    c = tf.matmul(tf.sparse_tensor_to_dense(a, 0.0),
                  tf.sparse_tensor_to_dense(b, 0.0),
                  a_is_sparse=True, b_is_sparse=True)
    

    请注意,可选的 a_is_sparseb_is_sparse 参数意味着“a(或 b)具有密集表示,但其大量条目为零",这会触发使用不同的乘法算法。

  • 对于稀疏向量的特殊情况(可能很大且分片)密集矩阵乘法,并且向量中的值为0或1, tf.nn.embedding_lookup operator may be more appropriate. This tutorial 更详细地讨论了何时可以使用嵌入以及如何调用运算符。

  • 对于稀疏 矩阵 由(可能很大且分片的)密集矩阵构成的特殊情况,tf.nn.embedding_lookup_sparse() 可能是合适的。此函数接受一个或两个 tf.SparseTensor 对象,其中 sp_ids 表示非零值,可选的 sp_weights 表示它们的值(否则默认为一个)。

最近,添加了 tf.sparse_tensor_dense_matmul(...),允许将稀疏矩阵乘以密集矩阵。

https://www.tensorflow.org/versions/r0.9/api_docs/python/sparse_ops.html#sparse_tensor_dense_matmul

https://github.com/tensorflow/tensorflow/issues/1241

为了让回答更完整:

tf.sparse_matmul(
    a,
    b,
    transpose_a=None,
    transpose_b=None,
    a_is_sparse=None,
    b_is_sparse=None,
    name=None
)

也存在:

https://www.tensorflow.org/api_docs/python/tf/sparse_matmul

好像

tf.sparse_matmul(
    a,
    b,
    transpose_a=None,
    transpose_b=None,
    a_is_sparse=None,
    b_is_sparse=None,
    name=None
)

不适用于两个 SparseTensors 的乘积。

abTensors 而不是 SparseTensors。我试过了,它不适用于 SparseTensors.

tf.sparse_matmul 用于相乘两个稠密张量而非稀疏类型的数据结构。如果给定矩阵(或两个矩阵)有许多零值,则该函数只是张量乘法的优化版本。同样,它不接受稀疏张量数据类型。它接受密集张量数据类型。如果值大部分为零,它可能会加快您的计算速度。

据我所知,还没有两个稀疏类型张量乘法的实现。但只有一个稀疏一个密​​集,即 tf.sparse_tensor_dense_matmul(x, y) !

在TF2.4.1中你可以使用tensorflow.python.ops.linalg.sparse.sparse_csr_matrix_ops中的方法乘以任意SparseTensor(我认为最多3维)。

应该使用类似下面的内容(通常将稀疏张量转换为 CSR 表示)

import tensorflow as tf
from tensorflow.python.ops.linalg.sparse import sparse_csr_matrix_ops


def tf_multiply(a: tf.SparseTensor, b: tf.SparseTensor):
    a_sm = sparse_csr_matrix_ops.sparse_tensor_to_csr_sparse_matrix(
        a.indices, a.values, a.dense_shape
    )

    b_sm = sparse_csr_matrix_ops.sparse_tensor_to_csr_sparse_matrix(
        b.indices, b.values, b.dense_shape
    )

    c_sm = sparse_csr_matrix_ops.sparse_matrix_sparse_mat_mul(
        a=a_sm, b=b_sm, type=tf.float32
    )

    c = sparse_csr_matrix_ops.csr_sparse_matrix_to_sparse_tensor(
        c_sm, tf.float32
    )

    return tf.SparseTensor(
        c.indices, c.values, dense_shape=c.dense_shape
    )

有一段时间我更喜欢 scipy 乘法(通过 py_function),因为这种乘法在 TF(2.3 和 2.4)中的表现不如 scipy。我最近再次尝试,要么我更改了我的代码,要么在 2.4.1 中进行了一些修复,使 TF 稀疏乘法在 CPU 和 GPU 中比使用 scipy 更快。