luggage baggage

Machine learning, data analysis, web technologies and things around me.

多変数クラメル・ラオの不等式の証明(フィッシャー情報量の意味づけの一つ)

統計学の分野で、クラメル・ラオ (Cramer-Rao) の不等式と呼ばれる有名な式があります:
\begin{equation}
V(t(z)) \geq \frac{1}{I(\theta)}.
\end{equation}ここで  z は確率変数で、一つのパラメータ  \theta で指定される確率分布  f_{\theta}(z) に従って生成されると仮定します。 t(z) は不偏推定量、 V(t(z)) はやはり確率変数である  t の分散、そして  I(\theta) はフィッシャー情報量です。不偏推定量とは、その期待値が  \theta に一致する、つまり「偏りのない」推定量のことです。最後にフィッシャー情報量とは  I \equiv -E[\partial_{\theta}^2f_{\theta}] で定義されるある種の「推定の良さ」を示すような量です( E は期待値を取る演算)。

クラメル・ラオの不等式によれば、不偏推定量の分散には下限が存在し、それがフィッシャー情報量の逆数に一致します。 I(\theta)が大きければ大きいほど不偏推定量の分散は小さくしうる、つまり期待値まわりでより狭い範囲での(=良い)推定ができるようになる、ということですね。

ところで、ここで書いた式は確率分布関数のパラメータが1次元の場合です。これが多次元になった場合でも同様の式がもちろん成立するのですが、その証明が意外と手元にある本に書いてなかったので、簡単に証明を残しておこうかと思います。

続きを読む

julialang でカルマンフィルタを書く

最近カルマンフィルタの勉強を少ししており、行列を含む数式を素直にプログラムできる言語があるといいなと感じていました。Python を長年書いてきたものの、毎回 numpy.array を用意したり numpy 関数を呼んだりするのが少し面倒になってきました。

そこで今回は、scientific computation に強みがあると言われ、最近 v1.0 の出た Julia 言語(julialang)を使って簡単なカルマンフィルタを実装してみたいと思います。julialang は数日前に使い始めたばかりなので、パフォーマンス最適化などは考えずにやっていきます。

続きを読む

multiprocessing で tfrecord 作成を高速化する話

お久しぶりです。

TensorFlow でモデル学習をする際、便利に使われるのがtf.dataAPI です。以前はtf.contribで提供されていましたが、非常に使い勝手の良い機能だったこともあり、現在は独立したモジュールとして存在しています。様々な形式のデータ入力に対応している中でも、公式に推奨されているのは
.tfrecordというバイナリ形式のデータを読み取るtf.data.TFRecordDatasetだと思います(むかしの Caffe でいう LMDB みたいなやつ)。

私はいま画像認識系の仕事をしているのですが、先日扱った画像は百数十万枚ほどあり、一枚一枚も10数MBと小さくはなかったため、単純に tfrecord を作成すると30時間以上もかかる状態でした。この記事では、その時に使った非常に雑な高速化手法をご紹介していきます。CPU 数が稼げる環境であれば、10倍速とかは十分に達成できる感じでした。

続きを読む

Python 機械学習コードを Cython でラップして C/C++ から使う

お久しぶりです。吉田弁二郎です。

Cython という便利なトランスパイラ(言語と言語の中間にある言語のようなもの)があります。Python ライクな文法で書ける Cython スクリプトは C/C++ コードに変換・コンパイルされた後に Python から呼び出し可能で、C/C++ ライブラリを Cython スクリプトから呼び出すことも難しくないので、Python ライブラリの高速化作業を効率良くおこなうためによく使われています。

著名なプロジェクトで言うと scikit-learn や pandas だったり、最近利用が広がり始めた cupy などで Cython が使われています。scikit-learn の例で言うと、例えばツリー系のアルゴリズムを実装したこのスクリプトは Cython によるものですね。

また逆の方向として、Python で書いたライブラリを C/C++ コードから手軽に呼び出したい、という時にも Cython を使うことができます。双方向のラッパーとして機能するのですね。今回の記事では、この方向で Cython を使うための簡単な例を紹介していきます。Cython の文法については詳しくは書かないので、ドキュメントもしくはデモコードなどを見ていただけるとよいと思います。

続きを読む

Python の defaultdict には注意しよう

こんにちは。

Python には標準的なデータ型に加えていくつかの便利な型が用意されています。特に collections モジュールには、以前記事に書いた deque や、今回取り上げる defaultdict が格納されています。

通常、辞書型のデータ d にデフォルト値を設定しながら値を詰めていく場合、d.setdefault(key, default_value) といったやり方をするのではないかと思います。このようにしない場合は、例えば d に保存されていないキー k で辞書にアクセスしてしまうと、KeyError が出てしまうのですね。

同様の用途で、より柔軟かつ(おそらく)高速な処理が実現できるのが defaultdict です。

続きを読む

SQLAlchemy + PostgreSQL で Upsert を行う(ユニークキーに重複があるデータのバルクインサート)

こんにちは。吉田弁二郎です。

タイトルにある Upsert とは、Update or Insert のことです。あるテーブルにデータを insert しようとするとき、ユニーク制約が効いているキーが過去データのものと重複して insert できない場合、update に切り替える処理のことですね。データ量が多くキー重複の懸念がある状況で multiple insert したい場合などに有効な手段の一つです。

私はよく PostgreSQL を使うのですが、Python 経由で操作したい時には psycopg2 とか SQLAlchemy を選ぶことが多いです。特に SQLAlchemy はオブジェクト的にデータベースを操作できるため、web アプリを開発する時に使っています。

今回は、PostgreSQL 9.5 以上で利用可能な upsert 構文 ON CONFLICT ... DO UPDATE を SQLAlchemy (>= 1.1) から使う方法について書いていきます。

続きを読む

Python のリスト操作は collections.deque が速い

こんにちは。吉田弁二郎です。

先日タスクスケジューラを Python で実装することがあり、深さ優先探索の方針で作業を進める必要がありました。その際、リストの先頭からデータを取り出し先頭にデータを入れる、ということをやったのですが、デフォルトの list ではなく collections.deque を使うと遥かに効率的に動作することを知ったので共有したいと思います(かなり旧聞にあたる内容ですが、ご容赦ください)。

続きを読む