自然言語処理の深遠

Deep Dive Into Natural Language Processing

Pythonで日本語の文字分散表現を学習する

f:id:Hironsan:20171108110523p:plain:w500

最近の自然言語処理では、文字レベルの言語処理が行われることがあります。 これら文字レベルの言語処理は、ユーザ生成コンテンツに有効であると言われています。 その理由として、ユーザ生成コンテンツのような崩れたテキストでは、形態素解析の性能が大幅に低下し、単語レベルの処理が上手くいかなくなることが挙げられています。

文字レベルの言語処理を行うなら、単語レベルの場合と同じく文字分散表現を事前学習したくなります。 文字分散表現を事前学習しておくことで、①良い文字ベクトルの初期値を得られる、②学習データに現れない文字のベクトルを教師なしで得られる、といった恩恵を受けられます。

本記事では、日本語の文字に対して文字分散表現を学習してみます。 本文は次の2つの内容で構成されています。

  • 学習データの準備
  • 文字分散表現の学習

学習データの準備

まずは、文字分散表現の学習に用いるデータを用意します。 以前、以下の記事で単語分散表現を学習するためのコーパスを作成したことがありました。 今回は、そのコーパスを文字分散表現の学習用に変換して使うことにしましょう。

hironsan.hatenablog.com

はじめに、コーパスのダウンロードと解凍を行います。 wgetを用いてコーパスをダウンロードし、unzipでファイルを解凍しましょう。 ファイルを解凍すると、ja.text8という名前のコーパスが現れます。

$ wget https://s3-ap-northeast-1.amazonaws.com/dev.tech-sketch.jp/chakki/public/ja.text8.zip
$ unzip ja.text8.zip 

次に、単語単位で区切られているja.text8を文字単位に区切りましょう。 文字単位で空白に区切っておくことで、コーパスの読み込みが簡単にできるようになります。 以下のスクリプトを書いて、文字単位の区切りに変換しましょう。

with open('ja.text8') as f:
    text = f.read()

chars = [c for c in text if c != ' ']

with open('ja.char8', 'w') as f:
    f.write(' '.join(chars))

上記のスクリプトを実行することで、文字単位に区切られたコーパスja.char8が生成されます。 ja.char8の中身をみると、以下のように空白を区切り文字として、文字単位に区切られていることがわかります。

ち ょ ん 掛 け ( ち ょ ん が け 、 丁 斧 掛 け ・ 手 斧 掛 け と も 表 記 ) と は 、 相 撲 の 決 ま り 手 の ひ と つ で あ る 。 自 分 の 右 ( 左 ) 足 の 踵 を 相 手 の 右 ( 左 ) 足 の 踵 に 掛 \ け 、 後 方 に 捻 っ て 倒 す 技 。 ...

学習用のデータが用意できたので、文字分散表現を学習しましょう。

文字分散表現の学習

作成したコーパスgensimword2vecを使って文字分散表現を学習させてみます。 ja.char8と同じディレクトリで、以下のコードを実行して学習させましょう。 文字分散表現の学習は数分で終わるはずです。

import logging
from gensim.models import word2vec

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
 
sentences = word2vec.Text8Corpus('ja.char8')
model = word2vec.Word2Vec(sentences, size=50, window=50, workers=4)

今回はハイパーパラメータとして、文字分散表現の次元数を50、windowサイズを50にしています。 次元数が比較的低次元なのは、文字は単語と比べて語彙数が少ないため、次元数を大きくする必要がないからです。 また、windowサイズを広めに取ったのは、トピックの近い文字が空間上で近くなるように学習させる意図があります。

学習が終わったら、実際に試してみます。

>>> model.most_similar(["膝"])
[('肘', 0.835448145866394),
 ('腱', 0.7766674160957336),
 ('蹴', 0.7529205083847046),
 ('腕', 0.7077324986457825),
 ('靱', 0.7001078128814697),
 ('腰', 0.697993278503418),
 ('踵', 0.685279369354248),
 ('痛', 0.6709409952163696),
 ('折', 0.6706937551498413),
 ('肩', 0.6704100370407104)]
>>> model.most_similar(["猫"])
[('犬', 0.7227709293365479),
 ('羊', 0.6398827433586121),
 ('昔', 0.6368851661682129),
 ('妖', 0.6360131502151489),
 ('裸', 0.6287463903427124),
 ('匂', 0.6252028346061707),
 ('鳥', 0.6074063181877136),
 ('蛇', 0.6036850810050964),
 ('禽', 0.5951928496360779),
 ('猿', 0.5902674198150635)]

うん、意図したとおりトピックの近い文字が空間上で近くなるように学習されたようですね。

おわりに

本記事では日本語のコーパス(ja.text8)を用いて文字分散表現の学習を行いました。 学習の際、windowサイズを広く取ることで、トピックの近い文字が空間上で近くなることが確認できました。 本記事が皆様のお役に立てば幸いです。

私のTwitterアカウントでも機械学習自然言語処理に関する情報をつぶやいています。

@Hironsan

この分野にご興味のある方のフォローをお待ちしています。

参考資料