0

私は、離散データの確率密度を構築する単純なタスクで、労力の面でjoblibを使用しています。要するに、私は、パフォーマンスの向上が2つの並列プロセスで飽和し、より多くのものを持つことで何も得られないという事実に困惑しています。私はこのプログラムを最適化するための他の可能なアプローチについても興味があります。私は最初に問題の詳細を少し詳しく説明します。joblibとパラレル化する - パフォーマンスの飽和と一般的な考慮事項

Xの形状(n_samples, n_features)と分類ラベルyの2進配列を考えます。実験の目的のために、これを行うであろう:

import numpy as np 
X = np.random.randint(0,2,size=[n_samples,n_features]) 
y = np.random.randint(0,10,size=[n_samples,]) 

機能joint_probability_binaryは、入力として特徴アレイX(個々の特徴)のカラムとラベルベクトルyを取り、それらの結合分布を出力します。何もない。

def joint_probability_binary(x, y): 

    labels = list(set(y)) 
    joint = np.zeros([len(labels), 2]) 

    for i in xrange(y.shape[0]): 
     joint[y[i], x[i]] += 1 

    return joint/float(y.shape[0]) 

今、私はXのすべての機能(すべての列)にjoint_probability_binaryを適用したいと思います。私の理解では、この処理(十分に大きな値のn_samplesが与えられている)は、マルチプロセッシングの並列処理には十分に粗い粒度になります。私は、このタスクを実行するための連続的かつ並列的な関数を書いた。

from joblib import Parallel, delayed 

def joints_sequential(X, y): 
    return [joint_probability_binary(X[:,i],y) for i in range(X.shape[1])] 

def joints_parallel(X, y, n_jobs): 
    return Parallel(n_jobs=n_jobs, verbose=0)(
     delayed(joint_probability_binary)(X = X[:,i],y = y) 
     for i in range(X.shape[1])) 

here提示として、次のように私は、グイド・ヴァンロッサム自身によって書かれたタイミング機能を適応:

import time 

def timing(f, n, **kwargs): 
    r = range(n) 
    t1 = time.clock() 
    for i in r: 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
     f(**kwargs); 
    t2 = time.clock() 
    return round(t2 - t1, 3) 

最後に、性能の変化やジョブの数への依存度を研究するために、私は

0を取得し、 n_samples = 20000n_features = 20ため

tseq = timing(joints_sequential,10, X=X,y=y) 
print('Sequential list comprehension - Finished in %s sec' %tseq) 

for nj in range(1,9): 
    tpar = timing(joints_parallel,10, X=X, y=y, n_jobs=nj) 
    print('Parallel execution - %s jobs - Finished in %s sec' %(nj,tpar)) 

を実行します

Sequential list comprehension - Finished in 60.778 sec 
Parallel execution - 1 jobs - Finished in 61.975 sec 
Parallel execution - 2 jobs - Finished in 6.446 sec 
Parallel execution - 3 jobs - Finished in 7.516 sec 
Parallel execution - 4 jobs - Finished in 8.275 sec 
Parallel execution - 5 jobs - Finished in 8.953 sec 
Parallel execution - 6 jobs - Finished in 9.962 sec 
Parallel execution - 7 jobs - Finished in 10.382 sec 
Parallel execution - 8 jobs - Finished in 11.321 sec 

1.

この結果は、かなりのビットは(4つのコアと2 GHzのインテルCore i7プロセッサーとOS X上でこれを実行している)、このタスクを並列から得られたことがありますことを確認しました。 しかし、私が最も目立つものは、性能がすでにn_jobs = 2で飽和していることです。各タスクのサイズを考えると、これはJoblibのオーバーヘッドだけで発生する可能性があると考えるのは難しいですが、やはり私の直感は限られています。私はより大きなアレイ、n_samples = 200000n_features = 40で実験を繰り返したが、これは同じ動作につながる: シーケンシャルリスト内包 - 完成1230.172秒で

Parallel execution - 1 jobs - Finished in 1198.981 sec 
Parallel execution - 2 jobs - Finished in 94.624 sec 
Parallel execution - 3 jobs - Finished in 95.1 sec 
... 

誰もがこのようなケースかもしれない理由についての直感を持っています(与えられました私の全体的なアプローチは十分に合理的です)

2.

最後には、全体最適化の観点から、どのようなこの種のプログラムのパフォーマンスを改善するための他の方法でしょうか?私は、ジョイント確率を計算する関数のCython実装を記述することで得られることはたくさんあると思っていますが、私はそれについての経験はありません。

答えて

0

私の経験によると、これは通常、コアが過剰加入しているためです。私のデスクトップのi7-3770では、次のようになっています。

Sequential list comprehension - Finished in 25.734 sec 
Parallel execution - 1 jobs - Finished in 25.532 sec 
Parallel execution - 2 jobs - Finished in 4.302 sec 
Parallel execution - 3 jobs - Finished in 4.178 sec 
Parallel execution - 4 jobs - Finished in 4.521 sec 

システムについて詳しく知りませんが、私はあまり手助けできません。しかし、しばしば、ラップトッププロセッサは、ハイパースレッディングまたは他の技術により、物理コアよりも多くの論理コアを有することになる。これはハイパースレッディングではうまくいくものではありません。 (たとえば、ここでIOによってブロックされるものは何もないので、追加のスレッドを使用することでパフォーマンスが向上することはありません)。

また、1つまたは2つのコアが頻繁に使用されている場合はクロックレートを自動的に増加させるCPUを持つこともできますが、すべてが頻繁に使用されると低下します。これにより、2つのコアのパフォーマンスを向上させることができます。

パフォーマンスをさらに向上させるには、pyfunc()関数を使用してnumpy ufuncとしてjoint_probability_binary()関数を記述し、Cバージョンを生成することをお勧めします。 https://docs.scipy.org/doc/numpy/reference/ufuncs.html

Numbaも助けてくれましたが、私は一度も使ったことがありませんhttp://numba.pydata.org/numba-doc/0.35.0/index.html

関連する問題