2009/04/25

大学3年の理系が行った、Ubuntu 9.04 Jaunty Jackalopeのアップグレードとメンテナンス



4月から大学3年生になりました。授業の内容が本格的になってきて、しかも事故によってまだ取得できていない前のセメスターの単位があったりとかで、結構大変です。

さて、4/23にUbuntuの新しいヴァージョン9.04 Jaunty Jackalope(軽快なツノウサギ)が発表され、その次の日には日本語版のRemix CDがダウンロードできるようになりましたので、いままで使っていた8.10から9.04にアップグレードすることにしました。その際に、8.10でいろいろアプリケーションやライブラリをインストールしたことによる不都合を起こしていたので、心機一転して一旦パーティションを初期化した後にクリーンインストールを行うという手法をとりました。
9.04が発表されたときは結構盛り上がるかなと思ったんですが、あんまりそのことをブログで書いている人が少なかったので、今回は自分が行ったアップデート作業を書いていきたいと思います。

Ubuntuの環境整理

1.VGAドライバのインストール
これは自動的にUbuntu側が認識してインストールを促してくれるので、特に悩む必要はないです。インストールしたら再起動して、ドライバが正常にインストールされているかを確認します。

2.アップデート・マネージャでアップデートのインストール
今回の場合、9.04の発表直後だったので何もありませんでしたが、通常はここでアップデートを行ってシステムの内容を最新に保ちます。

3.「日本語環境セットアップ・ヘルパ」を使用して日本語環境を整える
インストールしたいソフトを選択して、インストールを行います。Flashのプラグイン、Adobe Reader日本語版、IPAモナーフォントは結構お世話になるので、入れておいた方がいいかもしれません。

4.システムのフォントをIPAモナーフォントからVLゴシックに変更
3.でIPAモナーフォントをインストールするとシステムのフォントが自動的にIPAモナーフォントに変更されてしまいます。これを元のVLゴシックに戻すためにはターミナルを立ち上げて
$ sudo gedit /etc/fonts/conf.d/69-language-selector-ja-jp.conf
と入力。sans-serifとmonospaceの欄を

<edit name="family" mode="prepend" binding="strong">
<string>VL Gothic</string>
<string>IPAMonaGothic</string>
<string>IPAGothic</string>
<string>Sazanami Gothic</string>
<string>Kochi Gothic</string>
</edit>

のようにVL Gothicを先頭にもっていく。保存するとシステムのフォントとしてVLゴシックが使われるようになります。

5.システムの警告音をミュートにする
キーボードの打ち間違えでシステムのビープ音がいちいち鳴るのはとっても鬱々しいので、鳴らないように変更します。ターミナルを立ち上げて
$ sudo rmmod pcspkr
を入力。再起動後も鳴らないようにするには
$ sudo gedit /etc/modprobe.d/blacklist.conf
を入力。末尾に
blacklist pcspkr
を加えて保存します。

6.ホームフォルダの各フォルダを英語表記に直す
日本語でもいいんですが、ターミナルを使うといちいち日本語でフォルダを指定するのがめんどくさいので、英語表記に直します。ターミナル上から
$ LANG=C xdg-user-dirs-gtk-update
で英語表記に変更されます。再起動後はこの名前でいいのか聞かれるので、べつにいいよという感じのボタン(どんなんだったか忘れた)を押して英語表記のままにします。

以下の内容は各種ソフトやライブラリのインストールです。この操作はSynaptic上でも行えます。

7.各種コーデックのインストール、メディア環境を整える
各種コーデックをインストールして、メディア環境を整えます。ターミナル上から
$ sudo apt-get install ubuntu-restricted-extras
でインストールを行います。
ついでに動画鑑賞の定番であるvlcもインストール。
$ sudo apt-get install vlc
で簡単にインストールが行えます。

8.Nautilusの拡張
sudo apt-get install nautilus-gksu nautilus-open-terminal

9.日本語のLaTeX環境を整える
理系必須のLaTeX環境を整えます。「Ubuntu 8.10 Intrepid Ibex で 日本語 LaTeX 環境を整えてみよう」を参考にインストールを行います。
ついでにLaTeXのコンパイルが劇的に楽になるOMake(参考:OMake つかって LaTeX コンパイルしたら簡単すぎて身長が5cm伸びた)も同時にインストール。
$ sudo apt-get install omake
とっても簡単ですね。

