我正在尝试优化numpy中的方法,在图像的许多位置上评估高斯函数。现在,我正在围绕每个高斯的中心位置计算布尔掩码,并使用它们对数据数组进行索引,以节省计算时间。对于少量数据点,与通过np.argwhere
计算索引相比,布尔索引极大地加速了脚本。
不幸的是,似乎布尔索引似乎导致内存泄漏。以下示例使我的RAM达到最大值。我该如何预防?这是一个小问题,还是我做错了什么?我认为这可能是因为布尔索引创建了数据的副本,就像有人在this answer中写的那样。不再需要复制后,是否不应该释放内存?有没有办法手动释放内存?
import numpy as np import matplotlib.pyplot as plt class Image(): def __init__(self, nx, ny, px): x = np.linspace(0, nx * px, nx) y = np.linspace(0, ny * px, ny) self.x, self.y = np.meshgrid(x, y) self.data = np.zeros((nx, ny), dtype=np.uint8) self.nx = nx # number of pixels self.ny = ny self.px = px # pixel size [mm] def gaussian(self, x, y, x0, y0, amplitude=None, sigma=0.01): """ 2d gaussian function Parameters: x, y: coordinates of evaluation position x0, y0: center coordinates of Gaussian amplitude: amplitude of the Gaussian sigma: width of Gaussian """ if amplitude is None: amplitude = np.iinfo(self.data.dtype).max result = amplitude * np.exp( -((x - x0)**2 + (y - y0)**2) / (2 * sigma ** 2)) return result.astype(self.data.dtype) def mask_from_pos(self, x0, y0, radius_px): """ returns a square mask around the position (x0, y0) """ masks = np.zeros((x0.size, self.ny, self.nx), dtype=bool) i_center_x = (x0 // self.px).astype(int) i_center_y = (y0 // self.px).astype(int) for ix, iy, mask in zip(i_center_x, i_center_y, masks): y_start = max(0, min(iy - radius_px, self.ny - 1)) y_end = max(0, min(iy + radius_px + 1, self.ny)) x_start = max(0, min(ix - radius_px, self.nx - 1)) x_end = max(0, min((ix + radius_px + 1), self.nx)) mask[y_start: y_end, x_start: x_end] = True return masks def add_gaussians(self, posx, posy, radius_px=9): masks = self.mask_from_pos(posx, posy, radius_px) for x0, y0, mask in zip(posx, posy, masks): self.data[mask] += self.gaussian( self.x[mask], self.y[mask], x0, y0).astype(self.data.dtype) if __name__ == '__main__': image = Image(2000, 2000, 0.005) xy_max = 2000 * 0.005 x0 = np.random.rand(3000) * xy_max y0 = np.random.rand(3000) * xy_max image.add_gaussians(x0, y0) plt.figure(dpi=300, figsize=(8, 8)) plt.imshow(image.data, cmap=plt.get_cmap('gray'), extent=[0, xy_max, 0, xy_max])
我已经尝试调试此函数,并且python对象似乎都没有增长,所以我认为这是numpy中的问题,但我不确定100%。任何帮助,我们将不胜感激!预先感谢。
我发现了一种解决方案,它可以提供相同的结果,但不会占用大量内存。简单地用mask-generator代替mask-array的计算就可以了:
def mask_from_pos_gen(self, x0, y0, radius_px): """ yields a square mask around the position (x0, y0) """ i_center_x = (x0 // self.px).astype(int) i_center_y = (y0 // self.px).astype(int) for ix, iy in zip(i_center_x, i_center_y): mask = np.zeros(self.data.shape, dtype=bool) y_start = max(0, min(iy - radius_px, self.ny - 1)) y_end = max(0, min(iy + radius_px + 1, self.ny)) x_start = max(0, min(ix - radius_px, self.nx - 1)) x_end = max(0, min((ix + radius_px + 1), self.nx)) mask[y_start: y_end, x_start: x_end] = True yield mask
然后可以使用与mask_from_pos之前完全相同的方法来使用此方法,但是以这种方式释放内存。如果有人遇到相同的问题,请把它留在这里,希望一些麻木的大师能够解释这种现象。
我正在尝试优化numpy中的方法,在图像的许多位置上评估高斯函数。现在,我正在围绕每个高斯的中心位置计算布尔蒙版,并使用...
事实证明,布尔型索引不是解决此问题的最佳解决方案。与布尔型蒙版相比,使用numpy slice可以大大提高速度。