优化稀疏数组数学
Optimising Sparse Array Math
我有一个稀疏数组:term_doc
它的大小是622256x715的Float64。它非常稀疏:
- 在它的 ~444,913,040 个单元格中,通常只有大约 22,215 个单元格是非空的。
- 在 622256 行中,只有 4,699 行被占用
- 虽然 715 列都被占用了。
我想执行的运算符可以描述为返回该矩阵的行规范化和列规范化版本。
我写的朴素非稀疏版本是:
function doUnsparseWay()
gc() #Force Garbage collect before I start (and periodically during). This uses alot of memory
term_doc
N = term_doc./sum(term_doc,1)
println("N done")
gc()
P = term_doc./sum(term_doc,2)
println("P done")
gc()
N[isnan(N)] = 0.0
P[isnan(P)] = 0.0
N,P,term_doc
end
运行这个:
> @time N,P,term_doc= doUnsparseWay()
outputs:
N done
P done
elapsed time: 30.97332475 seconds (14466 MB allocated, 5.15% gc time in 13 pauses with 3 full sweep)
这很简单。
它会消耗内存,如果垃圾收集没有在正确的时间发生(因此我手动调用它),它将崩溃。
但它相当快
我想让它在稀疏矩阵上工作。
为了不磨灭我的记忆,
并且因为从逻辑上讲它是一个更快的操作——需要操作的单元更少。
我遵循了 this post and from the performance page of the docs 的建议。
function doSparseWay()
term_doc::SparseMatrixCSC{Float64,Int64}
N= spzeros(size(term_doc)...)
N::SparseMatrixCSC{Float64,Int64}
for (doc,total_terms::Float64) in enumerate(sum(term_doc,1))
if total_terms == 0
continue
end
@fastmath @inbounds N[:,doc] = term_doc[:,doc]./total_terms
end
println("N done")
P = spzeros(size(term_doc)...)'
P::SparseMatrixCSC{Float64,Int64}
gfs = sum(term_doc,2)[:]
gfs::Array{Float64,1}
nterms = size(term_doc,1)
nterms::Int64
term_doc = term_doc'
@inbounds @simd for term in 1:nterms
@fastmath @inbounds P[:,term] = term_doc[:,term]/gfs[term]
end
println("P done")
P=P'
N[isnan(N)] = 0.0
P[isnan(P)] = 0.0
N,P,term_doc
end
它永远不会完成。
最多输出"N Done",
但从不输出 "P Done"。
我已经离开它 运行 几个小时了。
- 如何优化它才能在合理的时间内完成?
- 或者如果这不可能,请解释原因。
首先,您要使 term_doc
成为一个全局变量,这对性能来说是个大问题。将其作为参数传递,doSparseWay(term_doc::SparseMatrixCSC)
。 (函数开头的类型注释没有任何用处。)
您想使用一种方法 similar to the answer by walnuss:
function doSparseWay(term_doc::SparseMatrixCSC)
I, J, V = findnz(term_doc)
normI = sum(term_doc, 1)
normJ = sum(term_doc, 2)
NV = similar(V)
PV = similar(V)
for idx = 1:length(V)
NV[idx] = V[idx]/normI[J[idx]]
PV[idx] = V[idx]/normJ[I[idx]]
end
m, n = size(term_doc)
sparse(I, J, NV, m, n), sparse(I, J, PV, m, n), term_doc
end
这是一个通用模式:当您想针对稀疏矩阵优化某些内容时,提取 I
、J
、V
并在 [=15= 上执行所有计算].
我有一个稀疏数组:term_doc
它的大小是622256x715的Float64。它非常稀疏:
- 在它的 ~444,913,040 个单元格中,通常只有大约 22,215 个单元格是非空的。
- 在 622256 行中,只有 4,699 行被占用
- 虽然 715 列都被占用了。
我想执行的运算符可以描述为返回该矩阵的行规范化和列规范化版本。
我写的朴素非稀疏版本是:
function doUnsparseWay()
gc() #Force Garbage collect before I start (and periodically during). This uses alot of memory
term_doc
N = term_doc./sum(term_doc,1)
println("N done")
gc()
P = term_doc./sum(term_doc,2)
println("P done")
gc()
N[isnan(N)] = 0.0
P[isnan(P)] = 0.0
N,P,term_doc
end
运行这个:
> @time N,P,term_doc= doUnsparseWay()
outputs:
N done
P done
elapsed time: 30.97332475 seconds (14466 MB allocated, 5.15% gc time in 13 pauses with 3 full sweep)
这很简单。 它会消耗内存,如果垃圾收集没有在正确的时间发生(因此我手动调用它),它将崩溃。 但它相当快
我想让它在稀疏矩阵上工作。 为了不磨灭我的记忆, 并且因为从逻辑上讲它是一个更快的操作——需要操作的单元更少。
我遵循了 this post and from the performance page of the docs 的建议。
function doSparseWay()
term_doc::SparseMatrixCSC{Float64,Int64}
N= spzeros(size(term_doc)...)
N::SparseMatrixCSC{Float64,Int64}
for (doc,total_terms::Float64) in enumerate(sum(term_doc,1))
if total_terms == 0
continue
end
@fastmath @inbounds N[:,doc] = term_doc[:,doc]./total_terms
end
println("N done")
P = spzeros(size(term_doc)...)'
P::SparseMatrixCSC{Float64,Int64}
gfs = sum(term_doc,2)[:]
gfs::Array{Float64,1}
nterms = size(term_doc,1)
nterms::Int64
term_doc = term_doc'
@inbounds @simd for term in 1:nterms
@fastmath @inbounds P[:,term] = term_doc[:,term]/gfs[term]
end
println("P done")
P=P'
N[isnan(N)] = 0.0
P[isnan(P)] = 0.0
N,P,term_doc
end
它永远不会完成。 最多输出"N Done", 但从不输出 "P Done"。 我已经离开它 运行 几个小时了。
- 如何优化它才能在合理的时间内完成?
- 或者如果这不可能,请解释原因。
首先,您要使 term_doc
成为一个全局变量,这对性能来说是个大问题。将其作为参数传递,doSparseWay(term_doc::SparseMatrixCSC)
。 (函数开头的类型注释没有任何用处。)
您想使用一种方法 similar to the answer by walnuss:
function doSparseWay(term_doc::SparseMatrixCSC)
I, J, V = findnz(term_doc)
normI = sum(term_doc, 1)
normJ = sum(term_doc, 2)
NV = similar(V)
PV = similar(V)
for idx = 1:length(V)
NV[idx] = V[idx]/normI[J[idx]]
PV[idx] = V[idx]/normJ[I[idx]]
end
m, n = size(term_doc)
sparse(I, J, NV, m, n), sparse(I, J, PV, m, n), term_doc
end
这是一个通用模式:当您想针对稀疏矩阵优化某些内容时,提取 I
、J
、V
并在 [=15= 上执行所有计算].