読者です 読者をやめる 読者になる 読者になる

超言理論

特に益もない日記である

2016年、一人暮らし大学院生が買ってよかったもの

ちょっと2016年を過ぎてしまいましたが、2016年に買ってよかったと思うものを書いていこうと思います*1
主に生活用品ですね。

1. 家庭用製麺機

フィリップス 家庭用製麺機 ヌードルメーカー HR2369-01

フィリップス 家庭用製麺機 ヌードルメーカー HR2369-01

これはL.A.に留学している時に知り合った学生とThanksgiving Dayにラーメンを作った時に初めて使ったんですけど、正直めちゃくちゃ驚きました。
自分の中の家庭用製麺機のイメージは、コシのない麺状の小麦粉の塊が出てくる(もしくは、めちゃくちゃ苦労して小麦粉を練って、パスタマシーンで麺状に切る)印象でした。でも、今時の製麺機は手間に対して品質がめちゃいいんですね。
麺を2~3人前作るのにもたかだか5分くらいでできますし、麺の太さも太めから細めまでアタッチメント一つで変えられるのでかなり便利です。それに、作った麺は適当に打ち粉をつけてラップかジップロックに詰めて冷凍しておけば、市販の冷凍うどんみたいに鍋にそのままブチ込むだけで食べられます*2
日本に帰ってきてから買って何度かラーメン作って食べましたけど、最高でした。


2. 寸胴

業務用アルミ寸胴鍋 24cm

業務用アルミ寸胴鍋 24cm

製麺機を買ったら当然寸胴も買いますよね。
ということで寸胴買いました。これでスープを作りますが、サイズ的にはやはり家庭用という感じなので、豚骨(特にげんこつ)を煮るのは厳しいですね。
そういう時は鳥の手羽です。白湯も清湯も両方できるし、失敗はしにくいし、味噌でも醤油でも塩でも合いやすいのでオススメです。

3. ミキサー
ミキサーにもいろいろあるんですけど、うちにあるのはこれです。

ミキサーはかなりオリとか繊維が残ってしまい、ジューサーはいい感じにできるけど掃除が面倒臭いイメージだったんで、どっちも敬遠してました。でも、牛乳や豆乳と一緒にミキサーにかけたらスムージーが作れて便利で簡単、と聞いたのでミキサーを買ってみたんですが、確かにその通りでした。
いつも朝は食べないか、腹持ちの良さそうなジュースやゼリーだったんですが、ミキサーを買ってからは、適当な野菜や果物(もっぱらバナナ)と豆乳でスムージーを作って飲んでます。
以前飲んでたこれも美味しくて腹持ちがいいんですが、スムージーのほうが安いですね。スムージー以外にも、りんごとかイチゴとかと梅酒とかワインとかのお酒と氷をミキサーにかけたらいい感じのカクテルができるので、それも時々飲んでます、健康的。
あと、このミキサー貧相な見た目に反してコーヒー豆や干し小魚なんかも粉砕できる以外と強力なやつで、料理(ミンチ作ったり、パスタソース作ったり)するのにも結構役立ちます。洗うのちょっとめんどいけど。


4. Fitbit
自分が買ったのはChargeなんですが、これはちょっと失敗でしたね。

これの新しいモデルのCharge2かAltaBlaze*3を買ったほうが良いと思います。理由は簡単で、ディスプレイが大きくて、モバイルから受け取れる通知や情報が全然違うからです。
Chargeは運動量や睡眠時間を計測するFitbitとしての機能には問題ないのですが、携帯電話の着信やメール、Twitterなんかの通知を受け取るためにはChargeだと不足(もしくはそもそも受け取れない)です。
なので、もし買うならCharge2かAltaBlaze*4をオススメしますね。


5. Fitbit Aria

これもFitbitなんですが、こっちは体重計です。先生から「30になってから体(主に腹)をなんとかしようと思っても遅い」みたいなことを言われたので、ちょっと気をつけるために体重計を買いました。
これ結構便利で、体重計で計った体重と体脂肪は自動でfitbitのサイトに記録されて、どのくらいの期間でどのくらいの体重変動があったのか簡単にわかります。本体のサイズも薄いのでその辺の棚とかに立てて入ります、さらに軽いので取り出すのも苦ではありません。常に設置するスペースがなくても問題なし。
ちなみに、さっき書いたスムージーを飲み続けたら3kgくらい痩せました。


6. ノイズキャンセリングヘッドホン

