Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Juliaで並列計算

11,597 views

Published on

Published in: Technology

Juliaで並列計算

  1. 1. Juliaで並列計算 2014年9月27日 第2回JuliaTokyo @sfchaos
  2. 2. 自己紹介 TwitterID:@sfchaos お仕事:データマイニング, セマンティックWeb, オントロジー, etc. 使用言語:R/C++/Perl/Python/etc. 1
  3. 3. アジェンダ 1.並列計算とJulia 2.並列化できる処理の例 3.Juliaでの並列計算の流れ 4.並列計算文法編 5.並列計算実践編 6.まとめ 2
  4. 4. 1. 並列計算とJulia 3
  5. 5. 並列計算とは 最近は、一般的なパソコンでも複数のコアを搭載すること が当たり前になってきた。 並列計算= 計算機、CPU、コアなどの計算リソースを 有効に活用して、並列的に処理を同時に実行すること 4 タスク1 タスク2 タスク3 タスク4 タスク1 タスク2 タスク3 タスク4 並列計算のイメージ
  6. 6. JuliaPowered by Parallel Computing Juliaの特徴の一つに、 標準で並列計算をサポートしている点がある。 5 Designedforparallelismanddistributed computation
  7. 7. JuliaPowered by Parallel Computing 速いといわれるJuliaで並列計算すれば、最強?? 6 Powered By Parallel Computing gc問題が残っている・・・?
  8. 8. 2. 並列化できる処理の例 7
  9. 9. k平均法 結果が初期値に依存するので、複数回の試行が望ましい。 複数回の試行は互いに独立しており、並列化可能。 8 ①各データにランダムに割り当 てたクラスターのラベルを用いて、 各クラスターのデータの中心を クラスターの中心とする。 ②各データから最も近いクラスター中心 のクラスターを新たなラベルとする。 ③各クラスターの データの中心を 新たなクラスター中心とする。 クラスター1 クラスター3 クラスター 中心 クラスター2 クラスター1 クラスター3 クラスター2 クラスター中心が収束するまで繰り返す
  10. 10. ブートストラップ法 ブートストラップ標本の作成や統計量計算は並列化可能。 9
  11. 11. ランダムフォレスト クラス分類・回帰を実行する機械学習の代表的な手法。 訓練データに対してサンプルのブートストラップと説明変数 のサンプリングを行って複数の決定木を構築。 テストデータに対して、各決定木の予測結果の多数決によ り予測を実行。 10
  12. 12. その他の並列化可能な処理 モンテカルロシミュレーション ハイパーパラメータ探索・クロスバリデーション (機械学習の予測モデル構築・評価) etc. 11
  13. 13. 3. Juliaでの並列計算の流れ 12
  14. 14. Juliaの並列計算のコンセプト Juliaの並列計算は、メッセージパッシングで実装。 ※通信方式はTCP/IPのソケット?(base/multi.jl参照) 通常のメッセージパッシングは、 プロセス間でデータや命令などを相互にやりとりする。 13 プロセス1 プロセス2 プロセス3 プロセス4 通常のメッセージパッシング データ、命令を プロセス間でやり取り
  15. 15. Juliaの並列計算のコンセプト Juliaのメッセージパッシングの実装は、 あるプロセスから他のプロセスへの一方通行。 14 マスタープロセス ワーカープロセス データ転送、処理の命令 あるプロセスから 他プロセスへの 一方通行
  16. 16. Juliaの並列計算のコンセプト そのため、ユーザは片方のプロセスだけ管理すればO.K. 15 マスタープロセス ワーカープロセス データ転送、処理の命令 あるプロセスから 他プロセスへの 一方通行 ユーザは片方のプロセスを 管理すればO.K.
  17. 17. Juliaにおける並列計算の流れ 16 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの生成 Step.1 ワーカープロセスの 生成
  18. 18. Juliaにおける並列計算の流れ 17 マスタープロセス ワーカープロセス Step.2 ワーカープロセスへの データ転送・処理の命令 Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令
  19. 19. Juliaにおける並列計算の流れ 18 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令 Step.3 ワーカープロセスでの 処理の実行 Step.3 ワーカープロセスでの 処理の実行
  20. 20. Juliaにおける並列計算の流れ 19 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令 Step.3 ワーカープロセスでの 処理の実行 Step.4 マスタープロセスから ワーカープロセスの 処理結果の参照 処理 結果 処理 結果 処理 結果 処理 結果 Step.4 マスタープロセスから ワーカープロセスの 処理結果の参照 参照
  21. 21. Juliaにおける並列計算の流れ 20 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令 Step.3 ワーカープロセスでの 処理の実行 Step.4 マスタープロセスから ワーカープロセスの 処理結果の参照
  22. 22. Juliaにおける並列計算の流れ 21 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令 Step.3 ワーカープロセスでの 処理の実行 Step.4 マスタープロセスから ワーカープロセスの 処理結果の参照 Step.3は、ワーカープロセスが マスタープロセスと独立して実行
  23. 23. Juliaにおける並列計算の流れ 22 マスタープロセス ワーカープロセス Step.1 ワーカープロセスの 生成 Step.2 ワーカープロセスへの データ転送・処理の命令 Step.3 ワーカープロセスでの 処理の実行 Step.4 マスタープロセスから ワーカープロセスの 処理結果の参照 以下では、 Step.1, 2, 4について説明
  24. 24. Step.1 ワーカープロセスの生成 ワーカープロセスを生成するタイミングは、 ①マスタープロセスの起動時 ②マスタープロセスの起動後 23 マスタープロセス Step.1 ワーカープロセスの生成
  25. 25. Step.1 ワーカープロセスの生成 マスタープロセスの起動時における生成 24 $ julia –p 4 julia> # ワーカープロセス数の確認 julia> nworkers() 4 julia> # マスターとワーカーの合計プロセス数の確認 julia> nprocs() 5 起動時にpオプションにワーカープロセス数を指定 ワーカープロセス数の確認
  26. 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. 27. Step.2 ワーカープロセスへの データ転送・処理の命令 処理の命令(リモートコール) 26 remotecall(nproc, function, args) あるプロセッサから他のプロセッサに引数を渡して関数を実行させ るための呼び出し。 返り値はリモートリファレンス(remote reference)というもの。
  28. 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. 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) マスタープロセスでデータを生成し、ワーカープロセスにデータを転送 ワーカープロセスでデータを生成 通信 オーバーヘッド 大 小 データ転送するしないは、 ケースバイケース
  30. 30. Step.4 マスタープロセスから ワーカープロセスの処理結果の参照 リモートリファレンスからの値の取得 29 fetch(expr)
  31. 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. 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 マスタープロセスから ワーカープロセスの 処理結果の参照
  33. 33. 4. Juliaで並列計算文法編 32
  34. 34. @spawnatマクロ 評価する式とワーカープロセスを指定して実行 33 @spawnat(p, expr) 第2引数で指定した式を第1引数で指定したワーカープロセスで実行
  35. 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引数で指定したワーカープロセスで実行
  36. 36. @spawnマクロ 引数で指定した式をいずれかのワーカープロセスで評価 35 @spawn(expr)
  37. 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. 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. 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
  40. 40. ワーカープロセスでの 変数・関数の評価 同様に、ソースコードやパッケージをすべてのワーカープロセ スに認識させるために、include関数やusing関数の前に @everywhereを付加する。 39 julia> @everywhere include("defs.jl") julia> @everywhere using Clustering ソースコードについては、require関数でもO.K. julia> require("defs.jl")
  41. 41. ワーカープロセスでの 変数・関数の評価 Julia起動時に、すべてのワーカープロセスにJuliaのソース コードの記述内容を認識させるためには、-Lオプションでファ イル名を指定する。 40 $ julia-p <n> -L file1.jl -L file2.jl driver.jl
  42. 42. 並列処理とループ計算 プロセス間でデータの転送が不要な場合は、 以下の2つの方法により並列計算の簡潔な記述が可能。 ①@parallel for構文 ②pmap関数 41
  43. 43. 並列処理とループ計算 ①@parallel for構文 42 julia> nheads= @parallel (+) for i=1:200000000 int(randbool()) end 99999830 実行例)200000000回、論理値を発生させて、合計値を算出
  44. 44. 並列処理とループ計算 ②pmap関数 43 julia> M = {rand(1000,1000) for i=1:10} julia> pmap(svd, M) 実行例)1000×1000の行列を10個生成して、 それぞれを特異値分解
  45. 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. 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
  47. 47. その他の話題 クラスタマネージャ マルチマシンのクラスタ上でのも並列分散を実行可能。 分散配列(distributed arrays) 並列計算用の配列。 •dzeros •dones •drand •drandn •dfill 47
  48. 48. 5. Juliaで並列計算実践編 48
  49. 49. 並列計算する処理 今回は、k平均法とランダムフォレストの並列計算を実行。 49 k平均法 (非階層的クラスタリング) ランダムフォレスト
  50. 50. k平均法の並列計算 k平均法は、Clusteringパッケージを用いて実行する。 50 julia> # Clusteringパッケージのインストール julia> Pkg.add(“Clustering”) juliastats/Clustering.jl
  51. 51. k平均法の並列計算 成分が一様乱数からなる5000×5000の行列を作成。 クラスタ数を10個に設定して、k平均法を実行。 51 using Clustering srand(123) # 成分が一様乱数からなる5000×5000の行列の作成 x = rand(5000, 5000) # クラスタ数 k = 10 # k平均法の実行 @time @parallel result = [kmeans(x, k; maxiter=50) for i=1:200] exec_km.jl
  52. 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倍の高速化
  53. 53. ランダムフォレストの並列計算 DecisionTreeパッケージを用いてランダムフォレストを実行。 53 参考資料: 第1回JuliaTokyo @gepuroJulia0.3でランダムフォレスト
  54. 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. ランダムフォレストの並列計算 ランダムフォレストは以下のように実行する。 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. ランダムフォレストの並列計算 並列計算と逐次計算の計算時間を比較。 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倍の高速化
  57. 57. ランダムフォレストの並列計算 4つのワーカープロセスを使った割には効果が薄い? Pimaインディアンデータセットでは、特徴量がたったの7個。 今回は、その中から4個をサンプリングしている。 特徴量が多いデータを使えば、 もう少し並列計算の効果が上がるはず。 どなたか、Rdatasetsパッケージに機械学習系の データセットを充実させてください! 57
  58. 58. 処理速度のまとめ 並列計算 (4ワーカー プロセス) 逐次計算 並列計算による 高速化 k平均法 (5000×5000の 行列、クラスター数 10) 260秒 743秒 約2.9倍 ランダムフォレスト (サンプル数、 特徴量の個数7) 8.85秒 12.91秒 約1.5倍 58 注) 並列計算と逐次計算で乱数を一致させておらず、 計算時間も複数回試行して比較すべきなので、 あくまでご参考
  59. 59. 6. まとめ 59
  60. 60. Juliaにおける並列計算 マスタープロセスからワーカープロセスへの一方通行メッセー ジパッシング(通信方式はソケット?) マスタープロセスからワーカープロセスにリモートコールで命令。 ワーカープロセスの処理結果(リモートリファレンス形式)は、 マスタープロセスがフェッチして参照。 60
  61. 61. Juliaにおける並列計算 今後の調査事項・課題 並列乱数生成(L’ecuyerの方法など) http://pseudotrue.com/2014/07/22/parallel- random-number-generation-in-julia/ できてる?できてない? フォーク等の他のワーカープロセス生成・通信方式での並列計算 は実行できるか? ロードバランシングのようなことはできる? メモリの管理(GC等) 61
  62. 62. 参考文献 公式ドキュメント M.M.Maza, Parallel Ccomputing with Julia 公式ドキュメントの内容がコンパクトにまとまっていて分かり やすい。 base/muil.jl なんだかんだで今はソースを直接読むのが、 理解向上の一番の近道? 62

×