10.各種計算ソフトのインストール
個人的によく使うライブラリやソフトをインストールします。
$ sudo apt-get install python-scipy python-matplotlib wxmaxima gnuplot r-base

所要時間にして約2時間。結構早く終わりました。Windowsだとあと2,3時間はかかるかもしれません。

まとめ

Ubuntuは初心者に優しいとかコマンド入力しなくてもいいとか言われていますがそれは全くの嘘で、ちょっとこみいったことをしようとすると依然としてターミナル上からの操作が必要とされます。
でも慣れればwindowsよりも保守管理がしやすいのは確か(apt-getで一括してすべてのソフトのアップグレード、インストール、アンインストールが行える)ですし、なにより理系がよく使うgnuplotやRが楽にインストールできるところがうれしいです。操作性もwindows上でインストールするよりたぶん数倍使いやすいと思うので、理系の方はUbuntuを試してみるという選択肢もありだと思います(べつにFedoraでもいいと思うけど)。

2009/04/12

辞書と組み合わせと再帰関数


Photo by joka2000, Double-flowered Cherry Blossoms

辞書が与えられて、そのキーと値の群の中でタプルやリストを持っている値を、任意の値で組み合わせたリストを返すという処理はどう実装すべきか悩んでいました。
言葉にすると難しく聞こえますが、要は
{"a":(1,2), "b":4, "c":(3,4)}という辞書が与えられた場合、返すリストは
[{"a":1, "b":4, "c":3},
{"a":1, "b":4, "c":4},
{"a":2, "b":4, "c":3},
{"a":2, "b":4, "c":4}]
となるわけです。

通常の行列のような処理は単純にループを2回回せばいいわけですが、今回の問題の場合ループ回数は変動するわけで、単純にループを回すわけにはいかない。どうすればいいのかちょっと考えて見たら、再帰関数を使えば案外スマートに実装できそうな気がしたので、実際にやってみました。


from copy import copy

def makeKwargsList(kwargs, exceptions=[]):
"""
タプルやリストを含んだ辞書から、それらの値を含む任意の組み合わせを
すべてリストとして返します.
例:
kwargs = {"a":(1,2), "b":3, "c":(True,False), "d":(1,2)}
exceptions = "d"の場合、返される辞書のリストは、
[{"a":1, "b":3, "c":True, "d":(1,2)},
{"a":1, "b":3, "c":False, "d":(1,2)},
{"a":2, "b":3, "c":True, "d":(1,2)},
{"a":2, "b":3, "c":False, "d":(1,2)}] となります.

kwargs : タプルやリストを含んだ辞書
exceptions : 組み合わせとして出力してほしくないキーのリスト
"""
if type(kwargs) != dict: raise TypeError
# キーワードの抽出
kwdict = {}
base = {}
for (key, value) in kwargs.items():
if (type(value) == list or type(value) == tuple) and \
(key not in exceptions):
kwdict[key] = value
else: base[key] = value
# key, kw の分離
keys = kwdict.keys()
values = kwdict.values()
kwargs_list = []
__makeKw(values, [], kwargs_list)
# 結合
r = [dict(zip(base.keys() + keys, base.values() + ag)) for ag in kwargs_list]
return r

def __makeKw(kwlist=[], base=[], kwargs_list=[]):
argslist = kwlist[0]
if len(kwlist) > 1:
newKwlist = kwlist[1:]
for kw in argslist:
new_base = copy(base)
new_base.append(kw)
__makeKw(newKwlist, new_base, kwargs_list)
else:
for kw in argslist:
new_base = copy(base)
new_base.append(kw)
kwargs_list.append(new_base)

__makeKw()が再帰関数で、この場合[(1,2),(3,4)]のリストから、[[1,3], [1,4], [2,3], [2,4]]をkwargs_listに代入させていく関数となっています。

