最近やってること

最近あまりインターネット活動してなかった気がするので、突然の近況のご紹介をします。最近は主に引越の準備をしながら、アマチュア無線1級の試験勉強をやってる。

半年くらいずっと引越しがしたかったところ、最近良い部屋がみつかったので、引っ越すことにした。今の家は都会にあって便利なんだけど、ちょっとせまくなってきたし、なんだか都会すぎて息苦しい感じがしてる。前の家は出社するときに毎朝鴨川の様子が見れて良かったのを思いだして、次の家は、多少交通が不便なものの自然が近くにあって、ちょっと広くて南向きに窓がついている部屋にした。出社がたいへんになるけど、まぁ歩けない距離ではないので運動だと思ってがんばりたい。

それとはまったく関係なく、アマチュア無線1級の免許をとろうとしてる。ちょっと前に電子工学の入門をしたのだけど、理論についてもうすこしまとまった知識を身に付けたいと思い、詳しそうな人に相談してみた。そうしたところ、複数の人からアマチュア無線の勉強するのはなかなか良いよという情報を得たので、いっちょやってみるかと思ってとりくんでる。

アマチュア無線は4級から1級まであって、ちょっと電波をだしたいだけなら4級をとればよい。ただ今回は、勉強ということで難しい試験に挑戦してみている。アマチュア無線自体はまじでまったくやったことがないので、試験では爆死する可能性は高いものの、試験の内容自体は交信の経験がなくても理解できるので、やってやれなくはない。昔は通信術の試験というのがあって、かなり高速なモールス信号を聞きとれないと合格できなかったらしいので、これは助かったといえる。

8月の試験に向けて、5月くらいからずっと勉強していて、試験の問題も大方は解けるようになってきた。一方。だいぶ飽きてきているところもあって、本業のWebっぽい勉強をしたら良いような気はしてる。今の段階でも、そこそこ電子工学について勉強できたので、目的ははたせたとも言えるけども、とはいえ、中途半端はよくない。ちゃんとまとまった知識をゲットできたという証がほしいし、勉強しているうちにアマチュア無線をやってみたくなって来たので、もうひとがんばりしたいところ。

試験と引越のタイミングが重なってしまっておいおいーって感じだし、なんか夏は胃腸へのダメージがつらくて息切れしがちなんだけど、なんとか元気にやっています。以上個人の日記でした。

微分積分チャレンジ成功

最近は、機械学習とか電子工学とかにちまちま入門してたんだけど、そうすると数学が結構出てくる。一応ふむふむとかいって勉強してるんだけど、とにかくめちゃくちゃ微分積分が苦手だったことを思いだすことになった。積の微分公式がわからなかった時のツイートが以下になります。

この状態で応用を学び続けるのは心配だということで、簡単な本を買ってきてちまちま練習問題をすることにした。

やさしく学べる微分積分

やさしく学べる微分積分

1次関数の微分積分、マクローリン展開などによる近似、2次関数の微分積分あたりくらいまでの基本を学べる。この本しか読んでないので他の本と特に比較はできないものの、ポイントおさえつつも、練習問題が難しすぎない感じで勉強しやすかったと思う。

例題と練習問題のセットが70問くらいあって、例題も含めてノートに書いてちまちま問いていくというスタイルで勉強していった。各問は小問にわかれてるので、個別の問題としては250問くらいありそう。

そういう感じでときどき中断したりしながらも3ヶ月くらいとりくんだ結果、ついに最後の問題を解くところまでできた。最後の問題は絶対ちょっとむずかしくしてあって、これまで登場したいろんなテクを活用する必要があって、ラスボス感があった(そして間違えた)。

https://www.instagram.com/p/BEoPvVJPpLF/

とにかく基本もおぼつかない状態だったので、一通り学びなおすのに成功したのはめでたい。このあとはたぶん線形代数と確率統計あたりが数学復習チャレンジになってきそう。

アニメ推薦くんの精度について

今季見るべきアニメを機械学習で推薦する に対してなんか精度評価のしかたおかしくない? とご意見をいただきました (指摘1, 指摘2 )

調べたところたしかにいろいろおかしくて、F値が0.9をこえるスコアも実際よりもかなり高いことがわかったのでご紹介します。ご指摘ありがとうございます :bow: 。

おかしかったところ