いろいろ種類があると思うんですが、とりあえずノイズキャンセリングヘッドホンというのを試してみたくてこれを買いました。
とりあえず使った感想としては、ノイズキャンセリングはかなりノイズが消えます。研究室で研究している時に聞こえるノイズ、例えば遠くの話し声や近くの人のキーボードのタイプ音、パソコンのファン、足音なんかはだいたい消えます。近くで話していたり、大声を出されたりすると消え切りません、あと高音(ビープ音とか)はあまり消えませんね。また、着けてる感じとしては、普通のヘッドホンよりちょっと重いですが気にならないレベル、あとは密閉性が高くて個人的には好みです。
研究室で使うために買ったんですが、このノイズキャンセリングヘッドホンをつけてゲーセンで音ゲーするとめちゃくちゃよく聞こえます(ちょっとゲームの効果音の一部が抑圧されてる感じもしますが、そもそも非ノイズ環境で生の音を聞いたことがないのでわからない)。
ノイズキャンセリングヘッドホン、めちゃ快適ですね。
あと、これに追加してiPodで音楽を聞く時のために、ネックストラップも買いました。
Simplism Lightningコネクター用ネックストラップ ブラック  TR-LSI-BK

Simplism Lightningコネクター用ネックストラップ ブラック TR-LSI-BK

こっちもオススメです。


7. ロードバイク
そうです、口車に乗ってロードバイクを買いました。

KHODAA BLOOM(コーダーブルーム) FARNA SL のアルテグラを買いました*5
運動全然してないんでキッツイんですけど、めっちゃ楽しいです。


以上7品でした。それではみなさま、よい2017年を。

*1:2017年1月16日23:16 あまりにもブログを書くのが久しぶりすぎて、リンクの貼り付け方を間違えていたので修正しました。

*2:もちろんスープはいりますけど

*3:2017年1月16日23:16 間違えてました

*4:2017年1月16日23:16 同上、間違えてました

*5:ここで出しているAmazonの商品とは異なります。あと、自転車はAmazonじゃなくて専門店で買ったほうがいいです、絶対。

NLP若手の会(YANS2015)に行ってきた

またかと思いましたか、それとも次こそ誤字かと思いましたか。
いいえ、これも正真正銘2015年に書きそびれたNLP若手の会の参加記録です。
こちらも書けなかったんですね、つまり供養です、内容はないです。


去年に引き続いて、NLP若手の会は合宿形式の1泊2日で開催されました。
去年は関東での開催だったので、今年は北陸、関西など色々な候補地が上がりました。
候補地の一つ、石川は自分の出身地で、お酒も食べ物も温泉もサイコーなので、ぜひ開催したい場所の一つでした。
そして、タイミングよく北陸新幹線開通の年*1というのもあって、石川の七尾 和倉温泉 ホテル海望で開催することになりました。
もう今年ことはめちゃくちゃ働いて働いて働き通すぞ!と思ったんですけど、実際はジャーナルの締め切りが下見に被ったり、ポスターの印刷を頼まれて前日入りして会場整備できなかったりなどなど、結局全然働けず結局なんのために委員になったんや……という感じになりました。始まる前からつらみが。いやでも始まったら普通に委員の仕事するから!!!と思って乗り切ります。

といっても、始まってからは普通に(アクティビティに参加したり温泉入ったりするのに)忙しいし、自分のデモ発表もあるしで忙しくて、気がついたら2日間が終わってました。仕事?なにそれ知らん。
自分のデモ発表では、今年こそ対話システムの発表をして、実際に対話システムでなにが問題で、どんな課題があるのかを話したくて、留学の準備しながら必死でデモシステムを作ってました。
発表したのは「快適度推定に基づく用例ベース対話システム」というやつで、これYANSと同時にジャーナルを書いてちょっと前に通りました、良かった*2
でも、デモ発表は歌詞生成がヤバかったですね、ヤバかった(褒め言葉)。

この時点で自分はD2だったんですけど、研究室内には関連する研究をしている同期とかはいなくて、正直周りがどうなっているのかわからず、(特に、就活が始まるので)結構焦ってたんですけど、YANSは同世代くらい(からちょい上)の人がたくさんいて、親身になって話を聞いてくれて、相談に乗ってくれるので、研究以外の事もたくさん話しました。
卒業したら研究がしたいのか、どんな分野に関わりたいのか、開発はしたいのか、何年くらい働きたいのか……正直、将来をまともに考えていなかった自分にとっては、将来に関する話ができる研究室外の同年代、年上の相手がいたのがYANSで最高の経験だったと思います。
就職先、今後の進退について最も影響を与えたのはきっと2015年のYANSと留学でした。


