にほんごのれんしゅう

日本語として伝えるための訓練を兼ねたテクログ

emotion2vec

emotion2vec

テキスト感情ベクタライザの提案 〜 doc2vec, fasttext, skipthoughtに続く第四のテキストベクタライザ 〜
ジョーク投稿です。正確なリプレゼンテーションかどうか、十分な検証をする必要があります)

感情は難しい

 コミュ症の人が何らか相手の感情を察しようとした場合、既存の知識や経験に基づいて相手が何を意図しているのか、把握することが難しいという悲しい事実があります。
 ディープラーニングってやつでなんとかして!案件ですね。

f:id:catindog:20170322223403p:plain
ここでは、感情を定量的に解析して確認する手法を提案します。

リプレゼンテーション(表象)の選択

 最も端的に感情を示している素性は何でしょうか。映像ではその人の行動であったり、表情であったりします。
 テキストの世界では、最近の若い人たちは、絵文字というものを使うことがあります。絵文字はその文脈では伝えきれてない感情を絵文字の表現力を借りて表現する場合で有効であります。

例) 
💢 -> ムカつく
❤ -> 好き好き
♪ -> 気分が上昇している

 なるほど。漫画はよく読むのでよくわかりますね。なんで漢字の書き取りがあって、絵文字の書き取りは小学校ではやらないんですかね。
 テキストにおいては、絵文字がそのテキストの秘められたリプレテーション(表象)になっているように仮説が立てられそうです。

手法

 Word Level CNNを用いて、テキストをベクトル化します。ベクトル次元数は2014次元で大きいです。
 Twitterのフリープランで400万ツイートものツイートを頑張って集めました。これを分かち書きして、fasttextで分散表現に置き直します。
 分散表現で記された文章をCNNにかけて、そのツイートに内在されていたはずの絵文字を予想するタスクを与えます。複数の絵文字がある場合、複数予想させます。
 結果として、感情を示すベクトルが獲得できるようになります。

  (epochは前回CNNでのテキスト認識で用いたoverfitにならない25epochを適応)
 optimizer:adam
  window size:1,2,3,4,5
  input-vector:256dim * 30dim
  output-vector:2048dim
 その他諸々はコードを参照ください

f:id:catindog:20170322230510p:plain

イメージ図。Ubuntuのimpressで作ったが見切れてる

コード

(商用利用する際には一声くださると助かります)
github.com

結果

 今回のemotion2vecは極端な不均衡データでありました。そもそも感情は自然に分布しないと思うので、それはいいのですが、特定の♪などの絵文字リプレゼンテーションになりがちになりました。
(テキストは小説家になろうの「蜘蛛ですが何か」からお借りしました)

text.ないわー。 
 😭 87 😂 5 💢 4 😳 32 💓 2 🙄 2 💗 22 😑 222 😊 2 👍 1 😢 1 💕 11 😇 1 💩 1
(悲しくて起こっている感情のベクタ) 
text.これで私は自由だー!
 ♡ 765 💕 5 😭 4 😂 4 😊 4 💓 3 👍 3 💗 3 🏻 2 😆 2 😍 22 🙌 2 😳 1 🙏 111 😌 1 
(自由の感情のベクタ)
text.《熟練度が一定に達しました。スキル『蜘蛛糸LV3』が『蜘蛛糸LV4』になりました》 
★ 945843 
(なんか事務口調のテキストには星がいっぱいつきます)
text.あ、でも蜘蛛猛毒だと大抵の相手は即死しちゃうな。
😱 8 💢 8 😭 7 😨 7 😡 6 💥 6 😇 55 💦 5 😂 4 😅 4 🏻 4 🙏 43
(ムンクっぽい何か)
text.マジかー。
😭 16 😂 6 😇 3 😳 3 😍 2 😢 2 😱 2 💕 22 🙄 1 💗 1 💓 1 💢 11 🙏 1 💦 1 🙈 1 😌 1 😅 1 
(マジかー)
text.「クソッ!?」
♡ 17 💢 10 💩 921111
(うんちのお気持ち)
text. うるせぇ、てめえ、ぶっ殺すぞ 
💢 99
(わかる) 
text. あのあの、エッチなのはダメなのです
♡ 257 💕 3 💦 3 😭 322 😂 2 😢 2 😊 11 😅 1 😇 1 😑 1 😌 1 
(ちゃんとハートと汗があるよ、電ちゃんっぽい発言を意図しました)

