ナンクル力学系

学んだ事を書き連ねていこう。

Archive for the ‘PC’ Category

Cの配列はa[i][j]とa[i*Nj+j]のどちらが速いか試してみた

with 3 comments

Cでベクトル演算沢山やるような数値計算をするときに多次元配列を a[i][j] と a[i*Nj+j] の どちらで書くのが速いか気になったので試してみた.(Njは添え字jの数ね.) x 始めは,

と思ってたけど,

とか良くわからないなと思ってたら

と教えてもらって,一筋縄な問題じゃなさそうだと思ったので.

サンプルで作ったのはのRNN(recurrent neural network). ソースは gist: 267098 – GitHub にある.結構キモいソースだと思うw.

1次元配列での実装(a[i*Nj+j])を rnn_ca1d.c に, 2次元配列での実装(a[i][j])を rnn_ca2d.c に書いてある.

rnn_ca1d.c は配列にアクセスするためのマクロを:

#define Wcc(i,j) self->wcc[ self->num_c*(i) + (j) ]
#define Bc(i)    self->bc[(i)]
#define Ec(i)    self->ec[(i)]
#define Uc(i,j)  self->uc[ self->num_c*(i) + (j) ]
#define Xc(i,j)  self->xc[ self->num_c*(i) + (j) ]

で書いていて, rnn_ca2d.c は:

#define Wcc(i,j) self->wcc[i][j]
#define Bc(i)    self->bc[i]
#define Ec(i)    self->ec[i]
#define Uc(i,j)  self->uc[i][j]
#define Xc(i,j)  self->xc[i][j]

で書いてある.あとの内容はほとんど同じ.

rnn_ca1d.c と rnn_ca2d.c を gcc と icc でそれぞれ -O2(デフォルトなはず) と -O3 オプションをつけてコンパイル.そして,実行時間を計ってみたのが以下:

tkf% make runtest 2> runtest.txt
for i in  rnn_ca1d-gcc-O2 rnn_ca1d-gcc-O3 rnn_ca1d-icc-O2 rnn_ca1d-icc-O3 rnn_ca
2d-gcc-O2 rnn_ca2d-gcc-O3 rnn_ca2d-icc-O2 rnn_ca2d-icc-O3; \
        do \
        printf "%s %d %d %d " \
        ./$i 30 1000 300 1>&2; \
        time ./$i 30 1000 300; \
        done
tkf% cat runtest.txt
./rnn_ca1d-gcc-O2 30 1000 300 1.65user 0.00system 0:01.65elapsed 99%CPU (0avgtex
t+0avgdata 0maxresident)k
0inputs+0outputs (0major+272minor)pagefaults 0swaps
./rnn_ca1d-gcc-O3 30 1000 300 1.56user 0.00system 0:01.57elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
(略)

結果が分かりにくいので整形してみる:

tkf% sed -e "N; s/\n//" runtest.txt | cut -f1,5 -d' '
./rnn_ca1d-gcc-O2 1.64user
./rnn_ca1d-gcc-O3 1.56user
./rnn_ca1d-icc-O2 0.80user
./rnn_ca1d-icc-O3 0.80user
./rnn_ca2d-gcc-O2 1.48user
./rnn_ca2d-gcc-O3 2.62user
./rnn_ca2d-icc-O2 1.07user
./rnn_ca2d-icc-O3 2.23user

分かることは,

  • icc で1次元配列(a[i*Nj+j])で実装したバージョンが一番速い.
  • 2次元配列(a[i][j])での実装は,gcc/iccのどちらでも -O3 の パフォーマンスが落ちる.不思議.
  • gcc -O2 だと,2次元配列(a[i][j])のほうが若干速い.
  • ※ 3回試してほとんど同じ結果だった.

ちなみに, make の時に出たメッセージを見ると2次元配列(a[i][j])での実装を-O3で コンパイルするとベクトル化されてるループが少ないことが分かる:

tkf% make all
gcc -lm -O2 rnn_ca1d.c -o rnn_ca1d-gcc-O2
gcc -lm -O3 rnn_ca1d.c -o rnn_ca1d-gcc-O3
icc -vec-report1 -O2 rnn_ca1d.c -o rnn_ca1d-icc-O2
rnn_ca1d.c(65): (col. 3) remark: ループがベクトル化されました。.
rnn_ca1d.c(67): (col. 5) remark: ループがベクトル化されました。.
rnn_ca1d.c(67): (col. 5) remark: ループがベクトル化されました。.
rnn_ca1d.c(20): (col. 3) remark: ループがベクトル化されました。.
rnn_ca1d.c(39): (col. 5) remark: ループがベクトル化されました。.
icc -vec-report1 -O3 rnn_ca1d.c -o rnn_ca1d-icc-O3
rnn_ca1d.c(65): (col. 3) remark: ループがベクトル化されました。.
rnn_ca1d.c(67): (col. 5) remark: ループがベクトル化されました。.
rnn_ca1d.c(67): (col. 5) remark: ループがベクトル化されました。.
rnn_ca1d.c(20): (col. 3) remark: ループがベクトル化されました。.
rnn_ca1d.c(39): (col. 5) remark: ループがベクトル化されました。.
gcc -lm -O2 rnn_ca2d.c -o rnn_ca2d-gcc-O2
gcc -lm -O3 rnn_ca2d.c -o rnn_ca2d-gcc-O3
icc -vec-report1 -O2 rnn_ca2d.c -o rnn_ca2d-icc-O2
rnn_ca2d.c(69): (col. 3) remark: ループがベクトル化されました。.
rnn_ca2d.c(71): (col. 5) remark: ループがベクトル化されました。.
rnn_ca2d.c(20): (col. 3) remark: ループがベクトル化されました。.
rnn_ca2d.c(39): (col. 5) remark: ループがベクトル化されました。.
icc -vec-report1 -O3 rnn_ca2d.c -o rnn_ca2d-icc-O3
rnn_ca2d.c(20): (col. 3) remark: ループがベクトル化されました。.
rnn_ca2d.c(39): (col. 5) remark: ループがベクトル化されました。.

iccの-O3オプションって-O2プラスアルファだと思ってたけど違うんだろうか. まあ,一次元配列で実装してれば問題ないことが分かったので良しとしよう!

あと,どの配列実装が速いかはたぶん計算に依存してるだろうから,この結果は 他の数値計算に適用できないと思う.これを書いてるときにちょっと添え字の 書き方間違えてて,その時の結果はかなり違ったし.だから,こういうテスト はなるべく実際の計算に近いソースで試すべきなんだろうな. 普通に行列xベクトルの計算プログラムじゃなくてRNNで試して良かった.

Advertisements

Written by tkf

January 1, 2010 at 11:00 pm

Posted in PC

Tagged with

Python で RNN (PyRNN) を書いたので公開します

with 2 comments

ソースはBitbucketに置いている. > tkf / PyRNN / overview — bitbucket.org

何が出来るかというと,こんなのとか(インパクトが欲しかったので,学習の様子をアニメーションにしてみた):

左上がエラーの学習曲線,右上がパラメタのRMSの学習曲線,左下が教示信号とネットワーク出力の相空間プロット,右下がコンテキストの相空間プロット.このアニメを作るソースはこれ(が吐いたpngをconvert -delay 5 *.png nn.mpgで変換).

