行列屋さんの作業ログ

行列まわりで色々やってたエンジニアの作業メモ&国内外旅行記ブログ

Rで並列計算 パラメータを変えながら計算を回す

行列分解の一種、CUR分解をパラメータを色々変えながら実行してみようと思った。

パラメータの組み合わせが500通り位あるので、せっかくだから並列化してみる。

ということでサンプルコードを書く。

2つの入力パラメータの積を返す、myprodという関数を定義した。

myprod <- function(a,b){
 return(a*b)
 }

この関数を、並列に回すのが今回の目標。もちろん、それぞれ別のパラメータを持たせながら。

使うのはsnowパッケージ(と、パラメータの組み合わせを作るためのreshapeパッケージ)

library(snow)
library(reshape)

パラメータの組み合わせを作る。

param1 <- 1:10
param2 <- 11:20
param <- expand.grid(param1,param2)

こんなかんじの組み合わせ100つ

> param
    Var1 Var2
1      1   11
2      2   11
3      3   11
4      4   11
(以下略)

普通に計算するなら下のようにする。結果はリストでまとまってくる。

lapply(1:dim(param)[1],function(i){
        myprod(param[i,1],param[i,2])
})

並列計算するなら、下のようにする。
まずは並列計算用のクラスター作成。今回は4コア。

hosts <- rep('localhost',4)
scl <- makeCluster(hosts, "SOCK")

次に、並列計算に使用するオブジェクトをエクスポートしてやる。今回はmyprodとparamをエクスポート。

clusterExport(scl,c('myprod','param'))

以上で準備完了。
parLapply(lapply関数の並列版)を使って計算する。

result_parallel <- parLapply(cl = scl,x = 1:dim(param)[1],fun = function(i){
        myprod(param[i,1],param[i,2])
})

計算自体はこれで完了。
計算が終わったら、使用したクラスタを止めてあげる。

stopCluster(scl)

並列計算の結果は、シングルコアで処理した時のともちろん同じ。

> identical(result_single,result_parallel)
[1] TRUE

さて、気になる計算時間(proc.timeを基に計算)は、
シングルが0.005s
並列時は、クラスタ生成から停止までで0.989s…うん遅い。
parLapplyにかかった時間は0.005s。この程度じゃ差が生まれなかった。

じゃあ、1000*1000の10000通りなら?
シングルなら80.051s
並列なら、クラスタ生成から停止まで30.489s
parLapplyだけなら25.305s

無事早くなってくれた。

並列化する方法はsnowパッケージで出来るものだけでも沢山あるし、他のパッケージとしてdoMCやffもある。
今回は、既存コードをからの変更点が一番少なさそうだったからこれを使ったけれど、1から作るなら別に良い方法があるかも。