本来のプログラマがどうやってこのようなアルゴリズムを組んでいるのかは残念ながら勉強不足で分かりませんが、とりあえずきちんと動作しますし、そこまで速度が重要となるような処理ではないですので(せいぜい100〜10000程度)、べつにこれでいいかなと。

それにしても、1年前は思いつかずに挫折していたであろうアルゴリズムが実際に組めるようになってくると、ちょっと成長している感がありますね。

2009/03/20

MeCabを用いてスパムフィルタを作ってみよう


Photo by vsz, night glow

以前このブログでMeCabによる形態素解析を紹介しました。正直その後すっかり取り上げたことを忘れてのほほんと過ごしていたわけです(*1)が、ふとしたことでベイジアンフィルタに関するアルゴリズムの記事を見つけ、日本語でこのような記事があるなんて珍しいなということで、ちょっくら実装してみようと思い立ったわけです。

形態素解析部分はMeCabくんがやってくれるので、こっちがするのは名詞を抜き出してデータベース辞書を作り、Graham方式を用いて実装したくらいです。正直ただ単純に実装しただけなのでそこまで参考にならないと思いますが、一応coderepos上に公開してみます。

svn checkout http://svn.coderepos.org/share/lang/python/spam Somewhere

でチェックアウトしてください。

テストにつきましては正直自分のメールアドレスにスパムが届かなかったので(*2)、『Google ニュース』を使って『政治』分野をスパム、『スポーツ』分野を非スパム文章として40件サンプルを手作業で作り(*3)、2つのセンテンス

大阪府の橋下徹知事が進める、府庁を大阪市の第三セクター「大阪ワールドトレードセンタービルディング」(WTC)に移転する構想について、公明党府議団は19日、「原案には賛成できない」として府議会で審議中の移転関連予算案と条例案に反対する方針を決めた。 公明党は自民党とともに知事与党の立場だが「議会として十分な議論ができていない。あまりに拙速だ」としている。条例案の可決には出席議員の3分の2以上の賛成が必要で、原案通りの可決は極めて厳しい状況となった。橋下知事は同日、高齢の障害者らの医療費自己負担を引き上げる案などを、議会側の求めに応じて修正する意向を議会側に伝達。府庁移転問題の好転を図る狙いがあるとみられるが、先行きは不透明だ。橋下知事は、府議会総務常任委員会であらためて移転への意欲を示し、記者団に「(反対は)公明の政治的決断。自民、民主、諸派に納得していただくよう精いっぱい頑張る。可能性はゼロではない」と述べた。

フィギュアスケートの金妍児(キムヨナ)(韓国)が過去の国際大会の練習中、日本選手に進路を妨害されたなどとする韓国メディアの報道について、日本スケート連盟は19日、韓国スケート連盟に対し、報道内容についての調査を求める要望書を提出した。また、国際スケート連合(ISU)に対しても同日、報道への見解を問う文書を提出した。日本スケート連盟によると、韓国側からの直接の抗議や、ISUからの警告はこれまでないという。同連盟の常山正雄専務理事は「日本選手が意図的に妨害した事実はなく、今回の報道には大変困惑しているし、遺憾」としている。


がきちんと判定されているか確かめました。これらの記事を選んだ深い理由は得にないです。
結果は、

$ python test.py
センテンス1がスパムである確率 : 1.0
センテンス2がスパムである確率 : 6.07068879794e-100
スパム文章のサンプル数 : 20
非スパム文章のサンプル数 : 20
スパム辞書が学習した単語数 : 1040
非スパム辞書が学習した単語数 : 854

大体大丈夫そうです。よかったよかった。

学んだこと

  • ベイズ理論を用いたフィルタリングは結構面倒かと思ってましたが、意外と楽でした。まぁ面倒な部分はMeCabがやってくれたっていうのもあるんでしょうけど。
  • pythonのreduce()はとてもエレガントに扱えて便利。たった一行ですむっていうのは気分いいですね。
  • どうでもいいですけどフレッシュネスバーガーのスパムバーガーはおいしいのでお勧めです。

うーんおいしそう!明日食べに行ってきます。

