使用python

时间:2017-04-23 13:51:04

标签: python algorithm numpy

我有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秒钟来处理它的函数。所以,基本上我的问题减少到了

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 map:

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个不同的批次,并为循环的不同部分运行相同的程序,并在谷歌云中的八核VM上运行八个单独的python实例。任何人都可以建议使用PyCuda进行map-reduce或者使用GPU的帮助可能是一个不错的选择吗?

1 个答案:

答案 0 :(得分:2)

multiprocessing.Pool解决方案是一个很好的解决方案,因为它使用了所有核心。所以它应该比使用普通旧地图快大约N倍,其中N是你拥有的核心数量。

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

我建议使用map,而不是普通imap_unordered(在处理完所有内容之前阻塞)。这是一个迭代器,它将在可用时立即开始返回结果,因此您的父进程可以开始进一步处理(如果有的话)。如果排序很重要,您可能希望返回一个元组(数字,数组)来标识结果。

您的函数返回一个2048个值的numpy数组,我假设它是numpy.float64使用标准映射函数将使用IPC将结果传输回父进程。在4核机器上,将导致4个IPC传输2048 * 8 = 16384字节,因此65536字节/秒。这听起来不太糟糕。但我不知道IPC(涉及酸洗和队列)将产生多少开销。

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

对于100000张图像和4个核心,每张图像大约需要一秒钟,您的程序的运行时间大约为8小时。

您最重要的优化任务是研究减少getvector函数的运行时间。例如,如果将图像的大小减半,它会运行吗? 假设运行时线性缩放到像素数量,那应该将运行时间缩短到0.25秒。