catch-img

自然言語処理の精度を向上させた”単語のベクトル表現”とは?簡単に実装してみた

レコメンドシステムで使われている”単語のベクトル表現”

Googleの開発者向けイベント「Google I/O 2017」内のマシンラーニング展示ブースで"Candy Sorter"というロボットが注目されました。 このロボットは、欲しいお菓子を言うとテーブルに並べられたお菓子から適当なものを取ってくれます。 そのデモを紹介しているビデオがあるのでご参照ください。(Candy Sorterは2:40辺りからです) www.youtube.com

人間が欲しいものを言ってから、ロボットが取ってきてくれるまでの流れは、ざっくり図で説明すると f:id:diaki-hk:20170627103710p:plain こんな感じです。 この図での、“〇〇の特徴を表すベクトル”が単語のベクトル表現であり、正式には“分散表現”と呼ばれるものです。

分散表現(あるいは単語埋め込み)とは、単語を高次元の実数ベクトルで表現する技術です。 岩波データサイエンス

高次元の実数ベクトルと言われてもピンと来ないですよね。これは実は難しいことではなく、

単語
大きさ
甘さ
黄色さ
りんご
0.23
0.42
0.02
バナナ
0.21
0.73
0.94
0.89
0.04
0.10

のように、単語を複数の特徴と数字で表現したものです。高次元なので、この特徴の項目を200個~300個にして表現します。 GoogleのTensorFlow、FacebookのFastTextというライブラリはディープラーニングを用いてテキストデータから分散表現されたモデルを獲得します。 Embedding Projector を見るとすごくイメージしやすいです。 このサービスはGoogleが提供しているもので、分散表現が3Dまたは2Dで可視化されたサービスです。これを用いて例えば"Japan"と入力すると f:id:diaki-hk:20170626174122p:plain (見づらいのでご了承ください…) “korea”,“chainese"とともに"manga"や"sony"といった日本に関連の深い単語が表示されます。"manga"と"anime"はとても近いことがわかります。 面白い技術です。これは使ってみたい!ということで

Pythonを使って"類似度が高い"単語を返してくるWebAPIを作ってみた

まず、単語を分散表現するモデルを作ります。このためにやることは、 ・ 学習に使用するテキストデータを取ってくる ↓ ・形態素解析をする ↓ ・単語の分散表現されたモデルを得る という感じです。 筆者の環境はmacOS , Python 3.6.1です。

まず、単語の形態素解析をしてくれるmecabというライブラリをインストールします MeCabをMacにインストールする手順 - Qiita を参考にしました。

$ ./bin/install-mecab-ipadic-neologd -n

を実行するときに管理者権限でないといけなかったので注意です。 次に、学習に使うテキストデータをWikipediaのダンプhttps://dumps.wikimedia.org/jawiki/latest/ からダウンロードします。 容量が大きくてダウンロードが完了するまで30分ほどかかりました… 次に、ダンプから整形されたテキストデータを作成してくれる wikiextractor をクローンします。

git clone https://github.com/attardi/wikiextractor
python wikiextractor/WikiExtractor.py -b 500M -o 出力先フォルダのパス ダンプデータのパス

これを実行すると、ダンプから一文ごとに改行されたテキストファイルが出力先フォルダのパスに作成されます。しばらくするとmacがうなり声をあげ始め発熱してきたのでctrl-Cで中断しました。 MacBookWikipediaの全ページのテキストをデータ整形するのは辛いことが判明しました。 そこで、自分でモデルを作ることはとりあえず諦めて qiita.com

こちらで公開されているモデルをダウンロードしました。Hironsanさんありがとうございます。NEologdと後ろに付いているものは新しい形態素解析アルゴリズムを使っていて、その方が性能がいいと思ったので そちらを選択しました。

今回はFlaskというウェブアプリケーション用のフレームワークと、gensimというベクトルモデルを扱うライブラリを使用しました。 普段Pythonは書かないので至らないコードですが、できるだけシンプルに書きました。 必要なライブラリをインストールルします。

$ pip install flask
$ pip install gensim

server.py

from flask import Flask, jsonify, request
import gensim

app = Flask(__name__)

# モデルをインポート
model = gensim.models.KeyedVectors.load_word2vec_format('model.vec', binary=False)

# ルーティング
@app.route('/word/<name>')
def word(name):
# 類似度が高い単語を10個持ってくる
    similar = model.most_similar(positive=[name])
    result = {
        "word": name,
        "similarWords": similar
    }
# json形式で返す
    return jsonify(ResultSet=result)

if __name__ == '__main__':
    app.run(debug=True)


として

$ python server.py

でサーバーを起動。 chromehttp://localhost:5000/word/EXILEとアクセスすると f:id:diaki-hk:20170626175053p:plainEXILE"と関連度が高いワードが返ってきました! TRIBE,ATSUSHI,SHOKICHI,E-girls,TAKAHIRO,MAKIDAI,CHEMISTRY などですね、一番上は"EXILE\u9b42"となってますがunicodeで"EXILE魂"となります。エンコード周りの処理は今回省略します。

ベクトルモデルなので model.most_similar(positive=[name],negative=[name2]) という形で、意味の足し引きも可能です。例えば、 ダウンタウン - 関西 + 関東 = とんねるず というような演算が可能になります。 “日本のメッシ"などよく言われる表現ですが、機械が本当の日本のメッシを決めてくれるかもしれません。 他にも外積など、色々な演算を組み合わせてどういう結果になるか見ていくと面白そうですね。

まとめ

学習されたモデルさえ手に入れれば(それが一番大変なのですが…)最新の自然言語処理で使われている技術を簡単に実装することができました。 今回はWikipediaで学習したモデルを使いましたが、2ちゃんねるで学習したモデルでは結果がかなり違っていたことでしょう。 ただデータ量を増やすだけではなく、作りたいサービスの内容を踏まえて、データの取捨選択をしていくことも考えなくてはなりませんね。

また、今回利用したモデルに使われたFastTextやGoogleのTensorFlowなどのライブラリは単語のベクトルモデルを作るだけです。そこからはベクトルという形で表現された単語を数学的にどう捉え、次の処理に繋げていくか、それがレコメンドシステムなどのサービスを作る上で重要なポイントになるでしょう。

サービス

    セキュリティー・ポリシー