考察

Word LevelじゃなくてChar Levelのほうがよかった気がする。
強い感情に引っ張られて大きなウェイトがつくので、感情の起伏を定量的に記すのもいいかもしれない

まとめ

 じつはこれはText GAN(SeqGAN)の副産物だったりします。SeqGANにはとにかく前処理が山ほどあって、なんとなく学習までのイメージがあるのですが、遠いです💦

RNNで「てにをは」を校正する

RNNで「てにをは」を校正する

余談

2017/3/19に、どの深層学習フレームワークがこれから深層学習を始める人におすすめなのかというアンケートをtwitterで取らせていただきました。

f:id:catindog:20170320174157p:plain
五位 Theano(個別カウント)

はじめに

 RNNによる文章校正がリクルートによって提案されて以来、調査タスクとして私のものとに来たりして、「できるんでしょう?」とか軽く言われるけど、実際には簡単にはできません。
 RNNによる文章生成ができるから、校正もできるというのが人間の自然な発想なのかもしれませんが、英語と日本語の違いに着目した場合、英語がアルファベットのみで構築されるのに比べて日本語は、漢字・ひらがな・カタカナと非常に多く、同じように問題を適応すると、すごい高次元の問題を解くこととなり、理想的なパフォーマンスになかなかなりません。
 まぁ、あんまり完成してるわけでない技術を完成したようにプレスリリースを出す企業様の印象操作もあり、正直どうかと思うんですけどね...まぁそれはいいです。

 さて、リクルートは文章生成プログラムとビームサーチで「てにをは」を修正するディープラーニングがあるということですが、RNNとビームサーチで実装したとのことです[1]
 いささか、どのように実装したのか不明瞭であったので、まとめ直しました。多分こういうことでしょう。
f:id:catindog:20170320172153p:plain

図1. 多分ビタビアルゴリズムのようにしているんだと思う
 
 さて、問題となるのが、計算量です。幅3で一文を探索した場合でも、修正する助詞が3つあれば、9回の評価が必要になります。しかも、GRUやLSTMは状態を保存するので、モデルの状態を固定して9つ別個に走らせる必要があるので、9倍のメモリも必要になります。(実はわたしは、このアプローチはだいぶ前に試して、お蔵入りにしました)

 これを別のアプローチで解決していきます。

問題

 文章校正ではコンテンツを持つ企業であれば、どこでも直面する問題であるので、RNNでの文章校正に意欲を燃やす企業が多い。
 このモチベーションは素人ライターや文章をあまり書いたことのない人などが、内容はおいておき、「てにをは」がおかしかったり、単語チョイスがおかしかったりすることに起因していて、直すのは人手が現在はほとんどであり、大変工数がかかるので簡易化したいという思惑があったりする。
 とくにキュレーションサービスを抱えている業者は、素人の日本語が変だったりして、修正することが多い。キュレーションサイト自体は、現在では、盗用であったり、健康に害を及ぼすニセの情報の発信も問題とされている。DeNAでは大炎上して40億近くも溶かしたらしい、人の命に関わる問題で適当やらかしたら、しょうがない気もする[2]
 問題のスコープを限定して、コンテンツの真偽性の検証ではなくて、「てにをは」の修正に焦点を当てる。
 また、キュレーションサイトに素人文章が多いということを利用して、修正箇所が多いほうが、キュレーションサイトであるという仮説を検証する。

提案

 RNNで助詞を予想させるタスクを行う。ただし、ビームサーチが必要になるのは次の文脈が確定されていなからであって、予想する文字の次の文脈を入力素性として利用する。
 これは、以前教師なし文章の復元の投稿でも用いた類似したアプローチであるが、単語粒度に拡張し、fastTextを適応してベクトル化して、「てにをは」を修正する問題である。
 通常、RNNを文章生成のタスクで利用するには、活性化関数にsoftmaxと損失関数categorical cross entropyを利用することが多い。しかし、鋭利すぎる出力が出ることが多いので、なだらかな出力が欲しかったので、活性化関数にsigmoid、損失関数にbinary cross entropyを用いたモデルで行う。
f:id:catindog:20170320172507p:plain

