RでdoMCを使ったお手軽並列計算

前書き
奥様1「ちょっと奥さん!最近のCPUってマルチコアになってて何でも並列計算とかできるらしいわよ?」
奥様2「え…でも並列計算の計算環境作成ってすごく面倒くさいんでしょう?」
マーク・パンサー「なんで?面倒くさくないよ?」
奥様2「え…でも大して速くならないんでしょ?」
マーク・パンサー「違うよ,全然違うよ」

ということでRでの並列計算のお話です.
以前にも
LAM/MPIのインストール for MacOSX
とかいう記事を書きましたが,正直このアプローチは面倒くさすぎるというか設定した私ももう一度やれと言われたら多分無理.
基本的に以前の記事はネットワーク経由での並列計算でしたが,今回はマシン単体での並列計算のお話.
つまり「近頃の若いマシンはマルチコアとかいう大層なものを積んでるんだから,精一杯こき使ってやろうぜい」というお話です.





なんで並列計算やる必要あるの?
さて,まずRでの並列計算についてですが,まずRの欠点として…
・基本的にオンメモリでデータを保持
・マルチCPU環境でも基本的に1コアで計算
・デフォルトで大規模データの処理が苦手(デフォルトでは2^31-1個までしか保持てきない)
など割と言い始めたらキリがないですが,今日のお話は2番目の「マルチCPU環境でも基本的に1コアで計算」です.
Rは基本的に1コアで計算してしまうので,並列計算をしてあげないと計算資源の無駄なわけです.



並列計算のパッケージっていろいろあるけど,どのパッケージを使えばいいの?
さて,Rで並列計算するには,まずどのパッケージを使えばいいの?という話が挙がります.
ちょっと調べただけでもdoNWS・doSNOW・doSMP・doMC・rMPIなど結構出てきます.
この中で最適なパッケージはどれかというと…ココの記事いわく…
http://www.revolutionanalytics.com/subscriptions/docs/RevolutionREnterprise4.0/parRman.pdfの22ページより…

The doNWS and doSNOW packages are parallel backends for clusters of workstations; they can be used on a single multi-core or multi-processor computer, but they are not optimized for such use.
The doSMP and doMC packages are parallel backends for foreach that are intended for parallel processing on a single computer with multiple cores or processors. The doSMP package is available on all platforms, while doMC, which depends on the multicore packages, is currently available only on Mac and Linux systems.
なので
doNWS・doSNOW: マルチコアシステムには最適化されていない
doSMP・doMC: マルチコアシステムに最適化されている
→というわけで、一台のマシンで使う場合はdoSMP・doMCが最適

さて,ここからは個人的な経験談なのですが,Mac版doSMPは経験上どうもうまく動かない傾向にあるので、並列計算を行うにあたってはdoMCを使うのが無難かなぁと思います.
(追記:今さら気づきましたがdoMCはLinuxかMac版しか無い模様.Windowsユーザの方はdoSMPを使うしかないようです…といってもコードの書き方は殆ど変わらなかったはず.)




doMCをインストールしよう
doMCのインストールは簡単.
セオリー通り
install.packages("doMC")
とやるだけです.依存パッケージも同時にインストールしてくれます.



doMCを使ってみよう
まずは参考までにサンプルコードを貼っておきます.とっても簡単です.
何のことはない,N個の正規乱数を発生させて,その和を取るということを1000回くりかえした計算時間を返すという単純なものです.
#計算コア数ベクトル生成(コア数: 1,2,4,6,8)
n_core <- c(1,seq(2,8,by=2))
#正規乱数発生数を設定
N <- 10^6
#計算時間の結果を突っ込む空マトリックスの作成
result.mat <- matrix(0,length(n_core),3)
for(i in 1:length(n_core)){
    registerDoMC(n_core[i])
    result <- system.time(foreach(i = 1:1000,.combine = "cbind") %dopar% {
        sum(rnorm(N))
    })
    core.d <- c(n_core[i],result[3])
    names(core.d) <- c("Cores","ProcTime")
    print(core.d)
    result.mat[i,] <- as.numeric(result)[1:3]
}
return(result.mat)
と言った感じです.ね?簡単でしょ?
普段のコードと違うところと言ったら
registerDoMC(n_core[i])

