16

コンテクスト

私はしばしば次のような状況に陥りました。

  • 処理する必要のある画像ファイル名のリストがあります
  • たとえばscipy.misc.imreadを使用して各画像を順番に読み取ります
  • 次に、各画像に対して何らかの処理を行い、結果を返します
  • 結果を画像ファイル名に沿ってシェルフに保存します

問題は、単に画像を読み取るだけで無視できないほどの時間がかかり、画像処理に匹敵するか、それよりも長くかかることです。

質問

ですから、理想的には画像nを処理しながら画像n+1を読み取ることができると考えていました。または、自動的に決定された最適な方法で複数の画像を一度に処理して読み取る方がさらに優れていますか?

マルチプロセッシング、スレッド、ツイスト、geventなどについて読んだことがありますが、どれを使用し、このアイデアを実装する方法がわかりません。誰かがこの種の問題の解決策を持っていますか?

最小限の例

# generate a list of images
scipy.misc.imsave("lena.png", scipy.misc.lena())
files = ['lena.png'] * 100

# a simple image processing task
def process_image(im, threshold=128):
    label, n = scipy.ndimage.label(im > threshold)
    return n

# my current main loop
for f in files:
    im = scipy.misc.imread(f)
    print process_image(im)
4

2 に答える 2

14

マルチプロセッシングパッケージは非常に使いやすいです。ガイドについては、キューの例を参照してください。生産者/消費者モデルに従います。1つ(または複数)のプロデューサープロセスが画像を読み取り、1つ(または複数)のコンシューマープロセスが画像処理を実行する必要があります。

あなたの例は次のようになります。

from multiprocessing import Process, Queue
import scipy

def process_images(q):
    while not q.empty():
        im = q.get()
        # Do stuff with item from queue

def read_images(q, files):
    for f in files:
        q.put(scipy.misc.imread(f))

if __name__ == '__main__':
    q = Queue()

    producer = Process(target=read_images, args=(q, files))
    producer.start()
    consumer = Process(target=process_images, args=(q, ))
    consumer.start()

これは、元のアイデアよりも少し簡単です。この例では、プロデューサーは、単にコンシューマーの1つ先を行くのではなく、できるだけ早くキューに追加します。プロデューサーがはるかに進んでいて、キューを保持するのに十分なメモリがない場合、これは問題になる可能性があります。問題が発生した場合は、マルチプロセッシングドキュメントをさらに深く理解できますが、開始するにはこれで十分です。

于 2012-09-18T20:04:57.683 に答える
14

フィリップの答えは良いですが、2つ以上のコアシステムを最大限に活用することはほとんどない2つのプロセス(1つの読み取り、1つのコンピューティング)しか作成しません。multiprocessing.Poolこれは、読み取りと計算の両方の側面を実行するプロセスを作成する(具体的には、そのマップメソッド)を使用する別の方法ですが、使用可能なすべてのコアをより有効に活用する必要があります(コアよりも多くのファイルがあると想定)。

#!/usr/bin/env python

import multiprocessing
import scipy
import scipy.misc
import scipy.ndimage

class Processor:
    def __init__(self,threshold):
        self._threshold=threshold

    def __call__(self,filename):
        im = scipy.misc.imread(filename)
        label,n = scipy.ndimage.label(im > self._threshold)
        return n

def main():
    scipy.misc.imsave("lena.png", scipy.misc.lena())
    files = ['lena.png'] * 100

    proc=Processor(128)
    pool=multiprocessing.Pool()
    results=pool.map(proc,files)

    print results

if __name__ == "__main__":
    main()

画像の数を500に増やし、のprocesses=N引数を使用すると、次のPoolようになります。

Processes   Runtime
   1         6.2s
   2         3.2s
   4         1.8s
   8         1.5s

私のクアッドコアハイパースレッドi7で。

より現実的なユースケース(つまり、実際の異なるイメージ)に入ると、プロセスはイメージデータがストレージからロードされるのを待つのにより多くの時間を費やす可能性があります(私のテストでは、キャッシュされたディスクから実質的に瞬時にロードされます)。計算と負荷のオーバーラップを増やすために、コアよりも多くのプロセスを明示的に作成する価値があります。ただし、現実的な負荷とハードウェアでの独自のスケーラビリティテストだけが、実際に何が最適かを判断できます。

于 2012-09-18T21:08:53.613 に答える