嫁の顔忘れてもTimecop.returnは忘れないでねという話

夜釣りでは初心者向けの狙い目といえばアナゴなんだそうです。岸壁で釣れちゃうんだとか。ウナギはお高いのでアナゴで一杯、とかあるんだろうか。
さて、Rubyでいろいろ開発していて時間(時刻・期間…)が絡むテストをするときTimecopが便利で広く使われます。
travisjeffery/timecop – GitHub

# 現在時刻を変える
> Timecop.travel(Date.parse('1998/12/1'))
=> 1998-12-01 00:00:00 +0900
> Date.today
=> Tue, 01 Dec 1998
 
# 時間の進行を止める
> Timecop.freeze(Time.parse('1998/12/1 0:00:00'))
=> 1998-12-01 00:00:00 +0900
> sleep(10)
> Time.now
=> 1998-12-01 00:00:00 +0900  # it's still 0:00:00
 
# 時間の進行を早める
> Timecop.travel(Time.parse('1998/12/1 0:00:00'))
> Timecop.scale(3600)
> sleep(2)
> Time.now
=> 1998-12-01 02:00:19 +0900  # it took 2 hours although only slept for 2 seconds

便利ですね。
時間をいじくるので、

  • タイムゾーン周りをミスってないか
  • DBMSのタイムスタンプやredisのexpireのようにruby処理系の時間を使わないものでは効かない

こんなかんじで注意が必要なのは当然なのですが、一番しんどいのはTimecopで変えた時間を戻し忘れたときの挙動不審なかんじでしょうか。
テストでTimecopを使う場合、このテのミスをするとたいてい別のテストケースに影響しますね。順序依存で効いてくるし煽りを食ったテストケース自体は何も悪く無いことがほとんどなので、心神耗弱状態になります。

  • なぜかCapybaraのCookieが取れなくなっている
  • redisではうまくいくのにredis_mockでテストすると想定外の挙動になる
  • Timeoutが狂う

こんなことで時間をムダにするのはあほらしいので、Timecop.returnを呼ぶのは絶対に忘れないようにしましょう。

> Timecop.travel(Time.parse('1998/12/1 0:00:00'))
> Timecop.return
> Date.today
=> Sun, 20 Dec 2015

「忘れないでね」「気をつけてね」はものごとの解決策としては最悪な思考停止なので、
Rails/RSpecをお使いなら、spec/spec_helper.rbにて

config.after(:each) do
  Timecop.return
end

なる設定をしておくべきです。
また、別の安全策として、Timecopのsafe_modeといい、Timecopを使うときはblockを与えることを強制し、block末尾でreturnが自動で行われるようにする仕組みがあります。
blockを渡さずに呼ぶと例外が飛ぶので、すぐに気づきます。

> Timecop.safe_mode = true
> Timecop.travel(Time.parse('1998/12/1 0:00:00'))
Timecop::SafeModeException: Safe mode is enabled, only calls passing a block are allowed.
...
> Timecop.travel(Time.parse('1998/12/1 0:00:00')) do
>   Date.today
> end
=> Tue, 01 Dec 1998
> Date.today
=> Sun, 20 Dec 2015

Rails/RSpecのみで使うなら、spec_helperのafterでケアするのがシンプルにして安全十分かと。
テスト以外でも使うなら、safe_modeにするようinitializerなどで設定しておくほうが安全そうです。

全部Githubに書いてあるんですけども、1ヶ月近くこれにハマってしまった自分が本当にあほらしかったので忘れないように…。

第29回関東CV勉強会でSelective Search for Object Recognitionを紹介してきました

初ガツオの季節です。都会なので目に青葉は映りません。山などないのでホトトギスもいません。テッペン原稿カケタカ!

さて、仕事がらComputer Vision的な活動はぜんぜんできていなかったこの1年でしたが、年明けたぐらいから気持ち的にも余裕ができてきたので、ちょいちょいと遊んでいました。
そして先日開催された関東CV勉強会で、かなりひさしぶりに外で専門分野のお話をさせていただく機会をいただき、検出界隈では有名と思われる手法Selective Search(*1)(*2)について紹介してきたので、簡単に振り返ってみたいと思います。