foreach(i = 1:1000,.combine = "cbind") %dopar% {hogehoge}
の所ぐらいです.

さて,それぞれの関数の意味ですが…
registerDoMC(hoge)
で使用するコア数の設定をすることができます,
例えばCore2DuoだったらregisterDoMC(2),Corei7だったら…これはCPUによって違いますね.
次に
result <- foreach(i = 1:1000,.combine = "cbind") %dopar% {hogehoge}
に並列計算の処理を書きます.
基本的にhogehogeの部分に書く処理内容はfor文と同じですが,結果がresultに保存されるので,その点だけは注意です.
つまり
result <- c()
foreach(i = 1:1000,.combine = "cbind") %dopar% {
    result[i] <- mean(rnorm(10000))
    }
とか書いてもダメで,
result <- foreach(i = 1:1000,.combine = "cbind") %dopar% {
    mean(rnorm(10000))
    }
と書いてくださいといいうことです.
返り値はいろいろな形が設定できます.詳しくはヘルプを見てね!って感じですが,cbindにしておけばベクトルで返してくれますし,デフォルトだとそれぞれの計算結果をリストで返してくれたはずです.
注意する点はこれぐらいでしょうか.
これでとっても簡単に計算ができます.




実際どれぐらい早くなるの?
ここまでの記事は正直ほかのサイトさんでも書かれてるので大して新しい情報は無いのですが,実際の効果についてはあまり触れられていないので,記入しておこうかなと思います.
以前機会があって結構大規模なマシンに触れる機会があったので,試しにテストして見ました.

・テスト内容
100,000個の標準正規乱数を1,000回発生させて,それぞれの和をとる計算にかかる時間を計測

・マシン
R for Linux 64bit (Ubuntu Linux 11.04)
CPU: Xeon 2.8GHz *2 (24 core)
RAM: 48GB



R for Mac OS X 64bit (Mac OS X 10.7.1)
CPU: Core i7 2.3GHz *1 (8 core)
RAM: 8GB
の2台で計測

結果
赤線がXeonのマシン,青線がCore i7のマシンになっています.
計算時間については1コア時の計算時間を1として正規化しています.
計算の内容にも依るのかなと思いますが,どちらも実コア数近辺までは計算速度が早くなっている気がします.
それ以降では計算効率がガクッと落ちてしまっています.
registerDoMC関数で指定するコア数は,実コア数までにしておくのが妥当かもしれません.

以上,これでみなさんもハッピー並列計算ライフをお楽しみください.

RStudio for Mac OS X で日本語のプロットが上手くいかない場合の対処法

皆さん,RStudio使ってますか?
ようやく日本語を入力できるようになりましたよ!
日本語のディレクトリ以下にあってもファイルを開けるようになりましたよ!
まだBuggyな部分はあるけどデイリービルド
http://www.rstudio.org/download/daily/desktop/
で日々修正されてますよ!
使わない手はありませんよ!


というわけでそんな中,Mac OS Xの環境で日本語をプロットしようとすると↓な感じで文字化けする問題はなかなか解決されていませんでした.


元々,R for Mac OS Xではデフォルトで日本語のプロットが出来ないという難がありましたが,
ココとかココの方々の偉大なTipsのお陰で特に問題なくプロットできていました.
しかし,その問題がRStudioで再発してしまっていて,にっちもさっちも行かない状態になっていたので,つたない英語で質問を投げてみたところ
ようやく解決法がわかりました,Rstudioのサポートの皆様に感謝感謝(こちらのtypoで迷惑かけて申し訳ない).

結局原因は,macfontdevsの設定にあったようで
macfontdevs=c("quartz","quartz_off_screen", "RStudio")
とすることでうまくいきました.
北大の久保先生のページに掲載されていた.Rprofileを元にRStudio向け修正版を書くと

