Python と gensim で doc2vec を使う

【追記】
doc2vec のアルゴリズムについて別記事で紹介しています.合わせてご覧下さい.
doc2vec(Paragraph Vector) のアルゴリズム


こんばんは,吉田です.
本来の〆切は次の金曜日ですが,色々忙しくなる前にサクッと更新しておきたいと思います.

新宿祭でのポスター発表&卒論の中間提出に向けて,研究室内も慌ただしくなってきました.4年生にとっては初めての論文執筆ということで,今までとは違う緊張感が漂ってきています(このブログの最新の記事が先週の月曜日の私の記事という事からもお察し下さい).初めての論文は慣れないことばかりで大変だと思いますが,年明け以降の修羅場の為の経験値稼ぎだと思って頑張って欲しいです.

さて,今回は最近研究で使っている doc2vec について紹介したいと思います.名前からも分かるように,巷で話題の word2vec の親戚で,ニューラルネットワークで文書のベクトル表現を学習するぜっというやつです.私が研究で使った例としては,観光スポットへ投稿されたレビュー集合をそのスポットを表す文書として学習データに使い,doc2vec で各観光スポットを表す特徴ベクトルを生成したりしました.例えば,渋谷のハチ公像(のベクトル)とコサイン類似度が高い観光スポット(のベクトル)はこんな感じになります.

sim_hachikou

同じ渋谷の待ち合わせ場所として有名な「モヤイ像」や上野公園の「西郷隆盛像」,更に銅像とは全く関係ありませんが待ち合わせ場所として有名な「新宿アルタ」や「梅田BIGMAN」など,結構納得の行く結果が出てきます.パラメータをいじったり学習モデルを変更すると学習結果の傾向も変わるので,今後も色々いじくり倒していく予定です.

さて,そんなわけで今回はこの doc2vec を使うための学習コードを紹介しようと思います.今回は,doc2vec の実装として多分一番ポピュラーな Python の自然言語処理ライブラリ gensim を使った方法を紹介します.

# -*- coding: utf-8 -*-

from gensim.models.doc2vec import Doc2Vec
from gensim.models.doc2vec import TaggedDocument

# 空のリストを作成(学習データとなる各文書を格納)
training_docs = []

# 各文書を表すTaggedDocumentクラスのインスタンスを作成
# words:文書に含まれる単語のリスト(単語の重複あり)
# tags:文書の識別子(リストで指定.1つの文書に複数のタグを付与できる)
sent1 = TaggedDocument(words=['どーも', '谷口', 'です', 'よーし', 'やってく', 'ぞ'], tags=['d1'])
sent2 = TaggedDocument(words=['どーも', '谷口', 'です', 'よーし', 'がんばる', 'ぞ'], tags=['d2'])
sent3 = TaggedDocument(words=['YO', '!', 'DJ', '浅野', 'の', 'ラップ', '講座', 'DAZE', '!'], tags=['d3'])
sent4 = TaggedDocument(words=['YO', '!', 'DJ', '浅野', 'の', 'フリー', 'スタイル', 'ラップ', 'DAZE', '!'], tags=['d4'])

# 各TaggedDocumentをリストに格納
training_docs.append(sent1)
training_docs.append(sent2)
training_docs.append(sent3)
training_docs.append(sent4)

# 学習実行(パラメータを調整可能)
# documents:学習データ(TaggedDocumentのリスト)
# min_count=1:最低1回出現した単語を学習に使用する
# dm=0:学習モデル=DBOW(デフォルトはdm=1:学習モデル=DM)
model = Doc2Vec(documents=training_docs, min_count=1, dm=0)

# 学習したモデルを保存
model.save('doc2vec.model')

# 保存したモデルを読み込む場合
# model = Doc2Vec.load('doc2vec.model')

# ベクトル'd1'を表示(型はnumpy.ndarray)
# print(model.docvecs['d1'])

# 各文書と最も類似度が高い文書を表示(デフォルト値:10個)
print(model.docvecs.most_similar('d1'))
print(model.docvecs.most_similar('d2'))
print(model.docvecs.most_similar('d3'))
print(model.docvecs.most_similar('d4'))

こんな感じで,文書を単語区切りにした物が学習データとして必要になるので,日本語テキストに適応するためには先に形態素解析とかをする必要があります.Python で形態素解析する方法は北山先生が以前書いたブログとかにまとまってますので,必要な方はそちらもご参照下さい.あと,学習したベクトルの正体は numpy.ndarray なので,このベクトルを正規化したり内積計算自力でしたかったり色々したい人は numpy.ndarray で検索したら良いと思います.

さて,最後の4行で print した結果は↓のようになります

[('d2', 0.10112232714891434), ('d4', -0.08996276557445526), ('d3', -0.11141477525234222)]
[('d1', 0.10112231969833374), ('d4', -0.07863812148571014), ('d3', -0.10516232997179031)]
[('d4', 0.04875180125236511), ('d2', -0.10516232252120972), ('d1', -0.11141477525234222)]
[('d3', 0.04875180125236511), ('d2', -0.07863812148571014), ('d1', -0.08996276557445526)]

谷口っぽい文書 d1 と d2 同士,浅野っぽい文書 d3 と d4 同士のコサイン類似度がちゃんと高くなりました.学習モデルをデフォルトの dm=1 にしたらちょっと上手くいかなかったので,学習モデルによっても色々結果は変わるはずです(タスクによって最適な学習モデルは変わるっぽい).

ちなみに,gensim は内部で Cython やら numpy やらを駆使していて内部ではゴリゴリのC言語のコードが動いているので,Python とは思えないくらい爆速で動きます(ココらへんの黒魔術には一生関わらないで生きていきたい).

さて,そんな感じで gensim 使うと結構簡単に doc2vec 動かせるよっという記事でした.うちの研究室でもこれから doc2vec 使う予定の人が何人かいるので,後輩たちの参考になれば幸いです(ここに書いたからにはこの記事読んでから質問しろよおんどりゃぁ).

ではでは,今回はこの辺でー.

広告

Python と gensim で doc2vec を使う」への1件のフィードバック

  1. ピンバック: doc2vec(Paragraph Vector) のアルゴリズム | kitayama lab

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中