図2. 今回利用したモデル

モデル

Keras2を使ってみました。
github.com

ネットワークのみ記す。

def build_model(maxlen=None, out_dim=None, in_dim=256):
 print('Build model...')
 model = Sequential()
 model.add(GRU(128*20, return_sequences=False, input_shape=(maxlen, in_dim)))
 model.add(BN())
 model.add(Dense(out_dim))
 model.add(Activation('linear'))
 model.add(Activation('sigmoid'))
 optimizer = Adam()
 model.compile(loss='binary_crossentropy', optimizer=optimizer)
 return model

コード全体はgithubを参照にしてください。
データセットを集めるプログラムは付属していないので、適宜各人、適宜、集めてください。
ubuntu用のfastTextバイナリが含まれます。Python3のみ動作検証しています。

実験

  • Yahoo! Newsの記事2月1日からのデータを1000MByteの学習データセットをもちいて学習させた
  • LSTMではなくGRUを用いた。2560unitも使う巨大なモデルである
  • 活性化関数はsigmoid
  • 損失関数はbinary cross entropy
  • 入力は助詞の周辺の単語19語、出力は助詞の種類
  • 単語の分散表現はFacebook社のfastTextを利用して256次元にエンベッディング
  • 修正する助詞は「が,の,を,に,へ,と,で,や,の,は,も,ば,と,し,て,か,な,ぞ,わ,よ」に限定した

評価

1. 訂正能力を確認するため、実際にいくつかのキュレーションサイトで試してみることで、定性的に評価する
 評価に4meeeというサイトの記事を用いた
2. キュレーションサイトと、Yahooヘッドラインの記事では訂正箇所の大小により差があることを定量的に評価する
 評価を4meeeの1000文, 日経新聞の1000文を調べることで、差があるかどうか定量的に評価する

結果

1. 訂正能力を確認. 実際にいくつかのキュレーションサイトで試してみることで、定性的に評価
(4mee.comさまのサイトを参照させていただきました)
(赤い文字が修正ポイントです)
間違いを指摘する例 1.
...いい,の,だろ,う,か,?,」,と,悩む,こと,,ある,かも,しれ,ませ,ん,ね,。,アラサー女子,が

0.435673713684082030.22929041087627410.126160755753517150.074866257607936860.051154583692550660.0237842295318841930.014887742698192596
… 以下略

間違いを指摘する例 2.
...理由,で,、,結婚,を,考え,られ,ない,という,方,,多い,かも,しれ,ませ,ん,。,ですが,、,それ

0.98368060588836670.4184749424457550.16642177104949950.0062757581472396850.0043656616471707820.0009334951755590737
...以下略

間違いを指摘する例 3.
...れ,て,いる,こと,は,あり,ませ,ん,。,理由,,ない,のに,定職,に,つか,ず,に,ふらふら,し

0.93805074691772460.114897608757019040.073563553392887120.053266808390617370.0262335799634456630.01495771761983633
...以下略

接続詞でだいぶ、異なった出力が得られるようです。人間も意識しないとわからない部分です。

2. キュレーションサイトと、Yahooヘッドラインの記事では訂正箇所の大小により差があることを定量的に評価

これは、日本語としてちょっと標準と離れることがキュレーションサイトでは多い、つまり、権威あるニュースサイトに比べると、訂正箇所がおおいという仮説を証明する。
評価を4meeeの1000文, 日経新聞の1000文を調べることで、差があるかどうか定量的に評価する

|実測値   | 日経 | 4meee |
|修正なし |  746 |   491 |
|修正あり |  254 |   509 |

カイ二乗検定などを試した結果、別の分布と言えるようだ。別のものであれば、キュレーションサイトと日経のサイトを判別する機械学習モデルの素性に組み入れても良いだろう。

結論

 ビームサーチを行わないモデルなので、探索が楽で高速に動作するというメリットがあり、softmax + categorial cross entropyと違って確率表現のように出力するので、しきい値等で、機械学習の結果を採用したり、却下したりすることができる。
 また、日本語の「てにをは」は厄介なので、日本語の勉強をしている非ネイティブの人や、研究者の方、日本人だが簡易的な校正が必要な方などの利用ケースが考えられる。
(なにか間違いがありましたら、twitterでこっそり教えてください)