本題に戻して、結局YANS2015もあまり働かず、忙しくアクティビティを遊び倒して温泉入って帰ってきたわけですけど、最後に胸を張って働いたと言えるのは会場の後片付けと荷物の配送(全員電車の関係で帰ったけど、自分は実家に泊まるので夕方まで待って会場の荷物を送って帰った)。
これでやっと自分が委員だった時のYANSが終われる。


YANS、結局委員の仕事はあんまりできなかったように思えます。
今はもう委員は委員長の推薦で選ばれますが、多分その方式だと自分が委員になることはなかったでしょう。
そんな最後の後任推薦で委員になって、YANSに参加する縁を持てたことは、きっと自分にとって幸いだったと思います。
2年間ありがとうございました、とても楽しかったです。
これからもこの最高に楽しいYANSが続いていきますように、これからは一参加者として盛り上げられたらいいなと思っています。

*1:と言っても自分は北陸-関西なので関係ないんですが

*2:快適度推定に基づく用例ベース対話システム

NLP若手の会(YANS2014)に行ってきた

もしかしてタイムリープしたかと思いましたか、それとも3年前の誰かと入れ替わってると思いましたか、単なる誤字だと思いましたか。
いいえ、これは正真正銘2014年に書きそびれたNLP若手の会の参加記録です。*1
つまるところ、供養です、内容はないです。


NLP若手の会というのは自然言語処理とその(かなり広い)関連分野の若手研究者・若手技術者との交流促進やアクティビティを高めることを目指したコミュニティです。
yans.anlp.jp
幸運にも(?)このコミュニティの運営をお手伝いする立場になったので、2014年と2015年の若手の会の開催に際して、委員として参加してきました。
今は違いますが、元々の運営委員の決定は退任する運営委員が後続を指名する形式で行われていて、自分も前任者から指名されて運営委員になりました。というのも、前任者は対話関係の研究者で、対話関係の研究をしている人を後続の委員にしたい、という話だったとおもいます。
一応、修士卒業の時点で対話関係の研究をしている人としてカウントされていて大変嬉しかった記憶があります。*2

閑話休題、2014年のNLP若手の会は三浦海岸のマホロバマインズ三浦で行われて、何年かぶりの合宿形式での開催でした。
発表のみでなく、アクティビティ、ハッカソンなど内容も盛り沢山にすることができて、とても濃密な2日間という印象でした。
自分は、当時研究していた言い換えデータ*3について発表しました。
公開時も結構色々な方に使ってもらったり、話題にしてもらったりしたので内容は特に書きませんが、発表して良かったと思っています。
また、実際にやりたいのは対話なんですよ、と話をしたら、いろんな方から対話について興味を持ってもらえたり、対話と関係しそうな情報を教えていただけて良い情報交換になりました。

ぶっちゃけ、委員にはなったものの合宿形式になったのも今年から、仕事もよくわからない感じで全然お手伝いできませんでした。
自分の係の仕事が(位置的に難しかったというのもあるんですけど)不十分だったように思えるのが結構心残りでした。
来年こそは頑張って委員の仕事をしよう、とは思ったんですけど、思っただけでした。これはまた別の話。

*1:なんでこんな時期に書くのか、って話になると思うんですけど、正直ここ3年くらいあまり自分のことを気持ちよく話せる状態ではなくて、ずっと書こうという気持ちだけがあって書かないまま時間が過ぎていって、ついにこんなところまで来てしまった。自分の日記なんだから何を書いてもいいんだろうとは思うんだけど、それならなおさら気分が乗らない時は書けなくなる気がする。

*2:でも、このころはまだ「対話の研究したい」っていうだけで、実際は言い換えとかの研究をしてた

*3:PPDB:Japanese - 日本語言い換えデータベース

PybrainでLSTM言語モデル動かしてみた

昔、自分が全然Neural Networkとかわからなかった頃、Pybrainというライブラリに興味を持ってNNLM(Neural Network Language Model)を作ろうと挑戦したことがあった。
ma13.hateblo.jp

結果だけ言うと全く出来てなかったわけなんだけど、ちょっとリベンジしようかと思ってほぼ同じ環境でNNLM(実際はRNNLM, LSTMLM)を作ってみた。
コードは以下Gistにある。

gist0eccd8d989ac11ef74a5

適当に書いたのでちょっと微妙なんだけど*1、簡単に解説する。

まず、学習するデータ(単語分割済み)を読みだして、sklearnのCountVectorizerのfittingに使う。

train_word = []
with open(filename,'r') as f:
    for line in f:
        for w in line.split():
            train_word.append(w)