*1 どれくらい忘れていたかというと、"MeCab python"で検索したら自分の記事がトップに出て、「そんなん書いたっけ?」と驚いたくらい。自分の欠点は熱しやすく冷めやすいところだと思う
*2 出会い系とかに登録していればたくさん来ていたかもしれない
*3 本来は4000件くらい作るらしいんですが、さすがに勘弁してください

追記

Robinson方式も扱えるようにレポジトリを更新しました。Robinson方式は未知の単語が出てきた際に、Graham方式よりも適切に判定が行えるアルゴリズムです。

$ python test.py
=====Graham方式による判定=====
センテンス1がスパムである確率 : 1.0
センテンス2がスパムである確率 : 6.07068879794e-100
=====Robinson方式による判定=====
センテンス1がスパムである確率 : 0.999957539928
センテンス2がスパムである確率 : 0.0234555720353
=====辞書に関する情報=====
スパム文章のサンプル数 : 20
非スパム文章のサンプル数 : 20
スパム辞書が学習した単語数 : 1040
非スパム辞書が学習した単語数 : 854

Robinson方式に対応させるために逆カイ二乗関数が必要になったので、今回はchi2pモジュール(http://garyrob.blogs.com/chi2p.py)を利用することにしました。chi2pモジュールはMIT Licenseの元で配布されています。

2009/03/05

PyBrain - a modular Machine Learning Library for Python


今、python界でPyBrainが熱い!…わけじゃないですけど、個人的にけっこう注目しているライブラリ。機械学習ライブラリにおける、期待の新人が出てきなような気持ちです。

0.PyBrainとは?

PyBrainっていうのはPythonによって動く、モジュール式の機械学習ライブラリです。python界ではいままでにもニューラルネットワークとかSVMなどを扱うライブラリが存在していましたが、PyBrainではそれらをより包括的に扱う、一種の環境としての機械学習ライブラリを目指しているようです。
PyBrainが優れているのはその思想もさることながら、扱っているアルゴリズムの多さにもあります。例えばFeaturesの欄を見てみると、
  • Backprop
  • Rprop
  • Policy Gradients
  • Support Vector Machines
  • Evolution Strategies
  • CMA-ES
  • Competitive Coevolution
  • Natural ES
  • Natural Actor-Critic
  • Reward-weighted regression
  • Evolino
  • Fitness Expectation Maximization
  • SPLA
  • PCA/pPCA
  • LSH for Hamming and Euclidean Spaces
と、比較的新しいアルゴリズムについても対応する予定のよう。(リファレンスをざっと見ると、まだ対応していないアルゴリズムはけっこう多いようです)とりあえずアルゴリズムについて確認したり、テストとして組んでみる分には申し分ない仕様です。

1.ダウンロード〜インストールまで

まず、PyBrainでは以下のツールが必要となるので、足りない場合は適宜apt-getやらeasy_installやらでインストールを行います。
  • g++
  • scipy
  • matplotlib
ちなみにホームページには書かれていませんが、自分はビルドした際にcblasが足りないと怒られてしまったので、ついでにそれもインストールします。
次に、PyBrainのサイトにアクセスして、Stable versionのソースコードを入手。圧縮ファイルを展開します。

~$ cd PyBrain-0.2
~/PyBrain-0.2$ ls
LICENSE arac docs examples pybrain setup.py

setuptoolsの慣例通りにビルド。

~/PyBrain-0.2$ sudo python setup.py build
arac/src/c/layers/common.c: In function ‘void make_layer(Layer*, int, int)’:
arac/src/c/layers/common.c:12: error: ‘malloc’ was not declared in this scope
arac/src/c/layers/common.c: In function ‘Layer* make_layer(int, int)’:
arac/src/c/layers/common.c:40: error: ‘malloc’ was not declared in this scope
Traceback (most recent call last):
File "setup.py", line 87, in <module>
compileArac()
File "setup.py", line 74, in compileArac
extra_postargs=['-O3', '-g0', '-DNDEBUG'])
File "/usr/lib/python2.6/distutils/ccompiler.py", line 697, in compile
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
File "/usr/lib/python2.6/distutils/unixccompiler.py", line 180, in _compile
raise CompileError, msg
distutils.errors.CompileError: command 'g++' failed with exit status 1