setHook(packageEvent("grDevices", "onLoad"),
    function(...){
        if(.Platform$OS.type == "windows")
            grDevices::windowsFonts(sans ="MS Gothic",
                                    serif="MS Mincho",
                                    mono ="FixedFont")
        if(capabilities("aqua"))
            grDevices::quartzFonts(
              sans =grDevices::quartzFont(
                c("Hiragino Kaku Gothic Pro W3",
                  "Hiragino Kaku Gothic Pro W6",
                  "Hiragino Kaku Gothic Pro W3",
                  "Hiragino Kaku Gothic Pro W6")),
              serif=grDevices::quartzFont(
                c("Hiragino Mincho Pro W3",
                  "Hiragino Mincho Pro W6",
                  "Hiragino Mincho Pro W3",
                  "Hiragino Mincho Pro W6")))
        if(capabilities("X11"))
            grDevices::X11.options(
                fonts=c("-kochi-gothic-%s-%s-*-*-%d-*-*-*-*-*-*-*",
                        "-adobe-symbol-medium-r-*-*-%d-*-*-*-*-*-*-*"))
        grDevices::pdf.options(family="Japan1GothicBBB")
        grDevices::ps.options(family="Japan1GothicBBB")
        }
)
attach(NULL, name = "JapanEnv")
assign("familyset_hook",
       function() {
       #2012/05/16修正:
       #通りすがりの方のコメントでRStudioだったのがRStudioGDに変わってることが分かりました
       #情報ありがとうございます!

            winfontdevs=c("windows","win.metafile",
                          "png","bmp","jpeg","tiff","RStudioGD")
            macfontdevs=c("quartz","quartz_off_screen","RStudioGD")
            devname=strsplit(names(dev.cur()),":")[[1L]][1]
            if ((.Platform$OS.type == "windows") &&
                (devname %in% winfontdevs))
                    par(family="sans")
            if (capabilities("aqua") &&
                devname %in% macfontdevs)
                    par(family="sans")
       },
       pos="JapanEnv")
setHook("plot.new", get("familyset_hook", pos="JapanEnv"))
setHook("persp", get("familyset_hook", pos="JapanEnv"))


で↓な感じで万事うまく行きました(赤色のが新規に書き加えたところ).
これで日本語をプロットするときもOKです.

やったね!

論文誌名の省略記法

いつも忘れてしまうのでメモメモ(ココを参考にしました)

#############国名
American: Am.
Japanese: Jpn.
Korean: Kor.
Royal: R.

#############学会とかジャーナルとか
Bulletin: Bull.
Conference: Conf.
Congress: Cong.
Journal: J.
Meeting: Meet.
Proceedings: Proc.
Report:
Rep.
Series: Ser.
Society: Soc.
Symposium: Symp.
Transactions: Trans.

#############その他
Acoustical: Acoust.
Advanced: Adv.
Analysis: Anal.
Annals: Ann.
Annual: Annu.
Applied: Appl.
Association: Assoc.
Communication: Commun.
Computing: Comput.
Cybernetics: Cybern.
Engineering: Eng.
Experimental: Exp.
Information: Inf.
Intelligence: Intell.
International: Int'l
Letters: Lett.
Mathematical: Math.
Processing: Process.
Recognition: Recognit.
Research: Res.
Science: Sci.
Statistics, Statistical: Statist.
System: Syst.
Technical: Tech.

例)
Journal of American Statistical Association→J. Am. Statist. Assoc.
Journal of Royal Statistical Society Series B→J. R. Statist. Soc. Ser. B.
The Annals of Statistics→Ann. Statist.

Rstudioがリリースされたよ!

ちょっと奥さん聞きました!?RStudioっていうR用のIDEがあるんですってよ!
ってことでR-bloggersの方で紹介されていたので使ってみました。
ダウンロードは↓から!
http://rstudio.org/

プラットフォームはMac,Linux,Windowsの全てに対応してるらしいので,Macユーザのあなた(というか俺)も安心です!
IDEの画面は↓のような感じ.

うむうむ,なかなかいい感じです.デフォルトではエディタが起動していませんが,起動してあげるときちんと色分けもされます.
コマンド入力途中にTabを押すと
な感じで,候補を出してくれます.すげぇ!
ちなみにエディタから実行するには
行のみの場合:Command+Enter
全体の場合:Command+Shift+Enter
でいけるようです.
EmacsのESSのようにfor文の補完がないのが残念ですが,まだ出たばっかりなのでしょうがないかな.

さて,気になる日本語対応ですが…
ガッデム!まだ対応していないようです…ここさえ治ればほぼパーフェクトなのですが.今後に期待といったところでしょう.
R向けのエディタはESSやTinn-Rなどがありましたが,若干一見さんお断りの雰囲気があったので,こういうのがスタンダードになってくれるとありがたいです.

