はやみずの「は」

一番苦手な作業に取り組むために

自分は今日やったこと、今日考えたことを毎日メモを残しておくというのがものすごく苦手である。

やらないよりも、やれば良いにきまっている。良いとはわかっているけれども、どうもそれをやろうとすると、「めんどくさいな」と思って気がついたらはてブをダラダラながめたりしてる。よくない。

面倒に感じる理由としては、考えていることがうまく言葉にまとまらなくて活字に落とせない苦しみ故みたいなことを除くと、ほとんどはメモを残すために手を動かす作業の細かい不便さが積み重なっていることが原因であるように感じる。

たとえば汎用的なテキストエディタでMarkdown記法でメモを記録していこうと思うと、適当にディレクトリを掘って日付をファイル名にして記録していくというスタイルが考えられる。

が、まず C-x C-f でそのディレクトリを開いて、日付を入力するのが面倒(Emacsならelispでそういう処理をする関数を定義しておけばいいかもしれない)。

その問題が解決できたとしても、EmacsでMarkdownを編集しているとプレビューを見ながら書きたくなってくる。KobitoMacdownを使えばライブプレビューをしながらMarkdownを書けるが、やはり汎用エディタなので↑にかいた日付とかでファイルを整理するのが面倒問題は以前としてある。

また、実験の結果のグラフなどをちょっと載せておきたいとおもったときに、Emacsでメモをとっていると画像の挿入がひどく面倒である。ファイルをどこか決まった(mdファイルを置いているディレクトリなど)場所にコピーして、そのファイル名をコピーしてEmacsに貼り付けて、Markdownの画像記法のための記号をチマチマ入力しなければいけない。

書いていくとほかにもきりがないが、汎用のツールではやはり自分のやりたいことを最短経路で完了させることができないストレスがあって、毎日コツコツ続けるためにはそういうストレスが最大のブロッカーだった。

そんなわけで、そのブロッカーを解消するために重い腰を上げて、日々のメモをとるためのGluentというツールを自分で作り始めた。 Sinatraアプリとして実装されていて、ファイルを作成しようとすると日付でデフォルトのファイル名がはいっていたり、Markdownのライブプレビューが表示できたり、カンマ・ピリオドの句読点変換ができたり、Markdown記法の入力補完がきいたり、編集中に自動でファイル保存してくれたり、ワンクリックで定型コミットメッセージでgit commitしてくれるなど、とりあえず自分の必要な機能を詰め込んであって、これを作ってからわりと快適に毎日メモをとることができるようになった。

f:id:hayamiz:20150405184157p:plain

編集画面はこんな感じ。テキストを選択すると文字数を下のステータスラインに表示したりとか、地味な機能もある。 textareaにファイルをドラッグ&ドロップすると、mdファイルを置いているディレクトリにファイルをアップロードして、markdown記法をtextareaに挿入してくれるなどの機能もある。

最近はWebサービス+ネイティブアプリ提供の場合でも、中身はHTML5で出来ていてガワだけ変えるみたいな話もあるけど、フロントエンドのことを割と何もしらない自分でも、UIを手軽につくるのは割と簡単にできるようになったもんだということを、こういうツールを作ってみると実感することができる。

そういう体験でいくと、某艦隊擬人化ゲームをプレイしていた時期は、クライアントが通信しているJSONをキャプチャして、現在の艦隊の情報をダッシュボード化するときにAngularJSを使った時にも、随分簡単にデータを反映したUIを作れるようになったもんだと関心した。

f:id:hayamiz:20150405185037j:plain

これを作ったのも、現在自分が持っている資源の把握とか、遠征から帰ってくる艦隊のキラ付け状況の把握とか、やっときゃいいのはわかってるけど面倒みたいな問題を解決するために、仕方なく自分専用ダッシュボードを作ろうと思ったのがモチベーションだった気がする。 おかげで割と快適にプレイしていたけど、あるときLinuxのブラウザがどれを使っても、ログインした後のローディング画面から先に進まなくなってしまったのでプレイしなくなってしまった。