これを作った理由は,Pythonだと簡単に式を書けるからバグ入りにくい,だからCで書いた本番用のテストに使える!と思ったから.だから,かなり計算効率は悪いけど分かりやすい書き方になっている(はず).これを使って本番用のネットの一つバグが落とせたのはかなりうれしかったけど,その本番用のはラボにいる別の人のより性能悪いっぽいので両方共にバグがあるかも(おいw

という訳で,バグレポートお待ちしてます!←ココ!

あ,簡単なネットワークの式はPyRNN v0.0 documentation で説明してます.

追記

  • README.rst にインストール方法書いてるけど,実はインストールしなくても使えます. toy/ElmanNet に色々遊べるスクリプトがあるので,それを一番根元のディレクトリ(setup.py がある場所)にもってきて実行すればおk(なはず.
  • numpy と matplotlib が必要です.
  • アニメの再生速度はlog scale(っぽく)速くしてます.実際は後半待つのが超ダルいです.
  • momentumという黒魔術項を入れて,ネットワークの学習を加速しますけどそのせいで暴れています.でも暴れているのを見るのが楽しいです.

Written by tkf

November 18, 2009 at 5:17 pm

Posted in 研究日誌, PC

Tagged with , ,

ローカルに Subversion のリポジトリを作る方法

leave a comment »

$HOME/tmp/svntest っていうディレクトリ以下に,リポジトリ repo1 を作って co1/repo1 にチェックアウトしてみた.

まずリポジトリを作る:

mkdir ~/tmp/svntest
svnadmin create $HOME/tmp/svntest/repo1

作ったリポジトリをチェックアウトして使う:

mkdir ~/tmp/svntest/co1
svn co file://$HOME/tmp/svntest/repo1 repo1
cd ~/tmp/svntest/co1/repo1/
touch README
svn add README
svn ci -m ""

Written by tkf

October 4, 2009 at 8:25 am

Posted in PC

Tagged with

matplotlib でタイル状にグラフをしきつめるようなプロットをする

leave a comment »

こういうグラフを書きたい:

https://i0.wp.com/farm3.static.flickr.com/2568/3977125592_ae7c87d90e.jpg
最近気づいたのは pylab は遅いけど matplotlib.pyplot だと早いということ. pylab を使うと簡単にかけそうだけど,たくさん書きたいので matplotlib.pyplot で頑張ることに.

どこの処理が時間かかってるのか計るコードも入れた (tm なんちゃらってのが計測している部分). 最新の matplotlib (0.99) が必要.

コード:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid import AxesGrid
import numpy

tm = []
def tm_append(tm):
    import time
    tm.append(time.time())
def tm_print_diff(tm):
    for (t0,t1) in zip(tm[:-1],tm[1:]):
        print t1 - t0

list_func = [ numpy.sin,
              lambda x: numpy.exp(-0.1*x),
              lambda x: numpy.sin(x)*numpy.exp(-0.1*x) ]
list_tmax = [5, 10, 15, 20]
nrows_ncols = (len(list_func), len(list_tmax))

tm_append(tm) ## time
F = plt.figure(1)
F.clf()
tm_append(tm) ## time
grid = AxesGrid(F, 111, # similar to subplot(111)
                nrows_ncols = nrows_ncols,
                axes_pad = 0.0,
                add_all=True,
                aspect=False,
                )
tm_append(tm) ## time

for ax in grid:
    ax.cla()
grid.set_label_mode('L')
tm_append(tm) ## time

i = 0
for f in list_func:
    for tmax in list_tmax:
        t = numpy.arange(0,tmax,0.1)
        grid[i].plot(t, f(t))
        i += 1
tm_append(tm) ## time

plt.draw()
plt.savefig('axesgrid.png')
#plt.show()
tm_append(tm) ## time

tm_print_diff(tm)

結果:

1.4825220108
2.09476304054
0.745758056641
0.0568108558655
1.95767402649

やっぱり, plt.figure (1行目) や AxesGrid (2行目) は時間かかるっぽいな. 二回目以降は for ax in grid 以下を実行してやれば良いので,かなりお得かな. ax.cla() した後で grid.set_label_mode(‘L’) して一番下と一番左以外の軸にラベルがつかないように しているのがミソ.

Written by tkf

October 3, 2009 at 10:50 pm

Posted in PC

Tagged with ,

PySmell で標準ライブラリ用の PYSMELLTAGS を作る

leave a comment »

pysmell /usr/lib/python2.5/ -o ~/PYSMELLTAGS とやると重すぎて使えなかったけど, pysmell /usr/lib/python2.5/ -x site-packages test -o ~/PYSMELLTAGS とやるとまともな速度で動いた.

ただ, os. とかの補完はちゃんと効かないっぽい? os.py のソース見てみたら 解析が難しそう(動的に読み込んでいる)感じだったから,それが原因かな?

参考

Written by tkf

September 24, 2009 at 3:18 pm

Posted in PC

Tagged with , ,

GNU screen でヘルプコマンドを読むときに使う –help|less を一発入力

leave a comment »

bind ^H stuff "--help 2>&1 | less"

.scrrenrc などに書く.

  • sutff STRING で, STRING をキーボードから入力した場合と同じことに.
  • 2>&1 で,標準エラー出力も less へ.

Written by tkf

September 24, 2009 at 12:58 pm

Posted in PC

Tagged with

英辞郎 IV (CD版) のデータを rdic で使えるように変換する方法

leave a comment »

ちょっと前に書いたメモだけど.rdic のおかげで英語の文章書いたり論文読んだりが Ubuntu だけで出来るのはうれしい.

  • Linux で使えるむちゃくちゃ便利な辞書 rdic を使いたい.
  • 英辞郎 IV (CD版) を使うとなぜか変換ミスるのでどうにかしたい.

PDIC1行形式へ書き出す

  • Personal Dictionary (PDICU.EXE) を起動
  • File > 辞書設定(詳細) > 辞書一覧の辞書の上で右クリック > 辞書の変換 > 変換形式をPDIC1行形式にして,ひたすら書き出す

cnv2rdic.rb が対応している PDIC1行形式ファイルを作る

出力されたテキストは,

  • エンコーディング: Shift_JIS (多分).
  • cnv2rdic.rb が対応しているのはセパレータが " : " のもの.
  • でも,英辞郎 IV は,セパレータが " /// " になってしまうみたい.

変換用のシェル関数(関数にする必要ないけどw):

cnv2colon () {
        for src in "$@"
        do
                trg=`basename $src`
                echo $trg
                nkf -w8 $src | sed "s/ \/\/\/ / \: /" | nkf -s > $trg
        done
}

cnv2rdic.rb で変換した後,行頭に"■"を加える

  • コマンドを実行する環境の文字コードに注意!
    • 端末の文字コード
      • これとシェルの文字コードがあっていないと,コピペ出来ない!
      • gnome-terminal の場合: メニューバー > 端末 > 文字コードの設定 > EUC-JP を選択
    • 環境変数 $LANG
      • export LANG=ja_JP.eucJP; export LANGVAR=ja_JP.eucJP

変換コマンド:

srcpath=$HOME/fsp_disk/misc/eijiro4/pdic-1l-txt/cnv2colon
ruby -Ke cnv2rdic.rb $srcpath/eijiro-112.txt | sort -k1,1 -t: -f | sed "s/^/■/" > eijiro-112.euc &
ruby -Ke cnv2rdic.rb $srcpath/waeiji-112.txt | sort -k1,1 -t: -f | sed "s/^/■/" > waeiji-112.euc &
ruby -Ke cnv2rdic.rb $srcpath/reiji-112.txt | sort -k1,1 -t: -f | sed "s/^/■/" > reiji-112.euc &
ruby -Ke cnv2rdic.rb $srcpath/ryaku-112.txt | sort -k1,1 -t: -f | sed "s/^/■/" > ryaku-112.euc &
ruby -Ke cnv2rdic.rb $srcpath/reiji-112.txt | sort -k1,1 -t: -f | sed "s/^/■/" > reiji-112.euc &

実行環境を整える

起動用スクリプト:

#!/bin/sh
export LANG=ja_JP.eucJP
export LANGVAR=ja_JP.eucJP

RD=${HOME}/misc/rdic/rdic-0.1.8
DICD=${RD}
VER=112
DICS="\
$DICD/eijiro-$VER.euc \
$DICD/waeiji-$VER.euc \
$DICD/ryaku-$VER.euc \
$DICD/reiji-$VER.euc"

gnome-terminal \
    --disable-factory \
    --window-with-profile=rdic \
    -e "$RD/rdic -b $DICS"
  • これに適当な名前をつけて実行権限をつければ(chmod u+x ファイル名)OK.
  • sudo ln -s ファイルへのパス /usr/local/bin/適当なファイル名(コマンド) とすれば, Alt + F2 で立ち上がる 「アプリケーションの実行」 で 補完が効くので便利.

おまけ

辞書ファイルの先頭部分を確認するための関数 (head して nkf で utf-8 に):

hnkf-w8(){ head $1 | nkf -w8 }

おまけ2

ちなみに,emacs から英辞郎を使う場合にも,セパレータの変換は必要.

参考

Written by tkf

September 24, 2009 at 9:46 am

Posted in PC

Tagged with ,