2012年8月31日金曜日

cos関数の線形最小二乗法

目的

データ$(x_i,y_i)$が複数($i=1 \cdots n$)与えられたとき、次のモデルのパラメータ$(a,b,c)$を線形最小二乗法により最適化する。

\[ y=a\cos(x + b) + c \]

方法

  1. 加法定理と$a' = a\cos b$、$b' = a\sin b$で変形し、3変数連立一次方程式の形にする。
  2. 平均自乗誤差を最小化する問題として線形最小二乗法の問題として解く。
  3. 求まった最適な($a',b',c$)から$a = \sqrt{a'^2 + b'^2}$、$b = \tan^{-1}(b'/a')$として元の変数を求める。

ソースコード

Jupyter NotebookのipynbファイルをGitHubで公開している.

STEP 1: 加法定理と変数変換でパラメータの線形和に

実際には、データ$(x,y)$には観測誤差が含まれて定式の等号は成り立たないので観測誤差をまとめて$\epsilon_i$と表すと、$i$番目のデータ$(x_i,y_i)$の関係は以下のように表現できる。

\[ \epsilon_i = a\cos(x_i + b) + c - y_i \]

ここでの最適化とはこの全てのデータに対して$\epsilon_i$が小さくなる$(a,b,c)$を探すことなので、その指標として平均自乗誤差$E = \sum_i^n \epsilon_i^2/n$を最小化する。加法定理で変形し、$a' = a\cos b$、$b' = a\sin b$と置くと以下のように変形できる。

\[ \begin{array}{ll} \epsilon_i &= a\cos(x_i + b) + c - y_i\\ &= a\{\cos(x_i)\cos(b) - \sin(x_i)\sin(b)\} + c - y_i\\ &= a'\cos(x_i) - b'\sin(x_i)\ + c - y_i \end{array} \]

STEP 2: 誤差関数を微分する

今、平均自乗誤差$E$を最小化しようとしているので、最適な値$(a',b',c)$では$E$が極値になることが必要条件である。

\[ \frac{\partial E}{\partial a'} = 0,\ \frac{\partial E}{\partial b'} = 0,\ \frac{\partial E}{\partial c} = 0 \]

以下、微分に関係ない定数$n$を左辺に移項して上式を実際に計算する。