参考文献

[1] LSTMとResidual Learningでも難しい「助詞の検出」精度を改善した探索アルゴリズムとは http://www.atmarkit.co.jp/ait/articles/1611/11/news016_2.html
[2] 第三者委員会調査報告書 http://v3.eir-parts.net/EIRNavi/DocumentNavigator/ENavigatorBody.aspx?cat=tdnet&sid=1450400&code=2432

新しく買ったWindows 10でneologd等の自然言語処理環境を構築する (+ XGBoost)

新しく買ったWindows 10でneologd等の自然言語処理環境を構築する (+ XGBoost)

はじめに

f:id:catindog:20170319214656p:plain

 自然言語処理機械学習とSE的なことを仕事としているのですが、現在務めている会社ではWindowsの利用を強く推奨されることがあります。これは、コンプラインスの関係でセキュリティ管理者が複数のOSを管理するコストは高いからWindowsに限定することが多いという理由に起因しています。
 この文章を書いている環境はUbuntu LinuxLibreofficeを用いています。文字コードUTF-8だと自然言語処理の観点で何かと都合がよく、MeCabなどの形態素解析エンジンもUTF-8ですし、Python3も内部の処理系がUTF-8で、GolangのRuneや、C++も文字処理粒度はUTF-8のものが増えています。
 こういう関係もあって、sjisをハックするなど、あまり技術的にこったことをしたくないというモチベーションのもと、Windows形態素解析と、みんな大好きXGBoostを導入するまでの一連の流れを示したいと思います。
 ツール属性の攻撃という言葉があって、これが案外馬鹿にできないというか、かなりの攻撃力を誇るので、できるだけ覚えるコスト下げたいという思いもあります。
 (この方法は2017年3月段階での、私がいじくってなんとか動かした方法ですので、正しく理解するには公式ドキュメントも注意深く参照することをおすすめします)

計画

1. Windows 10の持ち運べるノートパソコンであるLG gramの購入と、アップグレード
2. OSをNVMeに移動する
3. 日本語が処理できるようにcmdやcmderの代わりにputty, teratermやcygwind sshを利用する
4. mecabとneologdの導入
5. Anacondaとjupyter notebookの構築
6. XGBoostの導入

1. Windows 10の持ち運べるノートパソコンであるLG gramの購入と、アップグレード

 本当はMacBook Proがほしいのだが、2017年3月、もっとも高いメモリのモデルでも16GByteまでしかなく、加えて8GByte → 16GByteに変更するのに20000円もかかる。自分で取り替えられる場合、12000円程度ですむ。
 MacBookには、NVMeモデルがない。NVMeはSSDより高速な主記憶装置で、ディスクに大量にアクセスする操作が発生することが多い機械学習ではNVMeであるだけで、かなり処理時間が短縮できることがある。スワップ領域等を作成しておくと、メモリがあふれた時にもマシンが処理落ちして使い物にならなくなる時間が短縮できて大変よい。
 CPUは早いほうがいいが、ノートパソコンで重い計算をさせることは私は少ないのでCore i3でいいかなって感じです。

 LG gramの2017年のモデルが1キロを下回る軽さで、メモリを追加することも、NVMeに換装することもできます。96000円程度で秋葉原ツクモで10%還元で購入できました。そのポイントを利用してNVMeとDDR4の16GByteのメモリを購入しました。NVMeがsamsung 512GBのモデルで30000円程度,DDR4の16GByteで12000円程度でした。合計で、120000円程度です。
f:id:catindog:20170319212304p:plain

図1. ツクモで買ってきました

 全く文脈を無視しますが、ぼくは小林銅蟲先生を尊敬していまして、料理ブログよく見てるので、あのノリ羨ましいなって思います。
f:id:catindog:20170319212424p:plain

図2. PCの箱とNVMeとメモリとツクモちゃんのクリアファイルです
f:id:catindog:20170319212602p:plain
図3. 開けたときの様子、プラスチックで昔のMacBookを連想させます。ぼくは樹脂のほうが好きです
f:id:catindog:20170319212717p:plain
図4. 背面の様子です。開けていく
f:id:catindog:20170319212804p:plain
図5. 一キロ切っているモデルでメモリと記憶域交換できるのは本当にめずらしいです。よさを感じる
f:id:catindog:20170319212852p:plain
図6. メモリスロットとPCI-Expressです。
f:id:catindog:20170319212937p:plain
図7. 刺しました。(SSDからUSBディスクにOSを退避させた後です)
f:id:catindog:20170319213041p:plain
図8. メモリ20GByte認識して、NVMeの速度出ているようです

