系统信息
- 是否编写了自定义代码(与使用TensorFlow提供的库存示例脚本相反):是
- OS平台和发行版(例如,Linux Ubuntu 16.04):Debian Testing/Sid
- 从哪里安装的TensorFlow(从源代码还是二进制文件):二进制文件
- TensorFlow版本(请使用以下命令):2.3.0
- Python版本:3.8.5
- Bazel版本(如果从源代码编译):
- GCC/编译器版本(如果从源代码编译):
- CUDA/cuDNN版本:10.1.243/7.6.5
- GPU型号和内存:Quadro T2000
我通过numpy.load
加载了一个稀疏矩阵,形状为[16777216 5416537]
,有335548396个值(这是DrQA的TFIDF矩阵)。我想在计算过程中使用一个数据集并使用该矩阵。我已经尝试了不同的方法,一种非常慢,另一种则达到2GB限制(我猜优化器正在展开常量矩阵并过度填充图,但我不确定,而且我在使用Grappler配置进行测试时也没有成功)。
慢速版本(我有32GB和16个核心可用)如下所示:
indices, values, dense_shape = load_parts_of_sparse_matrix_as_np_arrays()
def f(x, indices, values, dense_shape):
m = tf.SparseTensor(indices, values, dense_shape=dense_shape)
return do_something(x, m)
ds = load_ds()
ds = tf.data.Dataset.zip((
ds,
tf.data.Dataset.from_tensors(indices).repeat(),
tf.data.Dataset.from_tensors(values).repeat(),
tf.data.Dataset.from_tensors(dense_shape).repeat(),
))
ds.map(f)
我猜每次迭代都在复制内存。
以下修改达到了2gb限制
indices, values, dense_shape = load_parts_of_sparse_matrix_as_np_arrays()
m = tf.SparseTensor(indices, values, dense_shape=dense_shape)
def f(x):
return do_something(x, m)
ds = load_ds()
ds.map(f)
这对我来说有点难以理解。我唯一的猜测是,TF将传递给map的函数用tf.function
Package ,然后跟踪该函数,检测到常量并以某种方式过度填充图形。我关闭了constant_folding没有成功。
到目前为止,唯一让我获得好结果的方法是禁用急切执行并使用占位符表示稀疏Tensor的部分,在其他任何方式下都会达到2GB的结果。遗憾的是,当我使用数据集时,我无法控制这一点。
我首先尝试在Stack Overflow上寻求帮助,但迄今为止还没有收到答复。
8条答案
按热度按时间afdcj2ne1#
Just to add, I am using
tf.sparse.sparse_dense_matmul
to multiply a dense tensor and a sparse one. I was previously using apy_function
and the sparse representation of the matrix was kept in the Python side withscipy.sparse
. This was fast (between 10-20 iterations per second.) I was expecting to have similar results in TF, but moving the constant matrix to the graph results in an almost 80-160x slower performance (between 4 to 8 seconds per iteration).I can still use the
py_function
in my application, but I guess there has to be a way to make TF faster than scipy for this task.ifsvaxew2#
额外的想法:我意识到慢速版本之所以更慢,是因为我使用参数
ds.map
运行了num_parallel_calls=32
。这导致了内存瓶颈。如果我将32减少到4,它会运行得更快(不明显的内存瓶颈),但与此相比仍然非常缓慢。fzsnzjdm3#
你好,@jorgeecardona,
第二种方法应该能够高效地工作,只要稀疏索引/值Tensor可以适应图的大小。由SparseTensor表示的密集矩阵的大小不应该有关系,因为只有索引/值/密集形状被序列化到图中。
如果索引/值太大,超过了2GB的图大小限制,我认为你可以通过提供一个生成器数据集来解决这个问题:
4dbbbstv4#
你好@aaudiber,感谢你的回答。我更新到了TF 2.4(在2.3版本中我无法使用
output_signature
参数),但性能仍然较低。数字与第一个实现非常相似,当我将num_parallel_calls
设置为16时,我觉得内存瓶颈也类似。这是否是稀疏乘法(
sparse_csr_matrix_ops.sparse_matrix_sparse_mat_mul
)的不良实现?目前基本上比使用py_function
和scipy.sparse
慢了10倍。最好的。
bzzcjhmw5#
嗯,生成器数据集的每个repeat()都会再次调用生成器函数,这可能会导致稀疏Tensor被复制。你能尝试在
.repeat()
之前为from_generator
数据集添加一个.cache()
变换吗?我刚刚编辑了上面的例子,在正确的位置插入了.cache()
。q8l4jmvw6#
你好,我没有看到缓存的改进。这是代码的一部分,以防它有所帮助:
使用scipy的代码在精神上并没有什么不同。
s1ag04yj7#
你好,
我仍然遇到这个问题,我能够用较少的值(如之前测试的那个)乘以一些稀疏矩阵,并且在 TensorFlow(CPU 和 GPU)上获得了更好的性能,比 scipy 更好。但是当我尝试使用一个类似的矩阵(与最初测试的矩阵具有相同数量的值)时,我遇到了 protobuf 限制:
我现在使用的是 TensorFlow 2.4.1。
如果在 dataset.map 的每次迭代中返回带有矩阵的 sparsetensor,它仍然可以工作,但这非常慢。如果在 dataset.map 之前创建稀疏Tensor,我就会遇到限制(我认为 map 跟踪函数并将 eager sparse tensor 注入到图中)。
wqsoz72f8#
你好,
感谢你打开这个问题。由于这个问题已经开放了很长时间,这个问题的代码/调试信息可能与当前代码库的状态不相关。
Tensorflow团队正在不断通过修复错误和添加新功能来改进框架。我们建议你尝试使用最新的TensorFlow version 和最新的兼容硬件配置,这可能会解决该问题。如果你仍然遇到问题,请创建一个新的GitHub问题,附上你的最新发现以及所有有助于我们调查的调试信息。
请按照 release notes 了解Tensorflow空间中最新发展的动态。