Rの高速化
-
Upload
antiplastics -
Category
Technology
-
view
15.960 -
download
7
Transcript of Rの高速化
Rの高速化
Kashiwa.R#1
11 / 11 / 11
@antiplastics
自己紹介
所属:
東京理科大学大学院
薬学研究科
修士課程2年
(来年からD進学予定)
専門: バイオインフォマティクス
twitterアカウント:
@antiplastics
趣味: バイク、サーフィン、アニメ、読書など
研究内容: マイクロアレイデータからの
発現変動遺伝子の検出
扱っているデータの構造
行 (生物の遺伝子数)*原核生物(大腸菌、緑膿菌など)
6000gene*真菌(カビ、酵母など)
10000gene
*真核生物(ヒト、マウスなど)
20000gene
列 (実験データの数)
*ますます増加するデータベースへの登録件数
*NGS(次世代シーケンサ)の登場
超多次元、多変量の大規模データ!!
×
実験1 実験2 実験3 実験287 実験288 実験289
遺伝子1 1.7 3.9 4.8 4.4 2.5 4.8
遺伝子2 -3.3 -0.2 0.2 -4.1 3.1 3.1
遺伝子5547 -1.2 4.6 -0.9 4.6 -4.4 1.5
遺伝子5548 1.3 2.7 1.6 6.1 -1.4 3.1
遺伝子5549 2.2 3.2 -1.4 1.3 -3.2 2.0
実験特異的遺伝子
発現の検出
など
発現変動遺伝子の検出
など
データ解析の現場の実情
動画
遅い!!!
(ノ; _ ;)ノ ┫:・'.::結果待ちに数日かかる事もたびたび。
計算が速く終わるかどうかは死活問題。
Rはパッケージがとても豊富。
library(“hogehoge”)とか打ったら小難しい計算も、関数が勝 手にやってくれるからコード行数も少なくて済む。
めちゃくちゃ便利!
だが現実問題これだけ遅いと、やってられない時も。
→Rを高速化させて、サクサク研究を進めたい!!
→速くしようと思ったらどこまで速くなるかをみてみよう。
使用するマシン
iMac(21.5inch)OS:
MacOSⅩ10.6.8SnowLeopard(64bit)
CPU:
2.8GHz Intel Corei7(コア数:4)
メモリ:
8GBHDD:
1TB
以下全てのプログラムはこのマシン上 で走らせる事とする。
比較する計算
以下の数値積分(中点法)により近時的に円周率 πを求める。
N(ステップ数)が増すほど精度が上がる
今回は1千万(107)ステップで計算する
=
Cのソースコード#include<stdio.h>#include<time.h>#define num_steps 10000000
int main(void){clock_t t1, t2;
t1 = clock();int i;double x,pi,sum=0.0,step;step = 1.0 / (double) num_steps;
for(i = 1;i <= num_steps; i++){x = (i - 0.5) * step;sum = sum + 4.0 / (1.0 + x * x);
}pi = step * sum;printf("%f¥n",pi);t2 = clock();
printf("%f¥n", (double)(t2 - t1) / CLOCKS_PER_SEC);return(0);
}
107という値をとる変数num_stepsを定義
ステップ
= 1/107を定義
各ステップ毎に長方形の面積を
計算し、最後に和を求める
Perlのソースコード
$t1 = (times)[0];$num_steps = 10000000;$step = 1.0 / $num_steps;
for($i = 1;$i <= $num_steps; $i++){$x = ($i - 0.5) * $step;$sum = $sum + 4.0 / (1.0 + $x * $x);
}$pi = $step * $sum;print $pi;print "¥n";
$t2 = (times)[0];$t3 = $t2 - $t1;print "$t3 秒¥n";
Pythonのソースコードimport sysimport timebefore = time.time()num_steps = 10000000sum = 0step = 1.0 / num_steps
for i in range(1,num_steps):x = (i - 0.5) * stepsum = sum + 4.0 / (1.0 + x * x)
pi = step * sumprint piprint "¥n"
after = time.time()print "Running Time =", after - before, "s"
Rubyのソースコードrequire "benchmark"num_steps = 10000000step = 1.0 / num_stepssum = 0
puts Benchmark::CAPTIONputs Benchmark.measure{
for i in 1 .. num_stepsx = (i - 0.5) * stepsum = sum + 4.0 / (1.0 + x * x)
endpi = step * sumputs pi}
結果
ランク 言語 実行時間(s)1 C 0.152 Python 5.193 Perl 5.594 Ruby 9.12
やはりCは最速。スクリプト言語とCの差は大きい。
R <R-2.12.1,64bit> のソースコード
before <- proc.time()
num_steps <- 10000000step <- 1.0 / num_stepssumm <- 0for(i in 1:num_steps){
x <- (i - 0.5) * stepsumm <- summ + 4.0 / (1.0 + x * x)
}pi <- step * summprint(pi)
after <- proc.time()print(after – before)
*このくらいのステップ数だと32bitのRは使えなくなるので注意。
結果
ランク 言語 実行時間(s)1 C 0.152 Python 5.193 Perl 5.594 Ruby 9.125 R 23.28new
遅い…orz
Rの高速化手法① プログラム修正
before <- proc.time()
num_steps <- 1:10000000step <- 1.0 / 10000000
x <- (num_steps - 0.5) * steppi <- sum((4.0 / (1.0 + x * x))*step)
print(pi)
after <- proc.time()print(after - before)
num_stepsを変数からベクトルへ変更
for文をやめて、ベクトルに
一度にアクセスするような
書き方をする
結果
ランク 言語 実行時間(s)1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R 23.28
new
スクリプト言語をぶち抜きましたwww
Rの高速化手法②
apply関数の使用
apply関数ファミリー
①で行なったベクトル、行列に同時にアクセス
するような計算を、より明示的にできる関数。入
力データの型、出力データの型の違いなどで、
apply(),lapply(), sapply(), mapply(), tapply() がある。
Rの高速化手法②
apply関数の使用
before <- proc.time()
num_steps <- 1:10000000step <- 1.0 / 10000000
menseki <- function(A){x <- (A - 0.5) * stepy <- 4.0 / (1.0 + x * x)return(y*step)
}
pi <- sum(sapply(num_steps,menseki))print(pi)
after <- proc.time()print(after - before)
各ステップで長方形の面積を求める計算は、一
度関数として定義する
sapplyを使って、配列num_stepsの各要
素に関数mensekiを適用する。
結果ランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R 23.287 R(apply) 54.16new
かえって遅くなった…。ただし、apply関数を覚 えておくといい事がある(後述)。
Rの高速化手法③ 並列化snowパッケージを使えば、先程のapply関数が並列に計算できる!
applyファミリー
snowのでのapplyファミリー
apply() parApply() #行列用
lapply() parLapply() #リスト用
sapply() parSapply() #ベクトル、行列用
mapply() ×
#グループ化されたデータ用
tapply() ×
#規則的なリストの作成
×
parRapply() #行列の行に対して
×
parCapply() #行列の列に対して
×
parMM() #行列同士の掛け算
Rの高速化手法③ 並列化before <- proc.time()library("snow")library(“Rmpi”)cl <- makeCluster(4,type=“MPI")
num_steps <- 1:10000000step <- 1.0 / 10000000clusterExport(cl,”step”)
menseki <- function(A){x <- (A - 0.5) * stepy <- 4.0 / (1.0 + x * x)return(y*step)
}
pi <- sum(parSapply(cl,num_steps,menseki))print(pi)
after <- proc.time()print(after - before)stopCluster(cl)
snowによりMPIクラスターを4個生成
各ステップで長方形の面積を求める計算
は、一度関数として定義する
snow内で並列化対応したsapplyであ
るparSapplyを使う
結果
ランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R(snow) 17.357 R 23.288 R(apply) 54.16
new
Rの高速化手法④ ffパッケージ
Rはメモリを逼迫させる。
→データはハードディスクから、必要に応じてメモリに ロードしたい。
*ベクトル、行列、因子などのデータ:
ffパッケージ*行列のデータ:
bigmemoryパッケージ
しかも上記の2つは並列化まであわせてやってくれる!
Rの高速化手法④ ffパッケージ
before <- proc.time()library(ff)library(snowfall)sfInit(parallel=TRUE, cpus=4,type=“MPI")num_steps <-ff(vmode="integer",1:10000000,length=10000000)
step <- 1.0 / 10000000sfLibrary(ff)sfExport("step")
menseki <- function(A){x <- (A - 0.5) * stepy <- 4.0 / (1.0 + x * x)return(y*step)
}pi <- sum(sfSapply(num_steps,menseki))print(pi)
after <- proc.time()print(after - before)
4つのクラスターを生成
ff,stepを各クラス
ターにエクスポート
snowfall内でのsapply()である、
sfSapply()を使う
結果ランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R(ff) 17.007 R(snow) 17.358 R 23.289 R(apply) 54.16
new
snowより若干速いくらい
Rの高速化手法⑤
バイトコンパイラーの使用
menseki <- function(A){x <- (A - 0.5) * stepy <- 4.0 / (1.0 + x * x)return(y*step)
}
list(.Code, list(7L, GETVAR.OP, 1L, LDCONST.OP, 2L, SUB.OP, 3L,
GETVAR.OP, 4L, MUL.OP, 5L, SETVAR.OP, 6L, POP.OP, LDCONST.OP,
7L, LDCONST.OP, 8L, GETVAR.OP, 6L, GETVAR.OP, 6L, MUL.OP,
9L, ADD.OP, 10L, DIV.OP, 11L, SETVAR.OP, 12L, POP.OP, GETVAR.OP,
12L, GETVAR.OP, 4L, MUL.OP, 13L, RETURN.OP), list({
x <- (A - 0.5) * stepy <- 4/(1 + x * x)return(y * step)
}, A, 0.5, A - 0.5, step, (A - 0.5) * step, x, 4, 1, x * x, 1 +
x * x, 4/(1 + x * x), y, y * step))
①library(“compiler”)②menseki2 <- cmpfun(menseki)③disassemble(menseki2)
バイトコンパイル前
バイトコンパイル後
あらかじめ構文解析後の関数にしておく。
人が見ても何しているのかわからない機械語に近い形式になる。
Rの高速化手法⑤
バイトコンパイラーの使用
before <- proc.time()library("compiler")
num_steps <- 1:10000000step <- 1.0 / 10000000
menseki <- function(A){x <- (A - 0.5) * stepy <- 4.0 / (1.0 + x * x)return(y*step)
}
menseki2 <- cmpfun(menseki)
pi <- sum(sapply(num_steps,menseki2))print(pi)
after <- proc.time()print(after - before)
バイトコンパイル
結果
ランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R(ff) 17.007 R(snow) 17.358 R 23.289 R(compiler + apply) 41.1410 R(apply) 54.16
new
並列化と組み合わせランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R(compiler + ff) 14.417 R(compiler + snow) 15.118 R(ff) 17.009 R(snow) 17.3510 R 23.2811 R(compiler + apply) 41.1412 R(apply) 54.16
new
new
Rの高速化手法⑥
R-2.14.0最新VerのR-2.14.0はかなり速い。
*全ての基本パッケージの関数があらかじめ、バ イトコンパイルされているとか
?
R-2.4.0 30.1s
R-2.8.0 30.8s
R-2.9.10 31.7s
R-2.10.0 31.7s
R-2.11.0 24.2s
R-2.12.1 23.28s
R-2.13.2 24.4s
R-2.14.0 ?
の順
64bit化
バイトコンパイル化
最終結果ランク 言語 実行時間(s)
1 C 0.152 R(プログラム修正) 0.303 Python 5.194 Perl 5.595 Ruby 9.126 R(compiler + ff) 14.417 R(compiler + snow) 15.118 R(ff) 17.009 R(snow) 17.3510 R(2.14.0) 22.0111 R 23.2812 R(compiler + apply) 41.1413 R(apply) 54.16
new
時間の関係でできなかった 高速化手法
• Revolution Rインストール時にコア数を勝手に調べて、マルチコア対応に計算を実行してくれる新型R (Windows、Redhat用)。普通のRより2〜3倍速いという噂。
• RCCコンパイラーR→C++に変換できます(Windows、Linux用)。
• RDBMSの利用Rでリレーショナルデータベース(MySQL,PostgreSQL,RODBC,MiniSQL)がいじれます。
• Hadoop,Mapreduceの利用http://www.slideshare.net/holidayworking/rmapreduce (以前のTokyo.Rのスライド)
• R+クラウドコンピューティングsegue: アマゾンがやっているlapply関数を並列に計算してくれるサービス(Mac,Linux用)。http://code.google.com/p/segue/