OSをNVMeに移動する

 これが一番めんどくさかったです。コントロールパネルからリカバリーディスクの作成を選んで、32GのUSBフラッシュメモリにOSのリカバリディスクを作成しました。
 かなり早いUSBフラッシュメモリを用いたのに全く速度がでない。。。4時間ぐらいかかりました。これはMicorsoftの怠慢では。途中で寝てしまいました。
f:id:catindog:20170319213224p:plain

図9. 遅すぎる
 終わったら、NVMeに取り替えてF10を押しながら起動して、USBから起動して復元を行います。(有料のソフトもいくつかみたけど、覚えるのつらすぎ)

3. 日本語が処理できるようにcmdやcmderの代わりにputty, teratermやcygwind sshを利用する

 Bash on WidowsというWindows上にUbuntuが動作する仕組みがあるのですが、コマンドプロンプトや、よくおすすめされるcmderというソフトは、日本語入力やファイルが壊滅的にダメで、これが原因でほんとつらい思いをしました。
 よく私が使う回避策は、Bash on Windowsssh-serverを起動して、teraterm等てアクセスする方法です。面倒ですが今のところこれが一番安定して、日本語が扱えます。

3.1 開発者モードを、コントロールパネルから有効にする
3.2 Windowsの機能の有効化または無効化 → Windows Subsystem for Linux (Beta) → チェックを入れて再起動
3.3 services.mscコマンドプロンプトに入力 -> SSH Server Broker,SSH Server Proxyの2つのサービスを無効にする
3.3 cmdを立ち上げる → bashと入力 → Linuxのインストール
3.4 Bash on Windowsに入る → sudo apt get install openssh-serverでインストール
/etc/ssh/sshd_configを編集

$ sudo vim /etc/ssh/sshd_config
変更→ UsePrivilegeSeparation no
変更→ PasswordAuthentication yes
コメントアウト → #Hostkey /etc/ssh/ssh_host_dsa/key
コメントアウト → #Hostkey /etc/ssh/ssh_host_ecdsa/key
コメントアウト → #Hostkey /etc/ssh/ssh_host_ed25519/key

コマンド実行(これをやらないとつながらない)

$ sudo ssh-keygen -t rsa -N '' -f ssh_host_rsa_key

sshdを起動

$ sudo /etc/init.d/ssh start

ここまでできれば、teratermcygwinsshで好きなように操作することができます。日本語もオッケーです。

4. mecabとneologdの導入

 これもUbuntuのインストール手順に従えば、問題ないです。標準のUbuntuLinuxにはデフォルト入ってないパッケージもあるので適宜入れていきます。

mecabソフトウェア各種インストール

$ sudo apt install mecab libmecab-dev mecab-ipadic
$ sudo apt install mecab-ipadic-utf8
$ sudo apt install python-mecab
$ sudo apt install python3-pip
$ sudo pip3 install mecab-python3
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
$ cd mecab-ipadic-neologd
$ ./bin/install-mecab-ipadic-neologd -n

mecabのデフォルト辞書をneologdに変更する

$ sudo vim /etc/mecabrc
変更 → dicdir = /usr/lib/mecab/dic/mecab-ipadic-neologd

動作確認(FGOは標準辞書にない)

$ echo "Fate/Grand Order" | mecab
Fate/Grand Order        名詞,固有名詞,一般,*,*,*,Fate/Grand Order,フェイトグランドオーダー, フェイトグランドオーダー
EOS

5. Anacondaとjupyter notebookの構築

最初Anacondaを使わずに入れようと思ったけど、ubuntuのwheelが通じないことながあって、Anacondaでインストールするのが楽でした。

Anacondaのパッケージを取得

$ wget https://repo.continuum.io/archive/Anaconda3-4.3.1-Linux-x86_64.sh

インストール(sudoするとパーミッションが面倒なのでしない)

$ sh Anaconda3-4.3.1-Linux-x86_64.sh
(ひらすらyesで進めていく)