計算機での性能測定実験と集計の手法について、あるいはただの愚痴

計算機を使った性能測定実験プログラムを実行して、集計するという処理をどこまでパターン化出来るかというのを、この数年、たまに考えている。が、なかなかこれだ、という答えにたどり着けるわけでもなく悶々としている。

このエントリは、その悶々とした気持ちをただ吐き出すためのものである。

この春でいまの研究室にきてから丸々6年になるので、この6数年ずっとデータベース研究をしていて、実験の作業として結局やっているのは、色んなプログラムの実行性能を測っては分析するということの繰り返しになる。

基本的には特定のプログラムを色々条件を変えながら何度も実行して、その結果をまとめることになる。大抵1回の実行時間は短くても数分、長い時には数時間で、それを何度もパラメタを変えて繰り返すので、結構長時間の実験になる。

当然パラメタを変えながらプログラムを繰り返し実行する部分は自動化することになる。 そのときに、自動化を実現する手段が悩ましい。

最も手軽なスタートポイントとしては、まずはシェルスクリプトのベタ書きだろう。 パラメタが複雑でない場合、適当にシェルの配列に値を書き込んでおいて、それをループで回してやればよい。 例えば次のようになる。

PARAM_LIST=(a b c d)
for param in ${PARAM_LIST[*]}; do
  ./test_program $param
done

このくらいはまあ簡単で、悩みようがない。

しかし、単にプログラムを実行するだけではいけない。自分は実行性能を計測したいのだ。例えば、データベースだと次のような項目を測定したい。

  • 実行に何秒かかったのか
  • CPU使用率の全体の平均や、時間による推移
    • 更にコアごとの使用率の違い
  • I/OのIOPSやスループットの平均、時間による推移

これを見ようと思うと、例えば sar -o perf.dat でデータを取得して、sar -d -f perf.dat で毎秒のI/O性能、sar -P ALL -f perf.dat で各CPUコアの毎秒の使用率を表示させることができるので、その値を加工すればできる。 が、出力がユーザに読みやすいように整形されている分、シェルスクリプトでパパっと集計するには都合がよくない。 さらに、sarを始めとしてsysstat系のiostatmpstatといったプログラムは大抵1秒間隔でしかデータを取れない。サービスで運用しているサーバはそれでよいだろうが、こちとら超高速なシステムの研究をしていたりするので、それでは話にならない。例えば、最初の0.1秒で一気に並列なタスクが立ち上がるのか、0.5秒かかって立ち上がっているのかでは圧倒的に話が違ってくるのである。

というわけで、これらの測定を極めて細かい間隔で測定できるようにperfmongerというツールをこしらえた。 1つのコマンドを実行して、その実行時間や諸々の性能情報を記録するには次のコマンドを叩けば良い。

perfmonger stat --logfile perf.dat --interval 0.1 -- ./test_program

この例では、0.1秒間隔で計測結果を perf.dat に保存している。結果のサマリを見たい場合には、次のコマンドを叩けば良い。

perfmonger summary perf.dat

そうすると、実行時間や、CPU使用率の平均値、各ブロックデバイス毎のI/O性能の平均値などを表示してくれる。

perfmonger summary --json perf.dat

とすると、JSON形式でサマリを出力してくれるので、サマリの値をあとから集計する用途にも良い。

さて、話を実験の自動化へ戻そう。 perfmongerのおかげで計測の作業は極めて単純化されたので、実験を流すスクリプトは次のように書くことができるようになった。

PARAM_LIST=(a b c d)
for param in ${PARAM_LIST[*]}; do
  perfmonger stat --interval 0.1 --logfile perf.$param.dat -- ./test_program $param
done

これで実行すれば、パラメタの値を a、b、c、d と変化させてプログラムを実行し、それぞれの結果が perf.a.dat、perf.b.dat、perf.c.dat、perf.d.dat に保存される。 あとはこれを perfmonger summary などを使って集計していけばよい。していけばよい、といってもそれはそれで面倒な問題があったりするが、ここでは一旦おいておく。

