この記事は第2のドワンゴ Advent Calendar 2015の24日目の記事です。
ドワンゴエンジニアの@ixixiです。
niconicoのデータをDeep Learningなアプローチで解析してみた話です。
nico-opendata
niconicoの学術目的用データ公開サイト https://nico-opendata.jp が最近オープンしました。
これまでも、国立情報学研究所にて、ニコニコ動画コメントデータや大百科データが公開されていましたが、 nico-opendataでは、ニコニコ静画のイラストデータの約40万枚のイラストとメタデータが研究者向けにデータ提供されています。
今回は、ニコニコ動画コメントデータ(誰でも取得可能)を用いたDeep Learningによるコメント解析例を紹介します。
超自然言語
ニコニコのコメントデータに限らず、twitterでのtweetやなど、Web上の言葉は非常に自由な表現が行われており、このことが文の解釈を阻む課題となっています。
通常の文章に比べ、例えば、以下のような表現は、意味の解析を難しくしています。
- 絶叫表現 - 「こなああああああゆきいいいいいい」「きたああああ」「SUGEEEEEEE」
- 顔文字 - 「(´・ω・`)ショボーン」「(゚∀゚)ラヴィ!!」「人生オワタ\(^o^)/」「囧」
- 話し言葉表現 - 「くっさ」「〜じゃね?」「やっべぇ!」
- 書き言葉ではない言い回し - 「マジキチwww」「みえ」「●REC」「おまwww」
- 特殊な擬音語・擬態語 - 「8888888」
- 略称 - 「ksk」「wktk」「NKT」「NDK」「乙」「今北産業」「〜な希ガス」
- サービス固有表現 - 「わこつ」「こうこつ」「うぽつ」「えんちょつ」「tmt」「184」「んc」
- 通常とは異なる意味 - 「※」「馬鹿なの?死ぬの?」「わろすわろす(「わろすわろす」と「わろす」ではニュアンスがかなり異なる)」
- テンプレート文法 -「なんでや!●●関係ないやろ!」「 あぁ^~●●が△△するんじゃぁ^~」「一体何◯なんだ...」
- 末尾()による意味の追加 - 「なんで・・・(泣」「美味しい(白目」
- 装飾 - 「こ れ は 酷 い(スペース区切り)」「\中村屋!/」
辞書ベースの処理では、基本的に「文章中の単語は全て辞書にある(それ以外は全て一律未知語)」ということが前提になっているため、上記のようなコメントは、そもそも文を適切に分解することは難しいと考えられます。
特に、テンプレート的表現や装飾表現を、正しく認識して扱うことはとても難しいものです。正規化にも限界があります。
辞書に頼らないアプローチとしては、N-gram(「ある文書中、N個の文字列の組み合わせがどの程度出現するかを素性とするモデル」)であれば、未知語は関係ありませんが、例えばスペース区切り装飾では全く別の素性となってしまい、人間が行っているような、文法構造を認識して構文解析を行い、そこから意味を取るというアプローチとはかけ離れています。
LSTMによるコメント解析
このような崩れた言葉について、どのようなアプローチで学習するのが良いでしょうか。
文全体でのマクロな特徴ではなく、文頭から文字単位で読んでいって、系列情報を扱えるモデルでコメントの意味を把握させてみたいと思います。
その為に、LSTMという、系列情報を学習可能なモデルを使って学習を行うこととします。
LSTMについては、「わかるLSTM ~ 最近の動向と共に」の記事が非常に詳しく、お薦めです。
タスク1: コメント次文字予測・自動生成
コメントの意味が取れていれば、途中までのコメントが与えられたとき、その後に続く文字をある程度予測出来るはずです。
これが出来るか試してみましょう。
つまり、「n文字目まで与えられた時に、n+1文字目を予測する」ことがタスクです。
辞書は一切使わず。キャラクタ(文字)べースで行います。
データセット
国立情報学研究所の情報学研究データリポジトリで公開されているコメントを利用します。
マエショリ
公開されている24億コメントをすべて学習させる必要は無さそうに思ったため、学習するコメントを以下のように抽出しました。
- 各動画の最後の10コメントを抽出
- その内、500万コメントをランダムサンプリング
- コメントをNFKC正規化し、末尾の同一文字繰り返しを2文字までに丸める(「テラワロスwwwwww」→「テラワロスww」)
- 当該コメント群から利用される文字をカウントし、利用上位5000文字を語彙とする
- 上位5000文字以外の文字を含むコメントは除外(ほとんど無い)
1について、各動画最初の10コメントではなく、最後の10コメントを対象にしたのは、最初のコメントは「1ゲット」とか「うp乙」などの特定のコメントが入る傾向が高くなるためです。また、純粋なランダムサンプリングでコメントを集めると、コメント量が膨大な特定の動画に学習が引っ張られるため、ニコニコ内での一般的な語彙を学習するにはあまり向いていないと判断したためです。(尚、コメントランキング一位の動画のコメント数は、1動画で3000万コメント超です)
3の繰り返し正規化は、次文字予測するにあたり、これを行わない場合、「"w"が来たら次の文字も"w"だ」と予測するだけで容易に正解率が上がるためです。
結果
GPUマシンで数日回したところ、次のような結果となりました。(線の色はモデルのパラメタが微妙に違うパターンです)
次の文字を40%程度当てることが出来ています。
これは、「何も無い状態からの1文字目」の予測と、「コメント終了」も含んでいます。
(ちなみに、先ほどの繰り返し正規化を行わない場合は、正解率は50%を超えます。)
コメント自動生成
次の文字の予測が出来るということは、それを利用して次々とコメントの続きが作れるはずです。
実際にやってみましょう。
入力 | 生成結果 |
---|---|
┗(^ | ┗(^o^ )┓三 |
日本語 | 日本語でおk |
/hi | /hidden |
おっく | おっくせんまん!おっくせんまん! |
らんら | らんらんるー |
ξ*・ |
ξ*・ヮ・* |
わっふ | わっふるわっふる |
かわい | かわいいww |
面白い結果としては、一個置きスペースや、カッコ対応もちゃんと学習しています。
入力 | 生成結果 |
---|---|
「は | 「はぁ?」 |
こ れ は | こ れ は ひ ど い |
(((( | (((((* ´ Д `*)))))(´Д`)( * ´д`) |
犯人は | 犯人はヤス |
直前の文字だけでなく、意味に合わせて生成していることを確認するため、「〜の」から始まるコメントを抽出して、「〜の」以降を生成してみます。
入力 | 生成結果 |
---|---|
この | この曲好きだ |
あの | あのさぁ・・ |
なんだこの | なんだこの画質 |
今の | 今のはなんだったんだw |
ミクの | ミクの声が聴こえる |
謎の | 謎の感動 |
ゲームの | ゲームの音が聞こえない |
他の | 他の人の動画でもみたいな |
うp主の | うp主の声好きだなぁ |
どうやら「の」の前までの文の意味がちゃんと取れているようです。
各「〜の」について、出力層(5002次元)の出力について、PCAで2次元に落として拡大してみると、例えば、以下のようなクラスタが存在していました。
「中国の」「日本の」が固まっていて「(国)の」という概念が固まっていたり、「当時の」「今日の」「今年の」「次の」などの「(時間)の」の概念が固まってたりします。
また、「(体の一部)の」や「(音/声)の」なども、次に繋がる文字が近い、ということが分かります。
タスク2: コメントからの動画カテゴリ予測
現在、niconicoの動画は30カテゴリあります。
(音楽 / 歌ってみた /ゲーム / アニメ / VOCALOID / 東方 / その他 / エンターテイメント /
演奏してみた / ラジオ / アイドルマスター / ニコニコインディーズ / スポーツ /
描いてみた / ニコニコ動画講座 / 料理 / R-18 / 動物 / 政治 / 科学 / 日記 / 例のアレ /
ニコニコ技術部 / 旅行 / 自然 / 作ってみた / 歴史 / 踊ってみた / ニコニコ手芸部 / 車載動画)
タスクは「1コメント与えられた時、そのコメントは何のカテゴリの動画なのか」を当てる、というタスクです。
学習セット例
以下のようなデータセットについて、本文カッコ内が正解ラベルです。
草コメント(「ww」)のようなコメントについては、それだけではカテゴリを識別することは難しく、このタスクは、人間でも相当な難易度のタスクです。
相当に熟練した人間でも精々20%程度しか正解出来ないタスクではないかと思います(筆者は、15%程度の正解率でした)。
アプローチ
タスク1の次文字予測で行ったモデルは、そのままではカテゴリ予測は使えないのですが、内部では文法構造や語彙の学習が出来ていると考えられ、これを利用することは価値がありそうです。
そのため、以下の4つのパターンで実験を行ってみました。
- 次文字予測モデルと同じ構造でゼロから学習するパターン
- 次文字予測学習済みモデルの出力層のみ付け替えて学習するパターン
- 次文字予測モデルに層を追加した構造でゼロから学習するパターン
- 次文字予測学習済みモデルに層を追加して学習したパターン
結果
何通りか試してみたのですが、結果としては「次文字予測学習済みモデルに層を追加して学習したパターン」が最も精度が高く、18%程度の正答率が出るようになりました。
可視化
出力層からの出力(30次元)をt-SNEで可視化すると、以下のようになります。
各コメントの色が、そのコメントが付いている動画のカテゴリです。
(見やすさのため、9カテゴリのコメントのみにしています)
パッと見ただけでも、色が固まっていそうに見えるかと思います。
どうやら、上手く意味が(カテゴリ分類に必要なレベルで)取れているようです。
類似コメントサジェスト
先ほど学習したコメントカテゴリ識別器は、出力層の一つ前の層を取り出すと、(カテゴリ識別に必要な)コメントの意味を表現する特徴量となっているとも解釈できます。
ということは、近傍探索を行うことで、意味的に類似したコメントを探すことが出来たり、コメントとコメントの間の意味的な距離のようなものも定義出来そうです。
アーキテクチャ
この仕組みは簡単にアプリケーションにすることが出来て、Jubatusというオンライン分類器を使えば、コメントの特徴量をID付きで投げてあげると、LSHやminhashなどの近似最近傍探索で、格納済みのコメントの内、特徴量が近いコメントを取得することが出来ます。Jubarecommenderを利用しました。
今回は、事前に一括でニコニコデータセットのコメントデータの特徴量をJubatusに格納しておきます。今回は行いませんが、この仕組みだと、Jubatusもオンラインで候補追加出来ますし、Chainerもオンラインで追加で学習出来るので、リアルタイム学習という面で面白いかも知れません。(学習率調整をどうするかという課題はあると思いますが。)
サジェスト例
上の白い入力フォームが入力コメント、下の「近傍投稿」が、類似しているコメントです。
「可愛いなぁ」という入力に対して、「かーわーいーいー」や「かぁわいい」「かわいい^^」「かわいすぎるううううううう>w<」「かわゆす」等と似たような特徴を持つコメントになりました。
「お疲れ様」と「乙」が同じ特徴を持つことが分かります。
「どうしてこうなった」≒「!?」
「勉強になるなぁ」≒「ほぅ」「へ〜」「fmfm」
ニコニコのコメント解析まとめ
LSTMのキャラクタベースのアプローチでは、辞書を一切使わずに、カテゴリラベルを教師データにするだけで、コメントの意味をある程度学習することができ、識別にも類似検索にも適用出来ることが分かりました。
カテゴリタグは高々30個しか無い荒い粒度ですが、主要タグレベルで学習させれば、更に細かい意味の学習が可能になると思います。
特に、類似コメントのサジェストについては、「お疲れ様です」と「乙」、「勉強になるな」と「fmfm」のような、利用している文字も全く違う、表面的には全く異なるコメントについて、意味として近いものをサジェスト出来るのは面白いと思います。
より細やかなコメント解析に向けて
以下記載する内容は、まだ実験中ですが、より細かく意味を学習するアプローチのアイデアについて述べます。
投稿コメント特徴の動画内における局所性
先ほど、カテゴリではなく、タグを使うともっと細かい意味の学習が出来るのではないかと書きましたが、更に言えば、タグ化されないレベルの細かい情報があるはずです。
一つの動画の中でも、シーンに応じて、持っているコンテクストが違い、付いているコメントの特徴が違うはずです。
「コメント特徴の動画内に局所性が存在する(同一内容のコメントは同一箇所近辺に投稿される)」ということは自然に仮定できそうです。
以下の動画では、「かわいい」という意味の言葉が局所的に発生していることが分かります。
動画内コメント位置からのコメント特徴の学習
この局所性から、コメントの意味を学習することを考えます。「意味的の距離がそのまま特徴量間の距離となる特徴量」を出力するネットワークを目指します。
F(c_1)は、このネットワークにコメントc_1を入れた時のk次元ベクトル(コメントの意味を表す特徴量)を表すものとします。
二つのコメント(c_1,c_2)があった時、その意味の近さが、特徴量ベクトルの距離 distance(F(c_1),F(c_2))として表現されるなら、その特徴量空間は、近傍探索などで有用な特徴量が抽出されるだろうと考えます。
出力される特徴量としては、以下の性質を期待します。
- c_1とc_2が同じタイムウィンドウ内のコメントであれば、意味的に同じコメントだろうから、コメント特徴量間の距離は近くなって欲しい。
- c_1とc_2が同じ動画でタイムウィンドウ外のコメントであれば、コメント特徴量間距離はある程度(α以上)離れて欲しい。
- c_1とc_2が別動画のコメントであれば、コメント特徴量間距離はある程度(β以上)離れて欲しい。
- 0<α<β
これを素直にloss functionとして実装すると、次のようになります。
- c1はc2は同一動画であり、c1の動画内位置近辺にc2がいるなら、
distance(F(c_1),F(c_2))
がloss。
- c1はc2は同一動画だが、c1の動画内位置近辺にc2がいないなら、
max(α-(F(c_1),F(c_2),0)
がloss。 - c1とc2が別動画なら
max(β-(F(c_1),F(c_2),0)
がloss
loss functionとしては、chainer v1.5から入ったcontrastive lossが使えそうですので、こちらを適用出来そうです(このFunctionを使わなくてもVariableのまま同等の処理は書けますが)。
この手法での実験結果がまとまったら、またどこかで記事にしようかなと思います。
[おまけ] contrative lossと相対関係の学習について(一般的な話)
contrastive lossは、y_nが1(同じクラス)ならベクトル間の距離がlossとなり、0(違うクラス)なら、指定したマージンより近かった分の距離がloss(マージン以上離れていたらlossは0)となります。つまり、「同じクラスなら出来るだけ固め、違うクラスならマージン分以上離れる」ように最適化されます。
このloss functionは以下のようになっています。
L = \frac{1}{2N} \left( \sum_{n=1}^N y_n d_n^2
+ (1 - y_n) \max ({\rm margin} - d_n, 0)^2 \right)
一般に、Nクラス分類の問題では、出力層をN次元にして、これにsoftmax_cross_entropyを適用して、入力に対して「どのクラスに一番近いか」を予測出来るように学習します。これは、最初にクラス数が分かっていることが前提のモデルです。
相対関係の学習ではクラス数は関係ありません。「(画像A,画像B)は同じ種類」「(画像C,画像D)は別の種類」のような形の、相対的な関係の情報だけで学習が進むので、最初に全体のクラス数を知っていない場合でも対応が出来るわけです。
ところで、一般的なNクラス識別から特徴を取り出す場合、その出力N次元、あるいはその前の層を特徴量とすることが多いです。例えば、画像分類でよく使われるVGGモデルでは、出力層直前は4096次元のベクトルとなり、これを特徴量とすることが多いと思います。
ただ、4096次元をt-SNEで2次元に落として可視化したものを見ても、かなり綺麗にクラスが分かれており、低次元でも、多次元の特徴を表現することは十分出来そうだと感じます。
なので、特徴量の出力層は低次元にして、その空間での距離を学習してみることにします。
例1 : MNISTでの例
ネットワークの最終出力層を2次元として「クラスが同じものを入力した場合、出力層の2次元ベクトルの距離が出来るだけ近くなるように、また、クラスが違うものを入れたら距離が1以上違う2次元ベクトルが出力される」ように学習させると、出力されるベクトルは次のようになります(2次元の出力なので、PCAやt-SNEは掛けずに出力そのままです)。
クラスのラベルを与えずに、与えられたペアが同じか違うかという情報だけで綺麗にクラス識別が出来ており、各クラス間の距離は10(クラス間のマージンとして設定した値)となっていることが分かります。
例2 : CIFAR-10での例
定番のCIFAR-10 datasetでもやってみましょう。
これは、10種類(airplane/automobile/bird/cat/deer/dog/frog/horse/ship/truck)の写真がそれぞれラベル付きで6000枚づつ入っているデータセットです。
クラス(airplane/automobile/...)より広いカテゴリ(動物/乗り物)についても同様にcontrastive lossを適用し、クラスのcontrastive lossと足してoptimizeしているため、カテゴリも分離されます。
階層的な関係も含めて、相対的な情報から良い感じに特徴空間を作れます。
尚、この手法を使う場合、単純にランダムにペアを集めるとペアの組のほとんどが別クラスのものになってしまうので、ここはそれぞれバランスよく学習データのペアを作る必要があります。
#おわりに
クリスマス、くりすます、くりす、ます。
Steins;Gateの「紅莉栖」が思い浮かぶ方もいらっしゃるのではないでしょうか。
ドワンゴでは、「紅莉栖」という名前の、数十台のTitan X4枚挿しノード群があります(内2台はメモリ1TB)。
ドワンゴでは、この紅莉栖の環境を使って、コメント解析に限らず、イラストの解析なども行っています。
例えば、https://nico-opendata.jp に掲載している、画像からの閲覧数・お気に入り数予測の実験は紅莉栖上で行われました。
コメントの解析に関しては、今年、ChainerでLSTMのモデルのコメント解析エンジンがniconicoのサービスの一部で本番導入されています。(本番環境はTesla GPUマシンです。)
今年はDeep Learningの年だったと言ってもよいぐらい、このワードを聞くことが増えた年だと思います。
「その後のシステム組み込みや運用を考えると、Deep Learning以外の手法の方が良くないか?」というようなケースも実際には多くありますが、ハマるところにハマればやはり強烈な効果が確かに出ます。
「機械学習の技術的負債」はとても大きいので、適切に目的を設定して、業務に合う適切なアルゴリズムを選び、適切にモデリングをして、適切に前処理を行って、適切にシステムに組み込み、適切に運用すること(とてもむずかしい)を強く意識しつつ、これからのサービスへの適用を考えていきたいと強く思った一年でした。
明日は25日、最後は @pocketberserkerさんです。