Contenu connexe Similaire à Juliaで並列計算 (20) Plus de Shintaro Fukushima Plus de Shintaro Fukushima (20) Juliaで並列計算6. JuliaPowered by Parallel Computing
Juliaの特徴の一つに、 標準で並列計算をサポートしている点がある。
5
Designedforparallelismanddistributed computation 20. Juliaにおける並列計算の流れ
19
マスタープロセス
ワーカープロセス
Step.1
ワーカープロセスの
生成
Step.2
ワーカープロセスへの
データ転送・処理の命令
Step.3
ワーカープロセスでの
処理の実行
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照
処理 結果
処理 結果
処理 結果
処理 結果
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照
参照 21. Juliaにおける並列計算の流れ
20
マスタープロセス
ワーカープロセス
Step.1
ワーカープロセスの
生成
Step.2
ワーカープロセスへの
データ転送・処理の命令
Step.3
ワーカープロセスでの
処理の実行
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照 22. Juliaにおける並列計算の流れ
21
マスタープロセス
ワーカープロセス
Step.1
ワーカープロセスの
生成
Step.2
ワーカープロセスへの
データ転送・処理の命令
Step.3
ワーカープロセスでの
処理の実行
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照
Step.3は、ワーカープロセスが
マスタープロセスと独立して実行 23. Juliaにおける並列計算の流れ
22
マスタープロセス
ワーカープロセス
Step.1
ワーカープロセスの
生成
Step.2
ワーカープロセスへの
データ転送・処理の命令
Step.3
ワーカープロセスでの
処理の実行
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照
以下では、
Step.1, 2, 4について説明 26. Step.1 ワーカープロセスの生成
マスタープロセスの起動後における生成
25
julia> nprocs()
1
julia> nworkers()
1
julia> # 4つのワーカープロセスの生成
julia> addprocs(4)
4-element Array{Any,1}:
2
3
4
5
julia> nprocs()
5
julia> nworkers()
4
addprocs関数で生成するワーカープロセスの個数を指定 27. Step.2 ワーカープロセスへの データ転送・処理の命令
処理の命令(リモートコール)
26
remotecall(nproc, function, args)
あるプロセッサから他のプロセッサに引数を渡して関数を実行させ るための呼び出し。
返り値はリモートリファレンス(remote reference)というもの。 28. Step.2 ワーカープロセスへの データ転送・処理の命令
処理の命令(リモートコール)
27
$ julia -p 2
julia> # 乱数種の設定
julia> srand(123)
julia> r = remotecall(2, rand, 2, 2)
RemoteRef(2,1,4)
実行例)ワーカープロセス2で、2×2の一様乱数の行列を生成
remotecall(nproc, function, args)
あるプロセッサから他のプロセッサに引数を渡して関数を実行させ るための呼び出し。
返り値はリモートリファレンス(remote reference)というもの。 29. Step.2 ワーカープロセスへの データ転送・処理の命令
データの転送
28
julia> A = rand(1000,1000)
julia> Bref= @spawn A^2
...
julia> fetch(Bref)
julia> Bref= @spawn rand(1000,1000)^2
...
julia> fetch(Bref)
マスタープロセスでデータを生成し、ワーカープロセスにデータを転送
ワーカープロセスでデータを生成
通信
オーバーヘッド
大
小
データ転送するしないは、
ケースバイケース 31. Step.4 マスタープロセスから ワーカープロセスの処理結果の参照
リモートリファレンスからの値の取得
30
$ julia -p 2
julia> # 乱数種の設定
julia> srand(123)
julia> r = remotecall(2, rand, 2, 2)
RemoteRef(2,1,4)
julia> fetch(r)
2x2 Array{Float64,2}:
0.353081 0.369369
0.235385 0.183653
実行例)ワーカープロセス2で作成した行列の値を取得
fetch(expr) 32. ここまでのまとめ Juliaにおける並列計算の流れ
31
$ julia –p 4
$ julia -p 2
julia> # 乱数種の設定
julia> srand(123)
julia> r = remotecall(2, rand, 2, 2)
RemoteRef(2,1,4)
julia> fetch(r)
2x2 Array{Float64,2}:
0.353081 0.369369
0.235385 0.183653
マスタープロセス起動時
julia>addprocs(4)
マスタープロセス起動後
Step.1
ワーカープロセスの
生成
Step.2
ワーカープロセスへの
データ転送・処理の命令
Step.3
ワーカープロセスでの
処理の実行
Step.4
マスタープロセスから
ワーカープロセスの
処理結果の参照 35. @spawnatマクロ (remotecallの代替)
評価する式とワーカープロセスを指定して実行
34
julia> s = @spawnat2 1 + fetch(r) RemoteRef(2,1,6)
julia> fetch(s)
2x2Array{Float64,2}:
1.34133 1.0674
1.76699 1.06808
実行例)ワーカープロセス2で1+fetch(r)を計算
@spawnat(p, expr)
第2引数で指定した式を第1引数で指定したワーカープロセスで実行 37. @spawnマクロ
引数で指定した式をいずれかのワーカープロセスで評価
36
julia> r = @spawn rand(2,2) RemoteRef(3,1,10)
julia> s = @spawn 1 .+ fetch(r) RemoteRef(3,1,11)
julia> fetch(s)
2x2 Array{Float64,2}:
1.03 1.16674
1.99027 1.89547
実行例)いずれかのワーカープロセスで生成した乱数に1を足して
フェッチする
@spawn(expr) 38. ワーカープロセスでの 変数・関数の評価
マスタープロセスで定義した関数は、 そのままではワーカープロセスで認識できない。
37
julia>function rand2(dims...)
return 2*rand(dims...)
end rand2
(generic function with 1 method)
julia> rand2(2,2)
2x2 Array{Float64,2}:
1.5369 1.34792
1.88103 0.790906
julia> @spawn rand2(2,2)
RemoteRef(2,1,13)
julia> exception on 2: ERROR: function rand2 not defined on process 2 in error at error.jl:21 in anonymous at serialize.jl:397 in anonymous at multi.jl:1279 in anonymous at multi.jl:848 in run_work_thunkat multi.jl:621 in run_work_thunkat multi.jl:630 in anonymous at task.jl:6 39. ワーカープロセスでの 変数・関数の評価
すべてのワーカープロセスで変数や関数を認識させるために @everywhereマクロを前につける。
38
julia> @everywhere function rand2(dims...)
2 * rand(dims...)
end
julia> @spawn rand2(2,2)
RemoteRef(2,1,20)
julia> fetch(r)
2x2 Array{Float64,2}:
1.92811 0.535094
1.40141 0.0465075 43. 並列処理とループ計算
①@parallel for構文
42
julia> nheads= @parallel (+) for
i=1:200000000 int(randbool())
end
99999830
実行例)200000000回、論理値を発生させて、合計値を算出 44. 並列処理とループ計算
②pmap関数
43
julia> M = {rand(1000,1000) for i=1:10}
julia> pmap(svd, M)
実行例)1000×1000の行列を10個生成して、 それぞれを特異値分解 45. リモートリファレンスの 動的なスケジューリング
pmap関数の実装
45
function pmap(f, lst)
np = nprocs() # determine the number of processes available
n = length(lst)
results = cell(n)
i= 1
# function to produce the next work item from the queue.
# in this case it's just an index.
nextidx() = (idx=i; i+=1; idx)
@sync begin
for p=1:np
if p != myid() || np == 1
@asyncbegin
while true
idx= nextidx()
if idx> n
break
end
results[idx] = remotecall_fetch(p, f, lst[idx])
end
end
end
end
end
results
end 46. 共有メモリの配列
UNIX/Linux環境で、実験的に共有メモリの配列が提供 されている。
46
julia> addprocs(3)
3-element Array{Any,1}:
2
3
4
julia> S = SharedArray(Int, (3,4), init= S -> S[localindexes(S)] = myid())
3x4 SharedArray{Int64,2}:
1 2 3 4
1 2 3 4
1 2 3 4
julia> S[3,2] = 7
7
julia> S
3x4 SharedArray{Int64,2}:
1 2 3 4
1 2 3 4
1 7 3 4 52. k平均法の並列計算
並列計算と逐次計算の実行時間を比較。
52
$ julia-p 4 exec_kmeans.jl
elapsed time: 259.546022396 seconds (1251034300 bytes allocated, 0.01% gctime)
exec_km.jl
並列計算(4ワーカープロセス)
$ juliaexec_kmeans.jl
elapsed time: 742.803273255 seconds (3499799548 bytes allocated, 0.33% gctime)
逐次計算
260秒
743秒
約2.9倍の高速化 54. ランダムフォレストの並列計算
ソースコードは、木の生成が並列化可能な実装。
54
function build_forest{T<:FloatingPoint, U<:Real}(labels::Vector{T},
features::Matrix{U}, nsubfeatures::Integer,
ntrees::Integer, maxlabels=0.5, partialsampling=0.7)
partialsampling= partialsampling> 1.0 ? 1.0 : partialsampling
Nlabels= length(labels)
Nsamples= int(partialsampling* Nlabels)
forest = @parallel(vcat) for iin [1:ntrees]
inds= rand(1:Nlabels, Nsamples)
build_tree(labels[inds], features[inds,:], maxlabels,
nsubfeatures)
end
return Ensemble([forest])
end
DecisionTree.jl
404
405
406
407
408
409
410
411
412
413 55. ランダムフォレストの並列計算
ランダムフォレストは以下のように実行する。
55
using RDatasets
using DecisionTree
# Pimaインディアンデータセット(妊娠回数、血圧などと糖尿病の罹患有無)
Pima_tr= dataset("MASS", "Pima.tr")
# 説明変数
features = array(Pima_tr[:, 1:7])
# 目的変数
labels = array(Pima_tr[:, 8]);
# ランダムフォレストの実行(特徴量数: 4個、生成する木の個数: 2000個、サンプルの選択割合: 70%)
@time model = build_forest(labels, features, 4, 2000, 0.7);
exec_rf.jl 56. ランダムフォレストの並列計算
並列計算と逐次計算の計算時間を比較。
56
$ julia-p 4 exec_rf.jl
elapsed time: 8.847219443 seconds (104840140 bytes allocated, 1.83% gctime)
exec_rf.jl
並列計算(4ワーカープロセス)
$ juliaexec_rf.jl
elapsed time: 12.908068361seconds (1479356232 bytes allocated, 11.24% gctime)
逐次計算
8.85秒
12.91秒
約1.5倍の高速化 58. 処理速度のまとめ
並列計算
(4ワーカー
プロセス)
逐次計算
並列計算による
高速化
k平均法
(5000×5000の 行列、クラスター数 10)
260秒
743秒
約2.9倍
ランダムフォレスト
(サンプル数、
特徴量の個数7)
8.85秒
12.91秒
約1.5倍
58
注) 並列計算と逐次計算で乱数を一致させておらず、
計算時間も複数回試行して比較すべきなので、
あくまでご参考 62. 参考文献
公式ドキュメント
M.M.Maza, Parallel Ccomputing with Julia 公式ドキュメントの内容がコンパクトにまとまっていて分かり やすい。
base/muil.jl
なんだかんだで今はソースを直接読むのが、 理解向上の一番の近道?
62