ところで、研究とは「未だ知らぬこと」を明らかにしていく作業である。未だ知らぬからこそ、観測するべきパラメタが a b c d の4つで十分かどうかも分からない。むしろパラメタを何度も変えながら、観測するべき空間に当たりをつけ、さらに注意深く調べるべき部分では細かくパラメタを変化させながらより詳細に分析を進めていくことになる。

つまり、上記のプログラムは、PARAMS_LIST を変えながら何度も実行することになる。

さらに、スクリプトを走らせながら色々考えていると、パラメタa、b、c まで測定が終わったところで、パラメタ c を与えたケースにのみプログラムにバグがあることが見つかったりする。 そうすると、再度実験を走らせ直してやる必要がある。一旦実行をとめて、デバッグし、PARAMS_LIST=(c d) に書き換えて実行する。 これで perf.a.dat、perf.b.dat、perf.c.dat、perf.d.dat が全部出揃ったので、結果を分析してみるとどうもおかしい。やや、プログラムにまたバグがあった。測り直し。

みたいなことをやっていると、perf.*.dat のどのデータは生きていて、死んでいるのかわからなくなってくる。 また、PARAM_LIST を直接何度も変更していると、結局測定に使うべきパラメタのセットはなんだったのかもわからなくなる。

時々刻々と進化していく実験プログラムに対して、それを実行した際の測定結果データが存在するのか、古いプログラムの測定結果データが存在するのか、そして測定に使うパラメタの集合はなにか、これらを管理できる枠組みで実験プログラムの実行を行うことが望ましそうに思えてくる。 あるいは、割り切りとして、毎回フルセットでPARAM_LISTを指定して、実行前に全データを消してしまうという大胆な方法もありうる。

ここで、設計の選択を迫られるのである。

前者のアプローチは、トータルで見たプログラムの実行回数は明らかに最小限にできるであろう。具体的にはMakefileなどを使った実現方法が考えられる。が、シェルスクリプトよりかは一段話がややこしくなり、自動化の部分を組むためにextraな労力が必要になる。 一方、後者は簡単なシェルスクリプトをそのまま使えるので自動化自体にはそれほど手間はかからないはずだ。が、結果を取得しているはずのプログラム実行に関しても何度も繰り返すことになるため、長時間を要するプログラムの実行には不向きに思われる。

この判断は、実際にどんなプログラムをどんな条件で動かすかによって損得が変わってくるので、毎回それを考えるのがダルい。ダルいが、自分の時間は割と貴重な資源なので、実験の全体に要する時間を最小化するために損得の評価を考えてやらねばならない。そこまで含めて自動化できると理想的なのだが。。。

この後にも更に厄介な悩みの種が色々と続くのだが、それはまた後日気が向いたら書くことにする。

よんだものWeekly

先日紹介したtech系Newsletterまとめを中心に、1週間で読んだ記事のなかで面白かったものを一言コメントと共に紹介する試みを始めてみようと思います。

原風景と感性

眺めているとほっと心が安らぐような風景がある。

自分の場合は、田園、里山、少し寂れた商店街、昼間なのにほとんど人が歩いていない町並み。おそらく原風景といわれるものなんだろうと思う。子供の頃に過ごした場所の景色が、象徴的に各人の心に刻み込まれているイメージの重ねあわせみたいなもの。

そういった原風景を眺めているような、じんわりと落ち着いた気持ちになれるアニメで蟲師というのがある。結構前にアニメの1期をやっていて、だいぶ間があいて去年2期をやって、この5月には劇場版が公開されるので、今からカレンダーに入れて心待ちにしている。