私の環境ではpython3.6のバイナリがAnacondaのPythonですので、Python3.6で実行できるようになります。

$ which python3.6
/home/{yourname}/anaconda3/bin/python3.6

なお、ipythonのkernelが不安定なので、以下のパッチを当てる必要があります。

conda install -c jzuhone zeromq=4.1.dev0

jupyter notebookのパスワードを作成します

In [1]: from notebook.auth import passwd
In [2]: passwd()
Enter password:
Verify password:
Out[2]: 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed' <-これをコピーしておきます

jupyter notebookにパスワードを設定

$ vim ~/.jupyter/jupyter_notebook_config.py
コピーした内容を貼り付け
c.NotebookApp.password = u'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'

ついでにjupyterで形態素解析ができるようにする

$ sudo ipython -m pip install mecab-python3

これでClient側のWindowsからwebブラウザ等でjupyter notebookが利用可能です。

例でスクリーンショットを載せます。
f:id:catindog:20170319214656p:plain

図10. jupyter notebook上で最新の形態素解析ができました

6. XGBoostの導入

 自分はlibsvm形式で直接xgboostのバイナリに放り込むことが多いのですが、やりかは何でもいいと思います。

$ git clone --recursive https://github.com/dmlc/xgboost
$ cd xgboost
$ make -j4
$ sudo ln -s /home/{yourname}/xgboost/xgboost /usr/local/bin/xgboost

サンプルのアガリクスの有効判定みたいなのをときます。

$ cd demo/binary_classification
$ python mapfeat.py
$ python mknfold.py agaricus.txt 1
$ xgboost mushroom.conf

いろいろ入れられそうですが、この辺にしておきます。
再度になりますが、自分はQiitaとか見てて結構ハマって、よくわかんないなぁとか思っていたのですが、公式ドキュメントで解決することが多かったです。私の今回の方法も、ひと月後には通用しないものになっているかもしれません。
公式ドキュメントを正しく理解することが一番の近道かもしれません。
(何か間違い等がありましたら、ツイッターでお知らせいただけると幸いです。)

alternative illustration2vec(高次元タグ予想器)について

alternative illustration2vec(高次元タグ予想器)について

f:id:catindog:20170311231233p:plain

図1. 予想結果のサンプル

はじめに

今回はillustration2vecを去年10月に知り、実装法を模索していたが、Kerasでの転移学習と、目的関数を調整することで同様の結果が得られるのではないかという仮説に基づいて、検証実験を行った。

illustration2vecのような画像のベクトル化技術に関してはアプローチは複数用意されており、どのような方法がデファクトかつ、もっとも精度が良いのかわかっていない。

以下、私が考えた3つの方法を記す。

  • 1. VGG16などの学習済みモデルの出力部分のみを独自ネットワークの入力にすることで、タグ予想問題に切り替える
  • 2. 上記のアプローチをとるが、入力に途中のネットワークのレイヤのベクトルも入力に加える
  • 3. キャラクタ判別問題などにタスクを切り替えて、タスク完了後ネットワークを学習させないようにフリーズして、途中のレイヤの出力、ボトルネック層の出力などを素性にしたlogistic regressionにて学習する

f:id:catindog:20170311231843p:plain

図2. 今回用いた転移学習の例

1,2は転移学習とよばれる学習済みのモデルを利用して再度学習する方法であるが、ネットワークの出力に近い部分を取り外して任意のネットワークに置換することで別の問題をとくことが可能になる。
この時、よく調整された評価用のVGG16やResNetなどは卓越した特徴量抽出機能を備えている。下手に独自の学習で悪影響を及ぼすより、フリーズと呼ばれる学習を反映しない状態に変換して特徴量抽出器のような使い方をすることができる。

タグの確率表現としての妥当性や多数でのパラメータでの多様性を考えると3が最も良いように見える。これはディープラーニングと既存の実績のある判別問題のアプローチを合成したハイブリットなアプローチである。

先行研究

オリジナルペーパ、やってる概要はつかめたのだが、学習用の実装が見当たらず、妄想であれこれいけるんじゃないかと検証していた

タグ予想という名前でプロダクトを出しており、githubで中間層のデータを参照するようなコードの断片を見つけて、自分の考えがそんなに間違いでないことを知る
なお、400次元に出力を限定しているがGPUのメモリを考えれば5000次元ぐらい行けるのになぜ?