train_word.append('<s>')
train_word.append('</s>')

vectorizer = CountVectorizer(analyzer=dummy, dtype=numpy.float64)
vectorizer.fit(train_word)
print('Vocab : '+str(len(vectorizer.vocabulary_)))
      
vocab_list = []
for k,v in sorted(vectorizer.vocabulary_.items(), key=lambda x:x[1] ):
    vocab_list.append(k)

ぶっちゃけたことを言うと、昔書いたコードがうまく動かなかったすべての原因はここにあって*2、sklearnのCountVectorizerは全語彙を.vocabulary_という辞書に入れて持っているんだけど、これ実は辞書の中身(key, value)が(単語, 単語の総数)とか、(単語のindex番号, 単語)とかではなく、(単語, 単語のindex番号)になっていて、つまるところ以下のようになっている。

vectorizer.vocabulary_.items()
{('a', 3), ('is', 2), ('this', 0), ('pen', 4), ('.', 5), ('I', 1)}

なので、CountVectorizerの出力と単語の対応をとる場合はvalueでsortした上でkeyを取り出す必要がある。正直頭おかしいと思うし、何のためにこうなっているのかはちょっと想像がつかなかった。これは、おそらくだけど、入力を一発でindexに置き換えるためにこういう構造になっているだろう。
つまり、vectorizer.vocabulary_[word]=indexのようにone-hot-vectorならどこを1にすればいいのかすぐにわかる、便利だね!!!!!!(白目)*3

そして、fittingしたvectorizerを使って単語のベクトル(one-hot vector)を作成

voc_size = len(vectorizer.vocabulary_)

ds = SequentialDataSet( voc_size, voc_size )
with open(filename,'r') as f:
    for line in f:
        ds.newSequence()
        # insert <s>
        p = numpy.array(vectorizer.transform(['<s>']).todense()).reshape(-1)
        for w in line.split():
            n = numpy.array(vectorizer.transform([w]).todense()).reshape(-1)
            ds.addSample(p, n)
            p = n
        # append </s>
        ds.addSample(p, numpy.array(vectorizer.transform(['</s>']).todense()).reshape(-1))

文頭文末にはそれを示す記号を入れる。

ネットワークの構築

net = RecurrentNetwork()
net.addInputModule(LinearLayer(voc_size, name='in'))
net.addModule(TanhLayer(2 ** _compsize, name='comp'))
net.addModule(LSTMLayer(2 ** _hiddensize, name='lstm'))
net.addOutputModule(SoftmaxLayer(voc_size, name='out'))

net.addConnection(FullConnection(net['in'], net['comp'], name='in_to_comp'))
net.addConnection(FullConnection(net['comp'], net['lstm'], name='comp_to_lstm'))
net.addConnection(FullConnection(net['lstm'], net['out'], name='lstm_to_out'))

net.addRecurrentConnection(FullConnection(net['lstm'], net['lstm'], name='recurrent_lstm'))
net.sortModules()

LSTMを使ってみたかったのでPybrainのLSTMLayerを利用する。
LSTMLayerに入れる前にTanhLayerで適当に入力の単語ベクトルを圧縮して、それから入力。

学習する。

ind = [ i for i in range(0, ds.getNumSequences()) ]
random.shuffle(ind)
batch_size = int(len(ind) / batches)
for batch_count in range(0, batches ):
    print(str(batch_count + 1)+' / '+ str(batches))
    batch = SequentialDataSet( voc_size, voc_size )
    for i in ind[batch_size * batch_count : min(len(ind), (batch_size * (batch_count + 1)))]:
        batch.newSequence()
        for _a,_b in ds.getSequenceIterator(i):
            batch.addSample(_a, _b)

    trainer = RPropMinusTrainer(net, dataset=batch, )
    trainer.train()

シャッフルしたデータから適当な個数に切り分けて、それぞれTrainerに入れる。
もっときれいに書けると思うしいちいちデータを作っているのがかなりダサい。

そして学習が終わったらテストで生成をしてみる。