で、しばらく前に蟲師を観ていたら、うちの妻に「またあの辛気臭いアニメ見てるの」といわれて、ちょっとはっとした。アクションもなければ派手なストーリー展開もないしなんだったらキャラクターもほとんど出てこない、森の中や夜のシーンも多いので色彩的に暗い画面も多い、美しい風景と音が作り出す穏やかな雰囲気を楽しむアニメなので、興味がない人にとっては辛気臭いアニメといって間違いでない。このアニメをみて心が安らぐのか、辛気臭いと思うかの違いはどこにあるのか、ふと気になった。

そこで一つの仮説として浮かんできたのが、原風景に重なるか否かなのではないか、ということ。 うちの妻は東京のど真ん中出身で、話を聞いてみたらどうも彼女の原風景は並ぶ華やかなショップが立ち並ぶ都会的な街並みと、そこを歩く沢山の人達のいる風景らしい。別に緑の多い里山を眺めていても取り立てて心が落ち着くということも無く、むしろ小洒落た都会の街並みのほうが落ち着くらしい。田舎生まれで小学生の頃は山の畑で昆虫を追いかけたり、近くの渓流でイワナやヤマメを釣ったりしていた自分からは想像もつかない感覚だが、幼いころの経験から構築された原風景というのはそのくらい物の感じ方を大きく変えてしまうものであることは間違いないらしい。

逆に、全く自分の原風景と重なるものは無いけれど、蟲師がすごく好きという人がいたら、何をどう感じて好きなのか是非に話を聞いてみたいものである。

特定のトピック着目型の文献サーベイ方法

特定のトピック(分野の中でも特定の問題や手法とその周辺情報)についての文献をサーベイする際に、最近自分がやっている方法のざっくりとしたまとめ。

根っこになる論文を見つける

  • (A) 自分が着目しているトピックの、そもそもの概念を考えだした論文
  • (B) そのトピックが属している研究分野の、最低限押さえておくべき有名論文

をまずは探しだす所から始める。このへんの"根っこ"になる論文を一通り抑えておくと、あとはこれらを引用して派生していった論文のグラフを辿るイメージでサーベイを進めていくことができる。これらを見つけるために派生論文を漁りながら根にたどり着くことになるので、根を掘り当てた後はすでに通った道をバックトラックすることになる場合も多い。

まずは注目しているトピックそのものの源流である(A)を探すところから始めるのがよい。既に具体的にこの論文、という文献が見つかっている場合にはこのステップは必要ない。 そうではない場合、話題として興味がある、あるいはこういう研究が過去にやられているはずなのだが具体的にどの論文かは知らない、という状態なので、とにかく広く浅く関連しそうな文献をかき集めていくことになる。 論文の集め方は、大体次のような手順で行っていく。

  • サーベイのメモ用に1つファイルを作っておく
    • Wordでもテキストファイルでもなんでもよいので、1つのファイルに全部まとめておくと情報が拡散しなくてよい
    • 自分はgluentを立ち上げて、Markdownでメモしていくスタイルをとっている
  • Google ScholarMicrosoft Academic Search で関係がありそうなキーワードを思いつくだけ入れて検索
    • 引っかかった論文をリスト化していく。自分はPapersに"seed"フォルダを作って放り込んでいくスタイル。Mendeleyでも同じことが出来ると思う
    • この段階ではそこまで関連が深く無さそうなものでもとにかく収集しておくのが重要
  • "seed"フォルダに収集した論文をフィルタリングしていく
    • フィルタされた論文を放り込む"filtered"フォルダを作る
    • まず関連研究を読み、トピックに関係しそうな論文が引かれていたら片っ端から"seed"に放り込む
    • 次にアブストラクトを読み、トピックに関連しそうなら"filtered"フォルダに放り込む
    • 本文は読まずに捌いていく
    • この際、他に興味があるトピックが出てきてもそっちに寄り道しないよう心がける。そういうトピックはメモ用ファイルに忘れないように記録しておく
  • "seed"を"filtered"に選別していく段階で、よく名前を見かけた著者をリストアップする
    • その著者の名前で文献を検索して、特に"filtered"に入っている論文が書かれた前後数年を中心に更に関連しそうな論文がないか調べる
      • 見つかればその都度"seed"に放り込んで上の手順を繰り返す
    • 計算機科学系だとDBLPを使えば著者の論文は一通り抑えられるので便利
  • "filtered"に入れた論文のアブストラクトとイントロダクション、必要に応じて詳細な内容まで見ながら、"filtered"の中でトピックに直接関係するものと、周辺領域のものとを分別していく
    • "filtered"の中にサブフォルダを作って整理するようにしている
    • 周辺領域が複数カテゴリに渡る場合には、カテゴリ毎にフォルダを作っておくのもよし
    • 本当は被引用数や引用している論文リストなどのメタデータも管理したいが、そういう機能を持っているソフトを知らないので知っている人がいたら教えて欲しい

