我有一个程序,我已经在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
让我们假设它必须在内存中保存这些不同矩阵的两个或三个副本 - 应该是一个相当小的足迹 - 也许< 100 MB。不幸的是,它似乎耗尽了可用的全部330MB(Python运行时也必须加载到这个空间中)。
更新
正如下面所建议的那样,我做了一些内存分析,确实是fft包含RAM使用的峰值,如下所示:
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
,但内存使用情况相同。
答案 0 :(得分:4)
要了解正在发生的事情,您可以查看fftconvolve
here的源代码。
傅里叶变换卷积背后的整个思想是时域中的卷积只是频域中的元素乘法。但是因为你正在使用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,这可能适用于你的情况。
答案 1 :(得分:1)
我按顺序尝试以下事项: