More Related Content More from Monta Yashi (11) R高速化2. 自己紹介
約40年前 大阪に誕生
約20年前 大学にてニューラルネットワーク&最適化
約15年前 開発会社にて各種開発を5年くらい
約10年前 現在(コンピュータ業界の)インフラ屋
趣味
3DCG
プログラミング(主にAndroid)
統計学はド素人、Rは素人
7. 推測を確認する
Rでは処理時間の詳細(プロファイル)を調べる「Rprof()」を用いる
エクセレントコード ウンコード
> a <- c(1:10^7)
> Rprof()
> for( i in 1:1) b <- sqrt(a)
> Rprof(NULL)
> summaryRprof()
$by.total
total.time total.pct self.time self.pct
"sqrt" 0.18 100 0.18 100
> a <- c(1:10^5)
> b <- c()
> Rprof()
> for( i in 1:length(a)) b[i] <- sqrt(a[i])
> Rprof(NULL)
> summaryRprof()
$by.total
[1] total.time total.pct self.time self.pct
<0 行> (または長さ 0 の row.names)
R上では原因を観測できない
バグ?
→0.02秒間隔では検出不可(Rprof.out)
10. arithmetic.c
想像を本腰入れて確認する
do_math1の正体
SEXP attribute_hidden do_math1(SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP s;
checkArity(op, args);
check1arg(args, call, "x");
if (DispatchGroup("Math", call, op, args, env, &s))
return s;
if (isComplex(CAR(args)))
return complex_math1(call, op, args, env);
#define MATH1(x) math1(CAR(args), x, call);
switch (PRIMVAL(op)) {
case 1: return MATH1(floor);
case 2: return MATH1(ceil);
case 3: return MATH1(sqrt);
case 4: return MATH1(sign);
math関数呼び出し
/* Mathematical Functions of One Argument */
static SEXP math1(SEXP sa, double(*f)(double), SEXP lcall)
{
SEXP sy;
double *y, *a;
R_xlen_t i, n;
int naflag;
if (!isNumeric(sa))
errorcall(lcall, R_MSG_NONNUM_MATH);
n = xlength(sa);
/* coercion can lose the object bit */
PROTECT(sa = coerceVector(sa, REALSXP));
PROTECT(sy = allocVector(REALSXP, n));
a = REAL(sa);
y = REAL(sy);
naflag = 0;
for (i = 0; i < n; i++) {
if (ISNAN(a[i]))
y[i] = a[i];
else {
y[i] = f(a[i]);
if (ISNAN(y[i])) naflag = 1;
}
}
ここでSQRT処理
17. 並列化(Rでの書式)
① ノードでRを起動する。
② クラスタノードを指定する。
③ 並列化処理を実行
④ 各ノードで指定された数だけR
プロセスを起動して処理
⑤ 結果を元のRに集約
① ターミナルにて「r」を実行
② cl <- makeCluster(c(“サーバ名”,〜略〜), type = “SOCK”)
registerDoSNOW(cl)
③ foreach(i = 1:1000) %dopar% { sum(rnorm(10000)) }
④ ※ライブラリがやります
⑤ ※ライブラリがやります
20. 並列化(転送データ 小、処理時間 短)
乱数ベクトルの合計を求める
system.time(for( i in 1:10^3 ) sum(rnorm(10^5)))
ユーザ システム 経過
8.486 0.000 8.483
単一プロセス
cl <- makeCluster(c("localhost”…), type = "SOCK")
registerDoSNOW(cl)
system.time(
foreach(i = 1:10^3) %dopar%{
sum(rnorm(10^5)) })
stopCluster(cl)
並列化
0
2
4
6
8
10
12
14
16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
時間(秒)
並列度
並列度と処理時間(5回平均)
処理時間
7.1倍の高速化!
21. 並列化(転送データ 小、処理時間 長)
乱数ベクトルの合計を求める
system.time(for( i in 1:10^2 ) sum(rnorm(10^7)))
ユーザ システム 経過
84.372 0.576 85.008
単一プロセス
cl <- makeCluster(c("localhost”…), type = "SOCK")
registerDoSNOW(cl)
system.time(
foreach(i = 1:10^2) %dopar%{
sum(rnorm(10^7)) })
stopCluster(cl)
並列化
10^3から
変更
10^5から
変更
約10倍
0
10
20
30
40
50
60
70
80
90
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
時間(秒)
並列度
並列度と処理時間(5回平均)
処理時間
13.2倍の高速化!
24. 並列化(転送データ 大、処理時間 短)
対象:LENAフル画像
処理:ランダムな点を返す
自主規制!
Width:1084
Height:2318
system.time(for(i in 1:10^3)
myimage[floor(runif(1,1,MAX_VALUE))])
ユーザ システム 経過
0.02 0.00 0.03
単一プロセス
cl <- makeCluster(c("localhost”…), type = "SOCK")
registerDoSNOW(cl)
system.time(
foreach(i = 1:num,.export=c(“myimage”,“MAX_VALUE”))
%dopar% myimage[floor(runif(1,1,MAX_VALUE))])
stopCluster(cl)
並列化
character vector of
variables to export.
0
2
4
6
8
10
12
14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
時間(秒)
並列度
並列度と処理時間(5回平均)
処理時間
25. 0
1000
2000
3000
4000
5000
6000
7000
8000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
時間(秒)
並列度
並列度と処理時間
処理時間
並列化(転送データ 大、処理時間 長)
対象:LENAフル画像
処理:k-meansで減色
自主規制!
Width:1084
Height:2318
for(i in 1:16)
kmeans(myimage2,centers=255,iter.max=10,nstart=i)
ユーザ システム 経過
0.02 0.00 2時間以上
単一プロセス
ret_better <- function(x,y) {
if (x$tot.withinss < y$tot.withinss) x
else y
}
res_kmean <- foreach(i =
1:16,.combine="ret_better") %dopar%{
kmeans(myimage2,centers=255,iter.max=50,nstart=i)
}
並列化
29. 並列化(転送データ 小、処理時間 中)
コラッツの問題(未解決問題)
以下を繰り返すとどんな
値も1に集約する
・偶数なら2で割る
・奇数なら3を掛け1を足す
0
0.5
1
1.5
2
2.5
3
3.5
4
4.5
5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
時間(秒)
並列度
並列度と経過時間(5回平均)
経過時間
31. 付録(コラッツの問題)
do_cluster <- function(num=10^4, client_num=1){
cl <- makeCluster(c("localhost","localhost",中略,"Slave03")[1:client_num], type = "SOCK")
registerDoSNOW(cl)
ret = system.time(foreach(i = 1:num,.combine = "cbind") %dopar% {
n <- i
while(n != 1){
if( n %% 2 == 0 ) n <- n / 2
else n <- 3 * n + 1
}
})
stopCluster(cl)
ret
}
rm(ret)
test_count <- 15
ret <- c()
for (i in 0:test_count) ret <- cbind(ret,do_cluster(num=10^3, client_num = (i%%16)+1))
32. 付録(減色処理)
library("biOps”)
myimage <- readJpeg("l_hires.jpg")
myimage2 <- matrix(myimage,ncol=3)
HEIGHT <- dim(myimage)[1]
WIDTH <- dim(myimage)[2]
ret_better <- function(x,y) {
if (x$tot.withinss < y$tot.withinss) x
else y
}
registerDoSNOW(makeCluster(2, type = "SOCK"))
res_kmean <- foreach(i = 1:30,.combine="ret_better") %dopar%{
kmeans(myimage2,centers=255,iter.max=50,nstart=i)
}
plot(imagedata(c(res_kmean$centers[res_kmean$cluster,]),type="rgb",ncol=HEIGHT,nrow=
WIDTH))