ここまでやると、着目しているトピックに関連する重要な論文は一通り集まった状態になり、何度か大雑把に目を通しているので、それらが引用している根となる論文が把握できている状態になっているはずなので、それらに印をつけておく。これで(A)の収集は完了。 更に、ここまで収集してきた論文から頻繁に引用されているものが(B)になる。集めた論文リストに対して、引用されている論文リストを被引用数でソートしてくれるような機能がある文献管理ソフトほしい。。

トピックに関する最近のトレンドを調べる

前段で集めた(A)を引用している論文で、最近のもの、とくにインパクトのあるジャーナルや会議で発表されているものを中心にリストアップする。 Google ScholarMicrosoft Academic Searchで、ある論文を引用している文献一覧を取得することができるので、その機能を使うと便利。 応用分野が広がっている技術とかだと、かなり関係のないものまで引っかかったりするので面倒だが、アブストラクトをざっとみて関係しそうなものを一旦リスト化して、さらに関係しそうなものを抽出していくというアプローチで地道に絞り込む。(A)や(B)の論文の著者が書いている論文だと"アタリ"である可能性が高い。

ここまでやると抑えておくべき論文群が手元にリスト化されており、さらにある程度関連度順に整理された状態になっているので、重要そうなものから精読していく。 どういう順番で読んでいくかが良いかは場合によるが、根っこになる古い論文は基本を抑えておく目的で、最近の論文はどういう方向性で論文をまとめるのが有望だと人々が考えているのかを把握する目的で、それぞれ読むことが多い。

論文の精読の仕方

まず、頑張るぞ、と気持ちを高める ← 一番重要

  • サーベイメモ用ファイルに論文タイトル、会議やジャーナル情報、著者名と所属を書く
    • 自分は人の名前がなかなか覚えられないので、できるだけ著者名は手打ちしながらこの人か、と確認するようにしている
  • アブストラクトと序章を丁寧に読み、扱っている問題と、論文のcontributionを把握する
  • 実験結果のグラフを眺める。説明文を読まないと意味が分からない場合もあるが、とりあえずは読まない
  • 結論を読んで、結局何を達成したかを確認
  • ここまで読んだところで、サーベイ用メモに要点を箇条書きでまとめる
  • 内容の詳細を読み込んでいく
    • 一気に全部読もうとするよりも、途中でもその日論文読みに当てられる時間に余裕を残して切り上げて、メモ用ファイルに理解した内容をざーっと書き出していく
    • このあたりのやり方は色々変えながら試している

PapersやMendeleyにもメモ書き機能があるのでそちらにメモを書いていくでも良いのかもしれないが、それだと特定のトピックを想定しながら論文を読んだ時に読み取って理解した内容が分散してしまうので、個人的にはあまりうまく機能しないように感じている。論文は何を読み取るつもりで読んでいるかによって、かなり見え方が変わってくることが多いので、それを軸に情報を1点集中させるのが後々見返した時に有用なように思う。

論文の読み方に関しては、色んな人たちがかなり参考になることを既にWebに公開しているので、それらが参考になるのであまり細かいことはここに書く必要はないかな