我正在实施EM-GMM的特殊情况。
X是形状为[1000000,900]的数据矩阵,是一个numpy mmap对象
Q是形状为[900,900]的精度矩阵,是一个ndarray
我还使用Multiprocessing库,使用相同的数据矩阵(X)在40个内核上同时遍历200个Q矩阵。
它适用于较小的尺寸,例如[1mil,196],[1mil,400],
但是当我尝试在进程的某个时刻运行[1mil,900]时会抛出异常:
OSError:[Errno 12]无法分配内存
我想这个问题是因为我有2个大计算,可能分配了大矩阵。
作为电子步骤的一部分,我需要计算:
np.sum(X.dot(Q) * X, axis=1)
作为M步的一部分,我需要计算(W是[1mil,1]权重向量):
(X.T * W).dot(X)
将来,我将不得不在更大尺寸(形状[2mil,2500]甚至[2mil,10k]的数据)上运行此EM-GMM
我该怎么做才能使计算效率更高?
编辑:
我注意到工作程序初始化使用的是pickle,因此X矩阵变成了ndarray,工作程序不共享它(这意味着X矩阵对所有工作程序都是重复的,并填满了我的RAM)>
我有一个解决方法的想法,如果已解决,将会更新。
但是,如果有人对如何处理有个好主意,我将不胜感激。
答案 0 :(得分:1)
原来,有2个不相关的问题导致RAM过度使用。
首先,为多处理工作者腌制时,已从磁盘完全读取memmap对象。
重复的数据为每个工作人员分配了6.7GB的额外RAM。
为了解决这个问题,我创建了一个共享的RawArray
并将数据加载到其中,并且在每个使用了np.frombuffer
的工作程序上。
第二,X.dot(Q)
和(X.T * W)
导致numpy分配了另一个X形矩阵,这是另一个6.7GB RAM
我通过以下线程创建了答案的变体:https://stackoverflow.com/a/21096605/5572523
由于我的矩阵是瘦高的,所以将它们切成薄片:
def _block_slices(dim_size, block_size):
count = 0
while True:
yield slice(count, count + block_size, 1)
count += block_size
if count >= dim_size:
raise StopIteration
现在我可以遍历数据批次(在处理weight = 0时也增加了一些额外的加速)
我设置了max_elements = 2 ** 27
,因为我使用的是float64,因此这将产生1GB的矩阵(如果我没记错的话)。
所以(X.T * W).dot(X)
变成了:
def weighted_outer_prod(X, W):
n, d = X.shape
max_rows = max(1, int(max_elements / d))
sigma = np.zeros([d, d])
for mm in _block_slices(n, max_rows):
sigma += batch_weighted_outer_prod(X[mm, :], W[mm])
return sigma
def batch_weighted_outer_prod(batch, W):
nz = W > 0
buff = np.empty(batch[nz].shape)
np.multiply(batch[nz], W[nz, np.newaxis], out=buff)
sigma = buff.T.dot(batch[nz])
del(buff)
return sigma
然后np.sum(X.dot(Q) * X, axis=1)
变成:(不用管函数名)
def calc_l_k(X, Q):
max_rows = max(1, int(max_elements / d))
l_k = np.empty(n)
for mm in _block_slices(n, max_rows):
l_k[mm] = batch_l_k(X[mm, :], Q)
return l_k
def batch_l_k(batch, Q):
buff = np.empty(batch.shape)
np.dot(batch, Q, out=buff)
np.multiply(buff, batch, out=buff)
l_k = -0.5 * np.sum(buff, axis=1)
del(buff)
return l_k
现在它以X形状[1mil,900]运行,我希望它仍可以在更大的尺寸上使用。