\[ \begin{array}{ll} n\frac{\partial E}{\partial a'} &= \frac{\partial}{\partial a'}\sum_i^n \epsilon_i^2\\ &= \sum_i^n \frac{\partial}{\partial a'} \epsilon_i^2\ = \sum_i^n 2\epsilon_i \frac{\partial}{\partial a'}\epsilon_i\\ &= \sum_i^n 2\{a'\cos(x_i) - b'\sin(x_i)\ + c - y_i \}\cos(x_i)\\ &= 2\{a'\sum_i^n\cos^2(x_i) - b'\sum_i^n \sin(x_i)\cos(x_i) + c\sum_i^n \cos(x_i) - \sum_i^n y_i\cos(x_i) \} = 0\\ % n\frac{\partial E}{\partial b'} &= \sum_i^n - 2\{a'\cos(x_i) - b'\sin(x_i)\ + c - y_i \}\sin(x_i) = 0\\ &= -2\{a'\sum_i^n\cos(x_i)\sin(x_i) - b'\sum_i^n\sin^2(x_i) + c\sum_i^n \sin(x_i) - \sum_i^n y_i\sin(x_i) \} = 0\\ % n\frac{\partial E}{\partial c} &= \sum_i^n 2\{a'\cos(x_i) - b'\sin(x_i)\ + c - y_i \} = 0\\ &= 2\{a'\sum_i^n\cos(x_i) - b'\sum_i^n\sin(x_i) + cn - \sum_i^n y_i \} = 0\ \end{array} \]

上記3つの方程式は、パラメータ$(a',b',c)$のみに注目すれば3変数の連立一次方程式である。大学生の線形代数の知識を使って、以下のように行列の式にすれば簡単に解ける。

\[ \left[ \begin{array}{ccc} \sum_i^n\cos^2(x_i)& -\sum_i^n \sin(x_i)\cos(x_i)& \sum_i^n \cos(x_i)\\ \sum_i^n\cos(x_i)\sin(x_i)& -\sum_i^n\sin^2(x_i)& \sum_i^n \sin(x_i)\\ \sum_i^n\cos(x_i)& -\sum_i^n\sin(x_i)& n \end{array} \right] \left[ \begin{array}{c} a'\\ b'\\ c \end{array} \right] = \left[ \begin{array}{c} \sum_i^n y_i\cos(x_i)\\ \sum_i^n y_i\sin(x_i)\\ \sum_i^n y_i \end{array} \right] \]

STEP 3: 変数変換を戻して答えを求める

求まった最適な($a',b',c$)から$a = \sqrt{a'^2 + b'^2}$、$b = \tan^{-1}(b'/a')$として元の変数を求める。プログラム上では関数atan2を使うと$a'=0$の場合分けの必要がない。使い方は以下のとおり(ただし、a_=$a'$、b_=$b'$)。

b = atan2(a_, b_)

2012年8月22日水曜日

折古の浜

折古の浜の思い出

私は子供のころよく親に連れられて折古の浜に海水浴をしに行った。夏休みはおじいちゃんのいる因島で過ごすのが定番だった。海水浴が一番の遊びだった。折古の浜だ。折古の浜までは家から歩いて行かねばならない。車のとおる大通りをとおって、細い道を左折すると右手にお宮さん下の公園、左手に井戸の手押しポンプがある。正面の冷んやり涼しいトンネルを抜けると海が見え、子供たちのキャーキャー言う声が聞こえてくる。小さな浜だけど子供と大人で結構いっぱいになったものだ。

海水浴場の真ん中に水面からわずかに頭を出す赤い飛び込み台があり、ここから飛び込んだり、潜って飛び込み台をくぐり抜けたりして遊んだ。浜にはブランコが設置されており、満潮の時はブランコを思いっきり漕いでそのままジャンプすれば海に飛び込むこともできた。

海水浴からの帰りは、必ず同じ道をとぼとぼ歩いて、井戸で塩気を落とす。井戸水は冷たかった。体が小さく冷えやすかった自分はこの井戸水を背中から浴びるのはあまり好きではなかった。それでもポンプの棒を上下に動かして水を流すのは面白かった。ここで綺麗に洗っても、帰り道は濡れたビーチサンダルが道路の砂を跳ね上げ、足の甲とビーチサンダルの鼻緒の部分の隙間に入るからピリピリと痛かった。

子供時代の夏休み一番の思い出と言えばお父さんとお姉ちゃんと、この折古の浜で遊んだことだ。さんざん遊んで夏の暑さをしのぎ、家に帰ったら畳で昼寝するのだ。クーラーなんかなくてもなんとなく涼しい。

ゴミだらけになっていた折古の浜

大人になって折古の浜を訪れてビックリした。真夏だというのにブランコも飛び込み台もなくなっており、浜はゴミだらけになっていた。そういえば島で子供の姿を見ない。日立造船の撤退が原因か、少子化なのか?そもそもこの浜を利用する人が殆ど居なくなってしまったのだとか。とにかく島全体が廃れてしまった上に、なぜか交通量もそんなに多くないはずの道路がビックリするほど広くなってしまっていた。

田舎っぽい雰囲気が良かったのに・・・中途半端に便利にしようとしてもダメなんじゃないか。どうろを広くしたって経済が活性化する訳じゃない。田中角栄以来の通り一遍の政治が、因島の古き良きまでもダメにしてしまっているように感じた。「どうろを通せば国が豊かになる」、「公共事業をやれば経済が活性化する 」いうことが、いつまでも成り立つわけないことくらい、これまでの失敗例で分かっているはずなのに・・・・一時的な票欲しさに政治家が土建の幸せのみに最適化された行動をとってしまうのだろう。本当に大事な物を失ってしまった気がした。

問題は若者が島を出たがること

根本的な問題は島に、若者が居なくなっていることだと思う。少子化で相対的に少なくなるのは、仕方がない。国家レベル、もしくは世界レベルの課題だから。しかし、日本の若者が東京ばかりに行ってしまうことくらいは、食い止めれないものか。島に仕事なければ、出ていかざるをえない。その結果、優秀な人材は都会にでてしまい、優秀でない人のみが残る。その中から市長だの、町長だの選出しても良くなるはずがない。道を作れば経済がよくなる、ありもしない天守閣の水軍城を作れば観光客があつまるなどと騙されて、バカをやってしまうのだ。そして、大事な大事な因島の良さを失ってしまう。その結果、魅力はなくなり若者は出てゆき、悪循環は続いてゆくのだ。

似たような現象は高度成長期どこの田舎でも起こった。どれだけ多くの人の収入が倍増しても、自然と向き合う一次産業の収入は上がらない。その結果、田舎から都会へと人が流れたのだ。
そして、この成長がとまったとき、もぬけの殻になっていた。私は因島の折古の浜でそれを見たのだ。ショックだった。なぜ、そうなったのか考えた。瀬戸内海の海砂を大量に採掘しているから、浜の砂がなくなり人が減ったのだとか、護岸工事で水が汚くなってしまって人が減ったのだとか、色々聞いた。しかし、それは本質ではないだろう。必要とされていれば汚くなれば浄化しようと、砂が減らないようにしようと、人が動いただろう。そうではなく、そもそも、使いたいと思う人が居なくなってしまったのだ。色々考えても行き着く先は、島の問題ではなく、国家をどうすべきなのかとい根本的問題になる。

因島の問題ではなく、国家システムの問題だ

つまり、折古の浜がひと気のないゴミだらけの浜になってしまった根本的理由は、砂の流失やがけ崩れなどではない。人が都心部に集中して生活せざるをえない社会システム、つまりは国家そのもののあり方の問題だと思う。経済の問題というより国家ビジョンの問題だ。この国がどこえ向かうべきなのかという。

では、高度成長した日本を逆行すべきなのか?そうは思わない。高度成長は、技術力を中心に様々な不便を便利にしてくれた。高速道路のお陰で全国どこでも車一台あれば自由な時間に行けるようになったし、何よりもひもじい思いをすることもなった。しかし、これまで便利だけを求めてきたおかげで、既に十分便利になってしまった今、一所懸命お金を稼いで購入したいというものも無くなってきたのではないか。高画質のテレビが売れない理由は分かる。白黒がカラー化したときの感動はすごかっただろう。しかし、カラーテレビが多少高画質化しても大したインパクトはない。

では、どうすればいいのか?経済成長すれば田舎が廃れるし、そうでなければ不便な世の中に逆戻りだ。既に便利になってしまった今、何も国民全体が活動意欲を持つような向上は望めないのか?私は、これに対して一つのアイデアがある。もっと成長すべきだと思う。今足りないものは便利ではなく、豊かさである。高速道路は出来た、新幹線はできた、テレビも車も買った。でも、この汚くなった世の中に皆満足しているか?便利さに加えて我々が満足できる美しさ豊かさを求めるべきではないか。

便利さだけではなく、豊かさを

高速道路のお陰で山の風景は台無しだ。東京も、大阪も便利だがゴミゴミしてる。ヨーロッパに行って思った。なぜ街並みが綺麗なのだろうと。それははなから見た目を意識してデザインされているからだ。便利さよりも豊かさが重視されている。日本は違う。便利優先でデザインされている。全て。だから、ちぐはぐで汚らしい。田舎に帰れば、高度成長以前の姿が残っていることがある。とても綺麗だ。古い家は自然と調和しており、街並みも統一感がある。これこそ豊かさではないかと思う。

高度成長期、祖父、父親の世代が、戦争で失った便利さだけをひたすらに求めて、技術力のみを頼って、便利な世の中を作り上げてくれた。これからは、技術と芸術だと思う。同じ高速道路を作るにしても、日本固有の自然の風景にマッチしたデザインにすべきではないか?街並みも、我々の服装も、すべべの人の美的感覚が向上するくらい、国家政策として芸術に力を入れるべきではないか?技術を軽視するのではない。技術と芸術、これを両方強化するのだ。そして、我々の価値観がやがては単なる便利追求だけから、豊かさの追求が加われば、そこに向けて国民の行動力が注がれることになる。インターネットがありとあらゆるものを変えつつある。その場に居なくてもできる仕事も多い。田舎に居ながらにして、今まで行なってきた仕事が出来れば、便利さと豊かさを両方得たことにはならないか。技術を使う方向性をそういう方向に向ければいいのではないかと思う。

後で知ったのだが、驚くべきことに高度成長もとになった所得倍増計画を立案した本人、当時の役人下村治がすごいことを言っている。

「経済的に高い水準を達成したうえでのことだが、ゼロ成長の日本は江戸時代のような姿になるのがいい。経済の後には文化とか芸術とか教養に力を入れる時代になるべきじゃないのかな。」

なななんと、既にこれを予言していたのだ。便利になってしまったら、経済成長が難しくなることまで見越して、次の策を述べているのだ。こういう先を見越す考えが今の政治家に全く無い証拠に、民主党も自民党も震災をきっかけにして、国土強靱化などと称して、また50年前と同じ事をやろうとしてる。今度は安心だそうだ。安心という消極的なキーワードでどれだけの人が動くのか疑問だ。

私たちは、そろそろこの国家のありかたをもう一度一から考えなおさないといけない。

2012年8月10日金曜日

has_binary_operator.hppでwarning C4819が大量発生

boost 1.50を使うとファイルboost/type_traits/detail/has_binary_operator.hppの文字コードの問題でこの警告が大量発生する。

boost/type_traits/detail/has_binary_operator.hpp : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。

問題は、このファイルの34行目。しかし、文字コードがダメなのかVisual Studioのバグなのか良くわからない。Visual Studio 2010で開くとこのように一見問題無さそうに見える。

//    warning C4547: '*' : operator before comma has no effect; expected operator with side-effect

Terapadで開くと「'*'」の次が文字化けしているのが分かった。

//    warning C4547: '*'?: operator before comma has no effect; expected operator with side-effect

これを別のスペースで上書きして対処した。

2012年8月7日火曜日

OpenCV(C++) 超々々入門

ヘッダファイルやライブラリの指定方法,画像のロード/セーブ,行列の操作方法のみに絞ってメモ書き.

Visual Studioのプロジェクト:
https://github.com/r168xr169/ForOpenCvSuperBeginner

インクルードファイルとライブラリ

正しくインストールされていればインクルード方法は至って簡単.

#include <opencv2/opencv.hpp>

ただし、ライブラリは使う機能に応じて指定する必要がある. 例えば下記のサンプルコードで使用されているimreadという関数は, OpenCV3.1.0ではopencv_imgcodecs310.libというファイルの中で実装されてる このライブラリを指定するためにVisual Studioではソースコード中に次のマクロを追加すればよい.

#pragma comment(lib, "opencv_imgcodecs310.lib")

しかし,単純なOpenCVのプログラムを書くだけでも複数のライブラリが必要なので上記方法で全部指定するのはかなり面倒. 今のところ このヘッダファイルを インクルードし必要なライブラリに対応する行だけコメントを外すのが今のところ一番簡単な方法.

画像のロードとセーブ

//ロード
cv::Mat_<cv::Vec3b> img_rgb = cv::imread("img000.png");

//セーブ
cv::imwrite("output1.png", img_rgb);

画素の参照、画素への代入

//画素(i, j)のrgb値を変数に代入
cv::Vec3b rgb = img_rgb(j, i);

//画素(i, j)のr値を変数に代入
uchar r = img_rgb(j, i)(0);

//画像(i, j)に色(0, 100, 200)を代入
img_rgb(j, i) = cv::Vec3b(0, 100, 200);

行列の初期化

cv::Mat_のinitializerを使う

意外と知られていないが便利な初期化機能.

//cv::Mat_の初期化機能
cv::Mat_<double> mat_ = (cv::Mat_<double>(3, 2) <<
    1.0, 2.0,
    3.0, 4.0,
    5.0, 6.0);

//cv::Matもcv::Mat_を介して初期化可能
cv::Mat mat2 = (cv::Mat_<double>(3, 2) <<
    1.2, 2.3,
    3.4, 4.5,
    5.6, 6.7);

配列のポインタに直接アクセス

配列の先頭ポインタdataを使って値をダイレクトに書き換えることも参照することも簡単.OpenGLのglTexSubImage2Dなど直接配列のポインタを渡さないと行けない場合など.
//memcpyでコピーしてしまう
cv::Mat_<cv::Vec3b> a = cv::imread("img000.png");    
a.data[0] = 0;
a.data[1] = 0;
a.data[2] = 255;

詳しくは