Python:多处理池内存泄漏

时间:2013-11-15 01:47:21

标签: python numpy multiprocessing

我有一系列时间课程是8640 x 400 编辑:第0个暗淡是位置,第1个暗淡是该位置的时间过程。

我需要计算每个点的交叉谱相干性,这些都可以独立完成。

因此我开始尝试使用多处理模块:

from multiprocessing import Pool
import numpy as np    
from matplotlib.mlab import cohere
from itertools import product    
from scipy.signal import detrend

# this is a module of classes that I wrote myself
from MyTools import SignalProcessingTools as sig

def compute_coherence(args):
    rowA = roi[args[0], :]
    rowB = roi[args[1], :]
    coh, _ =  cohere(rowA, rowB, NFFT=64, Fs=sample_rate, noverlap=32, sides='onesided')
    #TODO: use the freq return and only average the freq in particular range...

    return  np.sqrt(coh.mean())

### start here ###
# I detrend the data for linear features
roi = detrend(data=roi, axis=1, type='linear')
# and normalize it to std. Very simple method, uses x.std() in a loop 
roi = sig.normalize_std(roi)

roi = np.random.rand(8640, 386)# in reality this is a load from disk
length = roi.shape[0]
indices = np.arange(length)
# this gives me all combinations of indices i and j
# since I want the cross spectral coherence of the array
args = product(indices, indices) # note, args is an interator obj

pool = Pool(processes=20)
coh = pool.map(compute_coherence,  args)

这个程序使用超过20 GB,我没有看到明显的内存泄漏。 关于该主题有很多谷歌回报,但我真的不明白如何 追踪这一点。

编辑:大错... roi阵列不是8640x8640x400它只有8640 x 400 对不起......:|漫长的一天

也许我错过了一个错误......?

提前感谢您的想法...

[更新] 因此,在修改代码并玩弄评论部分之后, 我相信我已将内存问题缩小到cohere()方法。 运行代码并返回零数组工作正常。

这是更新版本:

from os import path, getenv
import numpy as np
from matplotlib import mlab
import scipy.signal as sig
from multiprocessing import Pool
from itertools import product
import Tools
from scipy.signal import detrend

from pympler import tracker
tr = tracker.SummaryTracker()
import gc


def call_back():
    gc.collect()

def call_compute(arg):
    start, stop = arg
    ind_pairs = indice_combos[start:stop]
    coh = np.zeros(len(ind_pairs), dtype=float)

    #tr.print_diff()

    for i, ind in enumerate(ind_pairs):
        row1 = ind[0]
        row2 = ind[1]

        mag, _ = mlab.cohere(roi[row1,:], roi[row2,:], NFFT=128, Fs=sample_rate, noverlap=64, sides='onesided')

        coh[i] = np.sqrt(mag.mean()) 
        #tr.print_diff()

    #tr.print_diff()    
    return coh

### start Here ###
imagetools = Tools.ImageTools()
sigtools = Tools.SignalProcess()

HOME = Tools.HOME
sample_rate = 1 / 1.65

mask_obj = imagetools.load_image(path.join(HOME, 'python_conn/Rat/Inputs/rat_gm_rs.nii.gz'))
mask_data = mask_obj.get_data()

rs_obj = imagetools.load_image(path.join(HOME, 'python_conn/Rat/Inputs/rs_4D.nii.gz'))
rs_data = rs_obj.get_data()

# logical index
ind = mask_data > 0 
roi = rs_data[ind, :]

# normalize with STD
roi = sigtools.normalize_nd(roi)
# detrend linear
roi = detrend(data=roi, axis=1, type='linear')
# filter
roi = sigtools.butter_bandpass(lowcut=0.002, highcut=0.1, sample_rate=sample_rate, data=roi, order=5)

# drop frames for steady state and filter noise
roi = roi[:, 16:] 

################
### testing ####
roi = roi[0:5000,:]
################
################

length = roi.shape[0]    

# setup up row and col vector of indices
indices = np.arange(length)
temp = product(indices, indices)# all possible combinations iterator
indice_combos = [ i for i in temp ] # make iterator into a list

num_cores = 10
chunk_size = len(indice_combos) / num_cores  # divdide the combo list for each core
grps = np.arange(0, len(indice_combos)+chunk_size, chunk_size)

#make the final list of args, where each item is a pair of stop and stop
args = [ [grps[i], grps[i+1]-1]  for i in range(0, len(grps)-1)]
args[-1][1] = args[-1][1] + 1

# deallocate some memory
grps = None

# Multi core
pool = Pool(num_cores)
coh = np.hstack(pool.map(call_compute, args, call_back()))

coh = coh.ravel()

out_path = path.join(HOME, 'python_conn/Rat/coh.npy')
np.save(out_path, coh)

map = np.zeros_like(mask_data)
map[ind] = coh.sum(0)

out_path = path.join(HOME, 'python_conn/Rat/coherence_map.nii.gz')
imagetools.save_new_image(map, out_path, rs_obj.coordmap)

[更新]

这不是cohere的错...我的坏......我希望开发人员不会看到这个......:| 我经常更改代码。所以我担心这个帖子不再有效了。

有什么帮助:

仅使用迭代器

发送进程多于一对的i,j来处理

有很多开销,但内存实际上并没有那么多。 我觉得我有点滥用了......但是当你在学习新东西时,总是很难准确到达......我很惊讶没有人讨厌我。我明天会发布自己的解决方案。

1 个答案:

答案 0 :(得分:0)

数字不加起来。正如@sashkello已经指出的那样,你有一个包含29,859,840,000个元素的数组。即使它们每个只占用1个字节,你也会使用30 GB,而不是20个。那么你没有透露什么呢? ; - )

后来:现在8640 * 400 = 3,456,000 - 所以“7500万元素”来自哪里? 7500万将接近8640 * 8640。

无论如何,要研究两件事:

  1. 如果不调用多处理机器,只需在主程序中执行一个块,它会消耗多少内存?

  2. 交叉产品(args)有多大?由于你的数组有多大似乎仍然存在混淆,所以无法从这里猜测。

  3. 另一件事我们需要知道:池中有多少个进程?普通Pool()表示“使用所有可用的”处理器,但无法猜测您拥有多少处理器。当然,每个人都会使用内存。