【发布时间】:2019-03-13 22:19:39
【问题描述】:
我正在实现一个特殊的 EM-GMM。
X 是形状为 [1000000, 900] 的数据矩阵,是一个 numpy mmap 对象
Q是一个形状为[900, 900]的精度矩阵,是一个ndarray
我还使用 Multiprocessing 库在 40 个内核上同时处理超过 200 个 Q 矩阵,使用相同的数据矩阵 (X)。
它适用于较小的尺寸,例如 [1mil, 196], [1mil, 400],
但是当我尝试在进程的某个时刻运行 [1mil, 900] 时会引发异常:
OSError: [Errno 12] 无法分配内存
我猜这个问题是因为我有 2 个大计算,这可能分配了大矩阵。
作为 E 步骤的一部分,我需要计算:np.sum(X.dot(Q) * X, axis=1)
作为 M 步的一部分,我需要计算(W 是 [1mil, 1] 权重向量):(X.T * W).dot(X)
将来我必须对更大尺寸的数据(形状 [2mil, 2500] 甚至 [2mil, 10k])运行这个 EM-GMM
我该怎么做才能使这些计算更节省内存?
编辑:
我注意到worker初始化使用pickle,所以X-matrix变成了ndarray并且worker不共享它(这意味着X-matrix被所有worker复制并填满了我的RAM)
我知道如何解决它,如果解决了会更新。
但如果有人知道如何处理它,我将不胜感激。
【问题讨论】:
-
np.einsum('ij, jk, ik -> i', X, Q, X)和np.einsum('ji, ij, jk -> ik', X, W, X)有帮助吗?也许在np.einsum中有一个optimize = True参数?不是memmap的专家,但这应该会阻止一些中间矩阵的形成(希望如此)。 -
* 乘法是逐元素乘法,而不是矩阵点积,所以我认为 einsum 不会有帮助
-
np.einsum('ij, ij -> ij', A, B)是元素乘法。这只是einsum允许线性代数一步完成。 (即ij, jk, ik -> ik, ik -> ik -> i和ji, ij, jk -> ij, jk -> ik)。这就是爱因斯坦求和符号的好处——您可以在一个框架内进行最常见的线性代数运算。 -
哦,我不知道。我会试试的,谢谢:)
-
您是否仅限于 numpy-memmap 或者您还可以使用更复杂的存储系统,例如 HDF5? Numpy memmap 仅在从磁盘连续读取数据时(沿 C 有序数组中的最后一个轴)提供良好的性能。您的所有计算都可以分成几部分,基本上即使在您的上一个示例中 [2mil, 10k],小于 2GB 的 RAM 也应该足够了(甚至更少,但磁盘 IO 将远高于高)。您在工人之间共享 X 矩阵,而不是将其复制给每个工人,对吗?您的 RAM 限制是多少?