【问题标题】:Memory usage in NumpyNumpy 中的内存使用情况
【发布时间】:2014-07-31 11:38:28
【问题描述】:

我在 Mac 上编写了一个程序,但由于 RAM 不足 (MemoryError) 而无法在我的 Raspberry Pi 上运行。

程序的本质是一些图像处理,它将一个 640x480 的 uint8 与一个两倍大小的 complex128 进行卷积。

我认为内存使用情况是: 初始图像:

640 x 480 x 8 bits / 8 bits / 1024 bytes = 300 kb

复矩阵:

640 x 480 x 2^2 x 128 bits / 8 bits / 1024^2 = 18.75 MB

让我们假设它必须在内存中保存这些不同矩阵的两到三个副本 - 应该是一个相当小的占用空间 - 可能

  1. 我的分析正确吗?
  2. 关于如何在 Python 中更好地管理内存的任何提示?

更新:

如下所示,我做了一些内存分析,确实是 fftconvolve 使 RAM 使用率达到峰值,如下:

Line # Mem 使用增量行内容

65   86.121 MiB    0.000 MiB     @profile
66                               def iriscode(self):
67   86.121 MiB    0.000 MiB       img = self.polar
68
69   86.379 MiB    0.258 MiB       pupil_curve = find_max(img[0:40])
70   86.379 MiB    0.000 MiB       blur = cv2.GaussianBlur(self.polar, (9, 9), 0)
71   76.137 MiB  -10.242 MiB       iris_fft = fit_iris_fft(radial_diff(blur[50:,:])) + 50
72
73   76.160 MiB    0.023 MiB       img = warp(img, iris_fft, pupil_curve)
74                                 # cv2.imshow("mask",np.uint8(ma.getmaskarray(img))*255)
75
76                                 global GABOR_FILTER
77  262.898 MiB  186.738 MiB       output = signal.fftconvolve(GABOR_FILTER, img, mode="valid")

不过,这种增长的幅度让我感到惊讶。任何想法我可以做些什么来减少它?我尝试使用complex64 而不是complex128,但内存使用量是一样的。

【问题讨论】:

  • 您的计算看起来正确,但您似乎做了很多假设而不是测试。你是如何进行卷积的?你在用scipy.signal.convolve2d吗?我不知道 numpy 2d 卷积函数。
  • scipy.signal.fftconvolve
  • 这是一个非常广泛的问题。显示一些代码,最好是一些分析; memory_profiler 专为 NumPy 繁重的程序而设计。
  • 感谢 larsmans- 我已经根据您的建议更新了问题

标签: python python-2.7 numpy scipy


【解决方案1】:

要了解是怎么回事,可以看fftconvolvehere的源码。

傅立叶变换卷积背后的整个想法是,时域中的卷积只是频域中的元素乘法。但是因为您使用的是 FFT,它会将您的函数视为周期性的,即好像卷积核缠绕在边缘上。所以为了得到正确的结果,数组用零填充到一个共同的形状,在你的情况下,它将是(1280+640-1, 960+480-1) = (1919, 1439)。为了加快计算速度,这个形状会进一步扩展到下一个更大的数字,它只有 2、3 或 5 作为主要因子,在您的情况下,这会导致 (1920, 1440) 形状。对于一个复杂的数组,它占用了1920 * 1440 * 16 / 2**20 = 42 MiB

您将有 2 个这样的数组,一个用于每个输入,另外两个在计算它们各自的 FFT 时再加上一个,当您将它们相乘时再加上一个,再加上另一个在您计算它们的逆 FFT 时得到你的卷积。

目前尚不清楚所有这些数组是否会同时共存,因为其中一些可能会在此过程中被垃圾收集,但在某些时候至少会有 3 个,可能是 4 个。添加 FFT 计算的一些开销,并且你已经解释了你的186 MiB

您可能想尝试非 FFT 卷积,它不需要所有的填充。您也可以尝试稍微优化scipy.signal.fftconvolve 中的代码。将this else block 替换为:

else:
    ret = fftn(in1, fshape)
    ret *= fftn(in2, fshape)
    ret = ifftn(ret)[fslice].copy()

应该去掉一个中间副本,给你 40 额外的 MiB,这可能对你的情况有用。

【讨论】:

    【解决方案2】:

    我会按顺序尝试以下操作:

    1. 使用常规卷积而不是 fftconvolve。
    2. 使用 scipy.weave 并执行您自己的卷积操作(从而避免 numpy 内存管理)。

    【讨论】:

    • Weave 已弃用且未维护。新代码应该改用 Cython。
    猜你喜欢
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 2011-07-23
    • 2012-11-10
    • 2014-07-11
    • 2015-04-11
    • 1970-01-01
    相关资源
    最近更新 更多