请注意,这与here基本上是同一个问题,但不幸的是,即使它被接受为答案,解决方案仍然不起作用。更重要的是,当存在多个相同的索引时,ufunc.at方法的主要用例之一就是失败。
现在我们将np.add
作为ufunc来演示我们的其余代码。
考虑对象
row_idx: A 1D numpy array of integers with shape=(N,)
col_idx: A 1D numpy array of integers with shape=(N,)
values : A 1D numpy array of floats with shape=(N,)
M : A 2D numpy array of floats with shape=(k,k)
重要的是,行和列组合不是唯一的,即以下不适用
(row_idx[i], col_idx[i]) == (row_idx[j], col_idx[j]) => i==j (1)
这意味着,要实现以下功能的更新
def update_loop(row_idx, col_idx, M):
for i in range(row_idx.size):
M[row_idx[i], col_idx[i]] += values[i]
当(1)不能保持时,以下方式不起作用(对于某些人来说可能出乎意料)。
def update_index(row_idx, col_idx, M):
M[row_idx, col_idx] += values
但幸运的是我们可以使用
def update_ufunc(row_idx, col_idx, M):
np.add.at(M, (row_idx, col_idx), values)
在Tensorflow中处理相同问题时,链接问题中的答案建议使用稀疏矩阵,因为值(row_idx, col_idx, values)
基本上代表稀疏矩阵。
特别是如果我们有以下对象
row_idx_tf: A 2D tensorflow tensor of integers with shape=(N,1)
col_idx_tf: A 2D tensorflow tensor of integers with shape=(N,1)
values_tf : A 2D tensorflow tensor of floats with shape=(N,1)
M_tf : A 2D tensorflow tensor of floats with shape=(k,k)
建议的代码基本上就是我们的情况
idx = tf.concat((row_idx, col_idx), 1)
sparse_tensor = tf.SparseTensor(idx, values, [k,k])
tf.sparse_add(M_tf, sparse_tensor)
但是,如果我们希望它的行为类似于np.add.at
方法,那么这取决于创建稀疏张量时,如果我们遇到索引i
,(row_idx[i], col_idx[i])
已存在于张量中,然后values[i]
被添加到张量中的当前条目。这在前一个问题的注释中提到,因为它显然是Scipy稀疏csr矩阵的默认行为。我可以确认这不是Tensorflow稀疏张量的行为。
因此,考虑使用稀疏张量的方法不起作用,在Tensorflow中执行等效Numpy unfunc.at方法的最有效方法是什么?
N.B。我想确保该方法充分利用可用HPC硬件的强大功能。基本上我们有N
个独立更新来执行,我们唯一需要注意的是多个线程试图同时更新M
中的相同条目。除此之外,它似乎完全平行。