pythonのfilter関数

pythonのビルトイン関数にfilterというのがある。これはリストに対して条件に合致する要素をとってくることができる。よくネットで見るのは、

>>> lis=["apple","grape","banana","apple pie"]
>>> filter(lambda x:x=="apple",lis)
['apple']

ところが、pythonのバージョンによってはどうやらオブジェクトで返ってくる場合があるようである。

>>> lis=["apple","grape","banana","apple pie"]
>>> filter(lambda x:x=="apple",lis)
<filter object at 0x7fd0dd679860>

>>> list(filter(lambda x:x=="apple",lis))
['apple']

少し試してみた感じ、たぶん上がpython2で下がpython3?
思わぬところで注意が必要なようだ。

そもそも、filter関数を使わずに

>>> lis=["apple","grape","banana","apple pie"]
>>> [word for word in lis if word=="apple"]
['apple']

とした方が、文字列の部分一致だとかリストのindex返したりだとか色々応用が利きそうな気もする。

chainer.functionsの関数の色々

ChainerはVariableに変数を渡してforwardパス、backwardパスを計算するので、パス内に特殊な操作が入ると計算ができなくなる、と困るのでいくつかchainer.functionsに便利な関数が用意されていた。ipython起動してchainer.functionsをインポートしてからdir(chainer.functions)とかで一度関数の一覧を見てみると結構役に立ちそうな関数があったりする。

今回は主に配列や行列操作でお世話になったので、それらをメモとしてまとめておく。

以下、

from chainer import functions as F

とする。

  1. F.reshape(shape) numpy.reshapeのVariable版。

  2. F.broadcast_to(x,shape)
    numpy.broadcast_toのVariable版。配列や行列のxをshape(タプル)に拡張してくれる。

  3. F.swapaxes(x,a,b)
    numpy.swapaxesのVariable版。aの次元とbの次元の数が逆になるように行列を操作してくれる。

  4. F.transpose(x)
    numpy.transposeのVariable版。

  5. F.expand_dims(x,axis)
    axisで指定した次元を新たに挿入する。axis=0でVariable([x])と同じことをしてくれる(Variableを呼び出すと再定義になってbackwardできなくなってしまうのでこれを使う)

  6. F.split_axis(x,split_size,axis)
    axisで指定した次元についてsplit_sizeコの配列or行列になるように分割してくれる。分割してできたVariable達はタプルで返される。

  7. F.concat(x,axis)
    axisで指定した次元について配列もしくは行列を結合する。Mコの2次元配列を組み合わせて3次元配列をつくる場合、F.expand_dims(hoge,0)としてxを3次元配列にしてから使わないとエラーが起こる

  8. F.matmul(a,b,transa=False,transb=False) numpy.dot,numpy.tensordotのVariable版。何気に転置してくれるtransa,transbがついている。別にF.transposeしても同じだと思うけど、せっかくなので使ってる。

  9. F.batch_matmul(x,y) F.matmulのバッチ付き版。例えば、3次元配列X(MxAxB)とY(MxBxC)があるとすると、以下と同じ計算を効率的にやってくれている。

Z=[]
for i in range(M):
    temp=F.matmul(X[i],Y[i])
    Z.append(F.expand_dims(temp,0))
Z=F.concat(Z,0)

for文を使わなくて良くなるのが助かる。中身はnumpy.tensordotとか使ってForwardとBackwardを定義している。

ソースコードを読んだら自分でもchainerのfunctionを書いてみたくなった。

value値がidの場合のkeyのとり方

chainerなどで言語処理を行うときには単語をidに変換して使うため、単語→idの関係を格納する辞書をvocabularyとして用いる。そのため、単語や文章を生成したいという場合にはid→単語に直す作業が必要になる。

逆引きの辞書をつくる手もあるが、idはint型なのでkeyにするためにstrに変換するのはちょっとな・・・と思うので別の方法をとる。idは単純に単語の番号なのでdictのkeyをid(value)から呼び出すにはkeyをリスト化してやればよい。例として以下のような場合を考える。

id_dict = {"love":1,"i":2,"you":3} #vocabulary例
output = [2,1,3] #目標は「i love you」を出力すること

このとき、出力outputを単語に変換するには以下のようにリスト化を行えばよい。word_listがリスト化によってできたリストだ。