勉強会情報

Continue reading

ndarrayとPySideのQImageとの相互変換

魚類はあまり変態しない(生まれた姿のまま大きくなる)ことが一般的で、カレイなどのように左右対称形から非対称になる…など、昆虫や両生類のそれに比べると控えめな程度にとどまるようです。

さてnumpyと愉快な仲間たちにおいて画像はndarrayとして表現されていて、それを表示するのに使うmatplotlibはちょっとしたGUI機能(widgetsモジュール)をもっています。
ただこれコード的にも絵的にもクセが強くごく単純なデモ以上のことは難しいので、何かしたいときはQtのPythonラッパーであるPySideを使っています。

んで、そのPySideで画像はQImageで扱われるので、裏っかわでndarrayで処理をしているならそれをQImageとの間で相互変換できる必要があります。

そのやり方はこちら。

(参考: python – QImage to Numpy Array using PySide – Stack Overflow

画素毎にループしてコピーするとかイケてないことしなくて済むから簡単だね!
QImageに持ってきてしまえばQPixmapにしてQLabelに突っ込んで表示するなりQPainterでお絵かきするなり、自由です。

2行N列のndarrayを一発で(1行目≦2行目)にするnumpy芸

各国における国民1人当たりの魚の年間消費量をランク付けすると、1位はモルディブなんだそうです。土地柄を考えると妥当な結果と言えそうで、6位の日本の2倍以上です。

Numpyにて、行同士の大小関係を強制したい、つまり「2行N列のndarrayがあるんだけど、各列ごとに、常に1行目の値が2行目よりも小さい値を取る必要がある」「そうでない列の値を強制的に上下交換させたい」という状況に遭遇しました。
生ループ回してひとつひとつチェックしては…とやってもいいんですが、それをPython側でやっていてはパフォーマンス上どうかなということで、Numpyのインデクス芸・スライス芸・ブロードキャスト芸あたりを駆使してやってみました。

もちろん、N行2列のndarrayの列間の大小関係を統一するのも同様に可能。

インデクシングなどの詳細の説明はここではしません。
日本語であればこのあたりがわかりやすそう(まだ見てない)。

性能やいかに?

Benchmarker.pyを使って、実行時間を比べてみました。
比較対象は、まぁ何も考えずに書くとそうなりますわな、というような雰囲気のコード(だとおもう)。
#ところで標準の時間計測モジュールtimeitが最高に嫌いなんだけどあれなんであんなふうになってしまったのかな。。。

こちらが実行結果。
proposedが本記事で紹介した黒魔術、conventionalがシンプルな方法。

##                             real    (total    = user    + sys)
col-proposed                 3.6327    3.6200    2.8100    0.8100
row-proposed                 3.6977    3.6900    2.8700    0.8200
col-conventional            49.9127   49.8600   49.7600    0.1000
row-conventional            51.3075   51.2600   51.1600    0.1000

だいたい14倍高速ですね。
メモリ上では行オーダーで格納される都合上、row-*とcol-*の間で速度差が出るのかなと思いましたが、たかだか2行/2列なので、関係ない模様(σが未知なのでなんともいえませんが。。)。

Pythonの高速化の鉄則は『生Python書くな』に尽きますが、それが改めて示された形になりましたとさ。

ただこのようなコード、後から読んだり他人に読ませたりするのはとても困難なので、あまり多用しないようにしましょう。

matplotlibやskimageのimshowとかでウィンドウが全く表示されないならbackendを変えてみよう

サメはいわゆる魚類(分類学的には魚類というのは無いんだそうですね)に含まれますが、普通に「さかな」と言ってイメージするような魚を指す場合、「硬骨魚綱」と呼ぶとだいたい一致するんだそうです。サメやエイは「軟骨魚綱」になります。ただし、タツノオトシゴも硬骨魚綱に含まれます。

さて、matplotlibやskimageなどを使っていて、どんな描画結果をウィンドウに出そうとしてもでないとき。
X周りはちゃんとしているのに、例えばこんなコードを実行しても、ウィンドウが表示されない場合。

import skimage.io
img = skimage.io.imread('/path/to/image.png')
skimage.io.imshow(img)

Render backendを疑ってみてください。
matplotlibが何をベースに描画を行っているかにより、絵の質や出力方式や出力先が変わります。
現在のRender backendを調べてみましょう。

>>> print matplotlib.get_backend()
agg

無印のAGGは、画面への出力には対応していません。
このようなbackendsを、”noninteractive backends”と呼んでいます。

Here is a summary of the matplotlib renderers (there is an eponymous backed for each; these are non-interactive backends, capable of writing to a file):
Usage — Matplotlib 1.4.3 documentation

ということで、画面への出力にも使えるもの”interactive backends”をrender backendにしてしまいましょう。
backendの変更はスクリプト内でもできますが、ホントに最初にやらないといけないので面倒です。
そこで、デフォルト設定を変更してしまいます。

matplotlibの設定ファイルを探し出します。例えばpyenvを使っていたら下記のようなかんじで出力されます。

>>> matplotlib.matplotlib_fname()
u'/your/home/.pyenv/versions/2.7.9/lib/python2.7/site-packages/matplotlib-1.4.2-py2.7-linux-x86_64.egg/matplotlib/mpl-data/matplotlibrc'

で、このファイルを書き換えます。

 - backend      : agg
 + backend      : Qt4Agg

interactive backendであれば何でもOKです。Aggがついてるやつがおすすめです。
また依存ライブラリは事前に入れる必要があります。
例えばQt4Aggの場合はPyQtやPySideが、GTKAggの場合はPyGTKのインストールが必要です。

調べればすぐなんですけども、backendにはinteractiveとnoninteractiveがあり、デフォルトになっている無印AggがGUIをサポートしていないというのがハマりポイントでした。
pyenv環境にpipで入れたわけですが、配布しているパッケージによっては最初からinteractive backendがデフォルトになっていることもあるようです。

Pythonのargparseからzsh補完スクリプトを吐いてくれるgenzshcompでQoLが上がった

タツノオトシゴって、あの見た目なのですが、実は魚類だったんです。なんとなく甲殻類と思っていた。最大の種は30cmを超えるそうで、あの姿でその大きさというのを想像するとちょっとこわい。。

Pythonでは、かなり強力なコマンド引数パーサとしてargparseが使えます。
いろんなオプションをもつコマンドを作ったら、引数の入力も面倒。
ということで、自分の作ったPythonスクリプト専用の補完がzshで効くようにしたいなーと思っていたら、genzshcompというパッケージがありました。

Continue reading

MacからLinuxにssh X11Forwardingする

スズキは出世魚ということで有名ですが、結局何種類の呼び方があるかご存知でしょうか?地方によるようですがなんと4〜5種類。上には上がいて、ボラは6種類。おぼえきれんわ!

さて、MacからLinuxなPCにX転送でsshしたいときの設定、ググればすぐわかるのですが自分の備忘録がてらにメモ。

前提として、普通にLinux同士でのSSH XForwardingまではできてると想定します。
(入り先のsshd_configのX11Forwardingをyesに)

Mac用X端末XQuartzの導入

MacではXが動いてないので、導入する必要があります。
brewでは入れられない模様。

XQuartz download

ダウンロードしてインストールしてください。

これでOK!

% ssh -X foobar@hoge.jp
$ DISPLAY=localhost:10.0 chrominum-browser

高速化Tips

Macに限ったことではないですがX転送を快適にする設定。

.ssh/configを編集して、

Host *
  Compression yes
  CompressionLevel 9
  Ciphers arcfour256

なる設定を追加すると、結構速くなります。
上2つの項目は説明不要でしょう。Ciphersは暗号化方式で、
How to speed up X11 forwarding in SSH – Xmodulo
等に記述がある通り、arcfour256でかなり高速になります。

イマドキなCUDA 6.5のインストール手順@Ubuntu

現在確認されている深海魚として最も深いところでは8,000メートルを超えるところで見つかったヨミノアシロという種だそうです。8,000メートルって。800気圧って。

さて、CUDAの開発環境の構築は昔から少々面倒で、多少のLinuxの知識と折れない心と英語力が必要です。
自分もこのたびわりと久しぶりに自宅PCにCUDA環境を構築したら、やり方も変わっていて躓いたので備忘録としてメモ。

Continue reading

お名前VPS(2G)に乗り換えたのでUnixBenchしてみた

鯖は青魚の中でも栄養が豊富なんだそうですが、一方で、水揚げしてから腐るまでが速く、食中毒には注意しないといけないお魚なのだそうです。

さて、新しい年も始まったので心機一転、4年間使っていたさくらVPSからお名前VPSに乗り換えてみました。
旧サーバの構成は手動かつアドホックで、記録もなくもはや再現不能な状況であったため、これをイチから見直しAnsibleで構成管理しDockerでアプリをデプロイする・・・というのが一番の目的でした。
いつでもぶっ壊して再構築できるので、これからは年単位で頻繁に乗り換えることになるかなー。
今回お名前VPSを選んだのは、所々のベンチマークの数値が良かったため。

ということで、借りたサーバについてベンチマークをしてみました。

Continue reading

「アジャイルなオフショア開発」というお話を聞いてきた

日本の水産物の最大の取引相手は、輸出入ともに中国(香港を含むとする)なんだそうです。輸入総額が輸出総額の8倍ぐらいあって、やはりあちらは単価が安いからなのかな〜などと愚考しております。

さて、社内勉強会で、GMOの藤村さんをお招きして「アジャイルなオフショア開発」と題してのご講演をいただきました。
タイトル的にはオフショアとアジャイル!?ん!?!?ですが、これが結構たのしかったので、記憶を頼りにメモ。

ざっくり内容

  • 口にすると成就する(かもよ!)

    • なんとかかんとかっていう女優さんが好きだー好きだーと言っていたらとツーショット撮影出来た話
    • 仕事もそうだとおもう!
  • オフショアの歴史。

    • 90年代からのもろもろ
    • トレンドが中国やベトナムやインドを行ったり来たり、今はミャンマーが熱かったり
    • 中国はもはや安くない。政治的な問題もある。インフラや技術力や日本語使えるエンジニアが整っている。
    • ベトナムは親日だし人件費わりと安いし、インフラや技術力や言語ではやや劣るけどバランスがとれてる

      • 今回はベトナムとのオフショアの話。ハノイ工科大学みたいな高度な拠点もあるので。
    • インドは英語的なメリットとか技術力はやっぱ高い。人件費はそんな安くない。

      • なので、やすさではなく技術力を重視したプロジェクトが多そう?
      • 優秀なエンジニアが集まりにくくなってる
    • ミャンマーは安い
  • 今回のお話はベトナムの会社とオフショア
  • できないことを諦める

    • 一回のやり取りで完成品が上がらない→諦める
    • 見積の精度が上がらない→諦める
    • 95%からが長い→諦める

      • 細かい修正にいちいち指示書とか超ダルい
    • そこで、RFCモデルの提案(詳細後述)
  • 研修はしないとだめ

    • 自習に期待するのは甘かった
    • 地頭がよく技術力はあるが実務的なところが弱い
    • 研修は今のところやりっぱなし感ある

      • フォローアップは課題
RFCモデル(僕の理解)

基本コンセプト

  • Request for Commentsではありません。念の為
  • ざっくりしたものを作ってもらう。95%までやってもらう。
  • 残りの作り込み

内容

  • HQ側(受注側、受け入れ担当者)がバックログを準備

    • 仕様をtrelloに書く
  • 作業側がタスクに分割
  • 通常WIP、Reviewと経ていくことが多いが・・・

    • Rough:70%程度の完成度を目指す(作業者サイド)

      • WIP
      • Review(受け入れ側)
    • Fill:95%程度の完成度を目指す(作業者サイド)

      • WIP
      • Review(受け入れ側)
    • Closing:100%にする(受注サイドのエンジニア!これ重要!)

      • つまり、最後の最後の詰めの実装は、持ち帰ってやっちゃう

ポイント

  • R/F/CそれぞれでWIP/Reviewがある
  • 仮定1:Roughは精度の高い見積もりが可能

    • 経験的な知見。(僕も経験的にそうおもう)
  • 仮定2:Roughに実際の作業時間と100%完成度に至る時間との間には固有の定数係数で説明される線形の関係がある
  • そこで、

    • Roughをやる時点でどんぐらいかかりそう?と聞いておく
    • 実際にRoughにかかった時間を測定しておく
    • 実際にClosingまでにかかった時間を測定しておく
    • Roughにかかる時間に対する、Closingにかかる時間の倍率を計算。

      • この情報を、タスクごとに収集しておく。
      • すると、あら不思議、特定の定数に収束してくる(仮定2)
    • そうすると、Roughの見積もりをした時点で、全体の見積もりが比較的精度よく推定できる(仮定1と仮定2の合わせ技)
  • 実際のプロジェクトでは、この係数は3弱に収束しそうであった。

    • つまり、「ざっくりしたもの作るのにどんぐらいかかりそうよ?」→「3日ぐらい?」→「(じゃ全体出来上がるのは8〜9日ぐらいか)」のような。
    • この値はプロジェクトに依存するだろう。

よかったこと

  • 自己組織化

    • 積んどけば勝手にやってくれる状況
    • レビューもお互いにやってくれる状態になったので品質が安定

課題

  • 開発モデルとしてのスケーラビリティ

    • 受け入れ担当者に負担が集中SPoFになる

      • タスクを積むのも、1つのタスクに対して3回以上のレビューをするのも、
    • アジャイルコーチの川口さんより:バックログを積む段階にもボトルネックが存在しそうね。
  • カジュアルに締め切りがブッチされる

    • 遅れるのはいいんですよべつに
    • 何も言わずに遅れられるとしんどいです

その他

  • 手戻りってある?受け入れ側がRoughからRoughに戻したり

    • あるね。齟齬があったりすると
  • 拠点数に対するスケーラビリティはどんな?

    • 試してないけど受け入れ側もチーム化したりするとかあるかも
  • 画面とかデザインとかを伴う場合は?アセットの共有とかは?

    • (聞き取れてない)

思ったこと

  • RFCモデルについて

    • メトリックの計測がだいぶ大事そう
    • タスクあたりのコミュニケーション頻度は増えるはずなので
    • Done is better than perfectであって、Roughでさくっとざっくりしたものを作ってもらうコンセプトは超イイとおもう
  • 今どきオフショアかよ。しかもこんなにがんばってまで。という声は、もっともだそうです

    • 今回のお話の元になったチームはアジアに投げてコスト低減だヒャッハーなザ・オフショアなかんじではなくて、ベトナムの技術的なところに期待してのものだったみたい。

      • なるほど、地域特化型?とでもいうのか、そういう種類のオフショアになってくるのかもな。
      • 受託で丸投げするよりはいいのかも。
      • 個人的に思ったのは、仮にここまでの体制を作れるような環境の会社であって、その国に頼りたい理由がないとすれば、オフショア等に頼らずともいい体制を作れそう。
  • 今日の話で一番自分にとって新鮮というか興味深かったのは、具体的なRFCモデルのことでなく、ひとつの開発モデルの生い立ちから育っているところまでの姿をお話として聞けたこと

    • 僕みたいな若い(若いんだってば)エンジニアにとっては、いろんなモデルや手法っていうのはパッケージ化され提供されたひとかたまりの知識体型としてまず入ってくるものであって、少なくとも最初に知った段階では過去の偉人の考えや屍の山はブラックボックス化されちゃってるんですよね

      • そこからいろいろ工夫だったり肉付けだったりしていくけど
    • なので、こういう風に成長途上なモデルとそれを考えた人の話聞けたのはなんか凄い楽しかった
    • 同時に、あ、こういうモデルを考えだすのって、そんなご大層なものじゃないんだとか思った

      • こんなん自分でも考えられるぜ!って言いたいのではなくて
      • 超頭いい人が美しい理論のもとに弾きだした答えではなく、
      • 僕のような普通の人が苦しみ苦しみ抜いてその時々考えたことを集めて体系化したという意味でなんだかすごい身近に感じた。
      • というか、今自分のチームでも自分たちなりのKAIZENをいろいろしてるし、それをまとめればそれだけでひとつのモデルになるなー