Python 如何对给定为矩阵行的特定指数集的均值计算进行矢量化?
我在pytorch中对一些代码进行矢量化时遇到问题。 numpy解决方案也会有所帮助,但pytorch解决方案会更好。 我将交替使用Python 如何对给定为矩阵行的特定指数集的均值计算进行矢量化?,python,numpy,vectorization,pytorch,Python,Numpy,Vectorization,Pytorch,我在pytorch中对一些代码进行矢量化时遇到问题。 numpy解决方案也会有所帮助,但pytorch解决方案会更好。 我将交替使用数组和张量 我面临的问题是: 给定大小为(n,X)的二维浮点数组X,以及大小为(n,n)的布尔二维数组a,计算X中按a中的行索引的行的平均值。 问题是A中的行包含数量可变的True索引 示例(numpy): 这个例子是可行的,但这个公式有三个问题: 对于较大的A和X,for循环速度较慢。我需要循环数万个索引 A[i]可能不包含True索引。这导致np.mean(np
数组
和张量
我面临的问题是:
给定大小为(n,X)的二维浮点数组X
,以及大小为(n,n)的布尔二维数组a
,计算X
中按a
中的行索引的行的平均值。
问题是A
中的行包含数量可变的True
索引
示例(numpy):
这个例子是可行的,但这个公式有三个问题:
A
和X
,for循环速度较慢。我需要循环数万个索引A[i]
可能不包含True
索引。这导致np.mean(np.array([])
,即NaN
。我希望它改为0- 将
的对角线元素设置为A
,以便始终至少有一个元素可供选择True
- 所有选定元素的总和,从该总和中减去
中的值(对角线在开始时保证为X
),然后除以False
元素的数量-每行至少1个True
NaN
,但我仍然需要一个覆盖所有索引的循环。
我怎样才能摆脱这个循环
这是我当前的pytorch代码:
import torch
A = torch.from_numpy(A).bytes()
X = torch.from_numpy(X)
A[np.diag_indices(len(A)] = 1 # Set the diagonal to 1
means = [(X[A[i]].sum(dim=0) - X[i]) / torch.clamp(A[i].sum() - 1, min=1.) # Compute the mean safely
for i in range(len(A))] # Get rid of the loop somehow
means = torch.stack(means)
我不介意你的版本看起来是否完全不同,只要它是可微的并产生相同的结果。我们可以利用
矩阵乘法
-
c = A.sum(1,keepdims=True)
means_np = np.where(c==0,0,A.dot(X)/c)
我们可以通过将A
转换为float32
dtype来进一步优化它,如果它还不是这样,并且精度损失还可以,如下所示-
In [57]: np.random.seed(0)
In [58]: A = np.random.randint(0,2,(1000,1000))
In [59]: X = np.random.rand(1000,1000).astype(np.float32)
In [60]: %timeit A.dot(X)
10 loops, best of 3: 27 ms per loop
In [61]: %timeit A.astype(np.float32).dot(X)
100 loops, best of 3: 10.2 ms per loop
In [62]: np.allclose(A.dot(X), A.astype(np.float32).dot(X))
Out[62]: True
因此,使用A.astype(np.float32).dot(X)
替换A.dot(X)
或者,为了解决行和为零的情况,这要求我们使用np。其中,我们可以将任何非零值赋值,比如1
到c
,然后简单地除以它,如下所示-
c = A.sum(1,keepdims=True)
c[c==0] = 1
means_np = A.dot(X)/c
这也避免了在那些零行和的情况下,我们从np.where
得到的警告。Nice!转换为pytorch很容易:将keepdim
重命名为keepdim
,用torch等价物和torch替换函数。其中
需要torch.Tensor([0])
而不是标量0。如果需要梯度,则必须指定计数。否则,由于被零除,向后更新将产生NaN。分割焊炬夹(计数,最小值=1)。
工作
c = A.sum(1,keepdims=True)
c[c==0] = 1
means_np = A.dot(X)/c