generation_max = 1000
output_candidates = [(['<s>'], 0.0)]
for _x in range(0, generation_max):
    output_seq = None
    output_per = float('inf')
    output_no = -1
    for i, (s, p) in enumerate(output_candidates):
        if output_per >= p:
            output_seq = s
            output_per = p
            output_no = i
    print(' '.join(output_seq) +' / '+ str(output_per) + ' ('+str(len(output_candidates))+')', end='\r', flush=True)

    if output_seq[-1] == '</s>' or len(output_seq ) > 20:
        print(' '.join(output_seq) +' / '+ str(output_per) + ' ('+str(len(output_candidates))+')', end='\n\n', flush=True)
        break

    output_candidates.remove((output_seq, output_per,))

    net.reset()
    ts = UnsupervisedDataSet(voc_size, )
    for w in output_seq:
        n = numpy.array(vectorizer.transform([w]).todense()[0]).reshape(-1)
        ts.addSample(n)

    for s, w in zip(net.activateOnDataset(ts)[-1], vocab_list):
        if s > 0.0:
            output_candidates.append((output_seq + [w], output_per - math.log(s),))

初期状態"<s>"から、次の単語の確率を推定して、文末に追加し、文と対数尤度をペアにして候補として記憶。
候補から最も対数尤度が高いものを選択して、次の単語の確率を推定して文末に追加し、また候補に戻す。これを文末または既定の長さになるまで繰り返す。
普通にある状態から最大の単語確率のものを選んでそのまま次の単語を推定してもよかったんだけど、全体で確率最大化したほうが生成される文の品質が良くなるかなと思ってこっちにしてみた。
当然のことなんだけど、文の候補数は1ループで語彙数分だけ増えるので、大規模なデータでこれを使うと非常にメモリを食う。


で、動かしてみるとこんな感じになる。

18 / 32
Error:6.45327155815e-05
Test generation :
<s> こんにちは 。 声 かけ て くれる の を 待っ て たん だ 。 </s> / -11.548804912609333 (107339)

19 / 32
Error:6.28088535697e-05
Test generation :
<s> こんばんは ー た 。 気軽 </s> / -2.1222976358696273 (46003)

20 / 32
Error:6.39956006963e-05
Test generation :
<s> こんにちは 。 声 かけ て くれる の を 待っ て たん だ 。 </s> / -10.342886978783383 (107339)

21 / 32
Error:6.44167821664e-05
Test generation :
<s> こんばんは ー 。 </s> / -2.719341666660525 (30669)

22 / 32
Error:6.32813259365e-05
Test generation :
<s> こんにちは 。 声 かけ て くれる ん です か ? </s> / -7.535082186820195 (84338)

23 / 32
Error:6.21185037777e-05
Test generation :
<s> こんばんは ー です ね </s> / -3.2706245155460785 (38336)

24 / 32
Error:6.40324274094e-05
Test generation :
<s> こんにちは 。 気軽 に 声 かけ て くれる ん です か ? </s> / -8.480708678997797 (99672)

25 / 32
Error:6.25260848365e-05
Test generation :
<s> こんばんは 。 </s> / -1.8480408894751301 (23002)

26 / 32
Error:6.38205037144e-05
Test generation :
<s> こんにちは 。 気軽 に 声 かけ て くれる の を 待っ て たん だ 。 </s> / -9.814649153298937 (122673)

27 / 32
Error:6.23060400758e-05
Test generation :
<s> こんばんは ー 。 ちょうど 退屈 し て た ん だ 。 </s> / -9.159558817603198 (92005)

これは対話破たん検出タスク*4の発話文をあつめて学習した。
発話文なので、口語で、かつ複数対話あるので挨拶や対話開始時のよくある発話を学習している。精度はそこそこって感じ。
コーパスのサイズは全文集めても千文単位で、このくらいのサイズなら別に問題なく学習が終わるんだけど、これより大きいサイズになると馬鹿みたいに時間がかかるうえに、精度もそれほどでない。
原因は既に分かっていて、PybrainがGPUに対応していないとか、数値計算/学習データあたりが大規模なデータで動くように対応してないとかそのへんの問題だと思われる*5
Pybrainは(CPUで)簡単にNeural Networkを動かせる、ってところで止めておいて、これ以上大規模/複雑なネットワークを学習するならchainerとかを使った方がよさげ。
そのへんのことを考えて、このプログラムはこれ以上手を付けないで、PybrainでRNNLMのリベンジ終了、ということにしておく。

今後の課題はchainerのお勉強です。

オンライン機械学習 (機械学習プロフェッショナルシリーズ)

オンライン機械学習 (機械学習プロフェッショナルシリーズ)

*1:キレイに書き直してまとめようと思ったんだけど諸事情でやめました、理由はあとで。

*2:つまり原因を解明するのに2年かかったわけだ!

*3:なんでvectorizer.transform()というメソッドが存在するのか…

*4:対話破綻検出チャレンジ

*5:これが先述の"諸事情"


Copyright © 2012-2016 Masahiro MIZUKAMI All Rights Reserved.