怒られてしまいました。どうやらmallocが定義されていないみたいなので、暫定的な処置として"arac/src/c/common.h"に以下の文を付け加えます。

#include <stdlib.h>

再度ビルドを行うと、ビルドがうまくいったみたいです。

~/PyBrain-0.2$ sudo python setup.py install

でインストール。無事インストールが完了しました。
正常に動くかどうか確かめてみます。

~/PyBrain-0.2$ python
Python 2.6.1+ (r261:67515, Feb 24 2009, 20:00:00)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pybrain
>>>

何事もなくインポートすることができました。

2.試しに使ってみる〜ニューラルネットワークの構築から学習

Pybrainのチュートリアル通りに、単純なFeed Forward型のニューラルネットワークを組んでみます。Pybrainではレイヤを個別に定義し、それらを繋げてネットワークを構成することもできるみたいですが、もっと簡単にネットワークを構成できるショートカットがあるみたいですので、それを利用します。

from pybrain.tools.shortcuts import buildNetwork
net = buildNetwork(2, 3, 1)


これで2つのインプット、3つの隠れユニット、1つのアウトプットから成るニューラルネットワークが出来上がりました。とても簡単ですね。
入力したインプットからアウトプットを出すには、activate()メソッドを用います。

net.activate([2,1])

buildNetworkの時点で各ニューロンはランダムな数値で初期化されていますので、既にactivate()ができる環境になっています。

ちなみに通常、各ニューロンに用いられる活性化関数はシグモイド関数が用いられますが、違う関数を用いたい場合は適宜指定することができるみたいです。まぁ好みの問題ですね。

from pybrain.structure import SoftmaxLayer
from pybrain.structure import TanhLayer
net = buildNetwork(2, 3, 1, hiddenclass=TanhLayer, outclass=SoftmaxLayer)


次に、教師あり学習を行うためにデータセットを用意しておきます。

from pybrain.datasets import SupervisedDataSet
ds = SupervisedDataSet(2, 1)
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))


こんな感じでインプットとアウトプットのサンプルを増やしていきます。
そして、構成されたネットワークに誤差逆伝播法で学習を行わせるため、trainerを作成します。

from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(net, ds)
trainer.train()


train()メソッドは返り値として誤り率を返しますが、もしある一定の割合に収束するまで学習を行わせたい場合、trainUntilConvergence()メソッドが有効です。そのまんまですね。

trainer.trainUntilConvergence(validationProportion=0.25)

だいたいニューラルネットワークの構築方法としてはそんな感じですが、他にもSVMを選択することもできるようです。詳しいことはPyBrainのドキュメントを参照してください。

3.使ってみて

とりあえずざっと使ってみた感想ですが、非常に組みやすく、かゆいところに手が届くような設計がなされているライブラリだと思います。まだバージョンは0.2ですし未完成な感じは否めないですけれど、将来が非常に楽しみなライブラリです。(しかも名前がカッコいい!!)

2009/02/12

Ambient Occlusion with Python


前々からやってみたかった、syoyoさんのAO benchでのコードをPython用に移植させてみました。上の画像はその出力結果です。ちなみに、出力を楽にするためにPython Imaging Library(PIL)を利用しています。

なんで前々からやってみたかったかというと、3Dでのレンダリングアルゴリズムの学習がしたかったから。ray tracing法やらAmbient Occlusionなどの手法は頭の中では分かってましたが、実際にどうやって動かしているのかは全然分かんなかったですから…今回の移植を通して、レンダラの実際の動きが少しだけですが掴めたような気がします。

それで気になる速度はというと、

  • サブサンプリング数:2
  • AOのサンプル数:8
  • 画像の長さと高さ:256px

という標準的な設定でレンダリングしたところ、
$ python sample.py
time:463.692063 sec
という結果が出ました(AMD Athlon 64 x2 3800+)。

まぁPythonですから大体予想してた通りの結果となりましたが、それにしてもものっそい遅いです。C言語での2.6secという結果を比べてみると、環境が違いますからそのまま評価することはできないんですがだいたい180倍くらい時間かかってます。もう少しなんとかできなかったかなー…