通过python有效地通过巨大的循环进行迭代



我有100000张图像,我需要获取每个图像的向量

imageVectors = []
for i in range(100000):
    fileName = "Images/" + str(i) + '.jpg'
    imageVectors.append(getvector(fileName).reshape((1,2048)))
cPickle.dump( imageVectors, open( 'imageVectors.pkl', "w+b" ), cPickle.HIGHEST_PROTOCOL ) 

getVector是一次拍摄1张图像并花费大约1秒钟来处理IT的函数。因此,基本上我的问题减少到

for i in range(100000):
    A = callFunction(i)  //a complex function that takes 1 sec for each call

我已经尝试过的东西是:(在此处只给出pseduo代码(

1(使用numpy vectorizer:

def callFunction1(i):
   return callFunction2(i)
vfunc = np.vectorize(callFunction1)
imageVectors = vfunc(list(range(100000))

2(使用Python地图:

def callFunction1(i):
    return callFunction2(i)
imageVectors = map(callFunction1, list(range(100000))

3(使用Python多处理:

import multiprocessing
try:
   cpus = multiprocessing.cpu_count()
except NotImplementedError:
   cpus = 4   # arbitrary default
pool = multiprocessing.Pool(processes=cpus)
result = pool.map(callFunction, xrange(100000000))

4(以不同的方式使用多处理:

from multiprocessing import Process, Queue
q = Queue()
N = 100000000
p1 = Process(target=callFunction, args=(N/4,q))
p1.start()
p2 = Process(target=callFunction, args=(N/4,q))
p2.start()
p3 = Process(target=callFunction, args=(N/4,q))
p3.start()
p4 = Process(target=callFunction, args=(N/4,q))
p4.start()
results = []
for i in range(4):
    results.append(q.get(True))
p1.join()
p2.join()
p3.join()
p4.join()

上述所有方法都花了很长时间。是否有比这更有效的其他方式,这样我也许我可以同时或以其他任何方式同时循环许多元素。


时间主要是由getvector函数本身花费的。在工作中,我将数据分为8个不同的批次,并在循环的不同部分运行相同的程序,并在Google Cloud的八核VM上运行八个单独的Python实例。谁能建议使用pycuda的地图减少或帮助GPU的帮助?

multiprocessing.Pool解决方案是一个很好的解决方案,从某种意义上说,它使用了所有内核。因此,它应该比使用普通旧地图快大的n倍,其中n是您拥有的核心数。

顺便说一句,您可以跳过确定内核的数量。默认情况下 multiprocessing.Pool使用与您的CPU一样多的过程。

我建议使用 imap_unordered而不是普通的 map(它阻止了直到处理所有内容(。这是一个迭代器,一旦获得结果,它将开始返回结果,以便您的父进程可以开始进一步处理。如果订购很重要,您可能需要返回元组(数字,数组(以识别结果。

您的函数返回2048个值的数组,我认为使用标准映射功能的numpy.float64将使用IPC将结果传递回父进程。在4核机器上,将导致4个IPC传输为2048*8 = 16384字节,因此65536字节/秒。听起来还不错。但是我不知道IPC的开销(涉及腌制和队列(会产生多少。

如果开销很大,您可能需要创建一个共享存储区域来存储结果。您将需要大约1.5 GIB来存储100000个2048 8字节浮子的结果。这是相当多的内存,但对于当前机器来说不是不切实际的。

对于100000张图像和4个核心以及每个图像的时间约为一秒钟,您的程序的运行时间将在8小时内。

优化的最重要任务是考虑减少getvector功能的运行时。例如,如果将图像的大小减少一半,它也会运行吗?假设运行时将线性缩放到像素的数量,这应该将运行时切为0.25s。

最新更新