実験

  • GPUの性能の関係でVGG16を改造することに決定
  • 1,2のアプローチの後、性能が出なければ、3のアプローチを導入(1がうまく行ったため行っていない)
  • http://danbooru.donmai.us/ というサイトから、scraperを回して画像とタグ情報を139万枚取得。評価者に馴染み深いドメインである必要があったため、艦これのタグが入っているものを優先。
  • オプショナルな情報として、アダルトスコアも習得
  • 学習時間の関係から5万枚を学習に使用した
  • VGG16を用いるため、150*150*3の画像が入力となる
  • 出力次元には特に制限を設ける必要性を感じなかったために4096次元にした
  • 多くの例ではVGG16の15層までをフリーズするが、性能試験を行ったところ、12層ぐらいのフリーズの方が今回のタスクでは性能が向上した
  • Dropoutは性能が改悪することがあったため、BN(BatchNormalization)で対応した
  • Activation関数に関しては、linearで出力した後Sigmoidをかけている(意味ない可能性ある)
  • 評価関数はbinary_crossentropyを用いている
  • optimizerはadam
  • 評価いはニコニコ静画の画像をもって行うものとする(学習データに含まれていない必要があるため、最新の投稿を用いる)

ネットワーク

  • (2に関して結果から言うと、どうしてもロス率の下がりが悪く、計算リソースの関係で諦めた)
  • 1のネットワークに関しての図は、図2を用いた。
  • Kerasでのモデル定義のコードを記す
def build_model():
  input_tensor = Input(shape=(150, 150, 3))
  vgg16_model = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
  dense  = Flatten()( \
             Dense(2048, activation='relu')( \
               BN()( \
                 vgg16_model.layers[-1].output ) ) )
  result = Activation('sigmoid')(\
             Activation('linear')( \
               Dense(4096)(\
                 dense) ) )
  model = Model(input=vgg16_model.input, output=result)
  for i in range(len(model.layers)):
    print(i, model.layers[i])
  for layer in model.layers[:12]: # default 15
    layer.trainable = False
  model.compile(loss='binary_crossentropy', optimizer='adam')
  return model

結果

良い結果になった。
以下に三つの例を載せる。
(画像の著作権ニコニコ静画及び絵を書いた人に帰属します)

f:id:catindog:20170311232415p:plain

図3.複数人数を把握することも可能

f:id:catindog:20170311232526p:plain

図4.楽器などの特殊な状況に対応できるか不安だったが正しく認識しているようだ

f:id:catindog:20170311232631p:plain

図5.トップに載せいている電ちゃんと同一(電ちゃんかわいい)

コード

今回は試行錯誤がたくさんあり、コードに微調整の後が大量に見て取れるかもしれない。赦してほしい。
github.com
git cloneする。

git clone https://github.com/GINK03/alt-i2v

画像のデータが必要な方はスクレイピング
(通信速度と頻度に関しては十分注意してください)
bautfulsoupとよばれるモジュールが必要です。

python3 danbooru_datasetgenerator.py --mode=scrape

ダウンロードが完了したら、タグ情報の前処理

python3 alt_i2v.py --maeshori 

高速に画像を処理するために、画像をベクトル化してKVSに格納する
numpy, pillow, msgpack, msgpack-numpy, plyvel+leveldbが必要です

python3 alt_i2v.py --build

トレイン

python3 alt_i2v.py --train

タグ情報を予想してみる

python3 alt_i2v.py --pred foojpg bar.jpg

結論

  • タグの予想は意外と簡単にできるし、精度も悪くない。
  • 今回作成したネットワークを用いることで類似画像検索や、その画像が何を示しているのかを概念的に把握することができる。これはSingle Shot DetectionやYolo V2とは異なったアプローチで状況の把握が可能になることを示している
  • 別に400次元に出力を限定する意味を感じなかったが正しかったようだ。RNNやってれば10000次元に到達することなんてザラだし。

謝辞

- 小林さんちのメイドラゴンのED 「イシュカン・コミュニケーション
「なんでルールはきゅうくつ?胸がしまっちゃうね、下等で愚かな価値観。だめって決定する、倫理なんていりませんよ」の流れ最高ですね。