我使用Python + Scipy来对齐化对角线上的随机条目的稀疏矩阵;特别是,我需要在光谱中间的特征值。我写的代码已经好几个月了,但是现在我正在查看更大的矩阵并且遇到了#Memory;" MemoryError" s。令我困惑/让我疯狂的是,错误只会在构建随机矩阵并对其进行对角化的几次迭代(即9次)之后出现,但我看不出我的代码存储任何东西的方式从一次迭代到下一次迭代在内存中是额外的,因此无法看到我的代码在第9次迭代期间如何失败而不是第1次。
以下是详细信息(如果我已经遗漏了任何内容,我会提前道歉,我在本网站发布新内容):
我构建的每个矩阵是16000x16000,具有15x16000非零条目。当我查看4000x4000大小的矩阵时,一切都运行良好。我的大部分代码都是
#Initialization
#...
for i in range(dim):
for n in range(N):
digit = (i % 2**(n+1)) / 2**n
index = (i % 2**n) + ((digit + 1) % 2)*(2**n) + (i / 2**(n+1))*(2**(n+1))
row[dim + N*i + n] = index
col[dim + N*i + n] = i
dat[dim + N*i + n] = -G
e_list = open(e_list_name + "_%03dk_%010ds" % (num_states, int(start_time)), "w")
e_log = open(e_log_name + "_%03dk_%010ds" % (num_states, int(start_time)), "w")
for t in range(num_itr): #Begin iterations
dat[0:dim] = math.sqrt(N/2.0)*np.random.randn(dim) #Get new diagonal elements
H = sparse.csr_matrix((dat, (row, col))) #Construct new matrix
vals = sparse.linalg.eigsh(H, k = num_states + 2, sigma = target_energy, which = 'LM', return_eigenvectors = False) #Get new eigenvalues
vals = np.sort(vals)
vals.tofile(e_list)
e_log.write("Iter %d complete\n" % (t+1))
e_list.flush()
e_log.flush()
e_list.close()
e_log.close()
我已经将num_itr设置为100.在第9次通过num_itr循环期间(如8行已写入e_log所示),程序崩溃并显示错误消息
无法扩展MemType 0:jcol 7438
追踪(最近一次呼叫最后一次):
File "/usr/lusers/clb37/QREM_Energy_Gatherer.py", line 55, in <module> vals = sparse.linalg.eigsh(H, k = num_states + 2, sigma = target_energy, which = 'LM', return_eigenvectors = False) File "/usr/lusers/clb37/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/sparse/linalg/eigen/arpack/arpack.py", line 1524, in eigsh symmetric=True, tol=tol) File "/usr/lusers/clb37/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/sparse/linalg/eigen/arpack/arpack.py", line 1030, in get_OPinv_matvec return SpLuInv(A.tocsc()).matvec File "/usr/lusers/clb37/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/sparse/linalg/eigen/arpack/arpack.py", line 898, in __init__ self.M_lu = splu(M) File "/usr/lusers/clb37/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/scipy/sparse/linalg/dsolve/linsolve.py", line 242, in splu ilu=False, options=_options)
的MemoryError
果然,每次在我的机器上运行时,程序都会在第9次通过循环期间失败,当我尝试在具有更多内存的机器上运行此代码时,程序会在崩溃之前通过更多迭代,所以它看起来计算机真的耗尽了内存。如果那就完好无损那么好,但我无法理解的是为什么程序在第一次迭代期间不会崩溃。我没有看到num_itr循环的8行中的任何一点,在这些行中,某些内容被写入内存,而不会在下一次迭代中被覆盖。我已经使用Heapy的heap()函数来查看我的内存使用情况,它只打印出&#34;总大小= 11715240字节&#34;在每次传球中。
我觉得那里有一些基本的东西,我不知道怎么回事这里,或者是我写的一些我不知道要去寻找的错误或一些关于记忆如何的细节被处理。任何人都可以向我解释为什么这个代码在第9次通过num_itr循环但不是第1次时失败了吗?
答案 0 :(得分:4)
好的,这似乎可以在Scipy 0.14.0上重现。
显然可以通过添加
来解决这个问题import gc; gc.collect()
在循环内部强制Pythons循环垃圾收集器运行。
问题出现在scipy.sparse.eigh
内的某处,有一个循环参考循环,其中包含:
class Foo(object):
pass
a = Foo()
b = Foo()
a.spam = b
b.spam = a
del a, b # <- but a, b still refer to each other and are not dead
原则上这仍然是完全可以的:虽然Python的引用计数不会检测到这样的循环垃圾,但是会定期运行集合来收集这些对象。但是,如果每个对象在内存中都非常大(例如,大Numpy数组),则定期运行过于频繁,并且在下一次循环垃圾收集运行完成之前就会耗尽内存。
因此,当您知道要收集大量垃圾时,解决方法是强制GC运行。 一个更好的解决方法是更改scipy.sparse.eigh,以便首先不会生成这样的循环垃圾。