//-------------------------------------------------------------------------------- //少ない知識ですが、恩返しと思いページを立ち上げています。 //加筆修正、大歓迎です。 markovchainmontecarlo(2015/09) //-------------------------------------------------------------------------------- &color(red){&size(30){並列計算(snowfall)};};~ ~ マルチコアが主流となってきているので、並列計算のパッケージである「snowfall」を紹介します。~ なお、特に断りが無い場合はSocketクラスターを使用しています。~ ~ &color(red){&size(40){現在編集中&br;調査中の内容があるため&br;信用に値しない内容も多分に含まれています。};};~ ---- &color(red){&size(20){目次};};~ #contents ---- *並列計算で計算速度は向上するか? [#ze3e7311] **並列計算のイメージ [#l002ea0d] &ref(並列概念.jpg);~ 並列化できる割合によって、理論上の限界が変わってきます。~ ([[アムダールの法則:https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A0%E3%83%80%E3%83%BC%E3%83%AB%E3%81%AE%E6%B3%95%E5%89%87]]を参照)~ ~ なお、計算負荷の不均一性やデータ入出力負荷が理由で、&size(20){&color(red){''かえって遅くなる''};};場合もあります。~ ~ 並列計算は計算速度向上の一つの手段にすぎません。~ 計算速度向上の手段はいくつもありますので、適切な方法を用いてください。~ [[CRAN Task View: High-Performance and Parallel Computing with R:https://cran.r-project.org/web/views/HighPerformanceComputing.html]] **どのような計算が並列化できるか [#rb82070b] 基本的にapply familyは全て並列化可能です。~ 詳細な条件としては、「計算の順序を入れ替えても計算結果が同じである」事になります。~ ~ apply familyも内部ではforを使用しているので、並列化できるfor・並列化できないforが存在します。 -並列化できないforの例 --ケース1:依存関係がある。~ 以下の例は、ひとつ前の数値に対して、関数hogeを適用するため並列化が出来ません。~ 順序よくx[1] → x[2] → x[3] → x[4] → x[5] と実行しないと正しい計算ができません。 for(i in 1:5){ x[i] <- hoge(x[i - 1]) } これは、マルコフ連鎖にも言える事であり、マルコフ連鎖の生成スピードを上げようとするならばRcppを使用するなど並列計算ではない方法を用いなくてはなりません。~ --ケース2:グローバル変数など、現在の環境以外の数値を変更する~ 以下の例は、Sys.sleepの時間によって休止する時間が不明であり、そのあとiをグローバル変数であるresultに代入するため並列化が出来ません。~ for(i in 1:5){ Sys.sleep(runif(1)) result <<- i } もし仮に、iが2の時の休止時間が一番長いとすると、これを並列計算してしまうとグローバル変数であるresultは2になってしまいます。 と、不安になるような事を書きましたが、上記のケースはどちらもsnowfallでは実現できないため、snowfallで並列計算を行う場合は気にしなくて大丈夫です。~ *各種パッケージ比較 [#t808b6d7] |BGCOLOR(silver):CENTER:package|BGCOLOR(silver):CENTER:利点|BGCOLOR(silver):CENTER:欠点|h |parallel|・デフォルトパッケージとしてインストールされる。&br;・誰でも使用できる?|・下記「snow」「multicore」のコピーみたいなものなので、少々使いにくい。&br;・snowで使用できたCPU使用状況を調査する「snow.time」が使用できない。| |multicore|・parallelパッケージの基礎となった優秀なパッケージ&br;(だと思う。ウィンドウズ環境しかないため使用していません。)|・うゐんどうずで動かない。| |snow|・様々な関数が用意されている。&br;・parallelパッケージの基礎となった優秀なパッケージ&br;・CPUの使用状況を調査する「snow.time」が使用できる。|・常にクラスターの指定をしなくてはならない。| |snowfall|・クラスターの指定をする必要がない。&br;・関数の引数が(ほとんど)一緒。&br;・並列計算と通常処理を同じ関数でこなせる。|・「snow」に依存するため、バージョンアップで「snow」についていっているか確認が必要?| *とりあえず動かす [#jf6ffc48] **主な流れ [#gc1e1bd0] +ライブラリーの読み込み > library(snowfall) 要求されたパッケージ snow をロード中です +sfInitでクラスターを準備する。 > sfInit(parallel = TRUE, cpus = 4) R Version: R version 3.2.2 (2015-08-14) snowfall 1.84-6 initialized (using snow 0.3-13): parallel execution on 4 CPUs. +(必要があれば)ワーカーに変数やオブジェクトを渡す。 > a <- 1:10 > sfExport("a") +snowfall 関数を使用して並列計算を行う。 > sfSapply(11:20, sum, a) [1] 66 67 68 69 70 71 72 73 74 75 +クラスターを止める > sfStop() Stopping cluster **cpu数 [#w237cd57] sfInitではcpusを指定します。~ ~ ご自身のPCのCPU数を指定しますが、以下のコードも取得できます。~ なお、ハイパースレッディングを備えたCPUではスレッド数が取得されます。~ > #parallelのdetectCoresを使用して取得します。 > library(parallel) > detectCores() [1] 4 スレッド数を指定するか、CPU数を指定するかはどちらでもいいと思います。~ ちなみに私[markovchainmontecarlo]はスレッド数を指定しています。 **並列関数は何を使用するのか[#t0cc6daa] とりあえず以下に従って、関数を書き換えてください。~ 引数は同じですので、いつも通りに計算できます。~ apply → sfApply lapply → sfLapply sapply → sfSapply ためしにsfSapplyを実行。約3倍の速度! > library(snowfall) 要求されたパッケージ snow をロード中です > sfInit(parallel = TRUE, cpus = 4) R Version: R version 3.2.2 (2015-08-14) snowfall 1.84-6 initialized (using snow 0.3-13): parallel execution on 4 CPUs. > set.seed(123) > x <- sample(1:20)/4 > system.time(sapply(x, Sys.sleep)) ユーザ システム 経過 0.0 0.0 52.5 > system.time(sfSapply(x, Sys.sleep)) ユーザ システム 経過 0.01 0.00 15.50 > sfStop() Stopping cluster > *並列処理問題BIG3 [#n64a44e8] 勝手にBIG3を決めてますが、意外とあたっていると思います。~ 以降、この「並列処理問題BIG3」に気を付けながら紹介していきます。 **並列化コーディング問題 [#sb5c037a] いくら並列化できるといっても、通常処理から並列化するのに関数をいちいち書き換えたりするのはとても面倒。~ 一般的なイメージとして~ +まずは、通常処理を小規模なデータで意図とする結果が得られるかを確認 +小規模なデータはそのままに、並列化のコードに書き換えてエラーと格闘 +小規模なデータで並列化をして、通常処理と同じ結果が得られることを確認 +晴れて、大規模並列化へ これ結構面倒ですよね。~ **計算負荷の不均一性問題 [#pf5d043e] 計算負荷が均一の場合は、あまり気にせず並列化を行えます。~ 24時間かかっていた処理を4コアで実行すると6時間で終わります。~ でも仮に、一つの計算がやたらと時間かかる場合で他のコアが待機状態になるコードを書いていたら~ 実際は18時間位かかってしまうかもしれません。~ 待機状態を以下に少なくして、PCやサーバー、ワークステーションの力を引き出してあげるかが重要です。~ **データ入出力負荷問題 [#qcc24116] 並列計算では、並列に計算します。(禅問答みたいですが・・・)~ 並列に計算させるなら、それぞれの計算先にデータを送らないといけません。~ 大容量のデータ転送が必要な場合、データの通信時間はバカになりません。~ 計算自体の時間は早くなっても、それ以上にデータ入出力負荷がかかっては元も子もありません。~ *▲▲▲▲▲ここまでOK▲▲▲▲▲ [#la0684bb] *snow.time でクラスターの使用状況を探る [#k4c6f72c] 関数snow.timeを使用することによって、各クラスターの使用状況を確認できます。~ > st.hoge <- snow.time(hoge) > st.hoge elapsed send receive node 1 node 2 node 3 node 4 21.75 0.00 0.02 13.77 12.24 14.50 12.00 snow.timeで得られた結果は、plotで詳細に状況を確認できます。 > plot(st.hoge) &ref(./fig00_snowtime.jpg,50%); -緑の四角:クラスター使用中~ -青の実線:結果をマスターに返すために待機中~ -赤の実線:マスターとクラスター間でデータの受け渡し~ -黒の破線:クラスター待機中~ *未実装関数の作成 [#xf75520c] 乏しい知識ですが、未実装関数を作成してみました。~ バグや誤りなど、お気づきの点がありましたら、指摘・加筆・修正のご協力をお願いいたします。~ **sfRapply [#v767753f] **sfCapply [#f6bc0d2c] **sfClusterMap [#ed6fc913] *Tips [#uf0ea58a] **並列関数の異端児 sfClusterApplySR[#e56ac7c7] **通常処理と並列処理の切り替え [#l2899007] **R起動時のsnowfallの設定 [#icb8d0f1] **乱数の使用 [#t017dce9] **並列計算を中断した場合 [#zaa1454b] 並列計算を中断した場合は、必ずworkerをsfStop()で一度終了させてください。~ 終了しないと、意図としない結果が返ってきます。~ > #普通に実行 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x}) [1] 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017 [18] 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.026 0.027 0.028 0.029 0.030 0.031 0.032 0.033 0.034 [35] 0.035 0.036 0.037 0.038 0.039 0.040 0.041 0.042 0.043 0.044 0.045 0.046 0.047 0.048 0.049 0.050 0.051 [52] 0.052 0.053 0.054 0.055 0.056 0.057 0.058 0.059 0.060 0.061 0.062 0.063 0.064 0.065 0.066 0.067 0.068 [69] 0.069 0.070 0.071 0.072 0.073 0.074 0.075 0.076 0.077 0.078 0.079 0.080 0.081 0.082 0.083 0.084 0.085 [86] 0.086 0.087 0.088 0.089 0.090 0.091 0.092 0.093 0.094 0.095 0.096 0.097 0.098 0.099 0.100 0.101 0.102 [103] 0.103 0.104 0.105 0.106 0.107 0.108 0.109 0.110 0.111 0.112 0.113 0.114 0.115 0.116 0.117 0.118 0.119 [120] 0.120 0.121 0.122 0.123 0.124 0.125 0.126 0.127 0.128 0.129 0.130 0.131 0.132 0.133 0.134 0.135 0.136 [137] 0.137 0.138 0.139 0.140 0.141 0.142 0.143 0.144 0.145 0.146 0.147 0.148 0.149 0.150 0.151 0.152 0.153 [154] 0.154 0.155 0.156 0.157 0.158 0.159 0.160 0.161 0.162 0.163 0.164 0.165 0.166 0.167 0.168 0.169 0.170 [171] 0.171 0.172 0.173 0.174 0.175 0.176 0.177 0.178 0.179 0.180 0.181 0.182 0.183 0.184 0.185 0.186 0.187 [188] 0.188 0.189 0.190 0.191 0.192 0.193 0.194 0.195 0.196 0.197 0.198 0.199 0.200 > #同じ作業を中断 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x}) > #変数を変えて20個のみ実行したが、前の結果が残っている? > sfSapply((1:20)/100, function(x){Sys.sleep(x); x}) [1] 0.010 0.020 0.030 0.026 0.027 0.028 0.029 0.030 0.031 0.032 0.033 0.034 0.035 0.036 0.037 0.038 0.039 [18] 0.040 0.041 0.042 0.043 0.044 0.045 0.046 0.047 0.048 0.049 0.050 0.051 0.052 0.053 0.054 0.055 0.056 [35] 0.057 0.058 0.059 0.060 0.061 0.062 0.063 0.064 0.065 0.066 0.067 0.068 0.069 0.070 0.071 0.072 0.073 [52] 0.074 0.075 0.076 0.077 0.078 0.079 0.080 0.081 0.082 0.083 0.084 0.085 0.086 0.087 0.088 0.089 0.090 [69] 0.091 0.092 0.093 0.094 0.095 0.096 0.097 0.098 0.099 0.100 0.101 0.102 0.103 0.104 0.105 0.106 0.107 [86] 0.108 0.109 0.110 0.111 0.112 0.113 0.114 0.115 0.116 0.117 0.118 0.119 0.120 0.121 0.122 0.123 0.124 [103] 0.125 0.126 0.127 0.128 0.129 0.130 0.131 0.132 0.133 0.134 0.135 0.136 0.137 0.138 0.139 0.140 0.141 [120] 0.142 0.143 0.144 0.145 0.146 0.147 0.148 0.149 0.150 0.151 0.152 0.153 0.154 0.155 0.156 0.157 0.158 [137] 0.159 0.160 0.161 0.162 0.163 0.164 0.165 0.166 0.167 0.168 0.169 0.170 0.171 0.172 0.173 0.174 0.175 [154] 0.176 0.177 0.178 0.179 0.180 0.181 0.182 0.183 0.184 0.185 0.186 0.187 0.188 0.189 0.190 0.191 0.192 [171] 0.193 0.194 0.195 0.196 0.197 0.198 0.199 0.200 > #残っているので再度実行して、うまくいっているように思われるが > sfSapply((1:20)/100, function(x){Sys.sleep(x); x}) [1] 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 > #やっぱり返る結果は意図としない結果。 > sfSapply((1:200)/1000, function(x){Sys.sleep(x); x}) [1] 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017 [18] 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.040 0.050 0.060 0.070 0.080 0.090 0.100 0.110 0.120 [35] 0.130 0.140 0.150 0.160 0.170 0.180 0.190 0.200 *参考文献・文書など [#mae70577] -DOCUMENT help(package=snow) help(package=snowfall) vignette("snowfall") -CRAN~ [[CRAN Task View: High-Performance and Parallel Computing with R:https://cran.r-project.org/web/views/HighPerformanceComputing.html]]~ -書籍~ [[Parallel R (英語):http://www.amazon.co.jp/Parallel-R-Q-Ethan-McCallum/dp/1449309925]]~ -rjpwiki~ [[Rで並列計算]]~ [[Tierney 氏の R バイトコンパイラー]]~ [[Rコード最適化のコツと実例集]]~ [[Rの関数定義の基本]]~ -Web Page~ [[snow Simplified:http://www.sfu.ca/~sblay/R/snow.html]] [[Easier Parallel Computing in R with snowfall and sfCluster:http://journal.r-project.org/archive/2009-1/RJournal_2009-1_Knaus+et+al.pdf]]~ [[Tutorial Parallel computing using R package snowfall:http://www.informatik.uni-ulm.de/ni/staff/HKestler/Reisensburg2009/PDF/snowfall-tutorial.pdf]]~ [[並列プログラミング入門(OpenMP編):http://www.hpci-office.jp/invite2/documents2/openmp_2014-11-25.pdf]]~ [[snowパッケージで並列化(R):https://sites.google.com/site/scriptofbioinformatics/bing-lie-hua-guan-xi/snowpakkejide-bing-lie-hua-r]]~ [[【R言語】ループ処理回避 (and/or) 並列化処理 組み合わせで、計算高速化 手法まとめ:http://qiita.com/HirofumiYashima/items/18d5aa87578115215230]]~ [[Rのちょっと速いコードの書き方:http://www.anlyznews.com/2012/02/r_11.html]]~ [[R の apply 徹底解説:http://d.hatena.ne.jp/a_bicky/20120425/1335312593]]~ *コメント[#lbb783b6] #comment(below) - とりあえずページを立ち上げました。 -- [[markovchainmontecarlo]] &new{2015-09-26 (土) 09:14:04};~ &counter;//20151006