教師データをあたえるときには1とラベル付けされたデータと0と、ラベル付けされたデータの数が同じになるように、オーバーサンプリングしました。

と元の記事にはあったのですが、このオーバーサンプリングが問題でした。オーバーサンプリングを教師データとバリデーションデータに分ける前に行ってしまっていたため、同じアニメの特徴とそのラベルが教師データとバリデーションデータの両方に含まれていました。

教師データに含まれるアニメを正しく分類できるのは当然ですから、教師データと同じアニメをバリデーションデータ含めて分類器を評価してしまうと、当然良い数値が出てしまいます。もちろんこれは妥当な評価ではありません。

妥当なオーバーサンプリング

この問題をデータを教師データとバリデーションデータに分けた後にオーバーサンプリングするようにして修正しました(コードの様子。この修正によって、より妥当なF値が得られるようになりました。ちなみに、F値は0.6強程度になっていうほど精度は高くないことがわかりました...。これはつらい。

分類器の改善

実は精度が悪かったとなるのもくやしいので、そのあと少しチューニングをしました。

  • オーバーサンプリングはあまり意味がなかったのでやめる
  • 特徴量が多そうだったので採用する特徴をおさえる
    • キャストを特徴にいれるのをやめる(声優さんは多様な性質のアニメに出演しそうなので)
    • 特徴として採用する人物の登場回数の閾値をあげる
  • 教師データ増やす(1200程度まで)
  • 最適化アルゴリズム変更してみる (Adam -> AdaGrad)
  • そのたパラメータの最適化

サンプルスクリプトもこのチューニングにあわせて更新しました(ただし、僕の好みによる教師データ向けのチューニングですが..)。

現在の精度

現在のところは、バリデーションデータ上で以下のような精度を出せています。

             precision    recall  f1-score   support

          0       0.93      0.98      0.96       443
          1       0.87      0.61      0.72        79

avg / total       0.92      0.93      0.92       522

いろいろ出ていますが、重要なのは 一番左に1 とかかれた行です。F値は0.72程度ですが、precisionはかなり0.9近くまでだせており、現実的には多くとも十数個にアニメを推薦しないと考えるとまちがっても1,2個ということで、ツールが推薦したアニメの妥当性はそこそこ高そうです。一方、recallは0.61とあまり高くありません。本来は気にいると考えられるアニメが、推薦されたアニメと同量近く存在することになります。

F値にもとづいた学習曲線をplotすると以下のようになります。そんなに高くないですね!!

f:id:hakobe932:20160416215401p:plain:w600

感想

評価方法をミスっていると土台がゆらいしまい、全部ひっくりかえるので妥当性の確認はきちんとしないとですね...。指摘してくださった方々ありがとうございました。

F値は結局そこまで高くなりませんでしたが、precisionはそこそこ出せる分類器を作れました。正直、推薦される件数は少ないのでrecallも追求できればしたいですね。あるいはスタッフの情報からアニメを分類するのはどこかで壁があってもうすこし他の情報が必要なのかもしれません。前の記事のブコメでもスタッフやキャストだけで判断できるか疑問に思われている方がたくさんいました。

思ったより前の記事に反響があってびっくりしました。その上にちょっとミスってたのでつらさ100倍でしたが、チューニングすればぎりぎりゆるせるかなーどうかなーとうくらいになったので許されてい...。もうすこし違った特徴が考えないとかなーと思うので、たまに改良していきたいですね。

今季見るべきアニメを機械学習で推薦する

Coursera で機械学習に入門成功できたので応用に挑戦してみました。ちょうど季節の変わり目ということで、過去に見て気にいったアニメの特徴を学習して、未知のアニメを、気にいりそうなアニメと気にいらなそうなアニメに分類するツールを作って、ソフトウェアに今季見るべきアニメを推薦してもらいたいと思います。

アニメの特徴量

あるアニメを気にいるかどうかは、話のおもしろさや、絵柄の感じ、キャラクターの魅力などによって決まりそうです。ただ、話のおもしろさや、絵の美しさ、キャラクターの魅力を特徴量として数値化するのはむずかしいので、アニメの映像を制作しているスタッフや会社、声を当てているキャストにフォーカスすることにしました。

Courseraの機械学習のコースでは、特徴として妥当かどうかを判断するのに、人間が同じ特徴を与えられて分類といったタスクが可能かを考えてみよとアドバイスしていました。アニメ作品の制作会社や監督、脚本、出演声優の名前を見ればなんとなく自分に合いそうなアニメかはわかる気がするので、特徴としては良さそうです。

特徴ベクトルの表現

各成分がアニメの制作会社やスタッフ、キャストなどに対応するような、ベクトルを考えます。あるアニメの特徴ベクトルは、そのベクトルによって表現します。ベクトルの各成分の値はその成分に対応するキャストやらが、そのアニメに関係していれば1していなれば0とします。例えば以下のようになります

タイトル属性 サンライズ 鳥海浩輔 櫻井孝宏 中村悠一 沢城みゆき 遠藤綾 金元寿子 ...
鉄血のオルフェンズ 1 1 1 1 0 0 1 ...
ワンパンマン 0 1 1 1 1 0 0 ...
おそ松さん 0 0 1 1 0 1 0 ...

ここではベクトルの大きさは7くらいですが、実際にはもっと沢山のアニメ関係者をベクトルに対応づけます。今回は学習に使ったアニメと推薦する対象になる今期のアニメの関係者を、出現頻度のおおいほうから1000くらい選びました。

しょぼいカレンダーの利用

アニメに関係している制作会社やスタッフ、キャストを自分で調査するのは非常に大変なので、いつもお世話になっているしょぼいカレンダーを利用させていただきました。

しょぼいカレンダーにはアニメ作品ごとのページがあって(例: http://cal.syoboi.jp/tid/3424)、スタッフやキャストの情報がそこにまとめらています。公開されているAPI を利用すれば、この情報を取得できるので利用します。

また、しょぼいカレンダーは各アニメにIDを振ってくれているので、そのIDをプログラム中で特定のアニメを指定するための識別子として利用させてもらいました。

過去に見たアニメの評価

自分の好みを学習して使いたいので、過去に見たアニメに対してラベル付けしていきます。ラベルはそのアニメを自分が特に気にいっていれば1を、そうでもなければ0をつけます。

ラベルづけのために、2013年から2015年に放送されたアニメを順番に表示して評価を入力できる、簡単なスクリプトを書きました。このスクリプトを使って、アニメにどんどん評価をあたえていってるのが以下の画像です。yと入力すれば特に気にいってる、それ以外はそうでもないという意味です。この調子で580個くらいのアニメを評価してラベルを付けました。

f:id:hakobe932:20160415142003g:plain

ニューラルネットワークを使った分類器

ここまでで580個くらいのラベル付きのアニメの特徴ベクトルが得られましたので、このデータに基づいて分類器を構築します。機械学習による分類器の手法をいろいろ試してみましたが、一番うまくいったニューラルネットワークを使った分類器を紹介します。

ニューラルネットワークの分類器を自分で丁寧に作っても良かったのですが、できるだけすでにある物を使うべしと、Courseraの機械学習でもいってましたし、Chainerを使ってみました。

Chainerではニューラルネットワーク自体は以下のように定義します。これは3層のニューラルネットワークになるような計算グラフを構築しています。入力ベクトルの長さを1000としているので、入力層は1000ノードあります。隠れ層は100ノードあって、出力層は2ノードです。活性化関数としてはsigmoid関数を使っています。

出力は長さが2のベクトルになっていて、1番目の成分の値は、入力された特徴ベクトルが0にラベル付けされるべき度数をあらわします。2番目の成分の値は同様に、入力された特徴ベクトルが1にラベル付けされるべき度数をあらわします。

from chainer import Chain
from chainer.links import Linear
from chainer.functions import sigmoid

class AnimeChain(Chain):
    def __init__(self):
        super(AnimeChain, self).__init__(
            l1=Linear(1000, 300),
            l2=Linear(300, 2)
        )
    def __call__(self, x):
        h1 = sigmoid(self.l1(x))
        o = self.l2(h1)
        return o

このニューラルネットワークに特徴ベクトルと正解のラベルを学習させるような関数を定義します。この関数では、ある段階でのニューラルネットワークで計算した結果と本来得たい数値の誤差を計算して、その誤差に基づいてニューラルネットワークを誤差が最小になる方向に更新していきます。この時に誤差を計算グラフの逆方向に伝搬させていったりする必要があるのですが、そこはライブラリがうまく隠蔽してくれていて、たくさんコードを書かずにすんでいます。細かなコードの意味はChainerのチュートリアルなどを参考にしてください。

from chainer.optimizers import Adam
from chainer import Variable
from chainer.functions import softmax_cross_entropy

# 各アニメの特徴ベクトルを持つ行列Xと、
# 各アニメへのラベル付けの結果を含むベクトルtを受けとって計算する
def train(X, t):
    model = AnimeChain() # 定義したニューラルネットワーク
    optimizer = Adam()   # Adamという方式を使って最適化する
    optimizer.setup(model)

    for e in range(1500):
        V_X = Variable(X) # 計算グラフに値を与えるときはVariableにくるむ
        V_t = Variable(np.array(t, dtype='int32'))

        V_y = model(V_X)
        model.zerograds()
        loss = softmax_cross_entropy(V_y, V_t) # 誤差を計算
        loss.backward()    # 逆伝播させてXの各成分ごとの誤差を計算
        optimizer.update() # 得られた誤差にもとづいてパラメータを更新
        if loss.data < 0.001: # lossが十分小さくなるまで繰り返す
            break
    return model

このtrain関数に対して、用意したアニメごとの特徴ベクトルと、手でがんばって入力したラベルを教師データとして与えることで、その内容を学習した分類器ができあがります。

教師データをあたえるときには1とラベル付けされたデータと0と、ラベル付けされたデータの数が同じになるように、オーバーサンプリングしました。0とラベル付けされたのほうが多かったので、オーバーサンプリングしないとあまり性能がでませんでした(F値で0.6くらいになってだいぶしょぼい)。

分類器の性能

用意したラベル付きのアニメの特徴ベクトル群を教師データとバリデーションデータにわけたあと、教師データをつかって学習した分類器でバリデーションデータのラベルを予測できるかどうかを確認しました。評価値としては、F値を使います。

この分類器の学習曲線は以下のようになります。教師データの数を増やせば増やすほど、バリデーションデータにおけるF値が0.9以上となっており、うまく学習できていることがわかります。だいたいサチってそうですが、教師データを増やすともうすこし良くなるかもしれません。

追記: 2016/04/16 12:54

オーバーサンプリングした結果をそのあとシャッフルしていたので、教師データとバリデーションデータに同じデータがはいってそうでした。細かくしらべてますが、こんなにスコアは良くなさそう..。0.7とかくらいでは...。グラフもまちがってそうです。

追記: 2016/04/16 22:20

評価については別にエントリを書きました。

hakobe932.hatenablog.com

実際に予測してみた

この分類器を使って実際に僕が今季見るべきアニメを予測しました。

僕が気にいったアニメを学習した分類器の結果なので、他の誰の役にも立ちませんが、自分としてはふむふむ納得という結果が得られました。けいおんの再放送がはいっていますが、ここ3年くらいのアニメしか教師データとしてあたえていないはずなので、これも機械によって予測されているはずです。けいおん最高。

実際のコード

Python3で書いたコードが素朴にGitHubにおいてあります。気がむいたら実行の仕方など書こうかと思います。 READMEに実行の仕方を追加しました。

追記:

↑のように雑な紹介しかしていないのに使ってみてくださってる方がいました! 実行の仕方の解説もあってすごすぎる!

wiroha.hatenablog.jp

続々ためしていただいています

zfhrp7.hatenablog.com

今季見るべきアニメを機械学習で推薦する - はこべブログ ♨

手元で実行した結果、カードキャプターさくらとけいおん!を見れば良いことが分かった

2016/04/15 20:15
b.hatena.ne.jp

まとめ

というわけで、Coursera で機械学習を学んだ成果として今季見るべきアニメ推薦くんを作ってみました。アニメの制作にかかわる、キャストとスタッフの人名にもとづいた特徴に基づいた学習で、なかなかの分類精度が出ることがわかりました。(追記: 2016/04/16 13:35 測定がミスっていて精度でているか謎です.. => 精度についての記事 を書きました。) 。そこそこ便利なツールができたと思います。

ここでは一本道で紹介しましたが、実際のところはロジスティック回帰やサポートベクターマシンなどいろんな手法をためしてみたり、あれこれパラメータ変更してみたり試行錯誤を重ねました。一週間くらいはF値が0.6からあがらなくてあきらめかけたものの、ためしにオーバーサンプリングしてラベルが1と0の教師データの割合を1:1にしたところめっちゃくちゃ精度があがったりして、良い学び体験を得られましたこれまちがってそうでした..つらい。

とにかく何か作ってみることには成功したのでニコニコしつつも、よく理解してないところも沢山あることもわかったので、なんか勉強します。

Coursera の Machine Learning 完走

CourseraのMachine Learningのコースを完走できた。11週間くらいかかったけど、かなり効率良く機械学習について学べてとても良かった。

コースは機械学習の手法について広く教えてくれる。教師あり学習の線形回帰やロジスティック回帰、ニューラルネットワークの構築の仕方、教師なし学習のK-meansや主成分分析などなど。それだけでなく、実践的な技とか勘所を教えてくれるのが良い。例えば、大量の教師データを集める前に、データ増やして改善しそうな性質になっているかを確認して、半年とかを無駄にしないようにしましょうとか、まずはシンプルな手法に取り組んで様子をみながら難しい手法を試してみると良いでしょうとか。

一週ごとに宿題があって理解を確認できるようになっている。宿題にはプログラミングの課題もあって、実際に機械学習のプログラミングの雰囲気を体験できる。単にアルゴリズムを実装するだけではなくて、グラフの様子をみながら改善していくといったフローになっていて自分でやるときも同じようにできそうで良い。簡単にはループで実装するところを、ベクトル化してシンプルな見た目、かつ高速に動作するように改良したりするのは、パズルっぽくておもしろかった(前もちょと書いてた)。

数学の知識がないと大変そうって思っていたものの、うろ覚えの基礎的な微分積分と線形代数でなんとかなった。とはいえ、手法の裏付けは数学的に証明されているので、できたらより納得感は高そう。もうちょっと理解したくて、微分積分勉強してる。微分積分は電子工学勉強するのにも使えるので便利そう。

f:id:hakobe932:20160409120611p:plain

11週間も時間を見つけてはビデオみたり、休みの日に宿題したりでちょっと忙しかった。しかし、機械学習分野のとっかかりを得るにはとても良くて、勉強して良かった。機械学習を使って自分で何か作ってみたりできそうだし、次に何を学ぶべきかもなんとなくわかる。何か役立つものを作ってみたい。

最後のビデオでは先生がそんな僕らに労いと感謝の言葉を繰り返し投げ掛けてくれて、涙なしでは見れないという感じでよかった。おすすめです。


あわせて読みたい:

blog.sushi.money

国立科学博物館

遊ぶ用事があって東京をうろうろしてる。土曜日はちょっと時間が余ったので国立科学博物館に行ってきた。



あんまり調査せずに行ってみたもののとても良かった。すごい豪華な理科室という趣で、恐竜から宇宙から産業機械からとにかく広範囲をカバーしたおもしろ展示が無限にある。理科の図鑑に載ってたいろんな動物の剥製があって見比べられるし、トリケラトプスやアーケロン、鯨の骨格は迫力がすごい。水中に浮いてる砂鉄が地場の中で整列する様子を確かめられるし、電磁誘導で遠くのLEDが光る様子を眺められる。

ただ、とにかく展示の分量が多くて全然回りきれなかった。3時間くらいいたけど3割くらいしかみれてない。油断してた。あと2回くらい訪れてコンプリートしたい。

(明示的に禁止されてる展示以外は写真が撮れる。)

計算機の歴史のコーナーがよくて真空管式やリレー式の巨大なコンピュータを眺められる。インテルのi4004とかも置いてあった。

ちまちまポケモンやってる

初代ポケモンが3DSのバーチャルコンソールで発売されたのでちまちまやってる。先日からビーダマンやっていたりとマインドが20年前に戻りつつある。

初代ポケモンはさすがに近代のポケモンと比較するとグラフィックなどは素朴なもののやっていておもしろくてすごい。次はあのポケモン進化させるぞ!とかどうやったら隣町に行けんるだ??とか、次々とやることがでてきて飽きない。モブが次にやることをあんまり言ってこないのがいいのかも。そのかわりミスるとフラッシュなしでイワヤマトンネルを抜けることになる。

いまはヤマブキシティやってきたところなので中盤くらい?もう少しすすんだらだれかポケモン交換したり対戦したりしましょう。