在Julia中用稀疏向量更新密集向量的速度很慢

在Julia中用稀疏向量更新密集向量的速度很慢,julia,sparse-matrix,Julia,Sparse Matrix,我正在使用Julia版本0.4.5,遇到以下问题: 据我所知,在稀疏向量和稠密向量之间取内积应该和用稀疏向量更新稠密向量一样快。后者要慢得多 A = sprand(100000,100000,0.01) w = rand(100000) @time for i=1:100000 w += A[:,i] end 26.304380 seconds (1.30 M allocations: 150.556 GB, 8.16% gc time) @time for i=1:100000 A

我正在使用Julia版本0.4.5,遇到以下问题: 据我所知,在稀疏向量和稠密向量之间取内积应该和用稀疏向量更新稠密向量一样快。后者要慢得多

A = sprand(100000,100000,0.01)
w = rand(100000)

@time for i=1:100000
  w += A[:,i]
end
26.304380 seconds (1.30 M allocations: 150.556 GB, 8.16% gc time)

@time for i=1:100000
  A[:,i]'*w
end
0.815443 seconds (921.91 k allocations: 1.540 GB, 5.58% gc time)
我自己创建了一个简单的稀疏矩阵类型,加法代码与内积相同

我做错什么了吗?我觉得应该有一个特殊的函数来执行w+=a[:,I]的操作,但我找不到它


非常感谢您的帮助。

假设您想要计算
w+=c*A[:,i]
,有一种简单的方法可以将其矢量化:

>>> A = sprand(100000, 100000, 0.01)
>>> c = rand(100000)

>>> r1 = zeros(100000)
>>> @time for i = 1:100000
>>>    r1 += A[:, i] * c[i]
>>> end
29.997412 seconds (1.90 M allocations: 152.077 GB, 12.73% gc time)

>>> @time r2 = sum(A .* c', 2);
1.191850 seconds (50 allocations: 1.493 GB, 0.14% gc time)

>>> all(r1 == r2)
true

首先,创建要与之相乘的常数的向量
c
。然后将
A
元素的de列乘以
c
的值(
A.*c'
,它在内部进行广播)。最后,减少
A
的列(部分
总和(..,2)

我在GitHub上问了同样的问题,我们得出了以下结论。从Julia 0.4开始添加SparseVector类型,并使用它添加BLAS函数LinAlg.axpy!,它通过稀疏向量
y
乘以标量
a
,就地更新(可能密集的)向量
x
,即有效地执行
x+=a*y
。但是,在Julia 0.4中,它没有正确实现。它只在Julia 0.5中起作用

@time for i=1:100000
  LinAlg.axpy!(1,A[:,i],w)
end
1.041587 seconds (799.49 k allocations: 1.530 GB, 8.01% gc time)
然而,这段代码仍然是次优的,因为它创建了SparseVector A[:,i]。使用以下功能可以获得更快的版本:

function upd!(w,A,i,c)
  rowval = A.rowval
  nzval = A.nzval
  @inbounds for j = nzrange(A,i)
    w[rowval[j]] += c* nzval[j]
  end
  return w
end

@time for i=1:100000
  upd!(w,A,i,1)
end
0.500323 seconds (99.49 k allocations: 1.518 MB)

这正是我需要达到的目标,经过一些研究,我们终于达到了目标,谢谢大家

你的两种方法并不相同。第一个可以替换为
w+=sum(A,2)
,而不使用for循环(首先在列上减少
A
,然后更新
w
)。这就是你想要的吗?如果是这样的话,时间是
0.348840秒(75个分配:1.530MB)
@imaluengo我想写一个迭代方法,在这里我会将w更新为矩阵列的若干倍。我只是通过做大量的添加来模拟这一点,展示它的速度非常慢。正如我所提到的,做
w+=c*A[:,I]
应该花费与
A[:,I]'*w
相同的时间。我自己做了稀疏实现,两个都有~1秒的时间。我只是想知道是否可以用SparSematrix XCSC类来完成。我了解所有这些,但我的观点是,这必须是我迭代算法的一部分,即在每次迭代
t
,我想为随机索引
I
更新
w+=c(w)*A[:,I]
,其中
c(w)
是当前
w
的函数。这意味着,我不能矢量化它,因为它是一个串行算法。因此,我的问题是,为什么加法比乘法慢,因为它肯定不应该是一个好的稀疏实现。我很确定,仍然有一些方法可以矢量化你想要做的事情。但无论如何,原因可能是在解释for循环时乘法是预先编译的。尝试将for循环放入函数中并进行预编译,您可能会获得更好的速度。不幸的是,将其放入函数中并没有帮助。我的目标类似于以下内容:
对于t=1:t;i=兰特(长度(w));w+=(X[:,i]'*w)*X[:,i];结束
。这是随机梯度下降的特例——一种串行优化算法。每次迭代都应该进行O(nnz(X[:,i])次失败。取内积是根据理论工作的,把它加在w上需要更多的时间(如原始帖子中的计时所示)。我很确定我在更新w时使用了错误的命令,或者SparSematrix XCSC存在问题。