単語ベクトルを2値ベクトル化

背景

以前、アトラクタ的なダイナミクスをもったニューラルネットワークで、単語の連想記憶を試した。 blog.hassaku-labs.com

この時点では、単語ベクトルをニューラルネットワークに入力する際、単にランダム行列射影を通して、次元数の調整をしただけで、連想記憶するベクトル情報自体は、連続値分散表現パターンのままであった。

しかしながら、シグモイド的な発火パターンを特徴としたニューラルネットワークの特性上、2値ベクトルの方が好ましい。

そこで、既存単語ベクトルを2値化する仕組みを探していたところ、手軽に出来そうな方法を見つけたので記録しておく。

word2bitsによる単語ベクトルの2値化

用いたのはword2bitsという手法。元々は、量子化によるデータのサイズ削減を目的としたものだが、類似度タスクでは性能が向上したとのことなので、連想記憶用の表現としても適していると思われる。

word2bitsについて、日本語で参考になりそうな記事はこちら。 medium.com

既存日本語単語ベクトルの変換

とりあえず検証用なので、比較的小さめの日本語単語ベクトルを用意すべく、こちらを利用させて頂きました。

github.com

$ wget https://s3-ap-northeast-1.amazonaws.com/dev.tech-sketch.jp/chakki/public/ja.text8.zip
$ unzip ja.text8.zip
$ wc ja.text8
       0  16900730 100000347 ja.text8
$ ls -lh ja.text8
-rw-r--r-- 1 imt adm 96M 10月  4  2017 ja.text8
(「権限 が ある こと も 認め て いる 。」のような分かち書きされた文章が、連結された1行で存在している)

word2bitsによる量子化を実行する。とりあえず次元数は200。

$ git clone https://github.com/agnusmaximus/Word2Bits.git
$ cd Word2Bits
$ ./word2bits -bitlevel 1 -size 200 -window 8 -negative 24 -threads 4 -iter 5 -min-count 5 -train ja.text8 -output 1b200d_vectors_ja -binary 1

検証

pythonから読み込んで、確認してみる。

$ ptpython
>>> from gensim.models import KeyedVectors
>>> wv_from_bin = KeyedVectors.load_word2vec_format("1b200d_vectors_ja", binary=True)
>>> wv_from_bin["サッカー"].shape
(200,)
>>> wv_from_bin["サッカー"]
array([ 0.33333334, -0.33333334,  0.33333334, -0.33333334,  0.33333334,
       0.33333334, -0.33333334, -0.33333334,  0.33333334,  0.33333334,
...
>>> wv_from_bin.most_similar_cosmul("サッカー", topn=10)
[('バスケットボール', 0.9099991321563721), ('選手', 0.8699991703033447), ('アメリカンフットボール', 0.8649991750717163), ('クラブ', 0.8649991750717163), ('バレーボール', 0.8599991798400879), ('ディフェン>ダー', 0.839999258518219), ('フットボール', 0.839999258518219), ('ポジション', 0.8349992632865906), ('ラグビー', 0.8349992632865906), ('ミッドフィールダー', 0.8299992680549622)]
>>> sum(wv_from_bin["サッカー"] > 0)
102
>>> sum(wv_from_bin["サッカー"] < 0)
98

0.3と-0.3が半々の2値ベクトルが用意できた。

さいごに

以前構築した単語の連想記憶モデルに、今回の2値ベクトルを取り入れて、再度色々試してみたい。おそらく、パターン間の距離に応じた、アトラクタの引き込みとかは、より適切になるはずだと思われる。