word_list = [0]*(len(id_dict)+1)      #リスト初期化 word_list[0]はout of vocabulary用にとっておく  
for key,value in id_dict.items(): #dictの各要素の呼び出し
    word_list[value] = key      #word_listの番号に注意

唯一注意点はword_listのインデックスをidと合わせることである。特に文頭文末記号を入れたり、id=0を未知語に割り当てたりするとずれることが往々にしてある。

words = []
for id_ in output:
    words.append(word_list[id_])

print(" ".join(words))
# 'i love you'

サイズの違う画像の扱い

reddit machine learningから、学習に使うときの画像の取り扱い方を独断と偏見によりまとめた。

www.reddit.com

方法(大体3通り)
1. 大きい画像に合わせて小さい画像の周りを0(黒)もしくは何らかの計算をした値で埋める
2. 小さい画像に合わせて大きい画像の周りを切り取る
3. 画像をリサイズして合わせる

表出する問題
1. 埋めたピクセル(黒とか)が画像全体の認識に影響を与える可能性がある
2. 切り取られた部分のアノテーションは考慮されなくなる
3. 引き伸ばし過ぎ、縮め過ぎると自然な画像では無くなってしまう(歪む、ぼやける)

どれが一番いいのかはぶっちゃけよく分かってない。
ただ、1.は元の画像に異物を混入しているわけで、あまり使いたくはないというイメージがある。

基本的に端に検出が必要なアノテーションなど無ければ画像の周りを適当な大きさに切り取って使えば良いだろう。

しかし、もしそうでなければリサイズかピクセルで埋め立てをする必要があるだろう。どちらも画像の縦横比が比較的1:1に近いかつ他の画像と極端に大きさが違わない場合は問題ないだろうが、ここらの使い分けってどうなってるのだろう?

PMXエディタのフォントがおかしい時の対処

PMXエディタ(PMXエディタ_0210: とある工房)を使用してみたら表示されるフォントが異様に大きく表示されてしまい読めない、という問題が起きたのでメモ。

 

参考:

kelorin jo BTA on Twitter: "windows10にしたら、PMXエディタの表示がなんかおかしいんですが。同じ症状になった方いらっしゃいますか http://t.co/QtNUBDVpdx"

 

自分はsurface pro2を使用していてwindows8.1で同様の症状が起きていた。

対処法をまとめると以下の通り。

1. 「コントロールパネル」->「ハードウェアとサウンド」->「ディスプレイ」

2. 項目のサイズの変更の「カスタム拡大率を設定」で大きさを「100%」に設定、適用

3. サインアウト、再ログイン

 

これだとデスクトップ含めて全体の表示がデフォルトの設定より小さくなるが、PMXエディタの表示は正常になった。

[Chainer 1.3.0] ValueError: Cannot find a common data type.

Chainerで連続時間のRNNを実装中に以下のようなエラーが出た。

Traceback (most recent call last):
File "mtrnn.py", line 182, in <module>
u_io, u_fh, u_sh, y= forward_one_step(model, x_batch[:,28*j:28*(j+1)],u_io, u_fh, Csc0, args.tau_io, args.tau_fh, args.tau_sh)
File "mtrnn.py", line 141, in forward_one_step
u_io2 = (1-1/tau_io)*u_io+(model.fh_to_y(fh))/tau_io
File "/home/is/seitaro-s/.virtualenvs/chainer/local/lib/python2.7/site-packages/chainer/function.py", line 174, in __call__
outputs = self.forward(in_data)
File "/home/is/seitaro-s/.virtualenvs/chainer/local/lib/python2.7/site-packages/chainer/functions/connection/linear.py", line 111, in forward
Wx = x.dot(self.W.T)

ValueError: Cannot find a common data type.

 

 

荷重値Wと入力fhの内積計算でエラーが出ているのでタイプを確認。

(fh,Wはエラーの該当部分を取った W=model.parameters[-2])

>>> type(fh)

<type 'numpy.ndarray'>

>>> type(W)

<class 'cupy.ndarray'>

 

隠れ層の変数をcupyに変換していなかったのが原因だった。

うっかりよく起こしそうな落ち度だったので備忘録として残しておく。