Mac OS X 10.6 Snow LeopardにOpenCV2.2をインストールする(Pythonでの動画出力問題解決(?)付き)

皆様、OpenCV2.2がリリースされましたね。
巷では
MacPortsで簡単インストール!これで君も明日からOpenCVユーザー!
って感じで話題になってますね。
嘘を言うな!
…っていうのは冗談で自業自得でした、ハイ。

結局何が原因だったかというと、昨年ソースから頑張ってインストールしたOpenCV。
それが邪魔してMacPortsのインストール時にコケてたみたいです。
というわけで
Mac OS X 10.6 Snow Leopard でMacPortsを使ったOpenCVのセットアップ方法(MacPortsで入れたPythonも使えるようにする)
なんて記事を参考にOpenCVをインストールしてしまったそこのあなた!
まずは頑張っていれたOpenCVをアンインストールしましょう。

cd opencv/build
sudo make uninstall
でアンインストールしましょう。これでさっぱり綺麗になったはずです。

これでようやくMacPortsでのOpenCVのインストールが出来ます。
インストール方法は実に簡単。
sudo port selfupdate(MacPortsのPort情報を最新に)
sudo port install opencv +python26(PythonでOpenCV使わない場合はsudo port install opencvおんりー)
でインストールできるはずです。
いい時代になったもんだ。というか今までの苦労なんだったんだ。


Pythonの動画書き出しで変な動画ファイルが出力される
ナウなヤングにPython大人気じゃないですか。
でOpenCVでも使えるってんだから使わない手はないじゃないですか。
ということで昨年あたりからPythonベースで(Windowsで)OpenCVの色々なものつくってきたんですが、んじゃそろそろメインのMacでもやるべかということでやってみたらハマった。
とりあえずサンプルコードのcamera.pyを改造して、動画の出力をやったら
こんな感じでどうも動画がうまく保存されない。ウィンドウにはきちんと表示されてるので、カメラが原因でもない、さてなんのこっちゃということでOpenCVのメーリングリストに色々と投げてみたんですが、とりあえず自己解決。

Windowsでは必要なかった(はず)なんだけど、
hogeimage = cv.QueryFrame(hoge)
でとってきたイメージを
copyimage = cv.CreateImage(size, cv.IPL_DEPTH_8U, 3)
で作った構造体に
cv.Copy(hogeimage, copyimage)
って感じでコピーしてから
cv.WriteFrame(writer,copyimage)
って感じで書きこまなきゃいかんらしい。
(ここでwriterはcv.CreateVideoWriterで作ったやつ
これ解決するのに1週間費やしてしまった…まぁ当然といえば当然なんだけど、むしろなんで今までWindowsで動いてたんだろうか。
とりあえずここを参考にちょっと変えたサンプルコードを載せておく。
(参考元では、上手く動かなかったcv.WriteFrame(writer,hogeimage)でやってるけど、他の人はこれでも動くのかしらん)
import cv

if __name__ == "__main__":
    #カメラの設定
    cam = cv.CaptureFromCAM(0)
    #カメラの情報から解像度取得
    size = (int(cv.GetCaptureProperty(cam, cv.CV_CAP_PROP_FRAME_WIDTH)),
        int(cv.GetCaptureProperty(cam, cv.CV_CAP_PROP_FRAME_HEIGHT)))
    #ビデオライタの作成:出力設定
    writer = cv.CreateVideoWriter(
        "video.avi",
        cv.CV_FOURCC('P','I','M','1'),
        30,
        size)
    #空の画像イメージ作成
    copyimage = cv.CreateImage(size, cv.IPL_DEPTH_8U, 3)
    #録画開始
    while True:
        #カメラから画像を取ってくる
        hogeimage = cv.QueryFrame(cam)
        #hogeimageの内容をcopyimageにコピー
        cv.Copy(hogeimage, copyimage)
        #コピーしたイメージを書き出し
        cv.WriteFrame(writer, copyimage)
        #画像の表示
        cv.ShowImage("Cam", copyimage)
        #ESC押したら終了
        if cv.WaitKey(10) == 27:
            break

とりあえずここ数日喉に引っかかってる骨がとれた感じ。
めでたしめでたし